@volter/world-core 2.0.37 → 3.0.1

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 (205) hide show
  1. package/README.md +4 -5
  2. package/app-route.cjs +12 -6
  3. package/app-route.d.cts +1 -1
  4. package/dist/app-route.cjs +12 -6
  5. package/dist/app-route.d.cts +1 -1
  6. package/dist/generated/pack-facts.json +1410 -3069
  7. package/dist/inject.cjs +64 -9
  8. package/dist/pack-facts.cjs +44 -0
  9. package/dist/src/actions.d.ts +3 -3
  10. package/dist/src/actions.js +22 -16
  11. package/dist/src/ancestry.d.ts +14 -2
  12. package/dist/src/ancestry.js +92 -2
  13. package/dist/src/anthropic-wire.d.ts +39 -0
  14. package/dist/src/anthropic-wire.js +136 -0
  15. package/dist/src/bytes.d.ts +7 -0
  16. package/dist/src/bytes.js +35 -0
  17. package/dist/src/changeset.d.ts +1 -1
  18. package/dist/src/changeset.js +0 -0
  19. package/dist/src/clickhouse/index.d.ts +3 -0
  20. package/dist/src/clickhouse/index.js +6 -0
  21. package/dist/src/clickhouse/sql.d.ts +233 -0
  22. package/dist/src/clickhouse/sql.js +4329 -0
  23. package/dist/src/clickhouse/types.d.ts +18 -0
  24. package/dist/src/clickhouse/types.js +47 -0
  25. package/dist/src/clickhouse/values.d.ts +146 -0
  26. package/dist/src/clickhouse/values.js +858 -0
  27. package/dist/src/client-bundle.js +2 -3
  28. package/dist/src/cors.d.ts +15 -0
  29. package/dist/src/cors.js +31 -0
  30. package/dist/src/derived-core.d.ts +487 -24
  31. package/dist/src/derived-core.js +788 -144
  32. package/dist/src/derived-real.d.ts +13 -0
  33. package/dist/src/derived-real.js +518 -0
  34. package/dist/src/derived.d.ts +35 -1
  35. package/dist/src/derived.js +61 -9
  36. package/dist/src/emit.js +1 -2
  37. package/dist/src/events.d.ts +206 -0
  38. package/dist/src/events.js +341 -0
  39. package/dist/src/executor.d.ts +3 -0
  40. package/dist/src/executor.js +19 -2
  41. package/dist/src/file-response.d.ts +6 -0
  42. package/dist/src/file-response.js +30 -0
  43. package/dist/src/fork.js +3 -2
  44. package/dist/src/git/history.d.ts +7 -0
  45. package/dist/src/git/history.js +24 -0
  46. package/dist/src/git/index.d.ts +1 -0
  47. package/dist/src/git/index.js +1 -0
  48. package/dist/src/git/lfs.d.ts +28 -0
  49. package/dist/src/git/lfs.js +66 -0
  50. package/dist/src/git/objects.js +3 -8
  51. package/dist/src/git/smart-http.d.ts +3 -1
  52. package/dist/src/git/smart-http.js +67 -6
  53. package/dist/src/graphql-wire.d.ts +29 -0
  54. package/dist/src/graphql-wire.js +101 -0
  55. package/dist/src/grpc-wire.d.ts +67 -0
  56. package/dist/src/grpc-wire.js +170 -0
  57. package/dist/src/h2.d.ts +40 -0
  58. package/dist/src/h2.js +656 -0
  59. package/dist/src/head.d.ts +32 -3
  60. package/dist/src/head.js +161 -40
  61. package/dist/src/history.d.ts +1 -1
  62. package/dist/src/history.js +6 -6
  63. package/dist/src/hpack.json +1 -0
  64. package/dist/src/index.d.ts +64 -75
  65. package/dist/src/index.js +58 -101
  66. package/dist/src/log.js +28 -19
  67. package/dist/src/machines.d.ts +50 -0
  68. package/dist/src/machines.js +151 -0
  69. package/dist/src/managed-database.d.ts +86 -0
  70. package/dist/src/managed-database.js +283 -0
  71. package/dist/src/multipart.d.ts +11 -0
  72. package/dist/src/multipart.js +51 -0
  73. package/dist/src/observe.d.ts +15 -5
  74. package/dist/src/observe.js +23 -9
  75. package/dist/src/openai-wire.d.ts +108 -0
  76. package/dist/src/openai-wire.js +337 -0
  77. package/dist/src/pack-assets.d.ts +3 -4
  78. package/dist/src/pack-assets.js +15 -10
  79. package/dist/src/pack-fetch.d.ts +77 -0
  80. package/dist/src/pack-fetch.js +449 -0
  81. package/dist/src/pack-paths.d.ts +12 -0
  82. package/dist/src/pack-paths.js +86 -0
  83. package/dist/src/packRegistry.d.ts +69 -162
  84. package/dist/src/packRegistry.js +55 -20
  85. package/dist/src/people.d.ts +13 -0
  86. package/dist/src/people.js +18 -0
  87. package/dist/src/placeholder-image.d.ts +5 -0
  88. package/dist/src/placeholder-image.js +114 -0
  89. package/dist/src/protobuf.d.ts +28 -0
  90. package/dist/src/protobuf.js +332 -0
  91. package/dist/src/redis/engine.js +1 -1
  92. package/dist/src/request-scope.d.ts +1 -1
  93. package/dist/src/request-scope.js +6 -4
  94. package/dist/src/resource-blob.d.ts +5 -0
  95. package/dist/src/resource-blob.js +11 -0
  96. package/dist/src/runtime.d.ts +85 -0
  97. package/dist/src/runtime.js +104 -0
  98. package/dist/src/s3/wire.d.ts +60 -0
  99. package/dist/src/s3/wire.js +157 -0
  100. package/dist/src/scenario.d.ts +3 -0
  101. package/dist/src/scenario.js +2 -0
  102. package/dist/src/schema-sample.d.ts +1 -0
  103. package/dist/src/schema-sample.js +21 -0
  104. package/dist/src/sealed-box.d.ts +14 -0
  105. package/dist/src/sealed-box.js +225 -0
  106. package/dist/src/serve-http.d.ts +14 -0
  107. package/dist/src/serve-http.js +27 -3
  108. package/dist/src/serve.d.ts +6 -0
  109. package/dist/src/serve.js +69 -14
  110. package/dist/src/signing.d.ts +135 -0
  111. package/dist/src/signing.js +222 -0
  112. package/dist/src/sigv4.d.ts +48 -0
  113. package/dist/src/sigv4.js +167 -0
  114. package/dist/src/smtp.d.ts +16 -0
  115. package/dist/src/smtp.js +72 -0
  116. package/dist/src/sockets.d.ts +51 -0
  117. package/dist/src/sockets.js +90 -0
  118. package/dist/src/state-system.d.ts +1 -0
  119. package/dist/src/state-system.js +1 -1
  120. package/dist/src/storage.d.ts +1 -1
  121. package/dist/src/storage.js +3 -3
  122. package/dist/src/trace-context.js +1 -1
  123. package/dist/src/twin-fetch.d.ts +0 -7
  124. package/dist/src/twin-fetch.js +0 -14
  125. package/dist/src/vendor-call.d.ts +6 -0
  126. package/dist/src/vendor-call.js +41 -0
  127. package/dist/src/world-store.js +1 -1
  128. package/dist/vendor-hosts.cjs +36 -125
  129. package/dist/vendor-hosts.d.cts +8 -0
  130. package/generated/pack-facts.json +1410 -3069
  131. package/inject.cjs +64 -9
  132. package/pack-facts.cjs +44 -0
  133. package/package.json +17 -3
  134. package/src/actions.ts +23 -16
  135. package/src/ancestry.ts +74 -2
  136. package/src/anthropic-wire.ts +137 -0
  137. package/src/bytes.ts +42 -0
  138. package/src/changeset.ts +5 -5
  139. package/src/clickhouse/index.ts +6 -0
  140. package/src/clickhouse/sql.ts +3059 -0
  141. package/src/clickhouse/types.ts +44 -0
  142. package/src/clickhouse/values.ts +697 -0
  143. package/src/client-bundle.ts +2 -3
  144. package/src/cors.ts +34 -0
  145. package/src/derived-core.ts +1013 -146
  146. package/src/derived-real.ts +434 -0
  147. package/src/derived.ts +73 -3
  148. package/src/emit.ts +1 -2
  149. package/src/events.ts +449 -0
  150. package/src/executor.ts +24 -2
  151. package/src/file-response.ts +27 -0
  152. package/src/fork.ts +3 -2
  153. package/src/git/history.ts +19 -0
  154. package/src/git/index.ts +1 -0
  155. package/src/git/lfs.ts +67 -0
  156. package/src/git/objects.ts +3 -5
  157. package/src/git/smart-http.ts +56 -6
  158. package/src/graphql-wire.ts +106 -0
  159. package/src/grpc-wire.ts +159 -0
  160. package/src/h2.ts +627 -0
  161. package/src/head.ts +132 -41
  162. package/src/history.ts +6 -6
  163. package/src/hpack.json +1 -0
  164. package/src/index.ts +82 -329
  165. package/src/log.ts +27 -18
  166. package/src/machines.ts +151 -0
  167. package/src/managed-database.ts +299 -0
  168. package/src/multipart.ts +51 -0
  169. package/src/observe.ts +31 -15
  170. package/src/openai-wire.ts +371 -0
  171. package/src/pack-assets.ts +15 -11
  172. package/src/pack-fetch.ts +458 -0
  173. package/src/pack-paths.ts +72 -0
  174. package/src/packRegistry.ts +79 -167
  175. package/src/people.ts +31 -0
  176. package/src/placeholder-image.ts +88 -0
  177. package/src/protobuf.ts +251 -0
  178. package/src/redis/engine.ts +1 -1
  179. package/src/request-scope.ts +8 -4
  180. package/src/resource-blob.ts +13 -0
  181. package/src/runtime.ts +344 -0
  182. package/src/s3/wire.ts +172 -0
  183. package/src/scenario.ts +4 -0
  184. package/src/schema-sample.ts +24 -0
  185. package/src/sealed-box.ts +182 -0
  186. package/src/serve-http.ts +31 -3
  187. package/src/serve.ts +58 -14
  188. package/src/signing.ts +231 -0
  189. package/src/sigv4.ts +158 -0
  190. package/src/smtp.ts +76 -0
  191. package/src/sockets.ts +140 -0
  192. package/src/state-system.ts +2 -2
  193. package/src/storage.ts +3 -3
  194. package/src/trace-context.ts +1 -1
  195. package/src/twin-fetch.ts +0 -20
  196. package/src/vendor-call.ts +41 -0
  197. package/src/world-store.ts +1 -1
  198. package/vendor-hosts.cjs +36 -125
  199. package/vendor-hosts.d.cts +8 -0
  200. package/dist/src/mirror-shell.d.ts +0 -2
  201. package/dist/src/mirror-shell.js +0 -13
  202. package/dist/src/v1-removed.d.ts +0 -159
  203. package/dist/src/v1-removed.js +0 -124
  204. package/src/mirror-shell.ts +0 -15
  205. package/src/v1-removed.ts +0 -172
@@ -9,7 +9,10 @@
9
9
  // ignore the registry entirely. Pure + deterministic.
10
10
  import { declareRateBudget, type RateBudgetDeclaration } from './rateBudget.ts';
11
11
  import type { TwinAuthStrategy } from './executor.ts';
12
- import { registerReferences, type ReferenceDeclaration } from './references.ts';
12
+ import { referenceField, registerReferences, type ReferenceDeclaration } from './references.ts';
13
+ import { deriveStateSystem, deriveVendorStateSystem } from './derived-real.ts';
14
+ import type { DerivedManifest, VendorManifest } from './derived-core.ts';
15
+ import type { DerivedSurface } from './derived.ts';
13
16
  import type { TwinEmitter } from './emit.ts';
14
17
  import { registerAuthStrategy, registerStateSystem, type StateSystemAdapters } from './state-system.ts';
15
18
 
@@ -20,13 +23,13 @@ import { registerAuthStrategy, registerStateSystem, type StateSystemAdapters } f
20
23
  * `browserRouting`, and no entry in the injector's `VENDOR_HOSTS` host map is possible (the
21
24
  * injector patches http/fetch and never sees the traffic). Such a pack is wired into a world
22
25
  * through app-read host/port env instead, and this value is what tells a reader that "no injector
23
- * entry" is STRUCTURAL rather than a missing wiring point. `packages/twin/smtp` (a line protocol)
24
- * is the first; `packages/twin/temporal` (gRPC: HTTP/2 framing its clients drive themselves) the
26
+ * entry" is STRUCTURAL rather than a missing wiring point. `@volter/twin-smtp` (a line protocol)
27
+ * is the first; `@volter/twin-temporal` (gRPC: HTTP/2 framing its clients drive themselves) the
25
28
  * second.
26
29
  *
27
30
  * Deliberately the transport CLASS, not the protocol name: naming the wire protocol would put a
28
31
  * vendor id in the kernel the moment a pack is named after its protocol, which is exactly what
29
- * `scripts/architecture.test.ts`'s "kernel does not branch on vendor identity" forbids. The
32
+ * A2, "the kernel does not branch on vendor identity" (`scripts/architecture-auto.ts`), forbids. The
30
33
  * specific protocol belongs on the pack's own `specSource`/`description`.
31
34
  */
32
35
  export type PackTransport = 'rest' | 'graphql' | 'web-api' | 'raw-tcp';
@@ -35,7 +38,7 @@ export type PackTransport = 'rest' | 'graphql' | 'web-api' | 'raw-tcp';
35
38
  * The pack's SERVE-FAMILY — the axis the invariant matrix keys strictness off, DECLARED
36
39
  * because it is the pack's own claim about what kind of thing it is (a heuristic over file
37
40
  * shapes would be the loose-scan disease). Orthogonal facts stay derived: transport is its
38
- * own field, a mirror is mirrorMutations in gate.ts, webhooks are the events module.
41
+ * own field, screens are the manifest's, webhooks are the events module.
39
42
  * 'crud' — stateful resource CRUD behind the vendor's API (the default family;
40
43
  * includes ingestion→grouping packs — the ingest door is a trait).
41
44
  * 'generative' — model-shaped surface serving deterministic stubs/scenarios; "cannot
@@ -48,22 +51,16 @@ export type PackTransport = 'rest' | 'graphql' | 'web-api' | 'raw-tcp';
48
51
  */
49
52
  /** THE PLATFORM PROTOCOL VERSION (runtime contract R16): `major.minor`. The major names the
50
53
  * descriptor shape, the factory signature, the doors and the adapter contract a package is
51
- * written against; a change that removes or alters a required shape bumps it, an additive
52
- * change bumps minor. A package declares the major it targets (`protocol`); the kernel serves
53
- * its own major, the previous one under a deprecation warning for one cycle, and refuses two
54
- * back. Undeclared reads as the previous major (deprecated) once there is one. */
55
- export const PROTOCOL_VERSION = '2.0';
54
+ * written against, and the build form it is made in (the derived pack); a change that removes or
55
+ * alters a required shape bumps it, an additive change bumps minor. A package declares the major
56
+ * it targets (`protocol`), and the kernel serves its own major and no other: a package that
57
+ * declares another, or none, is refused. */
58
+ export const PROTOCOL_VERSION = '3.0';
56
59
  export const PROTOCOL_MAJOR = Number(PROTOCOL_VERSION.split('.')[0]);
57
- /** Where a package's declared protocol stands against this kernel. */
58
- export function protocolStanding(declared: string | undefined): { major: number; standing: 'current' | 'deprecated' | 'refused' | 'assumed' } {
59
- // undeclared: written before a pack could say — the previous major once there is one, and
60
- // deprecated like any pack on it; the current major only while it is the first
61
- if (declared === undefined) return PROTOCOL_MAJOR > 1 ? { major: PROTOCOL_MAJOR - 1, standing: 'deprecated' } : { major: PROTOCOL_MAJOR, standing: 'assumed' };
62
- const major = Number(String(declared).split('.')[0]);
63
- if (!Number.isInteger(major) || major < 1) return { major: Number.NaN, standing: 'refused' };
64
- if (major === PROTOCOL_MAJOR) return { major, standing: 'current' };
65
- if (major === PROTOCOL_MAJOR - 1) return { major, standing: 'deprecated' };
66
- return { major, standing: 'refused' };
60
+ /** Where a package's declared protocol stands against this kernel: `current`, or `refused`. */
61
+ export function protocolStanding(declared: string | undefined): { major: number; standing: 'current' | 'refused' } {
62
+ const major = declared === undefined ? Number.NaN : Number(String(declared).split('.')[0]);
63
+ return major === PROTOCOL_MAJOR ? { major, standing: 'current' } : { major, standing: 'refused' };
67
64
  }
68
65
 
69
66
  export const PACK_ARCHETYPES = ['crud', 'generative', 'signed-protocol', 'engine-control', 'proxy'] as const;
@@ -176,8 +173,7 @@ export async function pullOnSchedule<T>(vendor: PullVendor, pull: () => Promise<
176
173
  * hostname — regional families like `^s3[.-][a-z0-9-]+\.amazonaws\.com$`). `pathPattern` (a
177
174
  * RegExp source over the pathname) splits a host shared between packs. `key` names the routing
178
175
  * identity the rule belongs to — the `<KEY>_TWIN_URL` env stem — when it is not the pack's own
179
- * vendor id (aws's consolidated twin answers under s3 / dynamodb / … ; gemini serves the
180
- * `googleauth` token exchange); a key belongs to ONE pack. `exclude: true` carves a host out of
176
+ * vendor id (aws's one twin answers under s3 and secretsmanager); a key belongs to ONE pack. `exclude: true` carves a host out of
181
177
  * the key's includes (`.upstash.io` minus `*-vector.upstash.io`): a key matches when any include
182
178
  * matches and no exclude does. Validated by scripts/pack-facts.ts: keys are `[a-z0-9-]+`, a
183
179
  * foreign key is never another pack's vendor id, belongs to one pack, and must appear in the
@@ -192,196 +188,71 @@ export type HostRule = ({ host: string } | { suffix: string } | { hostPattern: s
192
188
 
193
189
  export type RoundTripWrite = { method: string; path: string; body?: unknown; headers?: Record<string, string> };
194
190
 
191
+ /** A pack's descriptor: docs/contributing/architecture.md, "The descriptor". */
195
192
  export type TwinPack = {
196
- /** vendor id / service, e.g. 'stripe'. */
193
+ // Each field is defined once, in docs/contributing/architecture.md, "The descriptor"; a field is added there first.
197
194
  vendor: string;
198
195
  transport: PackTransport;
199
- /** Optional native frontend of the same state owner, selected explicitly on the pack CLI. */
200
- nativeTransport?: { protocol: string; flag: string; upstreamEnv: string };
201
- /** The serve-family (see PackArchetype). Every pack declares one. */
202
196
  archetype?: PackArchetype;
203
- /** The platform protocol MAJOR this package targets (R16), e.g. '1'. Undeclared reads as the
204
- * previous major (deprecated), or as the current major (recorded as assumed) while it is the first;
205
- * the scaffolder declares it. */
206
197
  protocol?: string;
207
- /** Pack-shipped assets (R20): files or directories under the pack dir the serve path reads through
208
- * the pack-asset seam (`getActivePackAssets`), never off the host. Declared so the deploy step
209
- * can place them behind the workerd assets binding. Paths relative to the pack dir. */
210
198
  assets?: string[];
211
- /** R2, resource level: declared subject types the twin genuinely serves but no replay can create —
212
- * born only of the vendor's own catalog, scheduler, account or a pull. Each names WHY. The cell
213
- * stays debt (adopted, never faked), but legibly: the runner separates these from open gaps. */
214
199
  resourcesUnreachable?: Record<string, string>;
215
- /** subject types the twin serves, e.g. ['customer','charge','payment_intent']. */
216
200
  resources: string[];
217
- /** the `world-<vendor>` operator bin, if any. */
218
201
  bin?: string;
219
- /** conformance field map { object: { field: type } } — vendored or derived from the spec. */
220
202
  conformanceFields?: Record<string, Record<string, string>>;
221
- /** where the exact surface came from (a spec path) — provenance for re-derivation. */
222
203
  specSource?: string;
223
- /** one-line human description. */
224
204
  description?: string;
225
- /** How this vendor's BROWSER SDK addresses its API — used by the zero-edit dev proxy so
226
- * the kernel proxy stays vendor-agnostic (it forwards/rewrites by these values, never by a
227
- * hardcoded vendor table). `apiPathPrefix`: the same-origin path the browser SDK calls
228
- * (e.g. Stripe.js → '/v1/'). `loaderHost`: the absolute API host to strip from the loaded
229
- * SDK so its calls become same-origin (e.g. 'https://api.stripe.com'). Omit for vendors
230
- * with no browser SDK. */
231
205
  browserRouting?: { apiPathPrefix: string; loaderHost?: string };
232
- /** How often this vendor's REAL API may be pulled. Omitted ⇒ `'on-demand'` (see `PullPosture`).
233
- * Declare `'continuous'` only for a vendor whose published limits genuinely tolerate a
234
- * scheduled sync, and say why in `pullPostureReason`. */
235
206
  pullPosture?: PullPosture;
236
- /** Why this posture — the limits that justify it. Required in review for `'continuous'`, since
237
- * that is the claim that can cost a lockout if it's wrong. */
238
207
  pullPostureReason?: string;
239
- /**
240
- * The vendor's CLIENT-SIDE RATE BUDGET — the ceiling, window and per-endpoint weights the pack's
241
- * guarded connector enforces before a live call goes out. Vendor knowledge as DATA, exactly like
242
- * `browserRouting`: the mechanism is the kernel's (`rateBudget.ts`), the numbers are the pack's.
243
- *
244
- * `registerPack` forwards this to `declareRateBudget`, so registering a pack arms its budget.
245
- * A pack that omits it is NOT unlimited — any budget built for that vendor falls back to
246
- * `DEFAULT_RATE_BUDGET` (see its docstring). `pullPosture` says "do not SCHEDULE this vendor";
247
- * this says "and here is the ceiling on an EXPLICIT pull". They are complementary, not
248
- * substitutes — the posture guards cadence seams, the budget guards the call itself.
249
- */
250
208
  rateBudget?: RateBudgetDeclaration;
251
- /**
252
- * The pack's DELIVER support (`emit` — see emit.ts): how to synthesize this vendor's
253
- * signed event/webhook deliveries from current twin state. Vendor knowledge on the
254
- * descriptor, like `browserRouting`; the kernel engine (`emitTwinEvent`) is generic.
255
- * The operator surface is the pack's own bin (`world-<vendor> emit`); a consumer that
256
- * registered the pack can also drive it via `volter-twin emit <vendor>`.
257
- */
258
209
  emitter?: TwinEmitter;
259
- /**
260
- * SERVE FACTORY OVERRIDE — normally DERIVED, declared only under ambiguity. The colocated
261
- * host (world-runtime/src/host.ts) mounts a pack by its `create<Name>TwinServer` factory
262
- * export (`({port,root,readOnly}) => {port,stop}`); `scripts/pack-facts.ts` reads that
263
- * export's name off the module, so a pack with exactly ONE such export declares nothing.
264
- * A pack exporting SEVERAL factories declares here which one `cli.ts serve` would have
265
- * booted — the judgment the exports alone cannot reveal (linear serves its DERIVED server
266
- * by default; the hand-written one is behind a flag). Must name a function export of the
267
- * pack's index module matching /^create\w*TwinServer$/.
268
- */
269
210
  serveExport?: string;
270
- /**
271
- * ADOPTION — how application repos betray that they talk to this vendor, so
272
- * `volter-world covers`/`init` can attribute the signal to this pack. Vendor knowledge as
273
- * DATA, same doctrine as `browserRouting`/`rateBudget`: the detector mechanism lives in
274
- * world-runtime; the names live here. Absorbs the central `SDK_TWINS` / `SDK_SCOPE_VENDORS` /
275
- * `ENV_STEM_VENDORS` / `VENDOR_WORLD_IDS` maps (the one wiring point NO gate enforced —
276
- * the class that let `@planetscale/database` escape, twin#255).
277
- */
278
211
  adoption?: {
279
- /** every official npm client of the API surface this pack models, e.g. ['stripe']. */
280
212
  sdks?: string[];
281
- /** PyPI distribution names (PEP 503 normalized: lowercase, `-`) the vendor's Python SDKs
282
- * ship under — the Python half of adoption discovery and coverage (`covers`). */
283
213
  pypi?: string[];
284
- /** npm scope prefixes whose members all belong to this vendor, e.g. ['@upstash/']. */
285
214
  scopes?: string[];
286
- /** credential-env-var stems, e.g. ['STRIPE'] for STRIPE_SECRET_KEY et al. */
287
215
  envStems?: string[];
288
- /** additional world service ids this vendor answers to (the VENDOR_WORLD_IDS case). */
216
+ configFiles?: Array<{ file: string; usage: 'application' | 'build' | 'deployment'; when?: string }>;
289
217
  worldIds?: string[];
290
- /** Vendor-facing tool packages whose calls belong to supporting workflow rather than the
291
- * application itself. The use is saved and selected by World discovery policy. */
292
218
  tools?: Array<{ package: string; usage: 'build' | 'deployment' }>;
293
219
  };
294
- /**
295
- * INTERCEPTION — the vendor hosts whose traffic the injector must route to this twin,
296
- * as serializable data (the committed `inject.cjs` table is GENERATED from these — it must
297
- * stay dependency-free preloaded CJS, so it consumes compiled output, never imports packs).
298
- * Exactly one of `hosts` or `hostsNone` per pack once migration completes: silence is not a
299
- * ruling. `pathPattern` (a RegExp source string, applied to the URL pathname) splits shared
300
- * hosts (the youtube/googleauth case). Absorbed `VENDOR_HOSTS`'s per-pack keys + the retired NO_INJECTOR_ENTRY
301
- * allowlist (hostsNone IS the ruling now).
302
- */
303
220
  hosts?: HostRule[];
304
- /** Why this pack deliberately has NO injector entry (explicit-endpoint wiring only). */
305
221
  hostsNone?: string;
306
- /**
307
- * HOSTS A TWIN CLAIMS WHILE IT RUNS — names a person makes answer to this vendor (a custom domain connected to a
308
- * bucket), which no descriptor can list. The twin lists the ones it answers now at its own `door` (GET, answering
309
- * `{ "hosts": [...] }`), and the World routes them to it as DNS would the vendor's; a host a descriptor's `hosts`
310
- * names is never taken from another pack this way.
311
- */
312
222
  hostsClaimed?: { door: string; note: string };
313
- /**
314
- * WORLD WIRING — the env var the vendor's own SDK documents for overriding its base URL,
315
- * which `volter-world init` injects pointing at the twin. `endpointEnvNone` declares the
316
- * deliberate absence WITH its reason (inventing a var the app never reads would make
317
- * `covers` report coverage while traffic still reaches the real vendor — the exact lie the
318
- * proof exists to catch). Absorbs init.ts's `APP_READ_ENDPOINT_ENV` map, where these
319
- * reasons lived as comments. Exactly one of the two once migration completes.
320
- */
321
223
  endpointEnv?: { name: string; templates?: Record<string, string>; note: string };
322
- /** Why this pack deliberately injects no endpoint env (see `endpointEnv`). */
323
224
  endpointEnvNone?: string;
324
- /**
325
- * PRISMA — the driver adapter a Prisma client reaches this database twin through, as DATA.
326
- * Prisma's client-engine build (the one a tab runs, and the one its edge client uses) refuses
327
- * to construct without a driver adapter; an application that constructs `new PrismaClient()`
328
- * against the vendor's URL gets this adapter from ITS OWN dependencies, constructed on the
329
- * URL in `urlEnv` (the endpoint template's variable), by the injector. The adapter package is
330
- * never installed by the World: absent from the application, the client is left as it was.
331
- */
225
+ /** The door that issues the application the credentials the twin will accept (a key made on the vendor's dashboard,
226
+ * and whatever names it: a database's URL, a project's id), and the env names it fills, each from a field of the
227
+ * answer: `init` writes `$issue:<service>` for each, and `up`, once this twin is running, POSTs the body to the door
228
+ * and sets each name to its field. A twin that holds its keys (refusing any it
229
+ * did not issue) declares one, so a World's applications hold keys it issued rather than fixtures it refuses. */
230
+ credentialDoor?: { path: string; body: Record<string, unknown>; fill: Record<string, string> };
231
+ /** Another pack of this vendor issues the API's credentials; architecture, descriptor World wiring. */
232
+ credentialIssuer?: string;
332
233
  prismaAdapter?: { adapter: string; export: string; urlEnv: string };
333
- /**
334
- * THE WORLD'S MANAGED DATABASE — the declared exception to kernel-held state (docs/contributing/architecture.md,
335
- * managed infrastructure: "A vendor whose data plane is a server in front of Postgres"): the pack's data plane is
336
- * served over the World's own managed Postgres, which the runtime binds as DATA, never through the environment. At
337
- * boot the runtime hands the connection URL of the World's managed `kind` service to the twin: `serve <arg> <url>` on
338
- * the spawn path, the factory's `database` option in the colocated host. A World whose database is not its own
339
- * managed infrastructure (none declared, or a URL outside it) binds nothing, and the twin refuses its data plane.
340
- */
234
+ managedService?: { kind: 'redis' | 'mongodb'; scheme: string; note: string };
341
235
  managedDatabase?: { kind: 'postgres'; arg: string; note: string };
342
- /** PROTOCOL 2 — the pack's half of the REAL state system (state-system.ts): perform one entry
343
- * against the vendor, refresh the parent log from it, ingest one signed webhook. All over the
344
- * kernel executor; the pack never holds a credential. Registered with the pack. */
236
+ sidePorts?: Array<{ name: string; option: string; flag: string; path?: string; note: string }>;
345
237
  stateSystem?: StateSystemAdapters;
346
- /** PROTOCOL 2 — how a root is kept current, the pack's way: `every` schedules a pull in a served
347
- * world (the root's `refresh.every` overrides), `webhook` says the vendor pushes to the ingest
348
- * door, `onDemand.atMost` is the least time between `volter twin <v> refresh` runs (a throttle for
349
- * a rate-limited vendor). Absorbs `pullPosture`. */
238
+ /** The pack has no vendor-backed half, and why (copied from the manifest by packOf). */
239
+ vendorBacked?: { none: string };
350
240
  refresh?: { every?: string; webhook?: boolean; onDemand?: { atMost: string } };
351
- /** PROTOCOL 2 — a minimal write on the vendor's wire the kernel can send blind (or a short
352
- * sequence whose LAST write creates something new every time): the branch round-trip
353
- * (docs/contributing/architecture.md#evidence) sends it, checkpoints, branches, sends it again on the branch, and
354
- * proves the tree contract with no pack code. */
355
241
  roundTrip?: RoundTripWrite | RoundTripWrite[];
356
- /** PROTOCOL 2 — which fields of which subject types hold another subject's id (docs/contributing/architecture.md
357
- * #alias-aware-lookup-at-the-request-boundary): the kernel resolves them through an adopted vendor id, in the tree and at the perform. */
358
242
  references?: ReferenceDeclaration[];
359
- /** PROTOCOL 2 — with `references`: a write on the wire that references the `roundTrip` write's subject;
360
- * `{{field}}` in its path or body is the referenced subject's field. The round-trip gate sends it
361
- * after simulating the parent's adoption and checks the reference followed. */
362
243
  referenceTrip?: RoundTripWrite;
363
- /** PROTOCOL 2 — shape parity (roadmap 4c): the origin the parity gate hands the refresh adapter when it
364
- * refreshes the twin from itself (`http://twin` + whatever path the adapter reads its scope from), and
365
- * `'held'` once the write handler and the refresh adapter store the same shape (the gate then asserts). */
366
244
  parityOrigin?: string;
367
245
  shapeParity?: 'held';
368
- /** PROTOCOL 2 — a refresh that cannot be exercised for effect when the parity gate refreshes the twin
369
- * from itself, and the refusal it answers with instead: `refusal` is text its thrown error carries,
370
- * `reason` why (an identity pull the twin's own wire refuses without a consent-minted token; a pulled
371
- * id inside the twin's reserved local namespace). The gate runs the refresh and passes it only on
372
- * that refusal; any other error fails. */
373
246
  refreshRefusal?: { refusal: string; reason: string };
374
- /** PROTOCOL 2 — HOW THIS VENDOR AUTHENTICATES, so the kernel executor can apply the sealed
375
- * credential the way the vendor actually reads it (docs/concepts/the-model.md#the-rules, rule 5). Absent means header
376
- * replacement, which is what `credential.headers` has always done — declare this ONLY for a
377
- * vendor that reads its key from the query string or wants a signature computed per request. */
378
247
  auth?: TwinAuthStrategy;
379
- /** PROTOCOL 2 — the ENGINE beside the tree, when the pack's state has a second half that is not a
380
- * projection (a git plane, S3 bytes, a SQL engine): the module that owns every write outside the
381
- * world store. The tree references engine objects by hash; the gate keeps such writes there. */
382
248
  engine?: { module: string; note?: string };
383
249
  };
384
250
 
251
+ /** The descriptor a pack declares as data in its manifest (docs/contributing/architecture.md, "The descriptor"): the
252
+ * pack's fields without the ones that are code or that the derived core supplies (the state system and refresh, round
253
+ * trips and references, parity, a rate budget, the emitter, conformance fields, the engine key, pull posture). */
254
+ export type PackDescriptor = Omit<TwinPack, 'stateSystem' | 'refresh' | 'refreshRefusal' | 'roundTrip' | 'references' | 'referenceTrip' | 'parityOrigin' | 'shapeParity' | 'rateBudget' | 'emitter' | 'conformanceFields' | 'engine' | 'pullPosture' | 'pullPostureReason'>;
255
+
385
256
  const registry = new Map<string, TwinPack>();
386
257
 
387
258
  /** Register (or replace) a pack descriptor. Returns it.
@@ -390,8 +261,49 @@ const registry = new Map<string, TwinPack>();
390
261
  * registering a pack is enough to give its vendor the ceiling it declared. `declareRateBudget`
391
262
  * is idempotent for an identical declaration and REFUSES a widening one, so re-registering is
392
263
  * safe and "register a fatter pack descriptor to buy a bigger budget" is not a move. */
264
+ /** A derived pack's descriptor, from its manifest (`manifest.descriptor`, named by the manifest's `vendor`). Given the
265
+ * pack's generated surface (a vendor of lanes: each lane's manifest and surface), the kernel derives what a pack never
266
+ * writes by hand (the real-system adapters, "Where it lives"): its state system (perform, refresh, ingest), the
267
+ * references its subjects hold (from the manifest's `embeds` and each `parent.field` naming its parent by id) and its
268
+ * rate budget (the manifest's). A descriptor that declares any of them by hand is refused. */
269
+ export function packOf(
270
+ manifest: { vendor: string; descriptor?: Omit<TwinPack, 'vendor'> } & Partial<Pick<DerivedManifest, 'rateBudget' | 'vendorBacked'>>,
271
+ surface?: DerivedSurface | Record<string, { manifest: DerivedManifest; surface: DerivedSurface }>,
272
+ /** the lanes beside a pack that has an API of its own */
273
+ beside: Record<string, { manifest: DerivedManifest; surface: DerivedSurface }> = {},
274
+ ): TwinPack {
275
+ if (!manifest.descriptor) throw new Error(`${manifest.vendor}: the manifest declares no descriptor (architecture, "The descriptor")`);
276
+ const hand = (['stateSystem', 'references', 'rateBudget'] as const).filter((k) => (manifest.descriptor as Record<string, unknown>)[k] !== undefined);
277
+ if (hand.length) throw new Error(`${manifest.vendor}: the descriptor declares ${hand.join(', ')} by hand; the kernel derives them from the manifest (architecture, "The real-system adapters")`);
278
+ const pack: TwinPack = { vendor: manifest.vendor, ...manifest.descriptor, ...(manifest.rateBudget ? { rateBudget: manifest.rateBudget } : {}) };
279
+ // a pack with no vendor-backed half says why, and derives no adapters
280
+ if (manifest.vendorBacked?.none) return { ...pack, vendorBacked: { none: manifest.vendorBacked.none } };
281
+ if (!surface) return pack;
282
+ const lanes = 'operations' in surface ? undefined : (surface as Record<string, { manifest: DerivedManifest; surface: DerivedSurface }>);
283
+ const units = lanes ? Object.values(lanes).map((l) => l.manifest) : [manifest as unknown as DerivedManifest, ...Object.values(beside).map((l) => l.manifest)];
284
+ const references = units.flatMap(derivedReferences);
285
+ return {
286
+ ...pack,
287
+ stateSystem: lanes ? deriveVendorStateSystem(manifest as unknown as VendorManifest, lanes) : deriveStateSystem(manifest as unknown as DerivedManifest, surface as DerivedSurface, beside),
288
+ ...(references.length ? { references } : {}),
289
+ };
290
+ }
291
+
292
+ /** The references a derived manifest's subjects hold: each `embeds` field naming another resource, and each child's
293
+ * `parent.field` when it holds the parent's id (a `value` template joins several parameters, so it holds no one id). */
294
+ function derivedReferences(m: DerivedManifest): ReferenceDeclaration[] {
295
+ const stored = (r: string): string => m.resources[r]?.storedAs ?? r;
296
+ const out: ReferenceDeclaration[] = [];
297
+ for (const [resource, decl] of Object.entries(m.resources)) {
298
+ for (const [field, to] of Object.entries(decl.embeds ?? {})) if (m.resources[to]) out.push(referenceField(stored(resource), field, stored(to)));
299
+ if (decl.parent && !decl.parent.value && !decl.parent.where && m.resources[decl.parent.resource]) out.push(referenceField(stored(resource), decl.parent.field, stored(decl.parent.resource)));
300
+ }
301
+ return out;
302
+ }
303
+
393
304
  export function registerPack(pack: TwinPack): TwinPack {
394
305
  if (!/^[a-z0-9-]+$/.test(pack.vendor)) throw new Error(`invalid pack vendor id: ${pack.vendor}`);
306
+ if (protocolStanding(pack.protocol).standing !== 'current') throw new Error(`${pack.vendor}: protocol ${pack.protocol ?? '(missing)'} refused; this kernel serves ${PROTOCOL_VERSION}`);
395
307
  if (pack.rateBudget) declareRateBudget(pack.vendor, pack.rateBudget);
396
308
  if (pack.stateSystem) registerStateSystem(pack.vendor, pack.stateSystem);
397
309
  if (pack.auth) registerAuthStrategy(pack.vendor, pack.auth);
package/src/people.ts ADDED
@@ -0,0 +1,31 @@
1
+ // The people a vendor's pages sign in (docs/contributing/architecture.md, "Who is on a screen"): a person is a `_person`
2
+ // row, `person:<email>`, keeping their password's hash, never the password, written by a sign-up door or page and read
3
+ // by a sign-in, the same way in every pack. World-ui's session kit signs them in.
4
+ import type { HandlerContext } from './derived-core.ts';
5
+ import { digest } from './signing.ts';
6
+
7
+ /** A person a vendor's pages know: their email, and whatever the vendor's sign-up keeps beside it. */
8
+ export type Person = Record<string, unknown> & { email: string };
9
+
10
+ const PERSON = '_person';
11
+
12
+ /** A password as a World keeps it: its hash, salted by whose it is. */
13
+ export const passwordHash = (email: string, password: string): string => digest('sha256', `password:${email.toLowerCase()}:${password}`);
14
+
15
+ /** A person, their password's hash and the fields the vendor's sign-up keeps, recorded. */
16
+ export async function recordPerson(ctx: HandlerContext, email: string, password: string, fields: Record<string, unknown> = {}): Promise<Person> {
17
+ const lower = email.toLowerCase();
18
+ const person = { ...fields, email: lower, password_sha256: passwordHash(lower, password) };
19
+ await ctx.record(PERSON, person, `person:${lower}`);
20
+ return person;
21
+ }
22
+
23
+ /** The person with this email, or undefined. */
24
+ export const personOf = (ctx: HandlerContext, email: string): Person | undefined =>
25
+ ctx.rowsRaw(PERSON).find((p) => p.email === email.trim().toLowerCase()) as Person | undefined;
26
+
27
+ /** The person whose email and password these are, or undefined. */
28
+ export function personWith(ctx: HandlerContext, email: string, password: string): Person | undefined {
29
+ const person = personOf(ctx, email);
30
+ return person && person.password_sha256 === passwordHash(person.email, password) ? person : undefined;
31
+ }
@@ -0,0 +1,88 @@
1
+ // A placeholder image (architecture, "A placeholder image is a kernel library too"): a real PNG of the size asked for, in
2
+ // one flat colour drawn from a seed, labeled in a tEXt chunk as the twin's, for generative packs that run no model.
3
+ // Importing it does nothing.
4
+ //
5
+ // The image data is a zlib stream (RFC 1950) of one fixed-Huffman deflate block (RFC 1951 §3.2.6): each row is the Sub
6
+ // filter (PNG §9.2, type 1), its first pixel as literals and the rest zeros, the zeros as a literal and then copies of
7
+ // distance 1. A flat image of any size is a few kilobytes.
8
+ import { sha256 } from './signing.ts';
9
+
10
+ const SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
11
+ const CRC = Array.from({ length: 256 }, (_, n) => { let c = n; for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; return c >>> 0; });
12
+ const crc32 = (b: Uint8Array): number => { let c = 0xffffffff; for (const x of b) c = CRC[(c ^ x) & 0xff]! ^ (c >>> 8); return (c ^ 0xffffffff) >>> 0; };
13
+
14
+ function chunk(type: string, data: Uint8Array): Uint8Array {
15
+ const out = new Uint8Array(12 + data.length);
16
+ const v = new DataView(out.buffer);
17
+ v.setUint32(0, data.length);
18
+ out.set([...type].map((c) => c.charCodeAt(0)), 4);
19
+ out.set(data, 8);
20
+ v.setUint32(8 + data.length, crc32(out.subarray(4, 8 + data.length)));
21
+ return out;
22
+ }
23
+
24
+ /** Deflate's bits, least significant first; a Huffman code is written most significant bit first. */
25
+ class Bits {
26
+ private out: number[] = [];
27
+ private acc = 0;
28
+ private n = 0;
29
+ put(value: number, count: number): void { for (let i = 0; i < count; i++) { this.acc |= ((value >> i) & 1) << this.n; if (++this.n === 8) { this.out.push(this.acc); this.acc = 0; this.n = 0; } } }
30
+ code(code: number, length: number): void { for (let i = length - 1; i >= 0; i--) this.put((code >> i) & 1, 1); }
31
+ bytes(): number[] { return this.n ? [...this.out, this.acc] : this.out; }
32
+ }
33
+ /** A literal byte in the fixed code: 0–143 are 8 bits from 0x30, 144–255 are 9 bits from 0x190. */
34
+ const literal = (w: Bits, b: number): void => (b < 144 ? w.code(0x30 + b, 8) : w.code(0x190 + b - 144, 9));
35
+ /** A copy of `length` (3–258) bytes at distance 1: length codes 257–285 (7 bits from 0 for 256–279, 8 bits from 0xc0 for
36
+ * 280–287) with their extra bits, then distance code 0 (5 bits, distance 1). */
37
+ const LENGTH_BASE = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258];
38
+ const LENGTH_EXTRA = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
39
+ function copy(w: Bits, length: number): void {
40
+ let i = LENGTH_BASE.length - 1;
41
+ while (LENGTH_BASE[i]! > length) i--;
42
+ const symbol = 257 + i;
43
+ if (symbol < 280) w.code(symbol - 256, 7); else w.code(0xc0 + symbol - 280, 8);
44
+ w.put(length - LENGTH_BASE[i]!, LENGTH_EXTRA[i]!);
45
+ w.code(0, 5);
46
+ }
47
+
48
+ function flatIdat(width: number, height: number, rgb: [number, number, number]): Uint8Array {
49
+ const w = new Bits();
50
+ w.put(1, 1); w.put(1, 2); // the last block, fixed Huffman
51
+ const zeros = (width - 1) * 3;
52
+ for (let y = 0; y < height; y++) {
53
+ literal(w, 1); for (const c of rgb) literal(w, c);
54
+ if (zeros > 0) {
55
+ literal(w, 0);
56
+ let left = zeros - 1;
57
+ while (left > 0) {
58
+ const n = left > 258 ? (left - 258 < 3 ? left - 3 : 258) : left;
59
+ if (n < 3) { for (let k = 0; k < n; k++) literal(w, 0); left -= n; continue; }
60
+ copy(w, n); left -= n;
61
+ }
62
+ }
63
+ }
64
+ w.code(0, 7); // end of block (256)
65
+ // Adler-32 of the raw rows: a zero byte leaves a as it is and adds a to b
66
+ let a = 1; let b = 0;
67
+ for (let y = 0; y < height; y++) {
68
+ for (const byte of [1, ...rgb]) { a = (a + byte) % 65521; b = (b + a) % 65521; }
69
+ b = (b + a * zeros) % 65521;
70
+ }
71
+ return Uint8Array.from([0x78, 0x01, ...w.bytes(), (b >> 8) & 0xff, b & 0xff, (a >> 8) & 0xff, a & 0xff]);
72
+ }
73
+
74
+ /** A real PNG of `size`, one flat colour drawn from `seed`, its tEXt Comment `[twin-stub] <label>`. */
75
+ export function placeholderPng(size: { width: number; height: number }, seed: string, label = `placeholder image, no model is run: ${seed}`): Uint8Array {
76
+ const [r, g, bl] = Buffer.from(sha256(seed), 'hex');
77
+ const ihdr = new Uint8Array(13);
78
+ const v = new DataView(ihdr.buffer);
79
+ v.setUint32(0, size.width); v.setUint32(4, size.height);
80
+ ihdr.set([8, 2, 0, 0, 0], 8); // 8-bit RGB, no interlace
81
+ // tEXt is Latin-1 without NUL: a label's other characters (a prompt's) are written as `?`
82
+ const text = Uint8Array.from(`Comment\0[twin-stub] ${label.replace(/[^\x20-\x7e\xa0-\xff]/g, '?')}`, (c) => c.charCodeAt(0));
83
+ const parts = [Uint8Array.from(SIGNATURE), chunk('IHDR', ihdr), chunk('tEXt', text), chunk('IDAT', flatIdat(size.width, size.height, [r!, g!, bl!])), chunk('IEND', new Uint8Array(0))];
84
+ const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
85
+ let at = 0;
86
+ for (const p of parts) { out.set(p, at); at += p.length; }
87
+ return out;
88
+ }