jam 0.9.3 → 0.10.0

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
@@ -1,6 +1,6 @@
1
1
  # jam
2
2
 
3
- `jam` serves JavaScript and TypeScript files as HTTP routes with isolated per-request execution.
3
+ `jam` is the canonical Jam install package.
4
4
 
5
5
  ## Usage
6
6
 
@@ -8,56 +8,21 @@
8
8
  jam [flags] [scripts-dir]
9
9
  ```
10
10
 
11
- ## Common Commands
11
+ ## Notes
12
12
 
13
- ```sh
14
- # Serve scripts from ./scripts on port 3000
15
- jam ./scripts
16
-
17
- # Development mode with detailed error pages
18
- jam --mode development ./scripts
19
-
20
- # Use a config file
21
- jam --config ./jamconfig.json ./scripts
22
-
23
- # Enable PHP-style globals
24
- jam --php ./scripts
25
- ```
26
-
27
- For the complete CLI surface, run:
13
+ - `jam` installs the matching `jam-<os>-<arch>` platform package through npm `optionalDependencies`.
14
+ - The platform package provides the Node SEA executable that actually runs the server.
15
+ - This package publishes the ambient `jam` TypeScript types.
28
16
 
29
- ```sh
30
- jam --help
31
- ```
17
+ ## Ambient Types
32
18
 
33
- ## Minimal Script
19
+ Ambient `jam` types are generated from `packages/jam-node/types/` when this package is built.
20
+ Fixtures/apps consume the published types with:
34
21
 
35
- ```ts
36
- export default {
37
- fetch() {
38
- return new Response("Hello from Jam");
22
+ ```json
23
+ {
24
+ "compilerOptions": {
25
+ "types": ["jam"]
39
26
  }
40
- };
27
+ }
41
28
  ```
42
-
43
- Saved as `scripts/app.ts`, this route is available at `/app`.
44
-
45
- ## Docs
46
-
47
- - [Introduction](../../docs/001-introduction.md)
48
- - [Getting Started](../../docs/002-getting-started.md)
49
- - [Build a Real App](../../docs/003-writing-scripts.md)
50
- - [Configuration](../../docs/004-configuration.md)
51
- - [Runtime APIs](../../docs/005-runtime-apis.md)
52
- - [Templates](../../docs/006-templates.md)
53
- - [Deployment](../../docs/007-deployment.md)
54
-
55
- ## Development
56
-
57
- `jam` has two entry points with different roles:
58
-
59
- - `bin/jam.js`: Node-facing dispatch shim for npm usage.
60
- - `src/entry.ts`: Bun runtime CLI entrypoint compiled into platform binaries.
61
-
62
- For repeatable runtime engineering workflows, see the repo-local skills index:
63
- [`../../skills/README.md`](../../skills/README.md).
package/bin/jam.js CHANGED
@@ -1,22 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // This is the user-facing Node entrypoint for the npm `jam` package.
4
- // `npx jam` and the package binary in `package.json` resolve here first.
5
- //
6
- // It exists because the published `jam` package is a tiny bootstrap layer:
7
- // it detects the host platform, resolves the corresponding platform package
8
- // (`jam-darwin-arm64`, `jam-darwin-x64`, `jam-linux-arm64`, `jam-linux-x64`),
9
- // and executes the native Jam binary shipped by that package.
10
- //
11
- // If the platform package is not installed yet, this shim tries to install it
12
- // on demand via `npm install <platform-package>@<version> --no-save`.
13
- // If Bun is available in a local repo checkout and no platform package is
14
- // present, it falls back to running `src/entry.ts` directly for development.
15
- //
16
- // `src/entry.ts` is the Bun source entrypoint used by platform package builds;
17
- // this file (`jam.js`) is the runtime dispatcher that selects and runs them.
18
-
19
- import fs from "node:fs";
20
3
  import path from "node:path";
21
4
  import { spawnSync } from "node:child_process";
22
5
  import { createRequire } from "node:module";
@@ -25,8 +8,6 @@ import { fileURLToPath } from "node:url";
25
8
  let require = createRequire(import.meta.url);
26
9
  let THIS_FILE = fileURLToPath(import.meta.url);
27
10
  let THIS_DIR = path.dirname(THIS_FILE);
28
- let PACKAGE_DIR = path.resolve(THIS_DIR, "..");
29
- let PACKAGE_JSON = path.join(PACKAGE_DIR, "package.json");
30
11
 
31
12
  function resolvePlatformPackageName() {
32
13
  let key = `${process.platform}-${process.arch}`;
@@ -72,61 +53,11 @@ function resolvePlatformBinary(packageName) {
72
53
  return path.join(path.dirname(packageJsonPath), "bin", "jam");
73
54
  }
74
55
 
75
- function getMainPackageVersion() {
76
- let packageJson = JSON.parse(fs.readFileSync(PACKAGE_JSON, "utf8"));
77
- return packageJson.version;
78
- }
79
-
80
- function installPlatformPackage(packageName) {
81
- let version = getMainPackageVersion();
82
- let packageSpec = `${packageName}@${version}`;
83
-
84
- let npmHasInstall = false;
85
- let npmVersionResult = spawnSync("npm", ["--version"], {
86
- stdio: "ignore"
87
- });
88
-
89
- if (
90
- typeof npmVersionResult.status === "number" &&
91
- npmVersionResult.status === 0
92
- ) {
93
- npmHasInstall = true;
94
- }
95
-
96
- if (!npmHasInstall) {
97
- throw new Error(
98
- "npm is required to install the platform package automatically."
99
- );
100
- }
101
-
102
- let result = runProcess(
103
- "npm",
104
- ["install", packageSpec, "--no-save", "--no-audit", "--no-fund"],
105
- {
106
- cwd: PACKAGE_DIR
107
- }
108
- );
109
-
110
- if (result !== 0) {
111
- throw new Error(`npm install failed for ${packageSpec} (status: ${result}).`);
112
- }
113
- }
114
-
115
56
  function runPlatformBinary(packageName, args) {
116
57
  let binaryPath = resolvePlatformBinary(packageName);
117
58
  return runProcess(binaryPath, args);
118
59
  }
119
60
 
120
- function maybeRunDevFallback(args) {
121
- let sourceEntrypoint = path.resolve(THIS_DIR, "../src/entry.ts");
122
- if (!fs.existsSync(sourceEntrypoint)) {
123
- return false;
124
- }
125
-
126
- runProcess("bun", [sourceEntrypoint, ...args]);
127
- return true;
128
- }
129
-
130
61
  function main() {
131
62
  let packageName = resolvePlatformPackageName();
132
63
 
@@ -144,36 +75,12 @@ function main() {
144
75
  let exitCode = runPlatformBinary(packageName, args);
145
76
  process.exit(exitCode);
146
77
  } catch (error) {
147
- let installError = null;
148
- if (
149
- error instanceof Error &&
150
- error.message.includes("Could not resolve") &&
151
- error.message.includes(`${packageName}/package.json`)
152
- ) {
153
- try {
154
- process.stderr.write(
155
- `[jam] Installing platform package ${packageName}...\n`
156
- );
157
- installPlatformPackage(packageName);
158
- let exitCode = runPlatformBinary(packageName, args);
159
- process.exit(exitCode);
160
- } catch (secondError) {
161
- installError = secondError;
162
- }
163
- }
164
-
165
- if (installError === null && maybeRunDevFallback(args)) {
166
- return;
167
- }
168
-
169
- let message = installError instanceof Error
170
- ? installError.message
171
- : error instanceof Error
172
- ? error.message
173
- : String(error);
78
+ let message = error instanceof Error
79
+ ? error.message
80
+ : String(error);
174
81
  process.stderr.write(
175
- `[jam] Could not find platform binary package ${packageName}. ` +
176
- `Try reinstalling dependencies. (${message})\n`
82
+ `[jam] Could not find the installed platform binary ${packageName}. ` +
83
+ `Reinstall the \`jam\` package so npm can restore the matching optional dependency. (${message})\n`
177
84
  );
178
85
  process.exit(1);
179
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jam",
3
- "version": "0.9.3",
3
+ "version": "0.10.0",
4
4
  "description": "An application server for isolated JavaScript",
5
5
  "license": "MIT",
6
6
  "author": "Michael Jackson <mjijackson@gmail.com>",
@@ -29,28 +29,22 @@
29
29
  ]
30
30
  },
31
31
  "optionalDependencies": {
32
- "jam-darwin-arm64": "0.9.3",
33
- "jam-darwin-x64": "0.9.3",
34
- "jam-linux-arm64": "0.9.3",
35
- "jam-linux-x64": "0.9.3"
36
- },
37
- "dependencies": {
38
- "@jridgewell/trace-mapping": "^0.3.31",
39
- "typescript": "^5.6.3"
32
+ "jam-darwin-arm64": "0.10.0",
33
+ "jam-darwin-x64": "0.10.0",
34
+ "jam-linux-arm64": "0.10.0",
35
+ "jam-linux-x64": "0.10.0"
40
36
  },
41
37
  "devDependencies": {
42
- "@types/node": "^22.15.31",
43
- "bun-types": "^1.2.8"
38
+ "@types/node": "^24.0.0",
39
+ "typescript": "^5.6.3"
44
40
  },
45
41
  "engines": {
46
- "bun": ">=1.2"
42
+ "node": ">=24.14.0"
47
43
  },
48
44
  "scripts": {
45
+ "build": "node ./scripts/build-types.js",
49
46
  "lint": "eslint .",
50
- "typecheck": "tsc -p tsconfig.json",
51
- "test": "bun run test:unit && bun run test:integration",
52
- "test:unit": "bun test ./src/**/*.test.ts",
53
- "test:integration": "bun test ./test/*.test.ts",
54
- "build:bin": "bun build ./src/entry.ts --compile --outfile ./dist/jam && bun build ./src/worker-thread.ts --target=bun --outfile ./dist/worker-thread.js"
47
+ "typecheck": "pnpm run build && tsc -p tsconfig.json",
48
+ "test": "node --eval \"\""
55
49
  }
56
50
  }
@@ -46,10 +46,135 @@ declare module "jam:test" {
46
46
  operator: string;
47
47
  }
48
48
 
49
+ export type AssertPredicate =
50
+ | RegExp
51
+ | (new (...args: unknown[]) => object)
52
+ | ((thrown: unknown) => boolean)
53
+ | object
54
+ | Error;
55
+
49
56
  export namespace assert {
50
- function ok(value: unknown, message?: string): asserts value;
51
- function equal(actual: unknown, expected: unknown, message?: string): void;
52
- function deepEqual(actual: unknown, expected: unknown, message?: string): void;
57
+ function ok(value: unknown, message?: string | Error): asserts value;
58
+ function equal(actual: unknown, expected: unknown, message?: string | Error): void;
59
+ function notEqual(actual: unknown, expected: unknown, message?: string | Error): void;
60
+ function fail(message?: string | Error): never;
61
+ function fail(
62
+ actual: unknown,
63
+ expected: unknown,
64
+ message?: string | Error,
65
+ operator?: string,
66
+ stackStartFn?: Function
67
+ ): never;
68
+ function ifError(value: unknown): void;
69
+ function match(string: string, regexp: RegExp, message?: string | Error): void;
70
+ function doesNotMatch(string: string, regexp: RegExp, message?: string | Error): void;
71
+ function strictEqual<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
72
+ function notStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
73
+ function deepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
74
+ function deepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
75
+ function notDeepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
76
+ function notDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
77
+ function throws(
78
+ fn: () => unknown,
79
+ message?: string | Error
80
+ ): void;
81
+ function throws(
82
+ fn: () => unknown,
83
+ expected: AssertPredicate,
84
+ message?: string | Error
85
+ ): void;
86
+ function doesNotThrow(
87
+ fn: () => unknown,
88
+ message?: string | Error
89
+ ): void;
90
+ function doesNotThrow(
91
+ fn: () => unknown,
92
+ expected: AssertPredicate,
93
+ message?: string | Error
94
+ ): void;
95
+ function rejects(
96
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
97
+ message?: string | Error
98
+ ): Promise<void>;
99
+ function rejects(
100
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
101
+ expected: AssertPredicate,
102
+ message?: string | Error
103
+ ): Promise<void>;
104
+ function doesNotReject(
105
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
106
+ message?: string | Error
107
+ ): Promise<void>;
108
+ function doesNotReject(
109
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
110
+ expected: AssertPredicate,
111
+ message?: string | Error
112
+ ): Promise<void>;
113
+ function partialDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
114
+ }
115
+
116
+ export function strict(value: unknown, message?: string | Error): asserts value;
117
+
118
+ export namespace strict {
119
+ export { AssertionError, strict };
120
+
121
+ function ok(value: unknown, message?: string | Error): asserts value;
122
+ function equal<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
123
+ function notEqual(actual: unknown, expected: unknown, message?: string | Error): void;
124
+ function fail(message?: string | Error): never;
125
+ function fail(
126
+ actual: unknown,
127
+ expected: unknown,
128
+ message?: string | Error,
129
+ operator?: string,
130
+ stackStartFn?: Function
131
+ ): never;
132
+ function ifError(value: unknown): void;
133
+ function match(string: string, regexp: RegExp, message?: string | Error): void;
134
+ function doesNotMatch(string: string, regexp: RegExp, message?: string | Error): void;
135
+ function strictEqual<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
136
+ function notStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
137
+ function deepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
138
+ function deepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
139
+ function notDeepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
140
+ function notDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
141
+ function throws(
142
+ fn: () => unknown,
143
+ message?: string | Error
144
+ ): void;
145
+ function throws(
146
+ fn: () => unknown,
147
+ expected: AssertPredicate,
148
+ message?: string | Error
149
+ ): void;
150
+ function doesNotThrow(
151
+ fn: () => unknown,
152
+ message?: string | Error
153
+ ): void;
154
+ function doesNotThrow(
155
+ fn: () => unknown,
156
+ expected: AssertPredicate,
157
+ message?: string | Error
158
+ ): void;
159
+ function rejects(
160
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
161
+ message?: string | Error
162
+ ): Promise<void>;
163
+ function rejects(
164
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
165
+ expected: AssertPredicate,
166
+ message?: string | Error
167
+ ): Promise<void>;
168
+ function doesNotReject(
169
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
170
+ message?: string | Error
171
+ ): Promise<void>;
172
+ function doesNotReject(
173
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
174
+ expected: AssertPredicate,
175
+ message?: string | Error
176
+ ): Promise<void>;
177
+ function partialDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
53
178
  }
54
179
 
55
180
  export interface SpyCall {
@@ -73,6 +198,102 @@ declare module "jam:test" {
73
198
  export function restoreAll(): void;
74
199
  }
75
200
 
201
+ declare module "jam:test/strict" {
202
+ export class AssertionError extends Error {
203
+ actual: unknown;
204
+ expected: unknown;
205
+ operator: string;
206
+ }
207
+
208
+ export type AssertPredicate = import("jam:test").AssertPredicate;
209
+
210
+ export function ok(value: unknown, message?: string | Error): asserts value;
211
+ export function equal<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
212
+ export function notEqual(actual: unknown, expected: unknown, message?: string | Error): void;
213
+ export function fail(message?: string | Error): never;
214
+ export function fail(
215
+ actual: unknown,
216
+ expected: unknown,
217
+ message?: string | Error,
218
+ operator?: string,
219
+ stackStartFn?: Function
220
+ ): never;
221
+ export function ifError(value: unknown): void;
222
+ export function match(string: string, regexp: RegExp, message?: string | Error): void;
223
+ export function doesNotMatch(string: string, regexp: RegExp, message?: string | Error): void;
224
+ export function strictEqual<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
225
+ export function notStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
226
+ export function deepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
227
+ export function deepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
228
+ export function notDeepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
229
+ export function notDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
230
+ export function throws(
231
+ fn: () => unknown,
232
+ message?: string | Error
233
+ ): void;
234
+ export function throws(
235
+ fn: () => unknown,
236
+ expected: AssertPredicate,
237
+ message?: string | Error
238
+ ): void;
239
+ export function doesNotThrow(
240
+ fn: () => unknown,
241
+ message?: string | Error
242
+ ): void;
243
+ export function doesNotThrow(
244
+ fn: () => unknown,
245
+ expected: AssertPredicate,
246
+ message?: string | Error
247
+ ): void;
248
+ export function rejects(
249
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
250
+ message?: string | Error
251
+ ): Promise<void>;
252
+ export function rejects(
253
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
254
+ expected: AssertPredicate,
255
+ message?: string | Error
256
+ ): Promise<void>;
257
+ export function doesNotReject(
258
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
259
+ message?: string | Error
260
+ ): Promise<void>;
261
+ export function doesNotReject(
262
+ promiseOrFn: Promise<unknown> | (() => Promise<unknown>),
263
+ expected: AssertPredicate,
264
+ message?: string | Error
265
+ ): Promise<void>;
266
+ export function partialDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
267
+ export function strict(value: unknown, message?: string | Error): asserts value;
268
+
269
+ export namespace strict {
270
+ export {
271
+ AssertionError,
272
+ deepEqual,
273
+ deepStrictEqual,
274
+ doesNotMatch,
275
+ doesNotReject,
276
+ doesNotThrow,
277
+ equal,
278
+ fail,
279
+ ifError,
280
+ match,
281
+ notDeepEqual,
282
+ notDeepStrictEqual,
283
+ notEqual,
284
+ notStrictEqual,
285
+ ok,
286
+ partialDeepStrictEqual,
287
+ rejects,
288
+ strict,
289
+ strictEqual,
290
+ throws
291
+ };
292
+ }
293
+
294
+ export default strict;
295
+ }
296
+
76
297
  declare type JamPhpFile = {
77
298
  name: string;
78
299
  type: string;