@volter/world-core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +29 -0
  3. package/app-route.cjs +154 -0
  4. package/app-route.d.cts +7 -0
  5. package/attach.cjs +80 -0
  6. package/dist/app-route.cjs +154 -0
  7. package/dist/app-route.d.cts +7 -0
  8. package/dist/attach.cjs +80 -0
  9. package/dist/generated/pack-facts.json +4306 -0
  10. package/dist/inject.cjs +1097 -0
  11. package/dist/network-policy.cjs +92 -0
  12. package/dist/network-policy.d.cts +10 -0
  13. package/dist/src/actions.d.ts +276 -0
  14. package/dist/src/actions.js +436 -0
  15. package/dist/src/ancestry.d.ts +22 -0
  16. package/dist/src/ancestry.js +238 -0
  17. package/dist/src/args.d.ts +3 -0
  18. package/dist/src/args.js +12 -0
  19. package/dist/src/blob-store.d.ts +55 -0
  20. package/dist/src/blob-store.js +186 -0
  21. package/dist/src/brand-tokens.d.ts +2 -0
  22. package/dist/src/brand-tokens.js +17 -0
  23. package/dist/src/changeset.d.ts +431 -0
  24. package/dist/src/changeset.js +0 -0
  25. package/dist/src/client-bundle.d.ts +1 -0
  26. package/dist/src/client-bundle.js +28 -0
  27. package/dist/src/credential.d.ts +38 -0
  28. package/dist/src/credential.js +114 -0
  29. package/dist/src/derived-core.d.ts +452 -0
  30. package/dist/src/derived-core.js +782 -0
  31. package/dist/src/derived.d.ts +84 -0
  32. package/dist/src/derived.js +122 -0
  33. package/dist/src/emit.d.ts +106 -0
  34. package/dist/src/emit.js +157 -0
  35. package/dist/src/executor.d.ts +120 -0
  36. package/dist/src/executor.js +387 -0
  37. package/dist/src/file-response.d.ts +3 -0
  38. package/dist/src/file-response.js +22 -0
  39. package/dist/src/fork.d.ts +26 -0
  40. package/dist/src/fork.js +68 -0
  41. package/dist/src/git/history.d.ts +36 -0
  42. package/dist/src/git/history.js +298 -0
  43. package/dist/src/git/index.d.ts +6 -0
  44. package/dist/src/git/index.js +6 -0
  45. package/dist/src/git/inflate.d.ts +11 -0
  46. package/dist/src/git/inflate.js +194 -0
  47. package/dist/src/git/objects.d.ts +64 -0
  48. package/dist/src/git/objects.js +161 -0
  49. package/dist/src/git/pack.d.ts +14 -0
  50. package/dist/src/git/pack.js +199 -0
  51. package/dist/src/git/refs.d.ts +19 -0
  52. package/dist/src/git/refs.js +35 -0
  53. package/dist/src/git/smart-http.d.ts +45 -0
  54. package/dist/src/git/smart-http.js +223 -0
  55. package/dist/src/hash.d.ts +38 -0
  56. package/dist/src/hash.js +48 -0
  57. package/dist/src/head.d.ts +140 -0
  58. package/dist/src/head.js +313 -0
  59. package/dist/src/history.d.ts +76 -0
  60. package/dist/src/history.js +322 -0
  61. package/dist/src/index.d.ts +73 -0
  62. package/dist/src/index.js +98 -0
  63. package/dist/src/lifecycle.d.ts +1 -0
  64. package/dist/src/lifecycle.js +8 -0
  65. package/dist/src/log.d.ts +254 -0
  66. package/dist/src/log.js +801 -0
  67. package/dist/src/mirror-shell.d.ts +2 -0
  68. package/dist/src/mirror-shell.js +13 -0
  69. package/dist/src/observe.d.ts +49 -0
  70. package/dist/src/observe.js +148 -0
  71. package/dist/src/pack-assets.d.ts +30 -0
  72. package/dist/src/pack-assets.js +88 -0
  73. package/dist/src/packRegistry.d.ts +374 -0
  74. package/dist/src/packRegistry.js +142 -0
  75. package/dist/src/placeholder-remote.d.ts +22 -0
  76. package/dist/src/placeholder-remote.js +86 -0
  77. package/dist/src/proxy.d.ts +25 -0
  78. package/dist/src/proxy.js +155 -0
  79. package/dist/src/rateBudget.d.ts +367 -0
  80. package/dist/src/rateBudget.js +925 -0
  81. package/dist/src/references.d.ts +18 -0
  82. package/dist/src/references.js +27 -0
  83. package/dist/src/remote-execute.d.ts +22 -0
  84. package/dist/src/remote-execute.js +1 -0
  85. package/dist/src/resource-blob.d.ts +10 -0
  86. package/dist/src/resource-blob.js +56 -0
  87. package/dist/src/scenario.d.ts +197 -0
  88. package/dist/src/scenario.js +425 -0
  89. package/dist/src/schemas.d.ts +78 -0
  90. package/dist/src/schemas.js +50 -0
  91. package/dist/src/serve-http.d.ts +48 -0
  92. package/dist/src/serve-http.js +340 -0
  93. package/dist/src/serve.d.ts +147 -0
  94. package/dist/src/serve.js +507 -0
  95. package/dist/src/shared-blob-index.d.ts +4 -0
  96. package/dist/src/shared-blob-index.js +126 -0
  97. package/dist/src/state-system.d.ts +70 -0
  98. package/dist/src/state-system.js +90 -0
  99. package/dist/src/storage.d.ts +101 -0
  100. package/dist/src/storage.js +337 -0
  101. package/dist/src/twin-fetch.d.ts +64 -0
  102. package/dist/src/twin-fetch.js +91 -0
  103. package/dist/src/types.d.ts +40 -0
  104. package/dist/src/types.js +1 -0
  105. package/dist/src/v1-removed.d.ts +159 -0
  106. package/dist/src/v1-removed.js +124 -0
  107. package/dist/src/volter-home.d.ts +5 -0
  108. package/dist/src/volter-home.js +10 -0
  109. package/dist/src/world-clock.d.ts +4 -0
  110. package/dist/src/world-clock.js +32 -0
  111. package/dist/src/world-env.d.ts +3 -0
  112. package/dist/src/world-env.js +22 -0
  113. package/dist/src/world-store-sql.d.ts +27 -0
  114. package/dist/src/world-store-sql.js +86 -0
  115. package/dist/src/world-store.d.ts +168 -0
  116. package/dist/src/world-store.js +475 -0
  117. package/dist/src/worldConfig.d.ts +9 -0
  118. package/dist/src/worldConfig.js +17 -0
  119. package/dist/stream-bridge.cjs +80 -0
  120. package/dist/vendor-hosts.cjs +200 -0
  121. package/generated/pack-facts.json +4306 -0
  122. package/inject.cjs +1097 -0
  123. package/network-policy.cjs +92 -0
  124. package/network-policy.d.cts +10 -0
  125. package/package.json +103 -0
  126. package/src/actions.ts +564 -0
  127. package/src/ancestry.ts +213 -0
  128. package/src/args.ts +14 -0
  129. package/src/blob-store.ts +185 -0
  130. package/src/brand-tokens.ts +17 -0
  131. package/src/changeset.ts +1032 -0
  132. package/src/client-bundle.ts +29 -0
  133. package/src/credential.ts +140 -0
  134. package/src/derived-core.ts +1004 -0
  135. package/src/derived.ts +176 -0
  136. package/src/emit.ts +242 -0
  137. package/src/executor.ts +431 -0
  138. package/src/file-response.ts +22 -0
  139. package/src/fork.ts +89 -0
  140. package/src/git/history.ts +177 -0
  141. package/src/git/index.ts +6 -0
  142. package/src/git/inflate.ts +125 -0
  143. package/src/git/objects.ts +110 -0
  144. package/src/git/pack.ts +105 -0
  145. package/src/git/refs.ts +25 -0
  146. package/src/git/smart-http.ts +149 -0
  147. package/src/hash.ts +66 -0
  148. package/src/head.ts +318 -0
  149. package/src/history.ts +246 -0
  150. package/src/index.ts +323 -0
  151. package/src/lifecycle.ts +8 -0
  152. package/src/log.ts +793 -0
  153. package/src/mirror-shell.ts +15 -0
  154. package/src/observe.ts +130 -0
  155. package/src/pack-assets.ts +81 -0
  156. package/src/packRegistry.ts +408 -0
  157. package/src/placeholder-remote.ts +81 -0
  158. package/src/proxy.ts +183 -0
  159. package/src/rateBudget.ts +1115 -0
  160. package/src/references.ts +46 -0
  161. package/src/remote-execute.ts +26 -0
  162. package/src/resource-blob.ts +57 -0
  163. package/src/scenario.ts +479 -0
  164. package/src/schemas.ts +56 -0
  165. package/src/serve-http.ts +299 -0
  166. package/src/serve.ts +618 -0
  167. package/src/shared-blob-index.ts +108 -0
  168. package/src/state-system.ts +115 -0
  169. package/src/storage.ts +407 -0
  170. package/src/twin-fetch.ts +147 -0
  171. package/src/types.ts +50 -0
  172. package/src/v1-removed.ts +172 -0
  173. package/src/volter-home.ts +11 -0
  174. package/src/world-clock.ts +33 -0
  175. package/src/world-env.ts +18 -0
  176. package/src/world-store-sql.ts +118 -0
  177. package/src/world-store.ts +572 -0
  178. package/src/worldConfig.ts +27 -0
  179. package/stream-bridge.cjs +80 -0
  180. package/vendor-hosts.cjs +200 -0
@@ -0,0 +1,29 @@
1
+ // A mirror's browser client from its `client/<name>.tsx` entry, runtime-neutral (the serve seam's helpers,
2
+ // docs/contributing/architecture.md#the-serve-seam): under Bun the same `Bun.build` every mirror ran at
3
+ // serve time; under Node the PREBUILT `<name>.bundle.js` beside the entry, written at pack time
4
+ // by scripts/publish/build.mjs into dist/client/. Built once per process and kept; a failed build
5
+ // is retried on the next call. Nothing here runs at module scope.
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+
8
+ const bundles = new Map<string, Promise<string>>();
9
+ type BunBuild = { build: (o: { entrypoints: string[]; target: 'browser'; minify: boolean }) => Promise<{ success: boolean; logs: Array<{ message: string }>; outputs: Array<{ text: () => Promise<string> }> }> };
10
+
11
+ export function bundleClient(entry: string): Promise<string> {
12
+ let pending = bundles.get(entry);
13
+ if (!pending) {
14
+ const bun = (globalThis as { Bun?: Partial<BunBuild> }).Bun;
15
+ pending = (bun && typeof bun.build === 'function'
16
+ ? (bun as BunBuild).build({ entrypoints: [entry], target: 'browser', minify: true }).then(async (result) => {
17
+ if (!result.success) throw new Error(result.logs.map((l) => l.message).join('\n') || `client build failed: ${entry}`);
18
+ return result.outputs[0]!.text();
19
+ })
20
+ : Promise.resolve().then(() => {
21
+ const prebuilt = entry.replace(/\.tsx?$/, '.bundle.js');
22
+ if (!existsSync(prebuilt)) throw new Error(`client bundle missing at ${prebuilt} — the package's \`build\` writes it (scripts/publish/build.mjs); Node serves the prebuilt client`);
23
+ return readFileSync(prebuilt, 'utf8');
24
+ }))
25
+ .catch((error) => { bundles.delete(entry); throw error; });
26
+ bundles.set(entry, pending);
27
+ }
28
+ return pending;
29
+ }
@@ -0,0 +1,140 @@
1
+ // THE SEALED CREDENTIAL STORE (docs/concepts/the-model.md, rule 5; custody ruled 2026-09-01:
2
+ // lives in core since v2 — a world that wraps reality seals its credential beside itself, and the
3
+ // kernel executor is the only reader). Originally the twins host's; the host re-exports it.
4
+ // cloud-side, idiomatic — like any web service). Real vendor credentials are:
5
+ // • WRITE-ONLY through the API: placement and deletion are the tenant's act; reads
6
+ // return metadata (placedAt, a fingerprint) and NEVER the secret — there is no
7
+ // read-back door, and none may ever be added.
8
+ // • ENVELOPE-ENCRYPTED: each credential gets its own random 256-bit DEK (AES-GCM);
9
+ // the DEK is wrapped by the deployment KEK, which lives in the platform's secret
10
+ // store (wrangler secret TWINS_CRED_KEK) and never in any bucket. KEK rotation is
11
+ // a re-wrap of DEKs, not a re-encryption of payloads.
12
+ // • OUTSIDE every namespace tree (beside keys and links, under '-/creds/'), so no
13
+ // flush, snapshot, or door can ever carry one.
14
+ // • CONSUMED only by the remote backing arm and the sync plane, through
15
+ // `openSealedCredential` — an in-process seam, never an HTTP surface.
16
+ //
17
+ // The payload is a JSON object; the convention the forward arm consumes is
18
+ // `{ headers: { authorization: "Bearer …", … } }` — credential APPLICATION is a value
19
+ // (which headers), never a per-vendor mechanism. WebCrypto only: workerd-clean.
20
+ //
21
+ // `secret` is the RAW material for the strategies that cannot be expressed as a header: a vendor
22
+ // that reads its key from a query parameter, or one that wants a signature computed per request
23
+ // (docs/concepts/the-model.md#the-rules, rule 5, "applies the credential by strategy"). It is optional and unread unless
24
+ // the pack declares such a strategy, so a header-authenticated vendor seals exactly what it sealed
25
+ // before. It is never logged and never enters pack code — the executor is the only reader.
26
+
27
+ export type CredentialPayload = { headers: Record<string, string>; secret?: string; keyId?: string } & Record<string, unknown>;
28
+
29
+ /** The at-rest form. All byte fields base64. The fingerprint is a short SHA-256 prefix
30
+ * of the payload — enough for an operator to recognize "the key ending a1b2…", never
31
+ * enough to recover anything. */
32
+ export type SealedCredential = {
33
+ v: 1;
34
+ dekIv: string;
35
+ wrappedDek: string;
36
+ iv: string;
37
+ ciphertext: string;
38
+ placedAt: string;
39
+ fingerprint: string;
40
+ /** when a vendor last rotated a field of it (an OAuth refresh token): placedAt and fingerprint stay the credential's
41
+ * identity across rotations, the ledgers keyed by the fingerprint with them */
42
+ rotatedAt?: string;
43
+ };
44
+
45
+ export interface CredentialStorage {
46
+ getSealed(namespace: string, vendor: string): Promise<SealedCredential | null>;
47
+ putSealed(namespace: string, vendor: string, sealed: SealedCredential): Promise<void>;
48
+ deleteSealed(namespace: string, vendor: string): Promise<void>;
49
+ /** Purge every vendor's sealed record for the namespace — the lifecycle DELETE calls
50
+ * this: a deleted namespace's credentials must not survive to be inherited by
51
+ * whoever re-provisions the name (review B1: the resurrection theft chain). */
52
+ deleteNamespace(namespace: string): Promise<void>;
53
+ }
54
+
55
+ export class MemoryCredentialStorage implements CredentialStorage {
56
+ readonly records = new Map<string, SealedCredential>();
57
+ async getSealed(namespace: string, vendor: string): Promise<SealedCredential | null> {
58
+ return this.records.get(`${namespace}/${vendor}`) ?? null;
59
+ }
60
+ async putSealed(namespace: string, vendor: string, sealed: SealedCredential): Promise<void> {
61
+ this.records.set(`${namespace}/${vendor}`, sealed);
62
+ }
63
+ async deleteSealed(namespace: string, vendor: string): Promise<void> {
64
+ this.records.delete(`${namespace}/${vendor}`);
65
+ }
66
+ async deleteNamespace(namespace: string): Promise<void> {
67
+ for (const key of [...this.records.keys()]) if (key.startsWith(`${namespace}/`)) this.records.delete(key);
68
+ }
69
+ }
70
+
71
+ const toB64 = (bytes: Uint8Array): string => {
72
+ // Chunked (review B3): a spread of the whole payload blows the arg-count stack well
73
+ // below the 4 MB body cap (verified ~1 MB on Bun, tens of KB on V8).
74
+ let bin = '';
75
+ for (let i = 0; i < bytes.length; i += 0x1000) bin += String.fromCharCode(...bytes.subarray(i, i + 0x1000));
76
+ return btoa(bin);
77
+ };
78
+ const fromB64 = (b64: string): Uint8Array<ArrayBuffer> => {
79
+ const bin = atob(b64);
80
+ const bytes = new Uint8Array(new ArrayBuffer(bin.length));
81
+ for (let i = 0; i < bin.length; i += 1) bytes[i] = bin.charCodeAt(i);
82
+ return bytes;
83
+ };
84
+
85
+ /** The KEK secret string (any length ≥ 16) normalizes to 32 key bytes via SHA-256 —
86
+ * operators paste one strong secret; the digest is the AES key material. */
87
+ async function importKek(secret: string): Promise<CryptoKey> {
88
+ // ≥32 chars (review M3): SHA-256 with no stretching is fine for MACHINE secrets
89
+ // (`openssl rand -base64 32`) and hopeless against a short human passphrase — the
90
+ // floor forces the former.
91
+ if (secret.length < 32) throw new Error('credential KEK must be at least 32 characters (generate with: openssl rand -base64 32)');
92
+ const material = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(secret));
93
+ return await crypto.subtle.importKey('raw', material, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
94
+ }
95
+
96
+ export async function sealCredential(kekSecret: string, payload: CredentialPayload, placedAt: string, slot = ''): Promise<SealedCredential> {
97
+ const kek = await importKek(kekSecret);
98
+ const plaintext = new TextEncoder().encode(JSON.stringify(payload));
99
+ const dekBytes = crypto.getRandomValues(new Uint8Array(32));
100
+ const dek = await crypto.subtle.importKey('raw', dekBytes, { name: 'AES-GCM' }, false, ['encrypt']);
101
+ const iv = crypto.getRandomValues(new Uint8Array(12));
102
+ const dekIv = crypto.getRandomValues(new Uint8Array(12));
103
+ // The SLOT ('{namespace}/{vendor}') rides as AAD (audit L16): a sealed record
104
+ // transplanted to another slot by a bucket-level writer refuses to open there.
105
+ const aad = new TextEncoder().encode(slot);
106
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData: aad }, dek, plaintext));
107
+ const wrappedDek = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv: dekIv }, kek, dekBytes));
108
+ // KEYED fingerprint (review m1): an unsalted hash prefix is an offline oracle for
109
+ // low-entropy payloads; HMAC under KEK-derived material keeps the operator UX
110
+ // (recognizable short id) with no oracle.
111
+ const macMaterial = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(`fingerprint:${kekSecret}`));
112
+ const macKey = await crypto.subtle.importKey('raw', macMaterial, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
113
+ const digest = new Uint8Array(await crypto.subtle.sign('HMAC', macKey, plaintext));
114
+ return {
115
+ v: 1,
116
+ dekIv: toB64(dekIv),
117
+ wrappedDek: toB64(wrappedDek),
118
+ iv: toB64(iv),
119
+ ciphertext: toB64(ciphertext),
120
+ placedAt,
121
+ fingerprint: [...digest.slice(0, 6)].map((b) => b.toString(16).padStart(2, '0')).join(''),
122
+ };
123
+ }
124
+
125
+ export async function openSealedCredential(kekSecret: string, sealed: SealedCredential, slot = ''): Promise<CredentialPayload> {
126
+ const kek = await importKek(kekSecret);
127
+ let dekBytes: ArrayBuffer;
128
+ try {
129
+ dekBytes = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: fromB64(sealed.dekIv) }, kek, fromB64(sealed.wrappedDek));
130
+ } catch {
131
+ throw new Error('credential unseal failed: wrong KEK or corrupted record');
132
+ }
133
+ const dek = await crypto.subtle.importKey('raw', dekBytes, { name: 'AES-GCM' }, false, ['decrypt']);
134
+ try {
135
+ const plaintext = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv: fromB64(sealed.iv), additionalData: new TextEncoder().encode(slot) }, dek, fromB64(sealed.ciphertext)));
136
+ return JSON.parse(new TextDecoder().decode(plaintext)) as CredentialPayload;
137
+ } catch {
138
+ throw new Error('credential unseal failed: wrong KEK or corrupted record');
139
+ }
140
+ }