@exodus/stasis 1.0.0-beta.3 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Node.js](https://img.shields.io/badge/Node.js-338750?style=for-the-badge&logo=Node.js&logoColor=FFF)](https://nodejs.org/)
6
6
  [![esbuild](https://img.shields.io/badge/esbuild-191919?style=for-the-badge&logo=esbuild)](https://esbuild.github.io/)
7
7
  [![metro](https://img.shields.io/badge/metro-FFF?style=for-the-badge&logo=Metro&logoColor=Ef4242)](https://metrobundler.dev/)
8
+ [![rollup](https://img.shields.io/badge/Rollup-EC4A3F?style=for-the-badge&logo=rollupdotjs&logoColor=FFF)](https://rollupjs.org/)
8
9
  [![webpack](https://img.shields.io/badge/WebPack-2B3A42?style=for-the-badge&logo=WebPack)](https://webpack.js.org/)
9
10
 
10
11
  Both lockfiles and bundles only include what is actually _used_.\
@@ -57,7 +58,8 @@ _Lockfiles (npm/pnpm/etc) not mentioned: they are like the "tarball" column, but
57
58
  | `stasis run --lock=add --bundle=add --mock app.js` | build without the app's side effects (network, fs writes) |
58
59
  | `stasis run --lock=add --child-process app.js` | also attest modules loaded in forked child processes (e.g. Metro transform workers) |
59
60
  | `stasis run --bundle=add --fs=sync app.js` | build a bundle that also captures sync `fs.readFileSync`/`readdirSync` reads |
60
- | `stasis bundle src/index.js` | build a bundle statically, without executing it |
61
+ | `stasis run --lock=add --import=./instrument.mjs app.js` | forward extra preload modules (repeatable) to the node process running the entry: a preload's own module graph is runner infrastructure like stasis's loader itself — evaluated, but not captured. Modules the app graph *also* reaches (or that execute through a preload-transplanted `require()` pipeline) are still attested like any other app code, so frozen replays and `--bundle=load` stay fail-closed |
62
+ | `stasis bundle src/index.js` | build a bundle statically, without executing it, into the `stasis.code.br` of the project root its paths are relative to (from a workspace package, the workspace root), where `stasis run --bundle=load` finds it |
61
63
  | `stasis bundle --add src/worker.js` | merge more entries (and their import graph) into an existing `stasis.code.br` instead of replacing it |
62
64
  | `stasis add a.js icon.svg` | add the listed files to the project's bundles (config-driven), with no dependency resolution |
63
65
  | `stasis add src assets` | same, expanding each directory to every file under it, minus an auto-excluded set unless explicitly named |
@@ -66,17 +68,22 @@ _Lockfiles (npm/pnpm/etc) not mentioned: they are like the "tarball" column, but
66
68
  | `stasis bundle --metro --platforms=ios,android app.js` | statically bundle the way Metro resolves: RN conditions + mainFields + `.ios`/`.android`/`.native` suffixes, all platforms at once, plus each bundled native dependency's `ios/`/`android/` sources + podspec |
67
69
  | `stasis bundle --metro --metro-resolver --platforms=ios,android app.js` | same, but resolve through the project's own `metro-resolver` (byte-for-byte Metro fidelity) instead of the built-in approximation; requires `metro-resolver` installed (it ships with `react-native`/`metro`) |
68
70
  | `stasis bundle --flow app.js` | statically bundle Flow-typed sources: when oxc can't parse a `.js`/`.cjs`/`.mjs` file, strip its Flow syntax and retry so the import graph resolves (needs the optional `flow-remove-types` dependency; the stored source stays the original bytes). Combines with `--jsx`/`--conditions`/`--mainFields`/`--metro` |
71
+ | `stasis bundle --typescript src/index.ts` | statically bundle TS sources that import by output name, the way tsc resolves: a `./x.js` (or `.jsx`/`.mjs`/`.cjs`) specifier with no such file on disk lands on its on-disk `./x.ts` or `./x.tsx` (`.tsx`/`.mts`/`.cts`) source, and an extensionless `./x` probes `./x.ts`, `./x.tsx` and `./x/index.ts(x)`; the same substitution applies to package `main`/`exports`/`imports` targets and bare subpaths, and an existing `.js` always wins over its `.ts` twin. None of this applies from or into `node_modules`, by real path: an installed package is used as published, while a monorepo's workspace packages, linked in through `node_modules`, really live outside it and resolve like the project's own files. On without the flag when every entry is TypeScript and their relative imports of JS outputs (`./x.js`) are each only on disk as the TS source (`./x.ts`) -- tsc's convention; a project of Node-compatible `.ts` files importing `./x.ts` keeps Node's resolution. Otherwise an import that fails but would resolve under it names the file and `--typescript` in the error. Combines with `--jsx`/`--conditions`/`--mainFields`/`--metro` (not `--metro-resolver`, which can't substitute) |
72
+ | `stasis bundle --typescript --tsconfig=tsconfig.build.json src/index.ts` | same, honoring tsconfig `compilerOptions.paths` aliases (e.g. `"@/*": ["./src/*"]`, resolved against `baseUrl`, `extends` followed) for bare specifiers nothing else resolves, an extensionless target completing as tsc's does (`.ts`, `.tsx`, then `.js`, `.jsx`, then the directory's `index`); without `--tsconfig`, the `tsconfig.json` beside the importing file's `package.json` applies when present: in a monorepo (a `pnpm-workspace.yaml` or `package.json` `workspaces` at or above the cwd) the nearest named `package.json` at or above the file, else the project's one (the nearest named `package.json` at or above the cwd); never for a file in `node_modules`, and no lookup walks through one |
73
+ | `stasis github-bundle --github=owner/name [--sha=<commit>] [--tag=<name>] [--directory=path] [--package-manager=pnpm] [src/index.js]` | statically bundle a GitHub repo at a commit, or the one `--tag` names (the default branch's head without either), as `stasis bundle` bundles a clone of it once installed: the tree is fetched (with `GITHUB_TOKEN` where set) and held to its git tree id, and the dependencies are laid out in memory from the lockfile alone (`pnpm`, `yarn1`, `npm`, or `soldeer` for `.sol` entries, a Soldeer git dependency on GitHub fetched as the repo is; without `--package-manager`, the one whose lockfile installs the directory, where only one's does), with nothing installed and no package script run; where no entries are given, they are the JS files the directory's `package.json` names (`main`, `exports`, `bin`), resolved as the build resolves (`--conditions`, `--mainFields`, `--metro --platforms`, `--typescript`), or for Soldeer its `.sol` files directly in it, under `contracts/`, and under its source directory (`foundry.toml`'s `src`, else `src/`), but tests, scripts, mocks and dependency or build directories; its paths, and the directory its `repo` names, are the directory's, or for a JS bundle, the innermost package's at or above it that holds every file it bundles (the project root's, where one is outside it, such as a sibling workspace package or the root's `node_modules`); written to `owner-name.<commit's first 7>.stasis.code.br` by default, `owner-name.<directory, its / made ->.<commit's first 7>.stasis.code.br` with `--directory` (each character outside `[A-Za-z0-9._-]` made `_`, and a directory too deep to fit in 255 characters cut, with a hash of it); takes `stasis bundle`'s options for the entries and `--lockfile` (as a library: `buildGitHubBundle` in `@exodus/stasis/vfs-bundle`, and `suggestedEntries` for the entries it would take, of a GitHub repo or a Vfs) |
74
+ | `stasis github-bundle --github=owner/name --generate=prisma packages/api/src/index.ts` | same, with the Prisma Client each project's `prisma generate` would write first: for each project the lockfile installs with a `prisma-client` generator in its schema (the one its Prisma config names as a string literal or `path.join` of them, else `schema.prisma` or `prisma/schema.prisma`), as the Prisma it installs (7.4.0 to 7.10.0: its `prisma`, or beside Prisma 8, the one its `@prisma/prisma7` runs) writes it, byte for byte, where the generator's `output` says, the bundle then carrying it as a source like any other. Nothing of the repo runs: the schema, the config's `schema` path, and the `tsconfig.json` and `package.json` the generator infers its module format and import extensions from are read as data, its installed `prisma` only for its version (and, for an edge runtime's client, the query compiler it ships). The client is generated by the optional `@prisma/client-generator-ts` 7.10.0 dependency and rewritten as the version installed writes it; a project it can't generate for is skipped with a warning |
69
75
  | `stasis build --output=out.js app.stasis.code.br [entry]` | rebuild a runnable JS bundle with esbuild, following the bundle's recorded import graph exactly (entry optional when the bundle has one) |
70
76
  | `stasis build --output=out.js stasis.lock.json [entry]` | same, reading + verifying sources from disk against the lockfile |
71
77
  | `stasis extract app.stasis.code.br` | unpack a bundle back to sources + a `stasis.lock.json` |
72
78
  | `stasis diff --stat a.lock.json b.stasis.code.br` | summarize module/file differences between two lockfiles/bundles |
73
79
  | `stasis prune` | trim `node_modules` to the lockfile, verifying the rest |
74
80
  | `stasis audit stasis.lock.json` | report npm advisories for a lockfile's dependencies |
75
- | `stasis audit app.stasis.code.br` | report npm advisories for a bundle's dependencies |
81
+ | `stasis audit app.stasis.code.br` | report advisories for a bundle's dependencies: npm packages by npm's advisories, crates vendored from a registry and Composer packages by OSV's, and Soldeer packages and GitHub repos (Foundry's `lib/`) by those their GitHub repository publishes, asked with `GITHUB_TOKEN` where it is set; a Composer dev version, and a crate vendored from git or with no `.cargo-checksum.json` (never sent to OSV), are listed as not audited |
76
82
  | `stasis audit --why app.stasis.code.br` | same, with the cross-module import paths that pull each flagged package in (`run: a -> b -> c`), prefixed by the consumer that imports each chain at the top level; a chain is skipped when its full tail is already listed as its own chain |
77
83
  | `stasis audit --why-deep app.stasis.code.br` | like `--why`, but keep those longer chains too (every path, shared tails collapsed to `a -> b -> ... -> d`) |
78
84
  | `stasis audit --why-full app.stasis.code.br` | like `--why`, but spell every chain out with no `...` collapse (combine with `--why-deep` for the complete raw listing) |
79
85
  | `stasis audit --reason=run app.stasis.code.br` | show only advisories related to one consumer (`run`); with `--why`, keep only that consumer's chains |
86
+ | `GITHUB_TOKEN=... stasis audit --repo-advisories stasis.lock.json` | also ask each dependency's GitHub repository for the advisories its maintainers published there, which npm's database has only once GitHub reviews them; needs a GitHub token in `GITHUB_TOKEN`. Each package's repository is the one its artifact records (its `package.json`'s, see `repo` in [file formats](https://github.com/ExodusOSS/stasis/blob/main/doc/file-formats.md)), else it is looked up in npm's registry, Packagist or crates.io and cached for a month in the user cache directory (`$XDG_CACHE_HOME/stasis`, `~/.cache/stasis`, `~/Library/Caches/stasis` on macOS, `%LOCALAPPDATA%\stasis\Cache` on Windows) |
80
87
  | `stasis sbom --format=spdx stasis.lock.json` | export an SPDX SBOM for a lockfile or bundle |
81
88
  | `stasis sbom --format=cyclonedx app.stasis.code.br` | export a CycloneDX SBOM for a lockfile or bundle |
82
89
 
package/bin/stasis.js CHANGED
@@ -3,9 +3,9 @@
3
3
  import { spawn } from 'node:child_process'
4
4
  import { once } from 'node:events'
5
5
  import { fileURLToPath } from 'node:url'
6
- import { basename, dirname, resolve } from 'node:path'
6
+ import { basename, dirname, isAbsolute, join, resolve } from 'node:path'
7
7
  import { existsSync, realpathSync } from 'node:fs'
8
- import { constants as osConstants } from 'node:os'
8
+ import { homedir, constants as osConstants } from 'node:os'
9
9
  import assert from 'node:assert/strict'
10
10
  import { parseBrotliQuality, parseLeadingOptions, parseResourcesOption } from '@exodus/stasis-core/util'
11
11
  import pkg from '../package.json' with { type: 'json' }
@@ -20,19 +20,79 @@ assert(basename(jsname) === 'stasis' || pathsEqual(jsname, fileURLToPath(import.
20
20
 
21
21
  function usage(prefix = '') {
22
22
  console.error(`${prefix}\nUsage:
23
- stasis run --lock=(add|replace|frozen|ignore) [--bundle=(add|replace|load|frozen|ignore)] [--bundle-file=path/to/bundle.br] [--resources-bundle-file=path/to/resources.br] [--dependencies] [--child-process] [--package-json] [--mock] [--fs=(sync|async)] [--resources=ext,ext] [--brotli-quality=0..11] path/to/file.js ...
24
- stasis bundle [--mapping=path/to/remappings(.txt|.toml)] [--add] [--output=(path|-)] path/to/file.sol ...
23
+ stasis run --lock=(add|replace|frozen|ignore) [--bundle=(add|replace|load|frozen|ignore)] [--bundle-file=path/to/bundle.br] [--resources-bundle-file=path/to/resources.br] [--dependencies] [--child-process] [--package-json] [--mock] [--import=module ...] [--fs=(sync|async)] [--resources=ext,ext] [--brotli-quality=0..11] path/to/file.js ...
24
+ (--import forwards extra preload modules (repeatable) to the node process running the entry,
25
+ e.g. --import=./instrument.mjs for a setup/instrumentation preload; a preload's own module
26
+ graph is runner infrastructure like stasis's loader itself, so it stays out of the
27
+ lockfile/bundle -- except modules the app graph also reaches, which are attested like any
28
+ other app code; with --mock, preloads run under the mock's side-effect denials, so a preload
29
+ that spawns helper processes cannot work there)
30
+ stasis bundle [--mapping=path/to/remappings(.txt|.toml)] [--manifests] [--add] [--output=(path|-)] path/to/(file.sol|dir) ...
31
+ (Solidity: a directory stands for every .sol file under it (a missing or empty one is skipped) --
32
+ "stasis bundle src test script" is what "forge build" compiles, "stasis bundle contracts" what
33
+ Hardhat does; imports resolve through the remappings "forge build" uses (remappings.txt,
34
+ foundry.toml's profile, FOUNDRY_PROFILE, lib/ auto-detection incl. dependencies' own configs),
35
+ else a root remappings.txt, then node_modules by file path; --mapping instead takes exactly the
36
+ remappings that one file lists; an import must reach a .sol file inside the project, and a
37
+ dependency's only other dependencies' files; --manifests also carries foundry.toml,
38
+ remappings.txt, foundry.lock, soldeer.lock, .gitmodules and package.json of the project and its
39
+ bundled dependencies, as written: RPC/Etherscan keys and URL credentials in them included)
25
40
  stasis bundle [--add] [--output=(path|-)] path/to/file.php ...
26
- stasis bundle [--scope=(node_modules|full)] [--conditions=cond1,cond2] [--mainFields=field1,field2] [--jsx] [--flow] [--resources=ext,ext] [--package-json] [--lockfile=path/to/stasis.lock.json] [--add] [--output=(path|-)] path/to/file.(js|ts) ...
27
- stasis bundle --metro [--metro-resolver] --platforms=ios,android [--platforms=web] [--jsx] [--flow] [--resources=ext,ext] [--package-json] [--lockfile=path/to/stasis.lock.json] [--add] [--output=(path|-)] path/to/file.(js|ts) ...
41
+ stasis bundle [--scope=(node_modules|full)] [--conditions=cond1,cond2] [--mainFields=field1,field2] [--jsx] [--flow] [--typescript [--tsconfig=path/to/tsconfig.json]] [--resources=ext,ext] [--package-json] [--lockfile=path/to/stasis.lock.json] [--add] [--output=(path|-)] path/to/file.(js|ts|jsx|tsx) ...
42
+ stasis bundle --metro [--metro-resolver] --platforms=ios,android [--platforms=web] [--jsx] [--flow] [--typescript [--tsconfig=path/to/tsconfig.json]] [--resources=ext,ext] [--package-json] [--lockfile=path/to/stasis.lock.json] [--add] [--output=(path|-)] path/to/file.(js|ts|jsx|tsx) ...
28
43
  stasis bundle [--add] [--output=(path|-)] path/to/file.(sh|bash) ...
29
- stasis bundle [--add] [--output=(path|-)] path/to/file.rs ...
30
- (writes to stasis.code.br by default; --output=- streams to stdout; --add merges into an
44
+ stasis bundle [--cargo] [--cargo-features=a,b,pkg/c] [--cargo-no-default-features] [--cargo-all-features] [--cargo-target=(triple|host)] [--cargo-manifests] [--add] [--output=(path|-)] path/to/file.rs ...
45
+ (Rust: each crate's Cargo features are resolved from Cargo.toml/Cargo.lock like "cargo build" of the
46
+ entries' packages, so #[cfg(feature = ...)] code that is off stays out -- by cargo's own resolver
47
+ when there is a Cargo.lock (version 3 or 4; an older one stops the build), --cargo-target and every
48
+ locked package in-tree, by replaying the manifests otherwise (said, with why); --cargo takes the resolution
49
+ from "cargo metadata" instead -- it runs cargo, so only on a project you trust; the --cargo-*
50
+ feature flags are cargo's --features / --no-default-features / --all-features for those packages;
51
+ --cargo-target asks rustc for the target's cfgs so #[cfg(unix)]-style code for other targets stays
52
+ out too, otherwise it is all kept; --cargo-manifests also bundles each bundled package's Cargo.toml
53
+ and build script (a vendored crate's .cargo-checksum.json too), the workspace Cargo.toml, Cargo.lock
54
+ and cargo configs, as written: tokens and URL credentials in them included)
55
+ (writes to stasis.code.br by default, a JS bundle's in the project root its paths are relative to,
56
+ where stasis run --bundle=load finds it; --output=- streams to stdout; --add merges into an
31
57
  existing bundle instead of replacing it (not with --output=-); --brotli-quality=0..11, default 9;
32
- --jsx parses JSX in .js/.cjs/.mjs files, e.g. React Native source (put JSX-in-TS in a .tsx file);
58
+ --jsx parses JSX in .js/.cjs/.mjs files, e.g. React Native source (.jsx/.tsx files need no flag;
59
+ put JSX-in-TS in a .tsx file);
33
60
  --flow strips Flow types from .js/.cjs/.mjs sources oxc can't parse (needs the optional flow-remove-types dep);
61
+ --typescript resolves TS the way tsc does: an import of ./x.js lands on ./x.ts when no .js is on disk
62
+ (likewise .mjs/.cjs -> .mts/.cts, extensionless ./x -> ./x.ts, incl. exports/imports/main targets),
63
+ honouring tsconfig compilerOptions.paths aliases (from the tsconfig.json beside the importing
64
+ file's package.json -- its workspace package's in a monorepo, else the project's -- or --tsconfig=path);
65
+ never from or into node_modules (by real path, so linked workspace packages still are); not with --metro-resolver; implied when every entry is TS and each relative ./x.js-style import
66
+ in them exists only as its TS source (otherwise a failing import it would resolve names it);
34
67
  --resources carries reached assets (e.g. --resources=png,svg) as resources instead of failing to bundle them;
35
- --package-json auto-includes each bundled module's package.json, even ones the scan never reached))
68
+ --package-json auto-includes each bundled module's package.json, even ones the scan never reached)
69
+ stasis github-bundle --github=owner/name [--sha=commit|--tag=name] [--directory=path] [--package-manager=(pnpm|yarn1|npm|soldeer)] [--package-manager-version=version] [--generate=prisma] [--lockfile=path/to/stasis.lock.json] [--output=(path|-)] [stasis bundle's options for the entries] [path/in/repo/to/(file.(js|ts|jsx|tsx)|file.sol|dir) ...]
70
+ (bundles a GitHub repo at a commit, or the one --tag names, its default branch's head without
71
+ either, as "stasis bundle" bundles a clone of it once installed: the tree is fetched (with
72
+ GITHUB_TOKEN where set) and held to its git tree id, and the dependencies are laid out in memory
73
+ from the lockfile alone, as "pnpm install --frozen-lockfile --ignore-scripts" (pnpm 9, 10, 11 or
74
+ 12), "yarn install --frozen-lockfile --ignore-scripts" (yarn 1.22), "npm ci --ignore-scripts"
75
+ (npm 10.9.3 to 10.9.9, or 11.11.1 to 11.21.0) or "soldeer install" (0.12, for .sol entries)
76
+ would: nothing is installed, no package script runs, and every tarball and zip is held to the
77
+ lockfile, all cached where "stasis audit" caches. Without --package-manager, the one whose
78
+ lockfile installs --directory (or the repo's root), if only one's does; at
79
+ --package-manager-version, else at the root package.json's packageManager pin, else pnpm
80
+ 10.33.4, yarn 1.22.22, npm 11.21.0 (which no packageManager pins) or Soldeer 0.12.0. The entries
81
+ are paths in --directory, or in the repo; without them, the JS files its package.json names as
82
+ main, exports and bin, resolved as the build resolves them (--conditions, --mainFields, --metro
83
+ --platforms, --typescript), or for Soldeer its .sol files directly in it, under contracts/, and
84
+ under its source directory (foundry.toml's src, else src/), but tests, scripts, mocks and
85
+ dependency or build directories; its paths, and the directory its repo names, are
86
+ --directory's, or of a JS bundle, the innermost package's at or above it holding every file it
87
+ bundles, the project root's where one is outside; not with --metro-resolver, --cargo* or --add;
88
+ --generate=prisma first writes, for each project with a "prisma-client" generator, the Prisma
89
+ Client its "prisma generate" would (Prisma 7.4.0 to 7.10.0), with the optional
90
+ @prisma/client-generator-ts 7.10.0 dependency: nothing of the repo runs, its schema and config
91
+ are read as data, and its prisma for its version alone;
92
+ writes to owner-name.<commit's first 7>.stasis.code.br by default,
93
+ owner-name.<--directory, its / made ->.<commit's first 7>.stasis.code.br with --directory, each
94
+ character outside [A-Za-z0-9._-] made _, and a directory too deep to fit in 255 characters cut,
95
+ with a hash of it; --output=- streams to stdout)
36
96
  stasis add path/to/(file|dir) ...
37
97
  (adds the listed files to the project's bundle(s) with no dependency resolution;
38
98
  a directory expands to its files. Requires a stasis.config.json (all fields optional).)
@@ -43,12 +103,20 @@ function usage(prefix = '') {
43
103
  stasis extract [--output=path/to/dir] path/to/bundle.stasis.code.br
44
104
  stasis diff --stat [--imports] path/to/(lockfile|bundle) path/to/(lockfile|bundle)
45
105
  stasis prune [path/to/project]
46
- stasis audit [--why|--why-deep] [--why-full] [--reason=consumer] path/to/file ...
47
- (--why lists, per advisory, the cross-module import paths that pull the package in,
106
+ stasis audit [--why|--why-deep] [--why-full] [--reason=consumer] [--repo-advisories] path/to/file ...
107
+ (audits the dependencies the files hold: npm packages by npm's advisories, vendored crates and
108
+ Composer packages by OSV's, and Soldeer packages and GitHub repos (Foundry's lib/) by those their
109
+ GitHub repository publishes, asked with GITHUB_TOKEN where it is set; a Composer dev version is
110
+ listed as not audited, no database having one;
111
+ --why lists, per advisory, the cross-module import paths that pull an npm package in,
48
112
  prefixed by the bundle consumer that imports each chain at the top level, e.g. "run: a -> b -> c";
49
113
  it skips chains whose full tail is already listed as its own chain -- --why-deep keeps them all;
50
114
  --why-full spells every chain out instead of collapsing repeated tails to "a -> b -> ... -> d";
51
- --reason=consumer shows only advisories related to that consumer, and with --why only its chains)
115
+ --reason=consumer shows only advisories related to that consumer, and with --why only its chains;
116
+ --repo-advisories also asks each package's GitHub repository for the advisories its maintainers
117
+ published there, before GitHub reviews them into the databases above; it needs a token in
118
+ GITHUB_TOKEN, and asks the repository each package's artifact records, else looks one up and
119
+ caches it for a month in the user cache dir, e.g. ~/.cache/stasis)
52
120
  stasis sbom --format=(spdx|cyclonedx) [--output=(path|-)] path/to/(lockfile|bundle) ...
53
121
  (streams to stdout by default; --output=- is explicit stdout)
54
122
  `.trim())
@@ -61,6 +129,14 @@ function setEnv(name, value) {
61
129
  process.env[name] = value === undefined ? '' : value
62
130
  }
63
131
 
132
+ // The per-user cache directory, as each platform names it (XDG ignores a relative path).
133
+ function userCacheDir() {
134
+ if (isAbsolute(process.env.XDG_CACHE_HOME ?? '')) return join(process.env.XDG_CACHE_HOME, 'stasis')
135
+ if (process.platform === 'darwin') return join(homedir(), 'Library', 'Caches', 'stasis')
136
+ if (process.platform === 'win32') return join(process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'), 'stasis', 'Cache')
137
+ return join(homedir(), '.cache', 'stasis')
138
+ }
139
+
64
140
  const command = argv.shift()
65
141
 
66
142
  if (command === '-v' || command === '--version') {
@@ -77,12 +153,13 @@ if (command === '-v' || command === '--version') {
77
153
  'child-process': { type: 'boolean' },
78
154
  'package-json': { type: 'boolean' },
79
155
  mock: { type: 'boolean' },
156
+ import: { type: 'string', multiple: true },
80
157
  fs: { type: 'string' },
81
158
  resources: { type: 'string' },
82
159
  'brotli-quality': { type: 'string' },
83
160
  }
84
161
  const values = parseLeadingOptions(argv, options, {
85
- valueFlags: ['--bundle', '--bundle-file', '--resources-bundle-file', '--lock', '--resources', '--brotli-quality'],
162
+ valueFlags: ['--bundle', '--bundle-file', '--resources-bundle-file', '--lock', '--import', '--resources', '--brotli-quality'],
86
163
  onError: usage,
87
164
  })
88
165
  if (argv.length === 0) usage('Nothing to run: no path to file given')
@@ -115,6 +192,15 @@ if (command === '-v' || command === '--version') {
115
192
  usage(`Error: ${cause.message}`)
116
193
  }
117
194
  }
195
+ // --import: extra preload module(s) passed through to the spawned node. Node resolves each
196
+ // against the project cwd; they ride AFTER stasis's own loader import.
197
+ const imports = values.import ?? []
198
+ if (imports.some((s) => s === '')) usage('Error: --import requires a module specifier (e.g. --import=./instrument.mjs)')
199
+ // Not a usage error: plain instrumentation/setup preloads still work under the mock; only ones
200
+ // that need the denied surfaces (spawning helper processes, network) die, and they do so loudly.
201
+ if (values.mock && imports.length > 0) {
202
+ console.warn("[stasis] Warning: --import preloads run under --mock's side-effect denials; a preload that spawns helper processes will fail there")
203
+ }
118
204
  // --child-process: forward forked-child (e.g. Metro worker) capture to the root via per-pid shards.
119
205
  const childProcess = values['child-process'] ? '1' : ''
120
206
  // --package-json: auto-include every bundled module's package.json. Only meaningful while WRITING
@@ -123,7 +209,7 @@ if (command === '-v' || command === '--version') {
123
209
  usage('Error: --package-json requires --bundle=(add|replace)')
124
210
  }
125
211
  const packageJSON = values['package-json'] ? '1' : ''
126
- console.warn('[stasis] Running stasis with config:', { lock, scope, bundle, ...(bundleFile && { bundleFile }), ...(resourcesBundleFile && { resourcesBundleFile }), ...(childProcess && { childProcess: true }), ...(packageJSON && { packageJSON: true }), ...(values.mock && { mock: true }), ...(values.fs && { fs: values.fs }), ...(resources && { resources }), ...(brotliQuality !== undefined && { brotliQuality }) })
212
+ console.warn('[stasis] Running stasis with config:', { lock, scope, bundle, ...(bundleFile && { bundleFile }), ...(resourcesBundleFile && { resourcesBundleFile }), ...(childProcess && { childProcess: true }), ...(packageJSON && { packageJSON: true }), ...(values.mock && { mock: true }), ...(imports.length > 0 && { import: imports }), ...(values.fs && { fs: values.fs }), ...(resources && { resources }), ...(brotliQuality !== undefined && { brotliQuality }) })
127
213
  if (debug) console.warn(`[stasis] Warning: stasis debug mode active`)
128
214
  setEnv('EXODUS_STASIS_LOCK', lock)
129
215
  setEnv('EXODUS_STASIS_SCOPE', scope)
@@ -166,6 +252,10 @@ if (command === '-v' || command === '--version') {
166
252
  // --mock uses stasis's loader-mock entry (composes the mock before installing the hooks).
167
253
  const loaderEntry = values.mock ? '../src/loader-mock.js' : '@exodus/stasis-core/loader'
168
254
  nodeArgs.push('--import', import.meta.resolve(loaderEntry))
255
+ // Passthrough preloads ride after the loader (and after --mock's denials), so they evaluate
256
+ // under its hooks; their module graphs pass through uncaptured unless the app graph reaches
257
+ // them -- then they're promoted into the capture (see core hooks.js).
258
+ for (const specifier of imports) nodeArgs.push('--import', specifier)
169
259
  const child = spawn(process.execPath, [...nodeArgs, ...argv], { stdio: 'inherit' })
170
260
  const [code, signal] = await once(child, 'close')
171
261
  // code is null when the child died from a signal; report 128+signo (shell convention) instead of the implicit 0
@@ -173,6 +263,7 @@ if (command === '-v' || command === '--version') {
173
263
  } else if (command === 'bundle') {
174
264
  const options = {
175
265
  mapping: { type: 'string' },
266
+ manifests: { type: 'boolean' },
176
267
  output: { type: 'string', short: 'o' },
177
268
  scope: { type: 'string' },
178
269
  lockfile: { type: 'string' },
@@ -183,25 +274,67 @@ if (command === '-v' || command === '--version') {
183
274
  platforms: { type: 'string', multiple: true },
184
275
  jsx: { type: 'boolean' },
185
276
  flow: { type: 'boolean' },
277
+ typescript: { type: 'boolean' },
278
+ tsconfig: { type: 'string' },
186
279
  resources: { type: 'string' },
187
280
  'package-json': { type: 'boolean' },
281
+ cargo: { type: 'boolean' },
282
+ 'cargo-features': { type: 'string', multiple: true },
283
+ 'cargo-no-default-features': { type: 'boolean' },
284
+ 'cargo-all-features': { type: 'boolean' },
285
+ 'cargo-target': { type: 'string' },
286
+ 'cargo-manifests': { type: 'boolean' },
188
287
  'brotli-quality': { type: 'string' },
189
288
  add: { type: 'boolean' },
190
289
  }
191
290
  const values = parseLeadingOptions(argv, options, {
192
- valueFlags: ['--mapping', '--output', '--scope', '--lockfile', '--conditions', '--mainFields', '--platforms', '--resources', '--brotli-quality', '-o'],
291
+ valueFlags: ['--mapping', '--output', '--scope', '--lockfile', '--conditions', '--mainFields', '--platforms', '--resources', '--tsconfig', '--cargo-features', '--cargo-target', '--brotli-quality', '-o'],
193
292
  onError: usage,
194
293
  })
195
294
  if (argv.length === 0) usage('Nothing to bundle: no entry file given')
196
- const allSol = argv.every((f) => f.endsWith('.sol'))
295
+ // A directory entry stands for the .sol files under it (Solidity only); an extensionless path
296
+ // that doesn't exist is a missing one (skipped with a warning).
297
+ const { directoryEntryError, isSolidityEntry } = await import('../src/cmd/bundle.js')
298
+ const dirError = directoryEntryError(argv)
299
+ if (dirError !== null) usage(`Error: ${dirError}`)
300
+ const allSol = argv.every((f) => isSolidityEntry(f))
197
301
  const allPhp = argv.every((f) => f.endsWith('.php'))
198
- const allJs = argv.every((f) => /\.(?:js|cjs|mjs|ts|cts|mts)$/u.test(f))
302
+ const allJs = argv.every((f) => /\.(?:js|cjs|mjs|ts|cts|mts|jsx|tsx)$/u.test(f))
199
303
  const allBash = argv.every((f) => /\.(?:sh|bash)$/u.test(f))
200
304
  const allRust = argv.every((f) => f.endsWith('.rs'))
201
305
  if (!allSol && !allPhp && !allJs && !allBash && !allRust) {
202
- usage('Error: bundle entries must all be .sol, all be .php, all be .js/.cjs/.mjs/.ts/.cts/.mts, all be .sh/.bash, or all be .rs')
306
+ usage('Error: bundle entries must all be .sol, all be .php, all be .js/.cjs/.mjs/.ts/.cts/.mts/.jsx/.tsx, all be .sh/.bash, or all be .rs')
203
307
  }
204
308
  if (values.mapping && !allSol) usage('Error: --mapping is only valid for .sol bundles')
309
+ // --manifests: carry the Solidity build's description files (foundry.toml, remappings.txt, ...).
310
+ const manifests = Boolean(values.manifests)
311
+ if (manifests && !allSol) usage('Error: --manifests is only valid for .sol bundles')
312
+ // --cargo: take the Rust feature/dependency resolution from `cargo metadata` (runs cargo; opt-in).
313
+ const cargo = Boolean(values.cargo)
314
+ if (cargo && !allRust) usage('Error: --cargo is only valid for Rust bundles')
315
+ // --cargo-features / --cargo-no-default-features / --cargo-all-features: cargo's own feature flags
316
+ // for the entries' packages (`pkg/feat` targets one, or a dependency). --cargo-features is
317
+ // repeatable and/or comma-separated; parseFeatureList is the one splitter (the resolver reuses it).
318
+ const { parseFeatureList } = await import('../src/loaders/cargo.js')
319
+ const cargoFeatures = parseFeatureList(values['cargo-features'] ?? [])
320
+ if (values['cargo-features'] !== undefined && cargoFeatures.length === 0) {
321
+ usage('Error: --cargo-features must list at least one feature (e.g. --cargo-features=serde,app/tls)')
322
+ }
323
+ const cargoNoDefaultFeatures = Boolean(values['cargo-no-default-features'])
324
+ const cargoAllFeatures = Boolean(values['cargo-all-features'])
325
+ // --cargo-target=<triple|host>: the build's target, whose cfgs (from `rustc --print cfg`) decide
326
+ // `#[cfg(unix)]`-style code. A triple is letters, digits, `-`, `_` and `.` (`x86_64-unknown-linux-gnu`).
327
+ const cargoTarget = values['cargo-target'] ?? null
328
+ if (cargoTarget !== null && !/^[\w.-]+$/u.test(cargoTarget)) {
329
+ usage('Error: --cargo-target must be a target triple or "host" (e.g. --cargo-target=aarch64-apple-darwin)')
330
+ }
331
+ // --cargo-manifests: carry each bundled package's Cargo.toml and build script, the workspace
332
+ // Cargo.toml, Cargo.lock and .cargo/config.toml too (the Rust counterpart of --package-json).
333
+ const cargoManifests = Boolean(values['cargo-manifests'])
334
+ if (!allRust) {
335
+ const given = { 'cargo-features': cargoFeatures.length > 0, 'cargo-no-default-features': cargoNoDefaultFeatures, 'cargo-all-features': cargoAllFeatures, 'cargo-target': cargoTarget !== null, 'cargo-manifests': cargoManifests }
336
+ for (const [flag, on] of Object.entries(given)) if (on) usage(`Error: --${flag} is only valid for Rust bundles`)
337
+ }
205
338
  if (values.scope && !allJs) usage('Error: --scope is only valid for JS bundles')
206
339
  if (values.scope && !['node_modules', 'full'].includes(values.scope)) {
207
340
  usage('Error: --scope must be node_modules or full')
@@ -223,6 +356,13 @@ if (command === '-v' || command === '--version') {
223
356
  // --flow: strip Flow type syntax (via the optional flow-remove-types dep) before parsing; JS-only.
224
357
  if (values.flow && !allJs) usage('Error: --flow is only valid for JS bundles')
225
358
  const flow = Boolean(values.flow)
359
+ // --typescript: resolve like tsc -- a specifier naming a missing JS output (./x.js, .mjs, .cjs,
360
+ // extensionless) lands on its on-disk TS source (./x.ts, .mts, .cts); an existing .js always wins.
361
+ if (values.typescript && !allJs) usage('Error: --typescript is only valid for JS bundles')
362
+ const typescript = Boolean(values.typescript)
363
+ // --tsconfig: the config whose compilerOptions.paths aliases --typescript honours (default: the
364
+ // tsconfig.json beside each importing file's package.json). Meaningless without --typescript.
365
+ if (values.tsconfig !== undefined && !typescript) usage('Error: --tsconfig is only valid with --typescript')
226
366
  // --mainFields: legacy package entry fields (e.g. react-native,browser,main) for the non-exports resolver.
227
367
  if (values.mainFields !== undefined && !allJs) usage('Error: --mainFields is only valid for JS bundles')
228
368
  const mainFields = values.mainFields === undefined
@@ -244,7 +384,7 @@ if (command === '-v' || command === '--version') {
244
384
  }
245
385
  if ((metro || platforms.length > 0) && !allJs) usage('Error: --metro is only valid for JS bundles')
246
386
  // --jsx: parse React Native's JSX-in-.js source in the static scanner (off by default; oxc,
247
- // like tsc, only auto-enables JSX for .jsx/.tsx). Orthogonal to the resolver, so it pairs with
387
+ // like tsc, auto-enables JSX for .jsx/.tsx only). Orthogonal to the resolver, so it pairs with
248
388
  // plain/--mainFields/--metro alike -- JS-only, since no other entry language is scanned.
249
389
  const jsx = Boolean(values.jsx)
250
390
  if (jsx && !allJs) usage('Error: --jsx is only valid for JS bundles')
@@ -275,6 +415,8 @@ if (command === '-v' || command === '--version') {
275
415
  usage('Error: --platforms is only valid with --metro')
276
416
  }
277
417
  if (metroResolver && !metro) usage('Error: --metro-resolver is only valid with --metro')
418
+ // metro-resolver can't substitute .js -> .ts, so --typescript would silently not apply -- reject it.
419
+ if (typescript && metroResolver) usage("Error: --typescript is not supported with --metro-resolver (the project's metro-resolver doesn't substitute .js -> .ts)")
278
420
  // --brotli-quality: valid for every entry language (no allJs gate).
279
421
  let brotliQuality
280
422
  if (values['brotli-quality'] !== undefined) {
@@ -292,6 +434,7 @@ if (command === '-v' || command === '--version') {
292
434
  cwd: process.cwd(),
293
435
  entries: argv,
294
436
  mappingFile: values.mapping,
437
+ manifests,
295
438
  output: values.output,
296
439
  scope: values.scope,
297
440
  lockfile: values.lockfile,
@@ -302,11 +445,90 @@ if (command === '-v' || command === '--version') {
302
445
  platforms,
303
446
  jsx,
304
447
  flow,
448
+ typescript,
449
+ tsconfig: values.tsconfig,
305
450
  resources,
306
451
  packageJSON,
452
+ cargo,
453
+ cargoFeatures,
454
+ cargoNoDefaultFeatures,
455
+ cargoAllFeatures,
456
+ cargoTarget,
457
+ cargoManifests,
307
458
  brotliQuality,
308
459
  add,
309
460
  })
461
+ } else if (command === 'github-bundle') {
462
+ const values = parseLeadingOptions(argv, {
463
+ github: { type: 'string' },
464
+ sha: { type: 'string' },
465
+ tag: { type: 'string' },
466
+ directory: { type: 'string' },
467
+ 'package-manager': { type: 'string' },
468
+ 'package-manager-version': { type: 'string' },
469
+ mapping: { type: 'string' },
470
+ manifests: { type: 'boolean' },
471
+ output: { type: 'string', short: 'o' },
472
+ scope: { type: 'string' },
473
+ lockfile: { type: 'string' },
474
+ conditions: { type: 'string' },
475
+ mainFields: { type: 'string' },
476
+ metro: { type: 'boolean' },
477
+ platforms: { type: 'string', multiple: true },
478
+ jsx: { type: 'boolean' },
479
+ flow: { type: 'boolean' },
480
+ typescript: { type: 'boolean' },
481
+ tsconfig: { type: 'string' },
482
+ resources: { type: 'string' },
483
+ 'package-json': { type: 'boolean' },
484
+ 'brotli-quality': { type: 'string' },
485
+ generate: { type: 'string', multiple: true },
486
+ }, {
487
+ valueFlags: ['--github', '--sha', '--tag', '--directory', '--package-manager', '--package-manager-version', '--mapping', '--output', '--scope', '--lockfile', '--conditions', '--mainFields', '--platforms', '--tsconfig', '--resources', '--brotli-quality', '--generate', '-o'],
488
+ onError: usage,
489
+ })
490
+ if (values.github === undefined) usage('Error: github-bundle requires --github=owner/name, the repo to bundle')
491
+ if (values.sha !== undefined && values.tag !== undefined) usage('Error: github-bundle takes --sha or --tag, not both')
492
+ // Whether each option applies to the entries is buildGitHubBundle's to say.
493
+ const list = (value) => [value ?? []].flat().flatMap((v) => v.split(',')).map((s) => s.trim()).filter(Boolean)
494
+ let brotliQuality
495
+ if (values['brotli-quality'] !== undefined) {
496
+ try {
497
+ brotliQuality = parseBrotliQuality('--brotli-quality', values['brotli-quality'])
498
+ } catch (cause) {
499
+ usage(`Error: ${cause.message}`)
500
+ }
501
+ }
502
+ // Tarballs, zips and GitHub trees are cached where `stasis audit` caches.
503
+ const { setCacheDir } = await import('../src/vfs-bundle.js')
504
+ setCacheDir(userCacheDir())
505
+ const { githubBundleCommand } = await import('../src/cmd/github-bundle.js')
506
+ await githubBundleCommand({
507
+ github: values.github,
508
+ sha: values.sha,
509
+ tag: values.tag,
510
+ directory: values.directory,
511
+ packageManager: values['package-manager'],
512
+ packageManagerVersion: values['package-manager-version'],
513
+ entries: argv.length === 0 ? undefined : argv,
514
+ mappingFile: values.mapping,
515
+ manifests: Boolean(values.manifests),
516
+ output: values.output,
517
+ lockfile: values.lockfile,
518
+ scope: values.scope,
519
+ conditions: list(values.conditions),
520
+ mainFields: values.mainFields === undefined ? undefined : list(values.mainFields),
521
+ metro: Boolean(values.metro),
522
+ platforms: list(values.platforms),
523
+ jsx: Boolean(values.jsx),
524
+ flow: Boolean(values.flow),
525
+ typescript: Boolean(values.typescript),
526
+ tsconfig: values.tsconfig,
527
+ resources: list(values.resources),
528
+ packageJSON: Boolean(values['package-json']),
529
+ generate: list(values.generate),
530
+ brotliQuality,
531
+ })
310
532
  } else if (command === 'add') {
311
533
  // add packs the listed files (no resolver), taking split targets + resource allowlist from
312
534
  // stasis.config.json; it takes no flags.
@@ -409,11 +631,20 @@ if (command === '-v' || command === '--version') {
409
631
  const { removed, validated } = prune({ root })
410
632
  console.warn(`[stasis] prune: validated ${validated.length} file(s), removed ${removed.length} file(s)`)
411
633
  } else if (command === 'audit') {
412
- const values = parseLeadingOptions(argv, { why: { type: 'boolean' }, 'why-deep': { type: 'boolean' }, 'why-full': { type: 'boolean' }, reason: { type: 'string' } }, { valueFlags: ['--reason'], onError: usage })
634
+ const values = parseLeadingOptions(argv, { why: { type: 'boolean' }, 'why-deep': { type: 'boolean' }, 'why-full': { type: 'boolean' }, reason: { type: 'string' }, 'repo-advisories': { type: 'boolean' } }, { valueFlags: ['--reason'], onError: usage })
413
635
  if (argv.length === 0) usage('Nothing to audit: no path to file given')
636
+ const repoAdvisories = Boolean(values['repo-advisories'])
637
+ if (repoAdvisories && !process.env.GITHUB_TOKEN) usage('Error: --repo-advisories requires a GitHub token in GITHUB_TOKEN')
638
+ // A Soldeer package's and a GitHub repo's advisories are their repository's, asked of GitHub with
639
+ // GITHUB_TOKEN where it is set; the client asks nothing for any other package by itself.
640
+ const github = (await import('@preventive/upstream/github.js')).createClient({ token: process.env.GITHUB_TOKEN || null })
641
+ // Upstream caches what it looks up (a package's GitHub repo, a month each) only where told to, and
642
+ // answers from it without asking: a per-user directory, never one shared with less trusted jobs.
643
+ const { setCacheDir } = await import('@preventive/upstream/npm.js')
644
+ setCacheDir(userCacheDir())
414
645
  const { audit, printAuditReport } = await import('../src/audit.js')
415
646
  const files = argv.map((f) => resolve(f))
416
- const report = await audit(files, { why: Boolean(values.why), whyDeep: Boolean(values['why-deep']), whyFull: Boolean(values['why-full']), reason: values.reason })
647
+ const report = await audit(files, { why: Boolean(values.why), whyDeep: Boolean(values['why-deep']), whyFull: Boolean(values['why-full']), reason: values.reason, repoAdvisories, github })
417
648
  printAuditReport(report)
418
649
  process.exitCode = report.rows.length === 0 ? 0 : 1
419
650
  } else if (command === 'sbom') {
package/package.json CHANGED
@@ -1,46 +1,57 @@
1
1
  {
2
2
  "name": "@exodus/stasis",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "File-level source bundles and lockfiles",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./esbuild": "./src/esbuild.js",
8
8
  "./webpack": "./src/webpack.js",
9
+ "./rollup": "./src/rollup.js",
9
10
  "./metro": "./src/metro.js",
10
11
  "./metro-transformer": "./src/metro-transformer.js",
11
12
  "./loader": "./src/loader.js",
12
13
  "./mock": "./src/mock.js",
13
14
  "./bundle": "./src/bundle.js",
15
+ "./bundle-reader": "./src/bundle-reader.js",
14
16
  "./cmd/bundle": "./src/cmd/bundle.js",
15
17
  "./cmd/build": "./src/cmd/build.js",
16
18
  "./diff": "./src/diff.js",
17
19
  "./lockfile": "./src/lockfile.js",
18
20
  "./prune": "./src/prune.js",
19
21
  "./sbom": "./src/sbom.js",
22
+ "./vfs-bundle": "./src/vfs-bundle.js",
20
23
  "./logo.svg": "./logo.svg"
21
24
  },
22
25
  "files": [
23
26
  "bin/stasis.js",
24
27
  "logo.svg",
25
- "src/apis/npm/index.js",
26
- "src/apis/npm/semver.cjs",
28
+ "src/audit-corrections.js",
27
29
  "src/audit.js",
28
30
  "src/babel.js",
29
31
  "src/babel-worker.cjs",
30
32
  "src/bundle.js",
31
33
  "src/bundle-from-lockfile.js",
34
+ "src/bundle-reader.js",
32
35
  "src/cmd/bundle.js",
33
36
  "src/cmd/build.js",
34
37
  "src/cmd/diff.js",
38
+ "src/cmd/github-bundle.js",
39
+ "src/cmd/output.js",
35
40
  "src/cmd/sbom.js",
36
41
  "src/diff.js",
37
42
  "src/esbuild.js",
43
+ "src/json-stream.js",
38
44
  "src/loader.js",
39
45
  "src/loader-mock.js",
40
46
  "src/loaders/bash.js",
47
+ "src/loaders/cargo.js",
48
+ "src/loaders/foundry.js",
41
49
  "src/loaders/rust.js",
42
50
  "src/loaders/solidity.js",
51
+ "src/loaders/solidity-ownership.js",
52
+ "src/loaders/toml.js",
43
53
  "src/loaders/php.js",
54
+ "src/loaders/paths.js",
44
55
  "src/lockfile.js",
45
56
  "src/metro.js",
46
57
  "src/metro-resolver.js",
@@ -48,9 +59,20 @@
48
59
  "src/mock.js",
49
60
  "src/parse.js",
50
61
  "src/prune.js",
62
+ "src/resolve-fields.js",
63
+ "src/resolve-node.js",
64
+ "src/resolve-typescript.js",
65
+ "src/rollup.js",
51
66
  "src/sbom.js",
52
67
  "src/scan.js",
53
- "src/webpack.js"
68
+ "src/vfs-bundle.js",
69
+ "src/vfs-bundle/entries.js",
70
+ "src/vfs-bundle/github.js",
71
+ "src/vfs-bundle/prisma.js",
72
+ "src/vfs-bundle/soldeer.js",
73
+ "src/vfs-bundle/tree.js",
74
+ "src/webpack.js",
75
+ "src/why.js"
54
76
  ],
55
77
  "engines": {
56
78
  "node": ">=24.14.0"
@@ -60,25 +82,35 @@
60
82
  },
61
83
  "repository": {
62
84
  "type": "git",
63
- "url": "git+https://github.com/ExodusOSS/stasis.git",
85
+ "url": "git+https://github.com/PreventiveMeasures/stasis.git",
64
86
  "directory": "stasis"
65
87
  },
66
88
  "author": "Exodus Movement, Inc.",
67
89
  "license": "MIT",
68
90
  "bugs": {
69
- "url": "https://github.com/ExodusOSS/stasis/issues"
91
+ "url": "https://github.com/PreventiveMeasures/stasis/issues"
70
92
  },
71
- "homepage": "https://github.com/ExodusOSS/stasis#readme",
93
+ "homepage": "https://github.com/PreventiveMeasures/stasis#readme",
72
94
  "dependencies": {
73
- "@exodus/stasis-core": "1.0.0-beta.3",
74
- "@exodus/stasis-plugins": "1.0.0-beta.3",
75
- "oxc-parser": "^0.94.0"
95
+ "@exodus/bytes": "^1.16.0",
96
+ "@exodus/stasis-core": "1.0.0-beta.6",
97
+ "@exodus/stasis-plugins": "1.0.0-beta.6",
98
+ "@preventive/archive": "1.0.0-beta.4",
99
+ "@preventive/deptree": "1.0.0-alpha.8",
100
+ "@preventive/lockfile": "1.0.0-alpha.7",
101
+ "@preventive/upstream": "1.0.0-alpha.10",
102
+ "@preventive/vfs": "1.0.0-beta.4",
103
+ "oxc-parser": "^0.152.0"
76
104
  },
77
105
  "peerDependencies": {
106
+ "@prisma/client-generator-ts": "7.10.0",
78
107
  "esbuild": "*",
79
108
  "flow-remove-types": "*"
80
109
  },
81
110
  "peerDependenciesMeta": {
111
+ "@prisma/client-generator-ts": {
112
+ "optional": true
113
+ },
82
114
  "esbuild": {
83
115
  "optional": true
84
116
  },