stitchkit 0.104.1 → 0.104.2

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/CHANGELOG.md CHANGED
@@ -15,6 +15,16 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
15
15
 
16
16
  ## [Unreleased]
17
17
 
18
+ ## [0.104.2] - 2026-10-04
19
+
20
+ ### Added
21
+
22
+ - `stitchkit/files/packaging`: one multi-target companion plugin packages both Darwin addons into a universal JS artifact; explicit per-architecture output paths preserve single-target and embedded recipes.
23
+
24
+ ### Fixed
25
+
26
+ - Native qualification waits for the helper’s actual first write instead of inferring readiness from startup timing.
27
+
18
28
  ## [0.104.1] - 2026-10-04
19
29
 
20
30
  ### Added
@@ -33,18 +33,54 @@ function nativeLoaderSource(assets) {
33
33
 
34
34
  // src/files/native-packaging.ts
35
35
  var OutputPathSchema = z2.string().min(1).refine((value) => !value.startsWith("/") && !/^[a-z]:/i.test(value) && !value.includes("\\") && value.split("/").every((part) => part !== ".." && part !== "." && part.length > 0), "Expected a relative output path without traversal");
36
- var OptionsSchema = z2.object({
36
+ var ArchitectureSchema = z2.enum(["arm64", "x64"]);
37
+ var CommonOptions = {
37
38
  platform: z2.string().min(1),
39
+ entryPath: OutputPathSchema.refine((value) => !value.includes("[") && !value.includes("]"), "Expected a fixed entry path without Bun naming templates")
40
+ };
41
+ var SingleOptionsSchema = z2.object({
42
+ ...CommonOptions,
38
43
  architecture: z2.string().min(1),
39
44
  delivery: z2.enum(["companion", "embedded"]),
40
- entryPath: OutputPathSchema.refine((value) => !value.includes("[") && !value.includes("]"), "Expected a fixed entry path without Bun naming templates"),
41
45
  assetPath: OutputPathSchema
42
- }).refine((input) => input.entryPath !== input.assetPath && !input.entryPath.startsWith(`${input.assetPath}/`) && !input.assetPath.startsWith(`${input.entryPath}/`), "Entry and addon must have non-overlapping paths");
46
+ });
47
+ var MultipleOptionsSchema = z2.object({
48
+ ...CommonOptions,
49
+ architecture: z2.array(z2.string().min(1)).min(1),
50
+ delivery: z2.literal("companion"),
51
+ assetPath: z2.record(z2.string().min(1), OutputPathSchema)
52
+ });
53
+ var OptionsSchema = z2.union([SingleOptionsSchema, MultipleOptionsSchema]).superRefine((input, ctx) => {
54
+ const targets = typeof input.architecture === "string" ? [input.architecture] : input.architecture;
55
+ if (new Set(targets).size !== targets.length)
56
+ ctx.addIssue({ code: "custom", message: "Architecture targets must be unique" });
57
+ const assetPaths = typeof input.assetPath === "string" ? [input.assetPath] : Object.values(input.assetPath);
58
+ const assetMap = input.assetPath;
59
+ if (typeof assetMap !== "string" && (Object.keys(assetMap).length !== targets.length || targets.some((target) => !Object.hasOwn(assetMap, target))))
60
+ ctx.addIssue({
61
+ code: "custom",
62
+ message: "Asset paths must name exactly the declared architectures"
63
+ });
64
+ const paths = [input.entryPath, ...assetPaths];
65
+ for (let at = 0;at < paths.length; at++) {
66
+ const left = paths[at];
67
+ if (!left)
68
+ continue;
69
+ for (const right of paths.slice(at + 1)) {
70
+ if (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`))
71
+ ctx.addIssue({
72
+ code: "custom",
73
+ message: "Entry and addons must have non-overlapping paths"
74
+ });
75
+ }
76
+ }
77
+ });
43
78
  var AssetSchema = z2.object({
44
79
  sourcePath: z2.string(),
45
80
  outputPath: z2.string(),
46
81
  sha256: z2.string().regex(/^[a-f0-9]{64}$/)
47
82
  });
83
+ var TargetAssetSchema = AssetSchema.extend({ architecture: ArchitectureSchema });
48
84
  var RefusalSchema = z2.object({
49
85
  state: z2.enum(["unsupported", "missing"]),
50
86
  platform: z2.string(),
@@ -65,48 +101,63 @@ function installedPackageRoot() {
65
101
  }
66
102
  function createNativePackaging(options) {
67
103
  const input = OptionsSchema.parse(options);
68
- if (input.platform !== "darwin" || input.architecture !== "arm64" && input.architecture !== "x64") {
69
- return {
70
- state: "unsupported",
71
- platform: input.platform,
72
- architecture: input.architecture,
73
- code: "NATIVE_TARGET_UNSUPPORTED"
74
- };
104
+ const declared = typeof input.architecture === "string" ? [input.architecture] : input.architecture;
105
+ const architectures = [];
106
+ for (const architecture of declared) {
107
+ const target = ArchitectureSchema.safeParse(architecture);
108
+ if (input.platform !== "darwin" || !target.success)
109
+ return {
110
+ state: "unsupported",
111
+ platform: input.platform,
112
+ architecture,
113
+ code: "NATIVE_TARGET_UNSUPPORTED"
114
+ };
115
+ architectures.push(target.data);
75
116
  }
76
117
  const root = installedPackageRoot();
77
118
  const layout = NativeLayoutSchema.parse(JSON.parse(readFileSync(resolve(root, "native-assets.json"), "utf8")));
78
119
  const manifest = z2.object({ name: z2.literal("stitchkit"), version: z2.string().min(1) }).parse(JSON.parse(readFileSync(resolve(root, "package.json"), "utf8")));
79
120
  const loaderPath = resolve(root, layout.loader);
80
- const sourcePath = resolve(root, layout.assets[input.architecture]);
81
- let bytes;
82
- try {
83
- bytes = readFileSync(sourcePath);
84
- } catch (cause) {
85
- if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") {
86
- return {
87
- state: "missing",
88
- platform: input.platform,
89
- architecture: input.architecture,
90
- code: "NATIVE_ASSET_MISSING"
91
- };
121
+ const assets = [];
122
+ const specifiers = {};
123
+ for (const architecture of architectures) {
124
+ const sourcePath = resolve(root, layout.assets[architecture]);
125
+ const outputPath = typeof input.assetPath === "string" ? input.assetPath : input.assetPath[architecture];
126
+ if (!outputPath)
127
+ throw new Error("Declared architecture has no output path");
128
+ let bytes;
129
+ try {
130
+ bytes = readFileSync(sourcePath);
131
+ } catch (cause) {
132
+ if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
133
+ return {
134
+ state: "missing",
135
+ platform: input.platform,
136
+ architecture,
137
+ code: "NATIVE_ASSET_MISSING"
138
+ };
139
+ throw cause;
92
140
  }
93
- throw cause;
141
+ const outputSpecifier = relative(dirname(input.entryPath), outputPath).split("\\").join("/");
142
+ specifiers[architecture] = input.delivery === "embedded" ? sourcePath : outputSpecifier.startsWith(".") ? outputSpecifier : `./${outputSpecifier}`;
143
+ const asset = {
144
+ sourcePath,
145
+ outputPath,
146
+ sha256: createHash("sha256").update(bytes).digest("hex")
147
+ };
148
+ assets.push(typeof input.architecture === "string" ? asset : { ...asset, architecture });
94
149
  }
95
- const outputSpecifier = relative(dirname(input.entryPath), input.assetPath).split("\\").join("/");
96
- const specifier = input.delivery === "embedded" ? sourcePath : outputSpecifier.startsWith(".") ? outputSpecifier : `./${outputSpecifier}`;
97
- const contents = nativeLoaderSource({ [input.architecture]: specifier });
150
+ const first = architectures[0];
151
+ if (!first)
152
+ throw new Error("Native packaging has no declared targets");
153
+ const contents = nativeLoaderSource(specifiers);
154
+ const external = new Set(Object.values(specifiers));
98
155
  return {
99
156
  state: "ready",
100
157
  platform: "darwin",
101
- architecture: input.architecture,
158
+ architecture: typeof input.architecture === "string" ? first : architectures,
102
159
  packageVersion: manifest.version,
103
- assets: [
104
- {
105
- sourcePath,
106
- outputPath: input.assetPath,
107
- sha256: createHash("sha256").update(bytes).digest("hex")
108
- }
109
- ],
160
+ assets,
110
161
  plugin: {
111
162
  name: "stitchkit-native-packaging",
112
163
  setup(build) {
@@ -122,7 +173,7 @@ function createNativePackaging(options) {
122
173
  }
123
174
  build.onLoad({ filter: /\.[cm]?js$/ }, (args) => args.path === loaderPath ? { contents, loader: "js" } : undefined);
124
175
  if (input.delivery === "companion") {
125
- build.onResolve({ filter: /./ }, (args) => args.importer === loaderPath && args.path === specifier ? { path: specifier, external: true } : undefined);
176
+ build.onResolve({ filter: /./ }, (args) => args.importer === loaderPath && external.has(args.path) ? { path: args.path, external: true } : undefined);
126
177
  }
127
178
  }
128
179
  }
@@ -1,19 +1,39 @@
1
1
  import { z } from 'zod';
2
- declare const OptionsSchema: z.ZodObject<{
2
+ declare const ArchitectureSchema: z.ZodEnum<{
3
+ arm64: "arm64";
4
+ x64: "x64";
5
+ }>;
6
+ declare const SingleOptionsSchema: z.ZodObject<{
3
7
  platform: z.ZodString;
8
+ entryPath: z.ZodString;
4
9
  architecture: z.ZodString;
5
10
  delivery: z.ZodEnum<{
6
11
  companion: "companion";
7
12
  embedded: "embedded";
8
13
  }>;
9
- entryPath: z.ZodString;
10
14
  assetPath: z.ZodString;
11
15
  }, z.core.$strip>;
16
+ declare const MultipleOptionsSchema: z.ZodObject<{
17
+ platform: z.ZodString;
18
+ entryPath: z.ZodString;
19
+ architecture: z.ZodArray<z.ZodString>;
20
+ delivery: z.ZodLiteral<"companion">;
21
+ assetPath: z.ZodRecord<z.ZodString, z.ZodString>;
22
+ }, z.core.$strip>;
12
23
  declare const AssetSchema: z.ZodObject<{
13
24
  sourcePath: z.ZodString;
14
25
  outputPath: z.ZodString;
15
26
  sha256: z.ZodString;
16
27
  }, z.core.$strip>;
28
+ declare const TargetAssetSchema: z.ZodObject<{
29
+ sourcePath: z.ZodString;
30
+ outputPath: z.ZodString;
31
+ sha256: z.ZodString;
32
+ architecture: z.ZodEnum<{
33
+ arm64: "arm64";
34
+ x64: "x64";
35
+ }>;
36
+ }, z.core.$strip>;
17
37
  declare const RefusalSchema: z.ZodObject<{
18
38
  state: z.ZodEnum<{
19
39
  missing: "missing";
@@ -26,8 +46,8 @@ declare const RefusalSchema: z.ZodObject<{
26
46
  NATIVE_TARGET_UNSUPPORTED: "NATIVE_TARGET_UNSUPPORTED";
27
47
  }>;
28
48
  }, z.core.$strip>;
29
- export type NativePackagingOptions = z.input<typeof OptionsSchema>;
30
- export type NativePackagingAsset = z.infer<typeof AssetSchema>;
49
+ export type NativePackagingOptions<Multiple extends boolean = false> = Multiple extends true ? z.input<typeof MultipleOptionsSchema> : z.input<typeof SingleOptionsSchema>;
50
+ export type NativePackagingAsset<Multiple extends boolean = false> = Multiple extends true ? z.infer<typeof TargetAssetSchema> : z.infer<typeof AssetSchema>;
31
51
  /** Structural Bun plugin protocol: declarations need no Bun runtime or ambient types. */
32
52
  export type NativePackagingPlugin = {
33
53
  name: string;
@@ -58,15 +78,17 @@ export type NativePackagingPlugin = {
58
78
  } | undefined) => unknown;
59
79
  }) => void;
60
80
  };
61
- export type NativePackagingResult = z.infer<typeof RefusalSchema> | {
81
+ export type NativePackagingResult<Multiple extends boolean = false> = z.infer<typeof RefusalSchema> | {
62
82
  state: 'ready';
63
83
  platform: 'darwin';
64
- architecture: 'arm64' | 'x64';
84
+ architecture: Multiple extends true ? z.infer<typeof ArchitectureSchema>[] : z.infer<typeof ArchitectureSchema>;
65
85
  packageVersion: string;
66
- assets: NativePackagingAsset[];
86
+ assets: NativePackagingAsset<Multiple>[];
67
87
  plugin: NativePackagingPlugin;
68
88
  };
69
89
  /** Resolve this installed package's asset graph, without parsing downstream loader text. */
70
90
  export declare function createNativePackaging(options: NativePackagingOptions): NativePackagingResult;
91
+ export declare function createNativePackaging(options: NativePackagingOptions<true>): NativePackagingResult<true>;
92
+ export declare function createNativePackaging(options: NativePackagingOptions<boolean>): NativePackagingResult<boolean>;
71
93
  export {};
72
94
  //# sourceMappingURL=native-packaging.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"native-packaging.d.ts","sourceRoot":"","sources":["../../src/files/native-packaging.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB,QAAA,MAAM,aAAa;;;;;;;;;iBAiBhB,CAAC;AACJ,QAAA,MAAM,WAAW;;;;iBAIf,CAAC;AACH,QAAA,MAAM,aAAa;;;;;;;;;;;iBAKjB,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACnE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAE/D,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,KAAK,EAAE;QACb,MAAM,EAAE;YACN,SAAS,CAAC,EAAE,OAAO,CAAC;YACpB,MAAM,CAAC,EAAE,MAAM,GAAG;gBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YACrC,WAAW,EAAE,MAAM,EAAE,CAAC;SACvB,CAAC;QACF,MAAM,EAAE,CACN,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,KAAK;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,GAAG,SAAS,KACjF,OAAO,CAAC;QACb,SAAS,EAAE,CACT,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YACf,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,MAAM,CAAC;SAClB,KAAK;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,GAAG,SAAS,KAClD,OAAO,CAAC;KACd,KAAK,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAC7B;IACE,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,OAAO,GAAG,KAAK,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,MAAM,EAAE,qBAAqB,CAAC;CAC/B,CAAC;AAaN,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CAoF5F"}
1
+ {"version":3,"file":"native-packaging.d.ts","sourceRoot":"","sources":["../../src/files/native-packaging.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB,QAAA,MAAM,kBAAkB;;;EAA2B,CAAC;AAQpD,QAAA,MAAM,mBAAmB;;;;;;;;;iBAKvB,CAAC;AACH,QAAA,MAAM,qBAAqB;;;;;;iBAKzB,CAAC;AAiCH,QAAA,MAAM,WAAW;;;;iBAIf,CAAC;AACH,QAAA,MAAM,iBAAiB;;;;;;;;iBAA2D,CAAC;AACnF,QAAA,MAAM,aAAa;;;;;;;;;;;iBAKjB,CAAC;AAEH,MAAM,MAAM,sBAAsB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAAI,QAAQ,SAAS,IAAI,GACxF,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GACrC,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACxC,MAAM,MAAM,oBAAoB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAAI,QAAQ,SAAS,IAAI,GACtF,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GACjC,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhC,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,KAAK,EAAE;QACb,MAAM,EAAE;YACN,SAAS,CAAC,EAAE,OAAO,CAAC;YACpB,MAAM,CAAC,EAAE,MAAM,GAAG;gBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YACrC,WAAW,EAAE,MAAM,EAAE,CAAC;SACvB,CAAC;QACF,MAAM,EAAE,CACN,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,KAAK;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,GAAG,SAAS,KACjF,OAAO,CAAC;QACb,SAAS,EAAE,CACT,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YACf,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,MAAM,CAAC;SAClB,KAAK;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,GAAG,SAAS,KAClD,OAAO,CAAC;KACd,KAAK,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAC9D,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAC7B;IACE,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,QAAQ,SAAS,IAAI,GAC/B,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,EAAE,GACpC,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACzC,MAAM,EAAE,qBAAqB,CAAC;CAC/B,CAAC;AAaN,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CAAC;AAC9F,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,CAAC,IAAI,CAAC,GACpC,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAC/B,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,GACvC,qBAAqB,CAAC,OAAO,CAAC,CAAC"}
@@ -20,7 +20,14 @@ It resolves the installed package's target/version and original addon SHA256.
20
20
  `platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit public inputs.
21
21
  The result is `ready` with assets and a structural Bun plugin, or `unsupported`/`missing` with a safe code.
22
22
  Malformed options/metadata and other filesystem errors fail rather than masquerade as missing.
23
- Companion mode places an external addon relative to the emitted entry; embedded mode lets
23
+ Companion accepts a single `architecture` string with an `assetPath` string, or an architecture
24
+ array with an exact per-architecture `assetPath` map. `NativePackagingOptions<true>` and
25
+ `NativePackagingResult<true>` describe the array form; default types preserve single-target signatures.
26
+ A ready array-form result carries the architecture array; `NativePackagingAsset<true>` identifies
27
+ each asset architecture. Default asset types and single-target runtime objects retain their three fields.
28
+ Targets must be unique; entry and all asset paths must be disjoint. One lazy loader chooses only
29
+ the actual runtime architecture, with no fallback.
30
+ Companion mode places external addons relative to the emitted entry; embedded mode lets
24
31
  Bun compile retain the matching addon. Keep JS builds without splitting, preserve every output,
25
32
  and copy each original asset to its `outputPath` after verifying `sha256`.
26
33
  This evolving entrypoint is a build dependency; runtime imports do not reach it.
package/llms/process.txt CHANGED
@@ -341,6 +341,27 @@ Archive the complete output directory with an integrity manifest, unpack to a cl
341
341
  verify the same hashes there, and run offline without the build tree or `node_modules`.
342
342
  A digest provides integrity, not authenticity: signature and trust policy remain application-owned.
343
343
 
344
+ From 0.104.2, one JS artifact can run on both Darwin architectures; change only the packaging inputs:
345
+
346
+ ```ts
347
+ const native = createNativePackaging({
348
+ platform: 'darwin', architecture: ['arm64', 'x64'], delivery: 'companion',
349
+ entryPath: 'app/native.js',
350
+ assetPath: { arm64: 'addons/arm.node', x64: 'addons/intel.node' },
351
+ })
352
+ ```
353
+
354
+ Use the same single plugin and copy loop above. A single-target loader deliberately refuses the
355
+ other architecture; two competing plugins cannot produce a universal loader. The array form
356
+ requires exactly one distinct output path per declared target. A ready result carries the target
357
+ array and both original asset hashes; `NativePackagingOptions<true>` /
358
+ `NativePackagingResult<true>` describe this form when explicitly annotating variables.
359
+ The loader selects only `process.arch`: a missing or wrong-architecture selected addon refuses,
360
+ even when the other valid addon is present. Linux runtime imports remain lazy and use Linux
361
+ process primitives without loading Darwin assets. Qualify the exact same JS bytes on real
362
+ Darwin arm64 and x64 machines, with both companions preserved through archive delivery.
363
+ Build-machine architecture and cross-build success cannot establish universal native support.
364
+
344
365
  For a standalone executable use `delivery: 'embedded'` and the same plugin in `Bun.build`
345
366
  with `compile: { outfile: ... }`. Bun embeds the selected addon; `assets` identifies its
346
367
  original bytes for qualification, not a companion that must be installed beside the executable.
package/llms-full.txt CHANGED
@@ -8457,6 +8457,27 @@ Archive the complete output directory with an integrity manifest, unpack to a cl
8457
8457
  verify the same hashes there, and run offline without the build tree or `node_modules`.
8458
8458
  A digest provides integrity, not authenticity: signature and trust policy remain application-owned.
8459
8459
 
8460
+ From 0.104.2, one JS artifact can run on both Darwin architectures; change only the packaging inputs:
8461
+
8462
+ ```ts
8463
+ const native = createNativePackaging({
8464
+ platform: 'darwin', architecture: ['arm64', 'x64'], delivery: 'companion',
8465
+ entryPath: 'app/native.js',
8466
+ assetPath: { arm64: 'addons/arm.node', x64: 'addons/intel.node' },
8467
+ })
8468
+ ```
8469
+
8470
+ Use the same single plugin and copy loop above. A single-target loader deliberately refuses the
8471
+ other architecture; two competing plugins cannot produce a universal loader. The array form
8472
+ requires exactly one distinct output path per declared target. A ready result carries the target
8473
+ array and both original asset hashes; `NativePackagingOptions<true>` /
8474
+ `NativePackagingResult<true>` describe this form when explicitly annotating variables.
8475
+ The loader selects only `process.arch`: a missing or wrong-architecture selected addon refuses,
8476
+ even when the other valid addon is present. Linux runtime imports remain lazy and use Linux
8477
+ process primitives without loading Darwin assets. Qualify the exact same JS bytes on real
8478
+ Darwin arm64 and x64 machines, with both companions preserved through archive delivery.
8479
+ Build-machine architecture and cross-build success cannot establish universal native support.
8480
+
8460
8481
  For a standalone executable use `delivery: 'embedded'` and the same plugin in `Bun.build`
8461
8482
  with `compile: { outfile: ... }`. Bun embeds the selected addon; `assets` identifies its
8462
8483
  original bytes for qualification, not a companion that must be installed beside the executable.
@@ -21993,7 +22014,14 @@ It resolves the installed package's target/version and original addon SHA256.
21993
22014
  `platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit public inputs.
21994
22015
  The result is `ready` with assets and a structural Bun plugin, or `unsupported`/`missing` with a safe code.
21995
22016
  Malformed options/metadata and other filesystem errors fail rather than masquerade as missing.
21996
- Companion mode places an external addon relative to the emitted entry; embedded mode lets
22017
+ Companion accepts a single `architecture` string with an `assetPath` string, or an architecture
22018
+ array with an exact per-architecture `assetPath` map. `NativePackagingOptions<true>` and
22019
+ `NativePackagingResult<true>` describe the array form; default types preserve single-target signatures.
22020
+ A ready array-form result carries the architecture array; `NativePackagingAsset<true>` identifies
22021
+ each asset architecture. Default asset types and single-target runtime objects retain their three fields.
22022
+ Targets must be unique; entry and all asset paths must be disjoint. One lazy loader chooses only
22023
+ the actual runtime architecture, with no fallback.
22024
+ Companion mode places external addons relative to the emitted entry; embedded mode lets
21997
22025
  Bun compile retain the matching addon. Keep JS builds without splitting, preserve every output,
21998
22026
  and copy each original asset to its `outputPath` after verifying `sha256`.
21999
22027
  This evolving entrypoint is a build dependency; runtime imports do not reach it.
package/llms.txt CHANGED
@@ -56,8 +56,8 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
56
56
  - **stitchkit/agent-runtime/react**: [llms/agent-runtime-react.txt](llms/agent-runtime-react.txt) 1.0 KB
57
57
  - **stitchkit/agent-runtime/realtime**: [llms/agent-runtime-realtime.txt](llms/agent-runtime-realtime.txt) 1.8 KB
58
58
  - **stitchkit/agent-runtime/harness-tools**: [llms/agent-runtime-harness-tools.txt](llms/agent-runtime-harness-tools.txt) 1.3 KB
59
- - **stitchkit/process**: [llms/process.txt](llms/process.txt) 25.4 KB
60
- - **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 1.5 KB
59
+ - **stitchkit/process**: [llms/process.txt](llms/process.txt) 26.6 KB
60
+ - **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 2.1 KB
61
61
 
62
62
  ## Upgrading slices
63
63
  - **Upgrading — how to move across versions**: [llms/upgrading.txt](llms/upgrading.txt) 10.3 KB
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.104.1",
3
+ "version": "0.104.2",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",