@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.
- package/LICENSE +202 -0
- package/README.md +29 -0
- package/app-route.cjs +154 -0
- package/app-route.d.cts +7 -0
- package/attach.cjs +80 -0
- package/dist/app-route.cjs +154 -0
- package/dist/app-route.d.cts +7 -0
- package/dist/attach.cjs +80 -0
- package/dist/generated/pack-facts.json +4306 -0
- package/dist/inject.cjs +1097 -0
- package/dist/network-policy.cjs +92 -0
- package/dist/network-policy.d.cts +10 -0
- package/dist/src/actions.d.ts +276 -0
- package/dist/src/actions.js +436 -0
- package/dist/src/ancestry.d.ts +22 -0
- package/dist/src/ancestry.js +238 -0
- package/dist/src/args.d.ts +3 -0
- package/dist/src/args.js +12 -0
- package/dist/src/blob-store.d.ts +55 -0
- package/dist/src/blob-store.js +186 -0
- package/dist/src/brand-tokens.d.ts +2 -0
- package/dist/src/brand-tokens.js +17 -0
- package/dist/src/changeset.d.ts +431 -0
- package/dist/src/changeset.js +0 -0
- package/dist/src/client-bundle.d.ts +1 -0
- package/dist/src/client-bundle.js +28 -0
- package/dist/src/credential.d.ts +38 -0
- package/dist/src/credential.js +114 -0
- package/dist/src/derived-core.d.ts +452 -0
- package/dist/src/derived-core.js +782 -0
- package/dist/src/derived.d.ts +84 -0
- package/dist/src/derived.js +122 -0
- package/dist/src/emit.d.ts +106 -0
- package/dist/src/emit.js +157 -0
- package/dist/src/executor.d.ts +120 -0
- package/dist/src/executor.js +387 -0
- package/dist/src/file-response.d.ts +3 -0
- package/dist/src/file-response.js +22 -0
- package/dist/src/fork.d.ts +26 -0
- package/dist/src/fork.js +68 -0
- package/dist/src/git/history.d.ts +36 -0
- package/dist/src/git/history.js +298 -0
- package/dist/src/git/index.d.ts +6 -0
- package/dist/src/git/index.js +6 -0
- package/dist/src/git/inflate.d.ts +11 -0
- package/dist/src/git/inflate.js +194 -0
- package/dist/src/git/objects.d.ts +64 -0
- package/dist/src/git/objects.js +161 -0
- package/dist/src/git/pack.d.ts +14 -0
- package/dist/src/git/pack.js +199 -0
- package/dist/src/git/refs.d.ts +19 -0
- package/dist/src/git/refs.js +35 -0
- package/dist/src/git/smart-http.d.ts +45 -0
- package/dist/src/git/smart-http.js +223 -0
- package/dist/src/hash.d.ts +38 -0
- package/dist/src/hash.js +48 -0
- package/dist/src/head.d.ts +140 -0
- package/dist/src/head.js +313 -0
- package/dist/src/history.d.ts +76 -0
- package/dist/src/history.js +322 -0
- package/dist/src/index.d.ts +73 -0
- package/dist/src/index.js +98 -0
- package/dist/src/lifecycle.d.ts +1 -0
- package/dist/src/lifecycle.js +8 -0
- package/dist/src/log.d.ts +254 -0
- package/dist/src/log.js +801 -0
- package/dist/src/mirror-shell.d.ts +2 -0
- package/dist/src/mirror-shell.js +13 -0
- package/dist/src/observe.d.ts +49 -0
- package/dist/src/observe.js +148 -0
- package/dist/src/pack-assets.d.ts +30 -0
- package/dist/src/pack-assets.js +88 -0
- package/dist/src/packRegistry.d.ts +374 -0
- package/dist/src/packRegistry.js +142 -0
- package/dist/src/placeholder-remote.d.ts +22 -0
- package/dist/src/placeholder-remote.js +86 -0
- package/dist/src/proxy.d.ts +25 -0
- package/dist/src/proxy.js +155 -0
- package/dist/src/rateBudget.d.ts +367 -0
- package/dist/src/rateBudget.js +925 -0
- package/dist/src/references.d.ts +18 -0
- package/dist/src/references.js +27 -0
- package/dist/src/remote-execute.d.ts +22 -0
- package/dist/src/remote-execute.js +1 -0
- package/dist/src/resource-blob.d.ts +10 -0
- package/dist/src/resource-blob.js +56 -0
- package/dist/src/scenario.d.ts +197 -0
- package/dist/src/scenario.js +425 -0
- package/dist/src/schemas.d.ts +78 -0
- package/dist/src/schemas.js +50 -0
- package/dist/src/serve-http.d.ts +48 -0
- package/dist/src/serve-http.js +340 -0
- package/dist/src/serve.d.ts +147 -0
- package/dist/src/serve.js +507 -0
- package/dist/src/shared-blob-index.d.ts +4 -0
- package/dist/src/shared-blob-index.js +126 -0
- package/dist/src/state-system.d.ts +70 -0
- package/dist/src/state-system.js +90 -0
- package/dist/src/storage.d.ts +101 -0
- package/dist/src/storage.js +337 -0
- package/dist/src/twin-fetch.d.ts +64 -0
- package/dist/src/twin-fetch.js +91 -0
- package/dist/src/types.d.ts +40 -0
- package/dist/src/types.js +1 -0
- package/dist/src/v1-removed.d.ts +159 -0
- package/dist/src/v1-removed.js +124 -0
- package/dist/src/volter-home.d.ts +5 -0
- package/dist/src/volter-home.js +10 -0
- package/dist/src/world-clock.d.ts +4 -0
- package/dist/src/world-clock.js +32 -0
- package/dist/src/world-env.d.ts +3 -0
- package/dist/src/world-env.js +22 -0
- package/dist/src/world-store-sql.d.ts +27 -0
- package/dist/src/world-store-sql.js +86 -0
- package/dist/src/world-store.d.ts +168 -0
- package/dist/src/world-store.js +475 -0
- package/dist/src/worldConfig.d.ts +9 -0
- package/dist/src/worldConfig.js +17 -0
- package/dist/stream-bridge.cjs +80 -0
- package/dist/vendor-hosts.cjs +200 -0
- package/generated/pack-facts.json +4306 -0
- package/inject.cjs +1097 -0
- package/network-policy.cjs +92 -0
- package/network-policy.d.cts +10 -0
- package/package.json +103 -0
- package/src/actions.ts +564 -0
- package/src/ancestry.ts +213 -0
- package/src/args.ts +14 -0
- package/src/blob-store.ts +185 -0
- package/src/brand-tokens.ts +17 -0
- package/src/changeset.ts +1032 -0
- package/src/client-bundle.ts +29 -0
- package/src/credential.ts +140 -0
- package/src/derived-core.ts +1004 -0
- package/src/derived.ts +176 -0
- package/src/emit.ts +242 -0
- package/src/executor.ts +431 -0
- package/src/file-response.ts +22 -0
- package/src/fork.ts +89 -0
- package/src/git/history.ts +177 -0
- package/src/git/index.ts +6 -0
- package/src/git/inflate.ts +125 -0
- package/src/git/objects.ts +110 -0
- package/src/git/pack.ts +105 -0
- package/src/git/refs.ts +25 -0
- package/src/git/smart-http.ts +149 -0
- package/src/hash.ts +66 -0
- package/src/head.ts +318 -0
- package/src/history.ts +246 -0
- package/src/index.ts +323 -0
- package/src/lifecycle.ts +8 -0
- package/src/log.ts +793 -0
- package/src/mirror-shell.ts +15 -0
- package/src/observe.ts +130 -0
- package/src/pack-assets.ts +81 -0
- package/src/packRegistry.ts +408 -0
- package/src/placeholder-remote.ts +81 -0
- package/src/proxy.ts +183 -0
- package/src/rateBudget.ts +1115 -0
- package/src/references.ts +46 -0
- package/src/remote-execute.ts +26 -0
- package/src/resource-blob.ts +57 -0
- package/src/scenario.ts +479 -0
- package/src/schemas.ts +56 -0
- package/src/serve-http.ts +299 -0
- package/src/serve.ts +618 -0
- package/src/shared-blob-index.ts +108 -0
- package/src/state-system.ts +115 -0
- package/src/storage.ts +407 -0
- package/src/twin-fetch.ts +147 -0
- package/src/types.ts +50 -0
- package/src/v1-removed.ts +172 -0
- package/src/volter-home.ts +11 -0
- package/src/world-clock.ts +33 -0
- package/src/world-env.ts +18 -0
- package/src/world-store-sql.ts +118 -0
- package/src/world-store.ts +572 -0
- package/src/worldConfig.ts +27 -0
- package/stream-bridge.cjs +80 -0
- 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
|
+
}
|