every-plugin 3.0.0-rc.14 → 3.0.0-rc.16
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/dist/build/artifact-names.cjs +9 -6
- package/dist/build/artifact-names.cjs.map +1 -1
- package/dist/build/artifact-names.d.cts +7 -5
- package/dist/build/artifact-names.d.cts.map +1 -1
- package/dist/build/artifact-names.d.mts +7 -5
- package/dist/build/artifact-names.d.mts.map +1 -1
- package/dist/build/artifact-names.mjs +8 -5
- package/dist/build/artifact-names.mjs.map +1 -1
- package/dist/build/contract-types.cjs +1 -1
- package/dist/build/rspack/build-report-plugin.cjs +1 -1
- package/dist/build/rspack/chunk-completeness-plugin.cjs +1 -1
- package/dist/build/rspack/compose.cjs +3 -3
- package/dist/build/rspack/generated-config.cjs +2 -2
- package/dist/build/rspack/index.cjs +5 -5
- package/dist/build/rspack/module-federation.cjs +1 -1
- package/dist/build/rspack/plugin.cjs +8 -8
- package/dist/build/rspack/utils.cjs +2 -2
- package/dist/build/ui/factory.cjs +3 -3
- package/dist/build/ui/generated-config.cjs +2 -2
- package/dist/build/ui/hash-artifacts-plugin.cjs +2 -2
- package/dist/build/ui/index.cjs +9 -9
- package/dist/build/ui/manifest-plugin.cjs +1 -1
- package/dist/build/ui/rsbuild-config.cjs +10 -10
- package/dist/build/ui/stubs.cjs +2 -7
- package/dist/build/ui/stubs.cjs.map +1 -1
- package/dist/build/ui/stubs.d.cts.map +1 -1
- package/dist/build/ui/stubs.d.mts.map +1 -1
- package/dist/build/ui/stubs.mjs +2 -7
- package/dist/build/ui/stubs.mjs.map +1 -1
- package/dist/cli.cjs +3 -3
- package/dist/client.cjs +8 -4
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts.map +1 -1
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +8 -4
- package/dist/client.mjs.map +1 -1
- package/dist/dev/serve.cjs +9 -9
- package/dist/errors.cjs +12 -2
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +15 -1
- package/dist/errors.d.cts.map +1 -1
- package/dist/errors.d.mts +15 -1
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +11 -2
- package/dist/errors.mjs.map +1 -1
- package/dist/index.cjs +8 -7
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/plugin.cjs +1 -1
- package/dist/remote-entry.cjs +1 -1
- package/dist/runtime/index.cjs +3 -3
- package/dist/runtime/mf-config.cjs +2 -2
- package/dist/runtime/mf-config.mjs +1 -1
- package/dist/runtime/services/module-federation.service.cjs +5 -5
- package/dist/runtime/services/normalize.cjs +1 -1
- package/dist/runtime/services/plugin-loader.service.cjs +5 -5
- package/dist/runtime/services/plugin.service.cjs +4 -4
- package/dist/runtime/services/secrets.service.cjs +2 -2
- package/dist/runtime/services/shared-identity.cjs +1 -1
- package/dist/runtime/validation.cjs +1 -1
- package/dist/ui/manifest/construct.cjs +18 -43
- package/dist/ui/manifest/construct.cjs.map +1 -1
- package/dist/ui/manifest/construct.d.cts +4 -13
- package/dist/ui/manifest/construct.d.cts.map +1 -1
- package/dist/ui/manifest/construct.d.mts +4 -13
- package/dist/ui/manifest/construct.d.mts.map +1 -1
- package/dist/ui/manifest/construct.mjs +14 -39
- package/dist/ui/manifest/construct.mjs.map +1 -1
- package/dist/ui/manifest/contract.cjs +1 -1
- package/dist/ui/manifest/descriptor.cjs +2 -2
- package/dist/ui/manifest/descriptor.mjs +1 -1
- package/dist/ui/manifest/generator.cjs +6 -6
- package/dist/ui/manifest/index.cjs +7 -7
- package/dist/ui/manifest/index.d.cts +3 -3
- package/dist/ui/manifest/index.d.mts +3 -3
- package/dist/ui/manifest/manifest-schema.cjs +1 -1
- package/dist/ui/manifest/mount-registry.cjs +6 -13
- package/dist/ui/manifest/mount-registry.cjs.map +1 -1
- package/dist/ui/manifest/mount-registry.d.cts +29 -36
- package/dist/ui/manifest/mount-registry.d.cts.map +1 -1
- package/dist/ui/manifest/mount-registry.d.mts +29 -36
- package/dist/ui/manifest/mount-registry.d.mts.map +1 -1
- package/dist/ui/manifest/mount-registry.mjs +6 -13
- package/dist/ui/manifest/mount-registry.mjs.map +1 -1
- package/dist/version-manifest.cjs +25 -0
- package/dist/version-manifest.cjs.map +1 -1
- package/dist/version-manifest.d.cts +13 -1
- package/dist/version-manifest.d.cts.map +1 -1
- package/dist/version-manifest.d.mts +13 -1
- package/dist/version-manifest.d.mts.map +1 -1
- package/dist/version-manifest.mjs +24 -1
- package/dist/version-manifest.mjs.map +1 -1
- package/package.json +28 -28
- package/skills/plugin-client/SKILL.md +2 -2
- package/src/build/artifact-names.ts +8 -5
- package/src/build/ui/stubs.ts +2 -7
- package/src/client.ts +9 -3
- package/src/errors.ts +10 -0
- package/src/ui/manifest/construct.ts +20 -65
- package/src/ui/manifest/index.ts +0 -2
- package/src/ui/manifest/mount-registry.ts +20 -20
- package/src/version-manifest.ts +27 -0
|
@@ -1,58 +1,51 @@
|
|
|
1
1
|
//#region src/ui/manifest/mount-registry.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Mount registry v2 —
|
|
3
|
+
* Mount registry v2 — shape-free (ADR 0008 §3).
|
|
4
4
|
*
|
|
5
|
-
* A mount is a
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* construction, so a plugin cannot ship a
|
|
12
|
-
*
|
|
5
|
+
* A mount is a host-owned pathless layout position. It carries no product
|
|
6
|
+
* semantics (no "dashboard", no shell, no chrome) — plugins bring their own
|
|
7
|
+
* layouts and route freely inside their subtree. A mount is declared by a
|
|
8
|
+
* ROOT-level pathless layout file whose `_`-prefixed segment names the mount
|
|
9
|
+
* (`_public.tsx` → `public`); the generator derives it and validates it
|
|
10
|
+
* against this registry; guards are ordinary beforeLoads attached HOST-side
|
|
11
|
+
* at construction from ConstructInput.guards, so a plugin cannot ship a
|
|
12
|
+
* route that escapes its mount's guard (plugins never construct route
|
|
13
|
+
* objects).
|
|
13
14
|
*
|
|
14
|
-
* `org`/`team` are declared vocabulary (parameterized membership
|
|
15
|
+
* `org`/`team` are declared vocabulary (parameterized membership) but
|
|
15
16
|
* unimplemented — construction rejects them until they land.
|
|
16
17
|
*/
|
|
17
18
|
interface MountDef {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
parameterized?: boolean;
|
|
19
|
+
/** The composing framework supplies this mount's guard via ConstructInput.guards. */
|
|
20
|
+
guarded: boolean;
|
|
21
21
|
implemented: boolean;
|
|
22
22
|
}
|
|
23
23
|
declare const MOUNT_REGISTRY: {
|
|
24
|
-
public: {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
implemented: true;
|
|
24
|
+
readonly public: {
|
|
25
|
+
readonly guarded: false;
|
|
26
|
+
readonly implemented: true;
|
|
28
27
|
};
|
|
29
|
-
authenticated: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
implemented: true;
|
|
28
|
+
readonly authenticated: {
|
|
29
|
+
readonly guarded: true;
|
|
30
|
+
readonly implemented: true;
|
|
33
31
|
};
|
|
34
|
-
admin: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
implemented: true;
|
|
32
|
+
readonly admin: {
|
|
33
|
+
readonly guarded: true;
|
|
34
|
+
readonly implemented: true;
|
|
38
35
|
};
|
|
39
|
-
org: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
parameterized: true;
|
|
43
|
-
implemented: false;
|
|
36
|
+
readonly org: {
|
|
37
|
+
readonly guarded: true;
|
|
38
|
+
readonly implemented: false;
|
|
44
39
|
};
|
|
45
|
-
team: {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
parameterized: true;
|
|
49
|
-
implemented: false;
|
|
40
|
+
readonly team: {
|
|
41
|
+
readonly guarded: true;
|
|
42
|
+
readonly implemented: false;
|
|
50
43
|
};
|
|
51
44
|
};
|
|
52
45
|
type MountId = Extract<keyof typeof MOUNT_REGISTRY, string>;
|
|
53
46
|
declare const MOUNTS: MountId[];
|
|
54
47
|
/** Bump when the registry shape changes — invalidates all compose digests. */
|
|
55
|
-
declare const MOUNT_REGISTRY_VERSION =
|
|
48
|
+
declare const MOUNT_REGISTRY_VERSION = 6;
|
|
56
49
|
/** Migration aliases: legacy `_`-segment names → canonical mounts. */
|
|
57
50
|
declare const MOUNT_ALIASES: Record<string, MountId>;
|
|
58
51
|
declare function resolveMountSegment(segment: string): MountId | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-registry.d.cts","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"mount-registry.d.cts","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"mappings":";;;;;;;;;;;;;;;;;UAiBiB;;EAEf;EACA;;cAGW;;aACD;aAAgB;;;aACT;aAAe;;;aACvB;aAAe;;;aACjB;aAAe;;;aACd;aAAe;;;KAGb,UAAU,qBAAqB;cAE9B,QAAwC;;cAGxC;;cAGA,eAAe,eAAe;iBAO3B,oBAAoB,kBAAkB"}
|
|
@@ -1,58 +1,51 @@
|
|
|
1
1
|
//#region src/ui/manifest/mount-registry.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Mount registry v2 —
|
|
3
|
+
* Mount registry v2 — shape-free (ADR 0008 §3).
|
|
4
4
|
*
|
|
5
|
-
* A mount is a
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* construction, so a plugin cannot ship a
|
|
12
|
-
*
|
|
5
|
+
* A mount is a host-owned pathless layout position. It carries no product
|
|
6
|
+
* semantics (no "dashboard", no shell, no chrome) — plugins bring their own
|
|
7
|
+
* layouts and route freely inside their subtree. A mount is declared by a
|
|
8
|
+
* ROOT-level pathless layout file whose `_`-prefixed segment names the mount
|
|
9
|
+
* (`_public.tsx` → `public`); the generator derives it and validates it
|
|
10
|
+
* against this registry; guards are ordinary beforeLoads attached HOST-side
|
|
11
|
+
* at construction from ConstructInput.guards, so a plugin cannot ship a
|
|
12
|
+
* route that escapes its mount's guard (plugins never construct route
|
|
13
|
+
* objects).
|
|
13
14
|
*
|
|
14
|
-
* `org`/`team` are declared vocabulary (parameterized membership
|
|
15
|
+
* `org`/`team` are declared vocabulary (parameterized membership) but
|
|
15
16
|
* unimplemented — construction rejects them until they land.
|
|
16
17
|
*/
|
|
17
18
|
interface MountDef {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
parameterized?: boolean;
|
|
19
|
+
/** The composing framework supplies this mount's guard via ConstructInput.guards. */
|
|
20
|
+
guarded: boolean;
|
|
21
21
|
implemented: boolean;
|
|
22
22
|
}
|
|
23
23
|
declare const MOUNT_REGISTRY: {
|
|
24
|
-
public: {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
implemented: true;
|
|
24
|
+
readonly public: {
|
|
25
|
+
readonly guarded: false;
|
|
26
|
+
readonly implemented: true;
|
|
28
27
|
};
|
|
29
|
-
authenticated: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
implemented: true;
|
|
28
|
+
readonly authenticated: {
|
|
29
|
+
readonly guarded: true;
|
|
30
|
+
readonly implemented: true;
|
|
33
31
|
};
|
|
34
|
-
admin: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
implemented: true;
|
|
32
|
+
readonly admin: {
|
|
33
|
+
readonly guarded: true;
|
|
34
|
+
readonly implemented: true;
|
|
38
35
|
};
|
|
39
|
-
org: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
parameterized: true;
|
|
43
|
-
implemented: false;
|
|
36
|
+
readonly org: {
|
|
37
|
+
readonly guarded: true;
|
|
38
|
+
readonly implemented: false;
|
|
44
39
|
};
|
|
45
|
-
team: {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
parameterized: true;
|
|
49
|
-
implemented: false;
|
|
40
|
+
readonly team: {
|
|
41
|
+
readonly guarded: true;
|
|
42
|
+
readonly implemented: false;
|
|
50
43
|
};
|
|
51
44
|
};
|
|
52
45
|
type MountId = Extract<keyof typeof MOUNT_REGISTRY, string>;
|
|
53
46
|
declare const MOUNTS: MountId[];
|
|
54
47
|
/** Bump when the registry shape changes — invalidates all compose digests. */
|
|
55
|
-
declare const MOUNT_REGISTRY_VERSION =
|
|
48
|
+
declare const MOUNT_REGISTRY_VERSION = 6;
|
|
56
49
|
/** Migration aliases: legacy `_`-segment names → canonical mounts. */
|
|
57
50
|
declare const MOUNT_ALIASES: Record<string, MountId>;
|
|
58
51
|
declare function resolveMountSegment(segment: string): MountId | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-registry.d.mts","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"mount-registry.d.mts","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"mappings":";;;;;;;;;;;;;;;;;UAiBiB;;EAEf;EACA;;cAGW;;aACD;aAAgB;;;aACT;aAAe;;;aACvB;aAAe;;;aACjB;aAAe;;;aACd;aAAe;;;KAGb,UAAU,qBAAqB;cAE9B,QAAwC;;cAGxC;;cAGA,eAAe,eAAe;iBAO3B,oBAAoB,kBAAkB"}
|
|
@@ -1,36 +1,29 @@
|
|
|
1
1
|
//#region src/ui/manifest/mount-registry.ts
|
|
2
2
|
const MOUNT_REGISTRY = {
|
|
3
3
|
public: {
|
|
4
|
-
|
|
5
|
-
gate: "none",
|
|
4
|
+
guarded: false,
|
|
6
5
|
implemented: true
|
|
7
6
|
},
|
|
8
7
|
authenticated: {
|
|
9
|
-
|
|
10
|
-
gate: "session",
|
|
8
|
+
guarded: true,
|
|
11
9
|
implemented: true
|
|
12
10
|
},
|
|
13
11
|
admin: {
|
|
14
|
-
|
|
15
|
-
gate: "admin",
|
|
12
|
+
guarded: true,
|
|
16
13
|
implemented: true
|
|
17
14
|
},
|
|
18
15
|
org: {
|
|
19
|
-
|
|
20
|
-
gate: "organization",
|
|
21
|
-
parameterized: true,
|
|
16
|
+
guarded: true,
|
|
22
17
|
implemented: false
|
|
23
18
|
},
|
|
24
19
|
team: {
|
|
25
|
-
|
|
26
|
-
gate: "team",
|
|
27
|
-
parameterized: true,
|
|
20
|
+
guarded: true,
|
|
28
21
|
implemented: false
|
|
29
22
|
}
|
|
30
23
|
};
|
|
31
24
|
const MOUNTS = Object.keys(MOUNT_REGISTRY);
|
|
32
25
|
/** Bump when the registry shape changes — invalidates all compose digests. */
|
|
33
|
-
const MOUNT_REGISTRY_VERSION =
|
|
26
|
+
const MOUNT_REGISTRY_VERSION = 6;
|
|
34
27
|
/** Migration aliases: legacy `_`-segment names → canonical mounts. */
|
|
35
28
|
const MOUNT_ALIASES = {
|
|
36
29
|
auth: "authenticated",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-registry.mjs","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"sourcesContent":["/**\n * Mount registry v2 —
|
|
1
|
+
{"version":3,"file":"mount-registry.mjs","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"sourcesContent":["/**\n * Mount registry v2 — shape-free (ADR 0008 §3).\n *\n * A mount is a host-owned pathless layout position. It carries no product\n * semantics (no \"dashboard\", no shell, no chrome) — plugins bring their own\n * layouts and route freely inside their subtree. A mount is declared by a\n * ROOT-level pathless layout file whose `_`-prefixed segment names the mount\n * (`_public.tsx` → `public`); the generator derives it and validates it\n * against this registry; guards are ordinary beforeLoads attached HOST-side\n * at construction from ConstructInput.guards, so a plugin cannot ship a\n * route that escapes its mount's guard (plugins never construct route\n * objects).\n *\n * `org`/`team` are declared vocabulary (parameterized membership) but\n * unimplemented — construction rejects them until they land.\n */\n\nexport interface MountDef {\n /** The composing framework supplies this mount's guard via ConstructInput.guards. */\n guarded: boolean;\n implemented: boolean;\n}\n\nexport const MOUNT_REGISTRY = {\n public: { guarded: false, implemented: true },\n authenticated: { guarded: true, implemented: true },\n admin: { guarded: true, implemented: true },\n org: { guarded: true, implemented: false },\n team: { guarded: true, implemented: false },\n} as const satisfies Record<string, MountDef>;\n\nexport type MountId = Extract<keyof typeof MOUNT_REGISTRY, string>;\n\nexport const MOUNTS = Object.keys(MOUNT_REGISTRY) as MountId[];\n\n/** Bump when the registry shape changes — invalidates all compose digests. */\nexport const MOUNT_REGISTRY_VERSION = 6;\n\n/** Migration aliases: legacy `_`-segment names → canonical mounts. */\nexport const MOUNT_ALIASES: Record<string, MountId> = {\n auth: \"authenticated\",\n authed: \"authenticated\",\n dashboard: \"authenticated\",\n organization: \"org\",\n};\n\nexport function resolveMountSegment(segment: string): MountId | undefined {\n if (segment in MOUNT_REGISTRY) return segment as MountId;\n return MOUNT_ALIASES[segment];\n}\n"],"mappings":";AAuBA,MAAa,iBAAiB;CAC5B,QAAQ;EAAE,SAAS;EAAO,aAAa;CAAK;CAC5C,eAAe;EAAE,SAAS;EAAM,aAAa;CAAK;CAClD,OAAO;EAAE,SAAS;EAAM,aAAa;CAAK;CAC1C,KAAK;EAAE,SAAS;EAAM,aAAa;CAAM;CACzC,MAAM;EAAE,SAAS;EAAM,aAAa;CAAM;AAC5C;AAIA,MAAa,SAAS,OAAO,KAAK,cAAc;;AAGhD,MAAa,yBAAyB;;AAGtC,MAAa,gBAAyC;CACpD,MAAM;CACN,QAAQ;CACR,WAAW;CACX,cAAc;AAChB;AAEA,SAAgB,oBAAoB,SAAsC;CACxE,IAAI,WAAW,gBAAgB,OAAO;CACtC,OAAO,cAAc;AACvB"}
|
|
@@ -12,10 +12,23 @@ let node_crypto = require("node:crypto");
|
|
|
12
12
|
* stops growing with artifact kinds and old versions stay fully servable.
|
|
13
13
|
*/
|
|
14
14
|
const SRI = zod.z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
15
|
+
/** Slot-relative directory holding one deploy's immutable file copies (#826). */
|
|
16
|
+
const VERSION_DIR_PATTERN = /^versions\/[0-9a-f]{16}$/;
|
|
15
17
|
const WorkspaceVersionManifestSchema = zod.z.object({
|
|
16
18
|
version: zod.z.string().regex(/^[0-9a-f]{16}$/),
|
|
17
19
|
builtAt: zod.z.string().optional(),
|
|
18
20
|
gitSha: zod.z.string().optional(),
|
|
21
|
+
/**
|
|
22
|
+
* Slot-relative directory (`versions/<dirId>`) holding this deploy's
|
|
23
|
+
* byte-immutable copies of every dist file (#826). When present, all
|
|
24
|
+
* artifact coordinates below resolve against `<slotBase>/<dir>/` — so a
|
|
25
|
+
* pinned child's entry fetches its expose chunk and chunks from the same
|
|
26
|
+
* frozen directory instead of the mutable slot root. Absent on legacy
|
|
27
|
+
* manifests: coordinates resolve against the slot root exactly as before.
|
|
28
|
+
* Derived from the `files` map (see `versionDirPath`), so it participates
|
|
29
|
+
* in the version hash without circularity.
|
|
30
|
+
*/
|
|
31
|
+
dir: zod.z.string().regex(VERSION_DIR_PATTERN).optional(),
|
|
19
32
|
entry: zod.z.string().min(1),
|
|
20
33
|
entryIntegrity: SRI,
|
|
21
34
|
ssr: zod.z.object({
|
|
@@ -65,6 +78,16 @@ function composeVersionManifest(input) {
|
|
|
65
78
|
version
|
|
66
79
|
});
|
|
67
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* The content-addressed directory name for one dist's file set (#826): a
|
|
83
|
+
* 16-hex hash over the canonical files map. Identical bytes → identical
|
|
84
|
+
* directory → re-deploying unchanged content is a server-side no-op, and a
|
|
85
|
+
* published pin's directory can never be rewritten by a later deploy
|
|
86
|
+
* (the upload service refuses conflicting writes under `versions/`).
|
|
87
|
+
*/
|
|
88
|
+
function versionDirPath(files) {
|
|
89
|
+
return `versions/${(0, node_crypto.createHash)("sha256").update(stableStringify(files)).digest("hex").slice(0, 16)}`;
|
|
90
|
+
}
|
|
68
91
|
function stableStringify(value) {
|
|
69
92
|
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
70
93
|
if (value && typeof value === "object") return `{${Object.entries(value).filter(([, v]) => v !== void 0).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).sort().join(",")}}`;
|
|
@@ -72,6 +95,8 @@ function stableStringify(value) {
|
|
|
72
95
|
}
|
|
73
96
|
|
|
74
97
|
//#endregion
|
|
98
|
+
exports.VERSION_DIR_PATTERN = VERSION_DIR_PATTERN;
|
|
75
99
|
exports.WorkspaceVersionManifestSchema = WorkspaceVersionManifestSchema;
|
|
76
100
|
exports.composeVersionManifest = composeVersionManifest;
|
|
101
|
+
exports.versionDirPath = versionDirPath;
|
|
77
102
|
//# sourceMappingURL=version-manifest.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-manifest.cjs","names":["z","createHash"],"sources":["../src/version-manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n\n/**\n * WorkspaceVersionManifest — the immutable per-deploy document at\n * `bundles/<account>/<gateway>/<workspace>/versions/<version>.json`\n * (ADR 0020, as amended; atomic-deploys MAP decision 1). The published\n * config's slot pins this document via its `pin` (`manifest` + the\n * manifest's own SRI); every artifact coordinate lives here, so the config\n * stops growing with artifact kinds and old versions stay fully servable.\n */\n\nconst SRI = z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);\n\nexport const WorkspaceVersionManifestSchema = z.object({\n version: z.string().regex(/^[0-9a-f]{16}$/),\n builtAt: z.string().optional(),\n gitSha: z.string().optional(),\n entry: z.string().min(1),\n entryIntegrity: SRI,\n ssr: z\n .object({\n entry: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n browserManifest: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n /** extra assets (css, icons) — logical name → served-object SRI */\n assets: z.record(z.string(), SRI).optional(),\n /** shared-dependency versions this build was built against */\n shared: z.record(z.string(), z.string()).optional(),\n /**\n * Full per-file digest map of the dist (object path → served-object SRI).\n * Written by `every-plugin`-based deploys so the next deploy can diff against\n * it and skip re-uploading unchanged files; readers that predate the field\n * ignore it (zod strips unknown keys). Participates in the version hash.\n */\n files: z.record(z.string(), SRI).optional(),\n /**\n * Source archive of the workspace subtree (object path → served-object SRI)\n * published beside the dists when the runtime opts in via\n * `publish.sourcePublish` — lets `bos import` dereference a published\n * config slot to the exact source bytes that build came from, with no\n * GitHub dependency. Readers that predate the field ignore it (zod strips\n * unknown keys). Participates in the version hash.\n */\n source: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n});\nexport type WorkspaceVersionManifest = z.infer<typeof WorkspaceVersionManifestSchema>;\n\n/** A published-artifact coordinate: object path within the bundle namespace + its served SRI. */\nexport type SourceRef = NonNullable<WorkspaceVersionManifest[\"source\"]>;\n\nexport interface VersionManifestInput {\n /** Omit: a per-build timestamp makes the same version id map to different\n * manifest bytes per machine, breaking the pin's SRI against the image's\n * staged copy and the CDN's immutability for republished versions. */\n builtAt?: string;\n gitSha?: string;\n entry: string;\n entryIntegrity: string;\n ssr?: { entry: string; integrity: string };\n browserManifest?: { file: string; integrity: string };\n assets?: Record<string, string>;\n shared?: Record<string, string>;\n files?: Record<string, string>;\n source?: { file: string; integrity: string };\n}\n\n/**\n * Compose the manifest with its `version` derived from the canonical content\n * of the artifact coordinates alone (key-sorted, `builtAt` excluded) —\n * identical bytes → identical version id regardless of when they were built,\n * so republishing unchanged content is a pointer no-op. Any changed\n * coordinate → a new version (and a new file).\n */\nexport function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest {\n const { builtAt: _builtAt, ...hashedInputs } = input;\n const version = createHash(\"sha256\")\n .update(stableStringify(hashedInputs))\n .digest(\"hex\")\n .slice(0, 16);\n return WorkspaceVersionManifestSchema.parse({ ...input, version });\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)\n .sort()\n .join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAM,MAAMA,MAAE,OAAO,CAAC,CAAC,MAAM,0BAA0B;
|
|
1
|
+
{"version":3,"file":"version-manifest.cjs","names":["z","createHash"],"sources":["../src/version-manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n\n/**\n * WorkspaceVersionManifest — the immutable per-deploy document at\n * `bundles/<account>/<gateway>/<workspace>/versions/<version>.json`\n * (ADR 0020, as amended; atomic-deploys MAP decision 1). The published\n * config's slot pins this document via its `pin` (`manifest` + the\n * manifest's own SRI); every artifact coordinate lives here, so the config\n * stops growing with artifact kinds and old versions stay fully servable.\n */\n\nconst SRI = z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);\n\n/** Slot-relative directory holding one deploy's immutable file copies (#826). */\nexport const VERSION_DIR_PATTERN = /^versions\\/[0-9a-f]{16}$/;\n\nexport const WorkspaceVersionManifestSchema = z.object({\n version: z.string().regex(/^[0-9a-f]{16}$/),\n builtAt: z.string().optional(),\n gitSha: z.string().optional(),\n /**\n * Slot-relative directory (`versions/<dirId>`) holding this deploy's\n * byte-immutable copies of every dist file (#826). When present, all\n * artifact coordinates below resolve against `<slotBase>/<dir>/` — so a\n * pinned child's entry fetches its expose chunk and chunks from the same\n * frozen directory instead of the mutable slot root. Absent on legacy\n * manifests: coordinates resolve against the slot root exactly as before.\n * Derived from the `files` map (see `versionDirPath`), so it participates\n * in the version hash without circularity.\n */\n dir: z.string().regex(VERSION_DIR_PATTERN).optional(),\n entry: z.string().min(1),\n entryIntegrity: SRI,\n ssr: z\n .object({\n entry: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n browserManifest: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n /** extra assets (css, icons) — logical name → served-object SRI */\n assets: z.record(z.string(), SRI).optional(),\n /** shared-dependency versions this build was built against */\n shared: z.record(z.string(), z.string()).optional(),\n /**\n * Full per-file digest map of the dist (object path → served-object SRI).\n * Written by `every-plugin`-based deploys so the next deploy can diff against\n * it and skip re-uploading unchanged files; readers that predate the field\n * ignore it (zod strips unknown keys). Participates in the version hash.\n */\n files: z.record(z.string(), SRI).optional(),\n /**\n * Source archive of the workspace subtree (object path → served-object SRI)\n * published beside the dists when the runtime opts in via\n * `publish.sourcePublish` — lets `bos import` dereference a published\n * config slot to the exact source bytes that build came from, with no\n * GitHub dependency. Readers that predate the field ignore it (zod strips\n * unknown keys). Participates in the version hash.\n */\n source: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n});\nexport type WorkspaceVersionManifest = z.infer<typeof WorkspaceVersionManifestSchema>;\n\n/** A published-artifact coordinate: object path within the bundle namespace + its served SRI. */\nexport type SourceRef = NonNullable<WorkspaceVersionManifest[\"source\"]>;\n\nexport interface VersionManifestInput {\n /** Omit: a per-build timestamp makes the same version id map to different\n * manifest bytes per machine, breaking the pin's SRI against the image's\n * staged copy and the CDN's immutability for republished versions. */\n builtAt?: string;\n gitSha?: string;\n dir?: string;\n entry: string;\n entryIntegrity: string;\n ssr?: { entry: string; integrity: string };\n browserManifest?: { file: string; integrity: string };\n assets?: Record<string, string>;\n shared?: Record<string, string>;\n files?: Record<string, string>;\n source?: { file: string; integrity: string };\n}\n\n/**\n * Compose the manifest with its `version` derived from the canonical content\n * of the artifact coordinates alone (key-sorted, `builtAt` excluded) —\n * identical bytes → identical version id regardless of when they were built,\n * so republishing unchanged content is a pointer no-op. Any changed\n * coordinate → a new version (and a new file).\n */\nexport function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest {\n const { builtAt: _builtAt, ...hashedInputs } = input;\n const version = createHash(\"sha256\")\n .update(stableStringify(hashedInputs))\n .digest(\"hex\")\n .slice(0, 16);\n return WorkspaceVersionManifestSchema.parse({ ...input, version });\n}\n\n/**\n * The content-addressed directory name for one dist's file set (#826): a\n * 16-hex hash over the canonical files map. Identical bytes → identical\n * directory → re-deploying unchanged content is a server-side no-op, and a\n * published pin's directory can never be rewritten by a later deploy\n * (the upload service refuses conflicting writes under `versions/`).\n */\nexport function versionDirPath(files: Record<string, string>): string {\n const id = createHash(\"sha256\").update(stableStringify(files)).digest(\"hex\").slice(0, 16);\n return `versions/${id}`;\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)\n .sort()\n .join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAM,MAAMA,MAAE,OAAO,CAAC,CAAC,MAAM,0BAA0B;;AAGvD,MAAa,sBAAsB;AAEnC,MAAa,iCAAiCA,MAAE,OAAO;CACrD,SAASA,MAAE,OAAO,CAAC,CAAC,MAAM,gBAAgB;CAC1C,SAASA,MAAE,OAAO,CAAC,CAAC,SAAS;CAC7B,QAAQA,MAAE,OAAO,CAAC,CAAC,SAAS;;;;;;;;;;;CAW5B,KAAKA,MAAE,OAAO,CAAC,CAAC,MAAM,mBAAmB,CAAC,CAAC,SAAS;CACpD,OAAOA,MAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACvB,gBAAgB;CAChB,KAAKA,MACF,OAAO;EACN,OAAOA,MAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACvB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;CACZ,iBAAiBA,MACd,OAAO;EACN,MAAMA,MAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACtB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;;CAEZ,QAAQA,MAAE,OAAOA,MAAE,OAAO,GAAG,GAAG,CAAC,CAAC,SAAS;;CAE3C,QAAQA,MAAE,OAAOA,MAAE,OAAO,GAAGA,MAAE,OAAO,CAAC,CAAC,CAAC,SAAS;;;;;;;CAOlD,OAAOA,MAAE,OAAOA,MAAE,OAAO,GAAG,GAAG,CAAC,CAAC,SAAS;;;;;;;;;CAS1C,QAAQA,MACL,OAAO;EACN,MAAMA,MAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACtB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;AACd,CAAC;;;;;;;;AA8BD,SAAgB,uBAAuB,OAAuD;CAC5F,MAAM,EAAE,SAAS,UAAU,GAAG,iBAAiB;CAC/C,MAAM,cAAUC,wBAAW,QAAQ,CAAC,CACjC,OAAO,gBAAgB,YAAY,CAAC,CAAC,CACrC,OAAO,KAAK,CAAC,CACb,MAAM,GAAG,EAAE;CACd,OAAO,+BAA+B,MAAM;EAAE,GAAG;EAAO;CAAQ,CAAC;AACnE;;;;;;;;AASA,SAAgB,eAAe,OAAuC;CAEpE,OAAO,gBADIA,wBAAW,QAAQ,CAAC,CAAC,OAAO,gBAAgB,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAClE;AACtB;AAEA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,eAAe,CAAC,CAAC,KAAK,GAAG,EAAE;CAC1E,IAAI,SAAS,OAAO,UAAU,UAC5B,OAAO,IAAI,OAAO,QAAQ,KAAK,CAAC,CAC7B,QAAQ,GAAG,OAAO,MAAM,MAAS,CAAC,CAClC,KAAK,CAAC,GAAG,OAAO,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAC7D,KAAK,CAAC,CACN,KAAK,GAAG,EAAE;CAEf,OAAO,KAAK,UAAU,KAAK,KAAK;AAClC"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/version-manifest.d.ts
|
|
3
|
+
/** Slot-relative directory holding one deploy's immutable file copies (#826). */
|
|
4
|
+
declare const VERSION_DIR_PATTERN: RegExp;
|
|
3
5
|
declare const WorkspaceVersionManifestSchema: z.ZodObject<{
|
|
4
6
|
version: z.ZodString;
|
|
5
7
|
builtAt: z.ZodOptional<z.ZodString>;
|
|
6
8
|
gitSha: z.ZodOptional<z.ZodString>;
|
|
9
|
+
dir: z.ZodOptional<z.ZodString>;
|
|
7
10
|
entry: z.ZodString;
|
|
8
11
|
entryIntegrity: z.ZodString;
|
|
9
12
|
ssr: z.ZodOptional<z.ZodObject<{
|
|
@@ -31,6 +34,7 @@ interface VersionManifestInput {
|
|
|
31
34
|
* staged copy and the CDN's immutability for republished versions. */
|
|
32
35
|
builtAt?: string;
|
|
33
36
|
gitSha?: string;
|
|
37
|
+
dir?: string;
|
|
34
38
|
entry: string;
|
|
35
39
|
entryIntegrity: string;
|
|
36
40
|
ssr?: {
|
|
@@ -57,6 +61,14 @@ interface VersionManifestInput {
|
|
|
57
61
|
* coordinate → a new version (and a new file).
|
|
58
62
|
*/
|
|
59
63
|
declare function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest;
|
|
64
|
+
/**
|
|
65
|
+
* The content-addressed directory name for one dist's file set (#826): a
|
|
66
|
+
* 16-hex hash over the canonical files map. Identical bytes → identical
|
|
67
|
+
* directory → re-deploying unchanged content is a server-side no-op, and a
|
|
68
|
+
* published pin's directory can never be rewritten by a later deploy
|
|
69
|
+
* (the upload service refuses conflicting writes under `versions/`).
|
|
70
|
+
*/
|
|
71
|
+
declare function versionDirPath(files: Record<string, string>): string;
|
|
60
72
|
//#endregion
|
|
61
|
-
export { SourceRef, VersionManifestInput, WorkspaceVersionManifest, WorkspaceVersionManifestSchema, composeVersionManifest };
|
|
73
|
+
export { SourceRef, VERSION_DIR_PATTERN, VersionManifestInput, WorkspaceVersionManifest, WorkspaceVersionManifestSchema, composeVersionManifest, versionDirPath };
|
|
62
74
|
//# sourceMappingURL=version-manifest.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-manifest.d.cts","names":[],"sources":["../src/version-manifest.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"version-manifest.d.cts","names":[],"sources":["../src/version-manifest.ts"],"mappings":";;;cAea,qBAAmB;cAEnB,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;;GAsDzC,EAAA,KAAA;KACU,2BAA2B,EAAE,aAAa;;KAG1C,YAAY,YAAY;UAEnB;;;;EAIf;EACA;EACA;EACA;EACA;EACA;IAAQ;IAAe;;EACvB;IAAoB;IAAc;;EAClC,SAAS;EACT,SAAS;EACT,QAAQ;EACR;IAAW;IAAc;;;;;;;;;;iBAUX,uBAAuB,OAAO,uBAAuB;;;;;;;;iBAgBrD,eAAe,OAAO"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/version-manifest.d.ts
|
|
3
|
+
/** Slot-relative directory holding one deploy's immutable file copies (#826). */
|
|
4
|
+
declare const VERSION_DIR_PATTERN: RegExp;
|
|
3
5
|
declare const WorkspaceVersionManifestSchema: z.ZodObject<{
|
|
4
6
|
version: z.ZodString;
|
|
5
7
|
builtAt: z.ZodOptional<z.ZodString>;
|
|
6
8
|
gitSha: z.ZodOptional<z.ZodString>;
|
|
9
|
+
dir: z.ZodOptional<z.ZodString>;
|
|
7
10
|
entry: z.ZodString;
|
|
8
11
|
entryIntegrity: z.ZodString;
|
|
9
12
|
ssr: z.ZodOptional<z.ZodObject<{
|
|
@@ -31,6 +34,7 @@ interface VersionManifestInput {
|
|
|
31
34
|
* staged copy and the CDN's immutability for republished versions. */
|
|
32
35
|
builtAt?: string;
|
|
33
36
|
gitSha?: string;
|
|
37
|
+
dir?: string;
|
|
34
38
|
entry: string;
|
|
35
39
|
entryIntegrity: string;
|
|
36
40
|
ssr?: {
|
|
@@ -57,6 +61,14 @@ interface VersionManifestInput {
|
|
|
57
61
|
* coordinate → a new version (and a new file).
|
|
58
62
|
*/
|
|
59
63
|
declare function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest;
|
|
64
|
+
/**
|
|
65
|
+
* The content-addressed directory name for one dist's file set (#826): a
|
|
66
|
+
* 16-hex hash over the canonical files map. Identical bytes → identical
|
|
67
|
+
* directory → re-deploying unchanged content is a server-side no-op, and a
|
|
68
|
+
* published pin's directory can never be rewritten by a later deploy
|
|
69
|
+
* (the upload service refuses conflicting writes under `versions/`).
|
|
70
|
+
*/
|
|
71
|
+
declare function versionDirPath(files: Record<string, string>): string;
|
|
60
72
|
//#endregion
|
|
61
|
-
export { SourceRef, VersionManifestInput, WorkspaceVersionManifest, WorkspaceVersionManifestSchema, composeVersionManifest };
|
|
73
|
+
export { SourceRef, VERSION_DIR_PATTERN, VersionManifestInput, WorkspaceVersionManifest, WorkspaceVersionManifestSchema, composeVersionManifest, versionDirPath };
|
|
62
74
|
//# sourceMappingURL=version-manifest.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-manifest.d.mts","names":[],"sources":["../src/version-manifest.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"version-manifest.d.mts","names":[],"sources":["../src/version-manifest.ts"],"mappings":";;;cAea,qBAAmB;cAEnB,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;;GAsDzC,EAAA,KAAA;KACU,2BAA2B,EAAE,aAAa;;KAG1C,YAAY,YAAY;UAEnB;;;;EAIf;EACA;EACA;EACA;EACA;EACA;IAAQ;IAAe;;EACvB;IAAoB;IAAc;;EAClC,SAAS;EACT,SAAS;EACT,QAAQ;EACR;IAAW;IAAc;;;;;;;;;;iBAUX,uBAAuB,OAAO,uBAAuB;;;;;;;;iBAgBrD,eAAe,OAAO"}
|
|
@@ -11,10 +11,23 @@ import { createHash } from "node:crypto";
|
|
|
11
11
|
* stops growing with artifact kinds and old versions stay fully servable.
|
|
12
12
|
*/
|
|
13
13
|
const SRI = z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
14
|
+
/** Slot-relative directory holding one deploy's immutable file copies (#826). */
|
|
15
|
+
const VERSION_DIR_PATTERN = /^versions\/[0-9a-f]{16}$/;
|
|
14
16
|
const WorkspaceVersionManifestSchema = z.object({
|
|
15
17
|
version: z.string().regex(/^[0-9a-f]{16}$/),
|
|
16
18
|
builtAt: z.string().optional(),
|
|
17
19
|
gitSha: z.string().optional(),
|
|
20
|
+
/**
|
|
21
|
+
* Slot-relative directory (`versions/<dirId>`) holding this deploy's
|
|
22
|
+
* byte-immutable copies of every dist file (#826). When present, all
|
|
23
|
+
* artifact coordinates below resolve against `<slotBase>/<dir>/` — so a
|
|
24
|
+
* pinned child's entry fetches its expose chunk and chunks from the same
|
|
25
|
+
* frozen directory instead of the mutable slot root. Absent on legacy
|
|
26
|
+
* manifests: coordinates resolve against the slot root exactly as before.
|
|
27
|
+
* Derived from the `files` map (see `versionDirPath`), so it participates
|
|
28
|
+
* in the version hash without circularity.
|
|
29
|
+
*/
|
|
30
|
+
dir: z.string().regex(VERSION_DIR_PATTERN).optional(),
|
|
18
31
|
entry: z.string().min(1),
|
|
19
32
|
entryIntegrity: SRI,
|
|
20
33
|
ssr: z.object({
|
|
@@ -64,6 +77,16 @@ function composeVersionManifest(input) {
|
|
|
64
77
|
version
|
|
65
78
|
});
|
|
66
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* The content-addressed directory name for one dist's file set (#826): a
|
|
82
|
+
* 16-hex hash over the canonical files map. Identical bytes → identical
|
|
83
|
+
* directory → re-deploying unchanged content is a server-side no-op, and a
|
|
84
|
+
* published pin's directory can never be rewritten by a later deploy
|
|
85
|
+
* (the upload service refuses conflicting writes under `versions/`).
|
|
86
|
+
*/
|
|
87
|
+
function versionDirPath(files) {
|
|
88
|
+
return `versions/${createHash("sha256").update(stableStringify(files)).digest("hex").slice(0, 16)}`;
|
|
89
|
+
}
|
|
67
90
|
function stableStringify(value) {
|
|
68
91
|
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
69
92
|
if (value && typeof value === "object") return `{${Object.entries(value).filter(([, v]) => v !== void 0).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).sort().join(",")}}`;
|
|
@@ -71,5 +94,5 @@ function stableStringify(value) {
|
|
|
71
94
|
}
|
|
72
95
|
|
|
73
96
|
//#endregion
|
|
74
|
-
export { WorkspaceVersionManifestSchema, composeVersionManifest };
|
|
97
|
+
export { VERSION_DIR_PATTERN, WorkspaceVersionManifestSchema, composeVersionManifest, versionDirPath };
|
|
75
98
|
//# sourceMappingURL=version-manifest.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-manifest.mjs","names":[],"sources":["../src/version-manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n\n/**\n * WorkspaceVersionManifest — the immutable per-deploy document at\n * `bundles/<account>/<gateway>/<workspace>/versions/<version>.json`\n * (ADR 0020, as amended; atomic-deploys MAP decision 1). The published\n * config's slot pins this document via its `pin` (`manifest` + the\n * manifest's own SRI); every artifact coordinate lives here, so the config\n * stops growing with artifact kinds and old versions stay fully servable.\n */\n\nconst SRI = z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);\n\nexport const WorkspaceVersionManifestSchema = z.object({\n version: z.string().regex(/^[0-9a-f]{16}$/),\n builtAt: z.string().optional(),\n gitSha: z.string().optional(),\n entry: z.string().min(1),\n entryIntegrity: SRI,\n ssr: z\n .object({\n entry: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n browserManifest: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n /** extra assets (css, icons) — logical name → served-object SRI */\n assets: z.record(z.string(), SRI).optional(),\n /** shared-dependency versions this build was built against */\n shared: z.record(z.string(), z.string()).optional(),\n /**\n * Full per-file digest map of the dist (object path → served-object SRI).\n * Written by `every-plugin`-based deploys so the next deploy can diff against\n * it and skip re-uploading unchanged files; readers that predate the field\n * ignore it (zod strips unknown keys). Participates in the version hash.\n */\n files: z.record(z.string(), SRI).optional(),\n /**\n * Source archive of the workspace subtree (object path → served-object SRI)\n * published beside the dists when the runtime opts in via\n * `publish.sourcePublish` — lets `bos import` dereference a published\n * config slot to the exact source bytes that build came from, with no\n * GitHub dependency. Readers that predate the field ignore it (zod strips\n * unknown keys). Participates in the version hash.\n */\n source: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n});\nexport type WorkspaceVersionManifest = z.infer<typeof WorkspaceVersionManifestSchema>;\n\n/** A published-artifact coordinate: object path within the bundle namespace + its served SRI. */\nexport type SourceRef = NonNullable<WorkspaceVersionManifest[\"source\"]>;\n\nexport interface VersionManifestInput {\n /** Omit: a per-build timestamp makes the same version id map to different\n * manifest bytes per machine, breaking the pin's SRI against the image's\n * staged copy and the CDN's immutability for republished versions. */\n builtAt?: string;\n gitSha?: string;\n entry: string;\n entryIntegrity: string;\n ssr?: { entry: string; integrity: string };\n browserManifest?: { file: string; integrity: string };\n assets?: Record<string, string>;\n shared?: Record<string, string>;\n files?: Record<string, string>;\n source?: { file: string; integrity: string };\n}\n\n/**\n * Compose the manifest with its `version` derived from the canonical content\n * of the artifact coordinates alone (key-sorted, `builtAt` excluded) —\n * identical bytes → identical version id regardless of when they were built,\n * so republishing unchanged content is a pointer no-op. Any changed\n * coordinate → a new version (and a new file).\n */\nexport function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest {\n const { builtAt: _builtAt, ...hashedInputs } = input;\n const version = createHash(\"sha256\")\n .update(stableStringify(hashedInputs))\n .digest(\"hex\")\n .slice(0, 16);\n return WorkspaceVersionManifestSchema.parse({ ...input, version });\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)\n .sort()\n .join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,0BAA0B;
|
|
1
|
+
{"version":3,"file":"version-manifest.mjs","names":[],"sources":["../src/version-manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n\n/**\n * WorkspaceVersionManifest — the immutable per-deploy document at\n * `bundles/<account>/<gateway>/<workspace>/versions/<version>.json`\n * (ADR 0020, as amended; atomic-deploys MAP decision 1). The published\n * config's slot pins this document via its `pin` (`manifest` + the\n * manifest's own SRI); every artifact coordinate lives here, so the config\n * stops growing with artifact kinds and old versions stay fully servable.\n */\n\nconst SRI = z.string().regex(/^sha384-[A-Za-z0-9+/=]+$/);\n\n/** Slot-relative directory holding one deploy's immutable file copies (#826). */\nexport const VERSION_DIR_PATTERN = /^versions\\/[0-9a-f]{16}$/;\n\nexport const WorkspaceVersionManifestSchema = z.object({\n version: z.string().regex(/^[0-9a-f]{16}$/),\n builtAt: z.string().optional(),\n gitSha: z.string().optional(),\n /**\n * Slot-relative directory (`versions/<dirId>`) holding this deploy's\n * byte-immutable copies of every dist file (#826). When present, all\n * artifact coordinates below resolve against `<slotBase>/<dir>/` — so a\n * pinned child's entry fetches its expose chunk and chunks from the same\n * frozen directory instead of the mutable slot root. Absent on legacy\n * manifests: coordinates resolve against the slot root exactly as before.\n * Derived from the `files` map (see `versionDirPath`), so it participates\n * in the version hash without circularity.\n */\n dir: z.string().regex(VERSION_DIR_PATTERN).optional(),\n entry: z.string().min(1),\n entryIntegrity: SRI,\n ssr: z\n .object({\n entry: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n browserManifest: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n /** extra assets (css, icons) — logical name → served-object SRI */\n assets: z.record(z.string(), SRI).optional(),\n /** shared-dependency versions this build was built against */\n shared: z.record(z.string(), z.string()).optional(),\n /**\n * Full per-file digest map of the dist (object path → served-object SRI).\n * Written by `every-plugin`-based deploys so the next deploy can diff against\n * it and skip re-uploading unchanged files; readers that predate the field\n * ignore it (zod strips unknown keys). Participates in the version hash.\n */\n files: z.record(z.string(), SRI).optional(),\n /**\n * Source archive of the workspace subtree (object path → served-object SRI)\n * published beside the dists when the runtime opts in via\n * `publish.sourcePublish` — lets `bos import` dereference a published\n * config slot to the exact source bytes that build came from, with no\n * GitHub dependency. Readers that predate the field ignore it (zod strips\n * unknown keys). Participates in the version hash.\n */\n source: z\n .object({\n file: z.string().min(1),\n integrity: SRI,\n })\n .optional(),\n});\nexport type WorkspaceVersionManifest = z.infer<typeof WorkspaceVersionManifestSchema>;\n\n/** A published-artifact coordinate: object path within the bundle namespace + its served SRI. */\nexport type SourceRef = NonNullable<WorkspaceVersionManifest[\"source\"]>;\n\nexport interface VersionManifestInput {\n /** Omit: a per-build timestamp makes the same version id map to different\n * manifest bytes per machine, breaking the pin's SRI against the image's\n * staged copy and the CDN's immutability for republished versions. */\n builtAt?: string;\n gitSha?: string;\n dir?: string;\n entry: string;\n entryIntegrity: string;\n ssr?: { entry: string; integrity: string };\n browserManifest?: { file: string; integrity: string };\n assets?: Record<string, string>;\n shared?: Record<string, string>;\n files?: Record<string, string>;\n source?: { file: string; integrity: string };\n}\n\n/**\n * Compose the manifest with its `version` derived from the canonical content\n * of the artifact coordinates alone (key-sorted, `builtAt` excluded) —\n * identical bytes → identical version id regardless of when they were built,\n * so republishing unchanged content is a pointer no-op. Any changed\n * coordinate → a new version (and a new file).\n */\nexport function composeVersionManifest(input: VersionManifestInput): WorkspaceVersionManifest {\n const { builtAt: _builtAt, ...hashedInputs } = input;\n const version = createHash(\"sha256\")\n .update(stableStringify(hashedInputs))\n .digest(\"hex\")\n .slice(0, 16);\n return WorkspaceVersionManifestSchema.parse({ ...input, version });\n}\n\n/**\n * The content-addressed directory name for one dist's file set (#826): a\n * 16-hex hash over the canonical files map. Identical bytes → identical\n * directory → re-deploying unchanged content is a server-side no-op, and a\n * published pin's directory can never be rewritten by a later deploy\n * (the upload service refuses conflicting writes under `versions/`).\n */\nexport function versionDirPath(files: Record<string, string>): string {\n const id = createHash(\"sha256\").update(stableStringify(files)).digest(\"hex\").slice(0, 16);\n return `versions/${id}`;\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)\n .sort()\n .join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,0BAA0B;;AAGvD,MAAa,sBAAsB;AAEnC,MAAa,iCAAiC,EAAE,OAAO;CACrD,SAAS,EAAE,OAAO,CAAC,CAAC,MAAM,gBAAgB;CAC1C,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;CAC7B,QAAQ,EAAE,OAAO,CAAC,CAAC,SAAS;;;;;;;;;;;CAW5B,KAAK,EAAE,OAAO,CAAC,CAAC,MAAM,mBAAmB,CAAC,CAAC,SAAS;CACpD,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACvB,gBAAgB;CAChB,KAAK,EACF,OAAO;EACN,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACvB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;CACZ,iBAAiB,EACd,OAAO;EACN,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACtB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;;CAEZ,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC,SAAS;;CAE3C,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;;;;;;;CAOlD,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC,SAAS;;;;;;;;;CAS1C,QAAQ,EACL,OAAO;EACN,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EACtB,WAAW;CACb,CAAC,CAAC,CACD,SAAS;AACd,CAAC;;;;;;;;AA8BD,SAAgB,uBAAuB,OAAuD;CAC5F,MAAM,EAAE,SAAS,UAAU,GAAG,iBAAiB;CAC/C,MAAM,UAAU,WAAW,QAAQ,CAAC,CACjC,OAAO,gBAAgB,YAAY,CAAC,CAAC,CACrC,OAAO,KAAK,CAAC,CACb,MAAM,GAAG,EAAE;CACd,OAAO,+BAA+B,MAAM;EAAE,GAAG;EAAO;CAAQ,CAAC;AACnE;;;;;;;;AASA,SAAgB,eAAe,OAAuC;CAEpE,OAAO,YADI,WAAW,QAAQ,CAAC,CAAC,OAAO,gBAAgB,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAClE;AACtB;AAEA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,eAAe,CAAC,CAAC,KAAK,GAAG,EAAE;CAC1E,IAAI,SAAS,OAAO,UAAU,UAC5B,OAAO,IAAI,OAAO,QAAQ,KAAK,CAAC,CAC7B,QAAQ,GAAG,OAAO,MAAM,MAAS,CAAC,CAClC,KAAK,CAAC,GAAG,OAAO,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAC7D,KAAK,CAAC,CACN,KAAK,GAAG,EAAE;CAEf,OAAO,KAAK,UAAU,KAAK,KAAK;AAClC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "every-plugin",
|
|
3
|
-
"version": "3.0.0-rc.
|
|
3
|
+
"version": "3.0.0-rc.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -194,50 +194,50 @@
|
|
|
194
194
|
"typecheck": "tsc --noEmit"
|
|
195
195
|
},
|
|
196
196
|
"peerDependencies": {
|
|
197
|
-
"@orpc/contract": "2.0.0-beta.
|
|
198
|
-
"@orpc/server": "2.0.0-beta.
|
|
199
|
-
"@orpc/tanstack-query": "2.0.0-beta.
|
|
200
|
-
"@orpc/zod": "2.0.0-beta.
|
|
197
|
+
"@orpc/contract": "2.0.0-beta.45",
|
|
198
|
+
"@orpc/server": "2.0.0-beta.45",
|
|
199
|
+
"@orpc/tanstack-query": "2.0.0-beta.45",
|
|
200
|
+
"@orpc/zod": "2.0.0-beta.45",
|
|
201
201
|
"@proj-airi/unplugin-drizzle-orm-migrations": "*",
|
|
202
202
|
"@rspack/core": "2.2.8",
|
|
203
|
-
"@tanstack/react-router": "1.170.
|
|
204
|
-
"@tanstack/router-generator": "1.167.
|
|
205
|
-
"effect": "4.0.0-rc.
|
|
206
|
-
"react": "19.
|
|
203
|
+
"@tanstack/react-router": "1.170.46",
|
|
204
|
+
"@tanstack/router-generator": "1.167.46",
|
|
205
|
+
"effect": "4.0.0-rc.118",
|
|
206
|
+
"react": "19.3.1",
|
|
207
207
|
"typescript": "^7.0.2",
|
|
208
|
-
"zod": "4.6.
|
|
208
|
+
"zod": "4.6.7"
|
|
209
209
|
},
|
|
210
210
|
"devDependencies": {
|
|
211
|
-
"@effect/vitest": "4.0.0-rc.
|
|
211
|
+
"@effect/vitest": "4.0.0-rc.118",
|
|
212
212
|
"@orpc/client": "2.0.0-beta.35",
|
|
213
213
|
"@orpc/openapi": "2.0.0-beta.35",
|
|
214
214
|
"@rspack/cli": "2.2.6",
|
|
215
|
-
"@tanstack/intent": "^0.
|
|
215
|
+
"@tanstack/intent": "^0.5.6",
|
|
216
216
|
"@types/node": "^25.1.0",
|
|
217
|
-
"@types/react": "^19.
|
|
218
|
-
"@types/react-dom": "^19.
|
|
217
|
+
"@types/react": "^19.3.0",
|
|
218
|
+
"@types/react-dom": "^19.3.0",
|
|
219
219
|
"@vitest/ui": "4.1.5",
|
|
220
220
|
"tsdown": "^0.22.0",
|
|
221
221
|
"vite-tsconfig-paths": "^6.0.5",
|
|
222
222
|
"vitest": "^4.1.8"
|
|
223
223
|
},
|
|
224
224
|
"dependencies": {
|
|
225
|
-
"@module-federation/enhanced": "^2.9.
|
|
226
|
-
"@module-federation/node": "^2.7.
|
|
227
|
-
"@module-federation/rsbuild-plugin": "^2.9.
|
|
228
|
-
"@module-federation/runtime-core": "^2.9.
|
|
229
|
-
"@module-federation/runtime-tools": "^2.9.
|
|
230
|
-
"@orpc/client": "2.0.0-beta.
|
|
231
|
-
"@orpc/contract": "2.0.0-beta.
|
|
232
|
-
"@orpc/experimental-effect": "2.0.0-beta.
|
|
233
|
-
"@orpc/openapi": "2.0.0-beta.
|
|
234
|
-
"@orpc/publisher": "2.0.0-beta.
|
|
235
|
-
"@orpc/server": "2.0.0-beta.
|
|
236
|
-
"@orpc/tanstack-query": "2.0.0-beta.
|
|
225
|
+
"@module-federation/enhanced": "^2.9.2",
|
|
226
|
+
"@module-federation/node": "^2.7.52",
|
|
227
|
+
"@module-federation/rsbuild-plugin": "^2.9.2",
|
|
228
|
+
"@module-federation/runtime-core": "^2.9.2",
|
|
229
|
+
"@module-federation/runtime-tools": "^2.9.2",
|
|
230
|
+
"@orpc/client": "2.0.0-beta.45",
|
|
231
|
+
"@orpc/contract": "2.0.0-beta.45",
|
|
232
|
+
"@orpc/experimental-effect": "2.0.0-beta.45",
|
|
233
|
+
"@orpc/openapi": "2.0.0-beta.45",
|
|
234
|
+
"@orpc/publisher": "2.0.0-beta.45",
|
|
235
|
+
"@orpc/server": "2.0.0-beta.45",
|
|
236
|
+
"@orpc/tanstack-query": "2.0.0-beta.45",
|
|
237
237
|
"@rsbuild/core": "2.2.8",
|
|
238
238
|
"@rsbuild/plugin-react": "2.1.0",
|
|
239
|
-
"@tanstack/router-generator": "1.167.
|
|
240
|
-
"@tanstack/router-plugin": "1.168.
|
|
239
|
+
"@tanstack/router-generator": "1.167.46",
|
|
240
|
+
"@tanstack/router-plugin": "1.168.48",
|
|
241
241
|
"sirv": "3.0.2",
|
|
242
242
|
"sonner": ">=2.0.0"
|
|
243
243
|
},
|
|
@@ -416,7 +416,7 @@ A child project inherits the parent's host, API, auth, and plugins via the `exte
|
|
|
416
416
|
|
|
417
417
|
```json
|
|
418
418
|
{
|
|
419
|
-
"extends": "bos://dev.everything.near/
|
|
419
|
+
"extends": "bos://dev.everything.near/everything.dev",
|
|
420
420
|
"account": "myapp.near",
|
|
421
421
|
"domain": "myapp.everything.dev"
|
|
422
422
|
}
|
|
@@ -433,7 +433,7 @@ This inherits:
|
|
|
433
433
|
|
|
434
434
|
```bash
|
|
435
435
|
bos init myapp.everything.dev \
|
|
436
|
-
--extends dev.everything.near/
|
|
436
|
+
--extends dev.everything.near/everything.dev \
|
|
437
437
|
--overrides ui,plugins \
|
|
438
438
|
--plugins apps,template
|
|
439
439
|
```
|
|
@@ -34,13 +34,16 @@ export function uiEntryFilename(input: { isBuild: boolean; server?: boolean }):
|
|
|
34
34
|
const HASH_SEGMENT_PATTERN = /\.[a-f0-9]{8,}\./;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Serving classification for bundle objects: anything
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* Serving classification for bundle objects: anything under a version
|
|
38
|
+
* directory (`versions/<dirId>/…`, #826) or a `versions/<id>.json` manifest
|
|
39
|
+
* is immutable by construction — the directory name is content-addressed and
|
|
40
|
+
* the upload service refuses conflicting writes under `versions/`; likewise
|
|
41
|
+
* any name carrying a content-hash segment (including hashed entrypoints
|
|
42
|
+
* like `remoteEntry.8f3a….js`). Fixed-name entrypoints and non-hashed files
|
|
43
|
+
* a redeploy replaces in place must revalidate.
|
|
42
44
|
*/
|
|
43
45
|
export function isImmutableBundlePath(name: string): boolean {
|
|
46
|
+
if (name === "versions" || name.startsWith("versions/")) return true;
|
|
44
47
|
const base = name.split("/").pop() ?? name;
|
|
45
48
|
return HASH_SEGMENT_PATTERN.test(base);
|
|
46
49
|
}
|