@nodesecure/mama
Version:
232 lines (166 loc) • 6.07 kB
Markdown
<p align="center"><h1 align="center">
/mama
</h1>
<p align="center">
Manifest Manager
</p>
## Requirements
- [Node.js](https://nodejs.org/en/) v24 or higher
## Getting Started
This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
```bash
$ npm i /mama
# or
$ yarn add /mama
```
## Usage example
```ts
import { ManifestManager } from "@nodesecure/mama";
const mama = await ManifestManager.fromPackageJSON(
process.cwd()
);
console.log(mama.document);
console.log(mama.integrity);
```
## Utils
This package exports a set of standalone utilities that are internally used by the ManifestManager class, but may also be useful independently for various tasks:
- [packageJSONIntegrityHash](./docs/packageJSONIntegrityHash.md)
- [parseNpmSpec](./docs/parseNpmSpec.md)
- [inspectModuleType](./docs/inspectModuleType.md)
- [scanLockFiles](./docs/scanLockFiles.md)
## ManifestManager API
### (static) fromPackageJSON(locationOrManifest: string | ManifestManager): Promise< ManifestManager >
Load a `ManifestManager` from a given location or return the instance if one is provided.
The **locationOrManifest** parameter can either be a `string` (representing a path) or a `ManifestManager` instance.
- If it is a `string`, it can either be a full path to a `package.json` or the path to the directory where one is located.
- If it is a `ManifestManager` instance, the method will return the instance directly.
> [!NOTE]
> When a `location` string is provided, it is automatically dispatched to the ManifestManager constructor options.
### (static) fromPackageJSONSync(locationOrManifest: string | ManifestManager): ManifestManager
Same as `fromPackageJSON` but using synchronous FS API.
### (static) isLocated<T>(mama: ManifestManager<T>): mama is LocatedManifestManager<T>
A TypeScript type guard to check if a `ManifestManager` instance has a location. This is particularly useful when working with manifests that may or may not have been loaded from the filesystem.
When the type guard is successful, the `location` property is available on the instance.
```ts
import { ManifestManager, type LocatedManifestManager } from "@nodesecure/mama";
import { expectType } from "tsd";
const locatedManifest = new ManifestManager(
{ name: "test", version: "1.0.0" },
{ location: "/tmp/path" }
);
if (ManifestManager.isLocated(locatedManifest)) {
// locatedManifest is now of type LocatedManifestManager
expectType<string>(locatedManifest.location);
}
```
### constructor(document: ManifestManagerDocument, options?: ManifestManagerOptions)
document is described by the following type:
```ts
import type {
PackumentVersion,
PackageJSON,
WorkspacesPackageJSON
} from "@nodesecure/npm-types";
type ManifestManagerDocument =
PackageJSON |
WorkspacesPackageJSON |
PackumentVersion;
```
And the `options` interface
```ts
export interface ManifestManagerOptions {
/**
* Optional absolute location (directory) to the manifest
*/
location?: string;
}
```
---
Default values are injected if they are not present in the document. This behavior is necessary for the correct operation of certain functions, such as integrity recovery.
```js
{
dependencies: {},
devDependencies: {},
scripts: {},
gypfile: false
}
```
> [!NOTE]
> document is deep cloned (there will no longer be any reference to the object supplied as an argument)
### getEntryFiles(): IterableIterator< string >
Deeply extract entry files from package `main` and Node.js `exports` fields.
### moduleType
Return the type of the module
```ts
type PackageModuleType = "dts" | "faux" | "dual" | "esm" | "cjs";
```
### spec
Return the NPM specification (which is the combinaison of `name`).
> [!CAUTION]
> This property may not be available for Workspaces (if 'name' or 'version' properties are missing, it will throw an error).
### integrity
Return an integrity hash (which is a **string**) of the following properties:
```js
{
name,
version,
dependencies,
license: license ?? "NONE",
scripts
}
```
If `dependencies` and `scripts` are missing, they are defaulted to an empty object `{}`
> [!CAUTION]
> This is not available for Workspaces
### author
Return the author parsed as a **Contact** (or `null` if the property is missing).
```ts
interface Contact {
email?: string;
url?: string;
name: string;
}
```
### dependencies and devDependencies
Return the (dev) dependencies as an Array (of string)
```json
{
"dependencies": {
"kleur": "1.0.0"
}
}
```
The above JSON will produce `["kleur"]`
### isWorkspace
Return true if `workspaces` property is present
> [!NOTE]
> Workspace are described by the interface `WorkspacesPackageJSON` (from /npm-types)
### location
A string representing the absolute path to the manifest file's directory, if it was provided in the constructor options. Otherwise, it is `undefined`.
```ts
const mama = new ManifestManager(
{ name: "test", version: "1.0.0" },
{ location: "/home/user/my-project/package.json" }
);
console.log(mama.location); //-> /home/user/my-project
```
### hasZeroSemver
Return true if `version` is starting with `0.x`
### flags
Since we've created this package for security purposes, the instance contains various flags indicating threats detected in the content:
- **isNative**: Contain an identified native package to build or provide N-API features like `node-gyp`.
- **hasUnsafeScripts**: Contain unsafe scripts like `install`, `preinstall`, `postinstall`...
```ts
import assert from "node:assert";
const mama = new ManifestManager({
name: "hello",
version: "1.0.0",
scripts: {
postinstall: "node malicious.js"
}
});
assert.ok(mama.flags.hasUnsafeScripts);
```
The flags property is sealed (It is not possible to extend the list of flags)
> [!IMPORTANT]
> Read more about unsafe scripts [here](https://www.nerdycode.com/prevent-npm-executing-scripts-security/)