@strangecyan/lastmile-modules
v0.1.0
Published
Internal: npm module resolution for Lastmile SDK builds. No semver guarantees; depend on @strangecyan/lastmile-check instead.
Readme
@strangecyan/lastmile-modules
Build-time npm dependency resolution for SDKs. Produces a serializable map of absolute
/node_modules/... paths to UTF-8 file contents for OverlayFS, without a filesystem dependency.
This package is source-first: its exports point to TypeScript and require no package build step.
SDK author API
SDK authors use the re-export from @strangecyan/lastmile-check:
import { modules } from '@strangecyan/lastmile-check';
const bundle = modules({ 'date-fns': '4.4.0' });Build the SDK with @strangecyan/lastmile-check/build. The builder resolves dependencies and replaces
the entire marker call with a plain { dependencies, files } object literal. The dependencies
preserve the direct requests (including ranges/tags), while files include transitive packages. No registry access, decompression,
semver, or resolver code belongs in the generated SDK runtime.
The runtime-only entry point @strangecyan/lastmile-modules exports exactly:
export type ModuleDependencies = Readonly<Record<string, string>>;
export type ModuleMap = Readonly<Record<string, string>>;
export interface ModuleBundle {
readonly dependencies: ModuleDependencies;
readonly files: ModuleMap;
}
export function modules(dependencies: ModuleDependencies, files?: ModuleMap): ModuleBundle;Without files, the marker throws an error explaining how to build the SDK. With files, it
returns { dependencies, files } synchronously, preserving both supplied records without fetching anything.
sdk() exposes these as sdk.dependencies and sdk.modules, respectively. For a standalone
built marker, use bundle.files to obtain the file map (previously the marker returned the map directly).
The old Modules class, preload(), and load() filesystem API have been removed.
Build-time resolver API
import { resolveModules } from '@strangecyan/lastmile-modules/resolve';
import type { ModuleMap } from '@strangecyan/lastmile-modules';
const files: ModuleMap = await resolveModules({ semver: '^7.7.0' });
// { '/node_modules/semver/package.json': '...', '/node_modules/semver/index.js': '...', ... }resolveModules(dependencies: ModuleDependencies): Promise<ModuleMap> is a separate,
Node-only entry point. It fetches metadata and gzip tarballs from the public npm registry
(and tarball URLs in that metadata), following ordinary dependencies transitively.
It supports exact versions, semver ranges, and published dist-tags such as latest or next.
* selects the highest matching stable version, not necessarily the latest tag.
Private registries/authentication, npm aliases, git, URL, workspace, and file specifiers are not supported.
Determinism and conflicts
- Root packages, dependency edges, and returned file keys are sorted lexically. For unchanged registry metadata/tarballs, input insertion order does not affect serialized output.
- Metadata, release selection, resolved releases, and tarball contents are cached per call. There is no cross-build cache or persistent lock. Pin versions for more reproducible builds; tags/ranges (including transitive ones) can change as the registry changes.
- Traversal is cycle-safe and installs identical selected versions only once.
- The layout is flat: one selected version per package name. Each requested range/tag is resolved independently to its highest match/tag target. If two requests select different versions, resolution rejects with both versions and dependency chains rather than overwriting files. This can also reject overlapping ranges that independently select different versions; there is no backtracking, range intersection solving, or nested installation. Align the ranges or resolve separate SDK maps. Do not merge conflicting maps by spreading them together.
- Any metadata, tarball, decompression, or extraction failure rejects the returned promise with dependency context; no partial map is returned.
Archive support and limits
- Supports gzip-compressed tar regular files, including empty text files, ustar prefixes,
PAX local/global
pathandsizerecords, and GNU long names. - Rejects absolute paths, Windows drive/backslash paths, traversal (
..), malformed sizes, truncated records, and duplicate extracted text paths. Paths are checked before and after removing the conventionalpackage/wrapper, including extended archive paths. - Extracts UTF-8 text only. Known binary extensions, NUL-containing files, and invalid UTF-8 are skipped. Symlinks, hard links, directories, and special entries are not mounted.
- This is a small text extractor, not a general tar implementation: no base-256 sizes, sparse files, archive checksum/integrity verification, permission preservation, or binary assets. No lifecycle scripts, peer dependency installation, optional dependency installation, native binaries, or executable shims. Optional entries also override/omit same-name ordinary dependencies.
- Bundled files under a package's
node_modulesare rejected: they could shadow resolved packages and bypass the flat layout's version-conflict checks. Use packages without bundled dependencies. - Use trusted packages/registries. Resolution is not a sandbox or a full npm installer, and does not impose download/extraction size limits. Packages depending on omitted features may not work.
Development
pnpm --filter @strangecyan/lastmile-modules typecheck
pnpm --filter @strangecyan/lastmile-modules testTests use deterministic in-memory registry metadata and generated tarballs; no live npm access is needed.
