every-plugin 3.0.0-rc.15 → 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.
Files changed (65) hide show
  1. package/dist/build/artifact-names.cjs +8 -5
  2. package/dist/build/artifact-names.cjs.map +1 -1
  3. package/dist/build/artifact-names.d.cts +7 -5
  4. package/dist/build/artifact-names.d.cts.map +1 -1
  5. package/dist/build/artifact-names.d.mts +7 -5
  6. package/dist/build/artifact-names.d.mts.map +1 -1
  7. package/dist/build/artifact-names.mjs +8 -5
  8. package/dist/build/artifact-names.mjs.map +1 -1
  9. package/dist/build/ui/stubs.cjs +2 -7
  10. package/dist/build/ui/stubs.cjs.map +1 -1
  11. package/dist/build/ui/stubs.d.cts.map +1 -1
  12. package/dist/build/ui/stubs.d.mts.map +1 -1
  13. package/dist/build/ui/stubs.mjs +2 -7
  14. package/dist/build/ui/stubs.mjs.map +1 -1
  15. package/dist/errors.cjs +11 -1
  16. package/dist/errors.cjs.map +1 -1
  17. package/dist/errors.d.cts +15 -1
  18. package/dist/errors.d.cts.map +1 -1
  19. package/dist/errors.d.mts +15 -1
  20. package/dist/errors.d.mts.map +1 -1
  21. package/dist/errors.mjs +11 -2
  22. package/dist/errors.mjs.map +1 -1
  23. package/dist/index.cjs +1 -0
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.mts +2 -2
  26. package/dist/index.mjs +2 -2
  27. package/dist/runtime/mf-config.cjs +1 -1
  28. package/dist/runtime/mf-config.mjs +1 -1
  29. package/dist/ui/manifest/construct.cjs +13 -38
  30. package/dist/ui/manifest/construct.cjs.map +1 -1
  31. package/dist/ui/manifest/construct.d.cts +4 -13
  32. package/dist/ui/manifest/construct.d.cts.map +1 -1
  33. package/dist/ui/manifest/construct.d.mts +4 -13
  34. package/dist/ui/manifest/construct.d.mts.map +1 -1
  35. package/dist/ui/manifest/construct.mjs +14 -39
  36. package/dist/ui/manifest/construct.mjs.map +1 -1
  37. package/dist/ui/manifest/descriptor.cjs +1 -1
  38. package/dist/ui/manifest/descriptor.mjs +1 -1
  39. package/dist/ui/manifest/index.d.cts +3 -3
  40. package/dist/ui/manifest/index.d.mts +3 -3
  41. package/dist/ui/manifest/mount-registry.cjs +6 -13
  42. package/dist/ui/manifest/mount-registry.cjs.map +1 -1
  43. package/dist/ui/manifest/mount-registry.d.cts +29 -36
  44. package/dist/ui/manifest/mount-registry.d.cts.map +1 -1
  45. package/dist/ui/manifest/mount-registry.d.mts +29 -36
  46. package/dist/ui/manifest/mount-registry.d.mts.map +1 -1
  47. package/dist/ui/manifest/mount-registry.mjs +6 -13
  48. package/dist/ui/manifest/mount-registry.mjs.map +1 -1
  49. package/dist/version-manifest.cjs +25 -0
  50. package/dist/version-manifest.cjs.map +1 -1
  51. package/dist/version-manifest.d.cts +13 -1
  52. package/dist/version-manifest.d.cts.map +1 -1
  53. package/dist/version-manifest.d.mts +13 -1
  54. package/dist/version-manifest.d.mts.map +1 -1
  55. package/dist/version-manifest.mjs +24 -1
  56. package/dist/version-manifest.mjs.map +1 -1
  57. package/package.json +1 -1
  58. package/skills/plugin-client/SKILL.md +2 -2
  59. package/src/build/artifact-names.ts +8 -5
  60. package/src/build/ui/stubs.ts +2 -7
  61. package/src/errors.ts +10 -0
  62. package/src/ui/manifest/construct.ts +20 -65
  63. package/src/ui/manifest/index.ts +0 -2
  64. package/src/ui/manifest/mount-registry.ts +20 -20
  65. package/src/version-manifest.ts +27 -0
@@ -1 +1 @@
1
- {"version":3,"file":"mount-registry.cjs","names":[],"sources":["../../../src/ui/manifest/mount-registry.ts"],"sourcesContent":["/**\n * Mount registry v2 — gates only, shape-free (ADR 0008 §3).\n *\n * A mount is a gate + a host-owned pathless layout position. It carries no\n * product semantics (no \"dashboard\", no shell, no chrome) — plugins bring\n * their own layouts and route freely inside their subtree. A mount is\n * declared by a ROOT-level pathless layout file whose `_`-prefixed segment\n * names the mount (`_public.tsx` → `public`); the generator derives it and\n * validates it against this registry; gates are attached HOST-side at\n * construction, so a plugin cannot ship a route that escapes its mount's\n * gate (plugins never construct route objects).\n *\n * `org`/`team` are declared vocabulary (parameterized membership gates) but\n * unimplemented — construction rejects them until they land.\n */\n\nexport interface MountDef {\n label: string;\n gate: \"none\" | \"session\" | \"admin\" | \"organization\" | \"team\";\n parameterized?: boolean;\n implemented: boolean;\n}\n\nexport const MOUNT_REGISTRY = {\n public: { label: \"public\", gate: \"none\", implemented: true },\n authenticated: { label: \"authenticated\", gate: \"session\", implemented: true },\n admin: { label: \"admin\", gate: \"admin\", implemented: true },\n org: { label: \"org\", gate: \"organization\", parameterized: true, implemented: false },\n team: { label: \"team\", gate: \"team\", parameterized: true, implemented: false },\n} 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 = 5;\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,OAAO;EAAU,MAAM;EAAQ,aAAa;CAAK;CAC3D,eAAe;EAAE,OAAO;EAAiB,MAAM;EAAW,aAAa;CAAK;CAC5E,OAAO;EAAE,OAAO;EAAS,MAAM;EAAS,aAAa;CAAK;CAC1D,KAAK;EAAE,OAAO;EAAO,MAAM;EAAgB,eAAe;EAAM,aAAa;CAAM;CACnF,MAAM;EAAE,OAAO;EAAQ,MAAM;EAAQ,eAAe;EAAM,aAAa;CAAM;AAC/E;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"}
1
+ {"version":3,"file":"mount-registry.cjs","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"}
@@ -1,58 +1,51 @@
1
1
  //#region src/ui/manifest/mount-registry.d.ts
2
2
  /**
3
- * Mount registry v2 — gates only, shape-free (ADR 0008 §3).
3
+ * Mount registry v2 — shape-free (ADR 0008 §3).
4
4
  *
5
- * A mount is a gate + a host-owned pathless layout position. It carries no
6
- * product semantics (no "dashboard", no shell, no chrome) — plugins bring
7
- * their own layouts and route freely inside their subtree. A mount is
8
- * declared by a ROOT-level pathless layout file whose `_`-prefixed segment
9
- * names the mount (`_public.tsx` → `public`); the generator derives it and
10
- * validates it against this registry; gates are attached HOST-side at
11
- * construction, so a plugin cannot ship a route that escapes its mount's
12
- * gate (plugins never construct route objects).
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 gates) but
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
- label: string;
19
- gate: "none" | "session" | "admin" | "organization" | "team";
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
- label: string;
26
- gate: "none";
27
- implemented: true;
24
+ readonly public: {
25
+ readonly guarded: false;
26
+ readonly implemented: true;
28
27
  };
29
- authenticated: {
30
- label: string;
31
- gate: "session";
32
- implemented: true;
28
+ readonly authenticated: {
29
+ readonly guarded: true;
30
+ readonly implemented: true;
33
31
  };
34
- admin: {
35
- label: string;
36
- gate: "admin";
37
- implemented: true;
32
+ readonly admin: {
33
+ readonly guarded: true;
34
+ readonly implemented: true;
38
35
  };
39
- org: {
40
- label: string;
41
- gate: "organization";
42
- parameterized: true;
43
- implemented: false;
36
+ readonly org: {
37
+ readonly guarded: true;
38
+ readonly implemented: false;
44
39
  };
45
- team: {
46
- label: string;
47
- gate: "team";
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 = 5;
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":";;;;;;;;;;;;;;;;UAgBiB;EACf;EACA;EACA;EACA;;cAGW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAQD,UAAU,qBAAqB;cAE9B,QAAwC;;cAGxC;;cAGA,eAAe,eAAe;iBAO3B,oBAAoB,kBAAkB"}
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 — gates only, shape-free (ADR 0008 §3).
3
+ * Mount registry v2 — shape-free (ADR 0008 §3).
4
4
  *
5
- * A mount is a gate + a host-owned pathless layout position. It carries no
6
- * product semantics (no "dashboard", no shell, no chrome) — plugins bring
7
- * their own layouts and route freely inside their subtree. A mount is
8
- * declared by a ROOT-level pathless layout file whose `_`-prefixed segment
9
- * names the mount (`_public.tsx` → `public`); the generator derives it and
10
- * validates it against this registry; gates are attached HOST-side at
11
- * construction, so a plugin cannot ship a route that escapes its mount's
12
- * gate (plugins never construct route objects).
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 gates) but
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
- label: string;
19
- gate: "none" | "session" | "admin" | "organization" | "team";
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
- label: string;
26
- gate: "none";
27
- implemented: true;
24
+ readonly public: {
25
+ readonly guarded: false;
26
+ readonly implemented: true;
28
27
  };
29
- authenticated: {
30
- label: string;
31
- gate: "session";
32
- implemented: true;
28
+ readonly authenticated: {
29
+ readonly guarded: true;
30
+ readonly implemented: true;
33
31
  };
34
- admin: {
35
- label: string;
36
- gate: "admin";
37
- implemented: true;
32
+ readonly admin: {
33
+ readonly guarded: true;
34
+ readonly implemented: true;
38
35
  };
39
- org: {
40
- label: string;
41
- gate: "organization";
42
- parameterized: true;
43
- implemented: false;
36
+ readonly org: {
37
+ readonly guarded: true;
38
+ readonly implemented: false;
44
39
  };
45
- team: {
46
- label: string;
47
- gate: "team";
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 = 5;
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":";;;;;;;;;;;;;;;;UAgBiB;EACf;EACA;EACA;EACA;;cAGW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAQD,UAAU,qBAAqB;cAE9B,QAAwC;;cAGxC;;cAGA,eAAe,eAAe;iBAO3B,oBAAoB,kBAAkB"}
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
- label: "public",
5
- gate: "none",
4
+ guarded: false,
6
5
  implemented: true
7
6
  },
8
7
  authenticated: {
9
- label: "authenticated",
10
- gate: "session",
8
+ guarded: true,
11
9
  implemented: true
12
10
  },
13
11
  admin: {
14
- label: "admin",
15
- gate: "admin",
12
+ guarded: true,
16
13
  implemented: true
17
14
  },
18
15
  org: {
19
- label: "org",
20
- gate: "organization",
21
- parameterized: true,
16
+ guarded: true,
22
17
  implemented: false
23
18
  },
24
19
  team: {
25
- label: "team",
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 = 5;
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 — gates only, shape-free (ADR 0008 §3).\n *\n * A mount is a gate + a host-owned pathless layout position. It carries no\n * product semantics (no \"dashboard\", no shell, no chrome) — plugins bring\n * their own layouts and route freely inside their subtree. A mount is\n * declared by a ROOT-level pathless layout file whose `_`-prefixed segment\n * names the mount (`_public.tsx` → `public`); the generator derives it and\n * validates it against this registry; gates are attached HOST-side at\n * construction, so a plugin cannot ship a route that escapes its mount's\n * gate (plugins never construct route objects).\n *\n * `org`/`team` are declared vocabulary (parameterized membership gates) but\n * unimplemented — construction rejects them until they land.\n */\n\nexport interface MountDef {\n label: string;\n gate: \"none\" | \"session\" | \"admin\" | \"organization\" | \"team\";\n parameterized?: boolean;\n implemented: boolean;\n}\n\nexport const MOUNT_REGISTRY = {\n public: { label: \"public\", gate: \"none\", implemented: true },\n authenticated: { label: \"authenticated\", gate: \"session\", implemented: true },\n admin: { label: \"admin\", gate: \"admin\", implemented: true },\n org: { label: \"org\", gate: \"organization\", parameterized: true, implemented: false },\n team: { label: \"team\", gate: \"team\", parameterized: true, implemented: false },\n} 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 = 5;\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,OAAO;EAAU,MAAM;EAAQ,aAAa;CAAK;CAC3D,eAAe;EAAE,OAAO;EAAiB,MAAM;EAAW,aAAa;CAAK;CAC5E,OAAO;EAAE,OAAO;EAAS,MAAM;EAAS,aAAa;CAAK;CAC1D,KAAK;EAAE,OAAO;EAAO,MAAM;EAAgB,eAAe;EAAM,aAAa;CAAM;CACnF,MAAM;EAAE,OAAO;EAAQ,MAAM;EAAQ,eAAe;EAAM,aAAa;CAAM;AAC/E;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"}
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;AAEvD,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;CAC5B,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;;;;;;;;AA6BD,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;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
+ {"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":";;cAca,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;GA2CzC,EAAA,KAAA;KACU,2BAA2B,EAAE,aAAa;;KAG1C,YAAY,YAAY;UAEnB;;;;EAIf;EACA;EACA;EACA;EACA;IAAQ;IAAe;;EACvB;IAAoB;IAAc;;EAClC,SAAS;EACT,SAAS;EACT,QAAQ;EACR;IAAW;IAAc;;;;;;;;;;iBAUX,uBAAuB,OAAO,uBAAuB"}
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":";;cAca,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;GA2CzC,EAAA,KAAA;KACU,2BAA2B,EAAE,aAAa;;KAG1C,YAAY,YAAY;UAEnB;;;;EAIf;EACA;EACA;EACA;EACA;IAAQ;IAAe;;EACvB;IAAoB;IAAc;;EAClC,SAAS;EACT,SAAS;EACT,QAAQ;EACR;IAAW;IAAc;;;;;;;;;;iBAUX,uBAAuB,OAAO,uBAAuB"}
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;AAEvD,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;CAC5B,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;;;;;;;;AA6BD,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;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
+ {"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.15",
3
+ "version": "3.0.0-rc.16",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -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/dev.everything.dev",
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/dev.everything.dev \
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 whose name carries a
38
- * content-hash segment (including hashed entrypoints like
39
- * `remoteEntry.8f3a….js`) is immutable by construction; fixed-name
40
- * entrypoints and non-hashed files a redeploy replaces in place must
41
- * revalidate.
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
  }
@@ -65,19 +65,14 @@ export type {
65
65
  ConstructedTree,
66
66
  ConstructInput,
67
67
  ConstructPluginRef,
68
- GateUser,
69
- HostContext,
70
68
  NavManifest,
71
69
  PluginManifest,
72
70
  ResolvedPlugin,
73
71
  RouteConfigModule,
74
72
  RouteOptionsBundle,
75
73
  } from "everything-dev/ui/manifest";
76
- export {
77
- CORE_UI_PLUGIN_KEY,
78
- ComposePayloadSchema,
79
- constructTree,
80
- } from "everything-dev/ui/manifest";
74
+ export { CORE_UI_PLUGIN_KEY, ComposePayloadSchema } from "everything-dev/ui/manifest";
75
+ export { constructTree } from "everything-dev/ui/compose";
81
76
  `,
82
77
  "src/globals.gen.ts": `// GENERATED FILE — do not edit. Regenerated from the installed framework version
83
78
  // by \`bos dev\` / \`bos build\` / \`bos typecheck\` (gitignored).
package/src/errors.ts CHANGED
@@ -68,6 +68,14 @@ export const NOT_FOUND = {
68
68
  }),
69
69
  } as const;
70
70
 
71
+ export const CONFLICT = {
72
+ status: 409,
73
+ data: z.object({
74
+ resource: z.string().optional(),
75
+ detail: z.string().optional(),
76
+ }),
77
+ } as const;
78
+
71
79
  export const FORBIDDEN = {
72
80
  status: 403,
73
81
  data: z.object({
@@ -105,6 +113,7 @@ export const PluginErrors = {
105
113
  SERVICE_UNAVAILABLE,
106
114
  BAD_REQUEST,
107
115
  NOT_FOUND,
116
+ CONFLICT,
108
117
  FORBIDDEN,
109
118
  TIMEOUT,
110
119
  CONNECTION_ERROR,
@@ -123,6 +132,7 @@ export const PLUGIN_ERROR_STATUS_MAP: Record<string, number> = {
123
132
  ...COMMON_ERROR_STATUS_MAP,
124
133
  TIMEOUT: 504,
125
134
  CONNECTION_ERROR: 502,
135
+ CONFLICT: 409,
126
136
  } as const;
127
137
 
128
138
  export type { PluginLoadFailureInfo, PluginWarningInfo } from "./runtime/errors";