@volter/world-runtime 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 (164) hide show
  1. package/LICENSE +202 -0
  2. package/dist/known-external-services.json +1108 -0
  3. package/dist/src/ancestry.d.ts +2 -0
  4. package/dist/src/ancestry.js +42 -0
  5. package/dist/src/app-url.d.ts +47 -0
  6. package/dist/src/app-url.js +239 -0
  7. package/dist/src/attach.d.ts +48 -0
  8. package/dist/src/attach.js +87 -0
  9. package/dist/src/branch.d.ts +20 -0
  10. package/dist/src/branch.js +65 -0
  11. package/dist/src/browser-proxy-cli.d.ts +2 -0
  12. package/dist/src/browser-proxy-cli.js +41 -0
  13. package/dist/src/ca-trust.d.ts +5 -0
  14. package/dist/src/ca-trust.js +64 -0
  15. package/dist/src/catalog.d.ts +31 -0
  16. package/dist/src/catalog.js +148 -0
  17. package/dist/src/changeset.d.ts +142 -0
  18. package/dist/src/changeset.js +570 -0
  19. package/dist/src/cli.d.ts +2 -0
  20. package/dist/src/cli.js +1262 -0
  21. package/dist/src/command-lifetime.d.ts +15 -0
  22. package/dist/src/command-lifetime.js +98 -0
  23. package/dist/src/configs.d.ts +18 -0
  24. package/dist/src/configs.js +119 -0
  25. package/dist/src/console-apart.d.ts +38 -0
  26. package/dist/src/console-apart.js +107 -0
  27. package/dist/src/consumers.d.ts +46 -0
  28. package/dist/src/consumers.js +200 -0
  29. package/dist/src/covers.d.ts +183 -0
  30. package/dist/src/covers.js +800 -0
  31. package/dist/src/fixture-env.d.ts +42 -0
  32. package/dist/src/fixture-env.js +221 -0
  33. package/dist/src/host-cli.d.ts +2 -0
  34. package/dist/src/host-cli.js +92 -0
  35. package/dist/src/host-fault-fixture.d.ts +32 -0
  36. package/dist/src/host-fault-fixture.js +100 -0
  37. package/dist/src/host-worker.d.ts +1 -0
  38. package/dist/src/host-worker.js +23 -0
  39. package/dist/src/host.d.ts +38 -0
  40. package/dist/src/host.js +135 -0
  41. package/dist/src/index.d.ts +48 -0
  42. package/dist/src/index.js +35 -0
  43. package/dist/src/infra-cli.d.ts +2 -0
  44. package/dist/src/infra-cli.js +136 -0
  45. package/dist/src/init.d.ts +227 -0
  46. package/dist/src/init.js +1117 -0
  47. package/dist/src/inject-map.d.ts +34 -0
  48. package/dist/src/inject-map.js +56 -0
  49. package/dist/src/lifecycle-record.d.ts +47 -0
  50. package/dist/src/lifecycle-record.js +196 -0
  51. package/dist/src/origin.d.ts +31 -0
  52. package/dist/src/origin.js +139 -0
  53. package/dist/src/pack-facts.d.ts +75 -0
  54. package/dist/src/pack-facts.js +98 -0
  55. package/dist/src/pglite-backing.d.ts +21 -0
  56. package/dist/src/pglite-backing.js +158 -0
  57. package/dist/src/pglite-host.mjs +147 -0
  58. package/dist/src/placeholder.d.ts +20 -0
  59. package/dist/src/placeholder.js +100 -0
  60. package/dist/src/prerequisites.d.ts +21 -0
  61. package/dist/src/prerequisites.js +49 -0
  62. package/dist/src/process-groups.d.ts +4 -0
  63. package/dist/src/process-groups.js +49 -0
  64. package/dist/src/project-inspect.d.ts +109 -0
  65. package/dist/src/project-inspect.js +827 -0
  66. package/dist/src/proxy-daemon.d.ts +2 -0
  67. package/dist/src/proxy-daemon.js +18 -0
  68. package/dist/src/redirect-proxy.d.ts +105 -0
  69. package/dist/src/redirect-proxy.js +665 -0
  70. package/dist/src/reflect.d.ts +74 -0
  71. package/dist/src/reflect.js +392 -0
  72. package/dist/src/resources.d.ts +26 -0
  73. package/dist/src/resources.js +22 -0
  74. package/dist/src/root.d.ts +114 -0
  75. package/dist/src/root.js +312 -0
  76. package/dist/src/run-task-worker.d.ts +1 -0
  77. package/dist/src/run-task-worker.js +38 -0
  78. package/dist/src/run-task.d.ts +18 -0
  79. package/dist/src/run-task.js +48 -0
  80. package/dist/src/runtime-test-support.d.ts +59 -0
  81. package/dist/src/runtime-test-support.js +205 -0
  82. package/dist/src/runtime.d.ts +256 -0
  83. package/dist/src/runtime.js +3502 -0
  84. package/dist/src/schema.d.ts +449 -0
  85. package/dist/src/schema.js +605 -0
  86. package/dist/src/serve.d.ts +30 -0
  87. package/dist/src/serve.js +82 -0
  88. package/dist/src/served-world.d.ts +194 -0
  89. package/dist/src/served-world.js +986 -0
  90. package/dist/src/service-exit.d.ts +46 -0
  91. package/dist/src/service-exit.js +195 -0
  92. package/dist/src/service-recorder.d.ts +1 -0
  93. package/dist/src/service-recorder.js +121 -0
  94. package/dist/src/sibling.d.ts +1 -0
  95. package/dist/src/sibling.js +9 -0
  96. package/dist/src/signals.d.ts +1 -0
  97. package/dist/src/signals.js +11 -0
  98. package/dist/src/storage-capacity.d.ts +8 -0
  99. package/dist/src/storage-capacity.js +61 -0
  100. package/dist/src/tail.d.ts +30 -0
  101. package/dist/src/tail.js +160 -0
  102. package/dist/src/tcp-port.d.ts +2 -0
  103. package/dist/src/tcp-port.js +36 -0
  104. package/dist/src/up-task-worker.d.ts +1 -0
  105. package/dist/src/up-task-worker.js +61 -0
  106. package/dist/src/up-task.d.ts +17 -0
  107. package/dist/src/up-task.js +49 -0
  108. package/dist/src/websocket-relay.d.ts +3 -0
  109. package/dist/src/websocket-relay.js +40 -0
  110. package/known-external-services.json +1108 -0
  111. package/package.json +83 -0
  112. package/src/ancestry.ts +36 -0
  113. package/src/app-url.ts +253 -0
  114. package/src/attach.ts +117 -0
  115. package/src/branch.ts +63 -0
  116. package/src/browser-proxy-cli.ts +44 -0
  117. package/src/ca-trust.ts +57 -0
  118. package/src/catalog.ts +156 -0
  119. package/src/changeset.ts +627 -0
  120. package/src/cli.ts +1111 -0
  121. package/src/command-lifetime.ts +79 -0
  122. package/src/configs.ts +110 -0
  123. package/src/console-apart.ts +90 -0
  124. package/src/consumers.ts +185 -0
  125. package/src/covers.ts +934 -0
  126. package/src/fixture-env.ts +230 -0
  127. package/src/host-cli.ts +90 -0
  128. package/src/host-worker.ts +23 -0
  129. package/src/host.ts +169 -0
  130. package/src/index.ts +171 -0
  131. package/src/infra-cli.ts +133 -0
  132. package/src/init.ts +1316 -0
  133. package/src/inject-map.ts +72 -0
  134. package/src/lifecycle-record.ts +168 -0
  135. package/src/origin.ts +134 -0
  136. package/src/pack-facts.ts +128 -0
  137. package/src/pglite-backing.ts +141 -0
  138. package/src/pglite-host.mjs +147 -0
  139. package/src/placeholder.ts +89 -0
  140. package/src/prerequisites.ts +66 -0
  141. package/src/process-groups.ts +33 -0
  142. package/src/project-inspect.ts +770 -0
  143. package/src/proxy-daemon.ts +21 -0
  144. package/src/redirect-proxy.ts +684 -0
  145. package/src/reflect.ts +440 -0
  146. package/src/resources.ts +22 -0
  147. package/src/root.ts +290 -0
  148. package/src/run-task-worker.ts +27 -0
  149. package/src/run-task.ts +44 -0
  150. package/src/runtime-test-support.ts +208 -0
  151. package/src/runtime.ts +3357 -0
  152. package/src/schema.ts +922 -0
  153. package/src/serve.ts +102 -0
  154. package/src/served-world.ts +812 -0
  155. package/src/service-exit.ts +175 -0
  156. package/src/service-recorder.ts +89 -0
  157. package/src/sibling.ts +10 -0
  158. package/src/signals.ts +10 -0
  159. package/src/storage-capacity.ts +60 -0
  160. package/src/tail.ts +205 -0
  161. package/src/tcp-port.ts +35 -0
  162. package/src/up-task-worker.ts +40 -0
  163. package/src/up-task.ts +45 -0
  164. package/src/websocket-relay.ts +32 -0
@@ -0,0 +1,82 @@
1
+ // Remote worlds (docs/guides/route-a-cli-through-the-world.md): a served world publishes its manifest over
2
+ // HTTP and opens ONE advertised TLS door (the reflect front terminating the
3
+ // advertised hostname alongside vendor hosts). The manifest an attacher
4
+ // fetches has every vendor rewritten to the advertised origin — the injector
5
+ // preserves the vendor Host header, the door routes by it, the twin answers.
6
+ // Read-only publication: the manifest endpoint tracks no attachers and takes
7
+ // no writes. An optional attach token protects manifest publication.
8
+ import { timingSafeEqual } from 'node:crypto';
9
+ import { createServer as createHttpServer } from 'node:http';
10
+ import { deriveWorldManifest } from "./attach.js";
11
+ import { statusWorld } from "./runtime.js";
12
+ export const MANIFEST_PATH = '/.well-known/volter-world';
13
+ /** The manifest a REMOTE attacher sees: every vendor behind the one advertised
14
+ * door. The serving side keeps routing against its own loopback env. */
15
+ export function advertiseWorldManifest(name, root, advertisedOrigin) {
16
+ const local = deriveWorldManifest(name, statusWorld(name, root).env);
17
+ const vendors = {};
18
+ // /__vendor/<id> keeps the fetch flow routable through the one door (the
19
+ // injector's fetch patch rewrites URLs wholesale and loses the vendor Host);
20
+ // the http/https flow still Host-routes and ignores the origin's path.
21
+ for (const vendor of Object.keys(local.vendors))
22
+ vendors[vendor] = `${advertisedOrigin}/__vendor/${vendor}`;
23
+ return { ...local, vendors };
24
+ }
25
+ export async function startManifestServer(options) {
26
+ const server = createHttpServer((request, response) => {
27
+ if (options.token !== undefined) {
28
+ const presented = (request.headers.authorization ?? '').replace(/^Bearer\s+/i, '');
29
+ const expected = Buffer.from(options.token);
30
+ const actual = Buffer.from(presented);
31
+ if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {
32
+ response.writeHead(401, { 'content-type': 'text/plain' });
33
+ response.end('attach token required\n');
34
+ return;
35
+ }
36
+ }
37
+ if (request.method !== 'GET' || (request.url !== MANIFEST_PATH && request.url !== '/')) {
38
+ response.writeHead(404, { 'content-type': 'text/plain' });
39
+ response.end('volter-world: GET ' + MANIFEST_PATH + '\n');
40
+ return;
41
+ }
42
+ response.writeHead(200, { 'content-type': 'application/json' });
43
+ response.end(`${JSON.stringify(options.manifest(), null, 2)}\n`);
44
+ });
45
+ await new Promise((resolveListen, reject) => {
46
+ server.once('error', reject);
47
+ server.listen(options.port ?? 0, options.host ?? '0.0.0.0', () => resolveListen());
48
+ });
49
+ const address = server.address();
50
+ return {
51
+ port: typeof address === 'object' && address ? address.port : (options.port ?? 0),
52
+ async close() {
53
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
54
+ },
55
+ };
56
+ }
57
+ /** Fetch a remote world's manifest. Accepts the manifest URL itself or the
58
+ * world's base URL (the well-known path is appended). */
59
+ export async function fetchRemoteManifest(ref, options = {}) {
60
+ const base = ref.replace(/\/$/, '');
61
+ const url = base.endsWith(MANIFEST_PATH) ? base : `${base}${MANIFEST_PATH}`;
62
+ const response = await fetch(url, options.token === undefined ? undefined : { headers: { authorization: `Bearer ${options.token}` } });
63
+ if (!response.ok)
64
+ throw new Error(`remote world manifest: ${url} → ${response.status}`);
65
+ const manifest = (await response.json());
66
+ if (typeof manifest.name !== 'string' || typeof manifest.vendors !== 'object' || manifest.vendors === null) {
67
+ throw new Error(`remote world manifest: ${url} returned no manifest`);
68
+ }
69
+ return manifest;
70
+ }
71
+ /** The env a remote env-attachment exports: vendor twin URLs (the advertised
72
+ * door), suggested fake credentials, CA trust, and the injector preload. */
73
+ export function remoteAttachEnv(manifest, options) {
74
+ const env = { ...manifest.env };
75
+ for (const [vendor, origin] of Object.entries(manifest.vendors)) {
76
+ env[`${vendor.toUpperCase()}_TWIN_URL`] = origin;
77
+ }
78
+ env.NODE_OPTIONS = `--require ${options.injectPath}`;
79
+ if (options.caFile !== undefined)
80
+ env.NODE_EXTRA_CA_CERTS = options.caFile;
81
+ return env;
82
+ }
@@ -0,0 +1,194 @@
1
+ import { type HistoryReference } from '@volter/world-core';
2
+ import { type TwinStreamConnection, type TwinStreamSink } from '@volter/world-core';
3
+ import { type Changeset, type Receipt } from '@volter/world-core';
4
+ import { rootForControlRoot } from './root.js';
5
+ import type { WorldInstance } from './schema.js';
6
+ export declare const TOKEN_HEADER = "x-volter-token";
7
+ /** The header the injector carries a hosted World's token in (inject.cjs, VOLTER_TWINS_KEY). */
8
+ export declare const TWINS_KEY_HEADER = "x-twins-key";
9
+ /** fetch that waits out a world still booting: a refused connection is retried for `forMs`. */
10
+ export declare function fetchReady(input: string, init: RequestInit, forMs?: number): Promise<Response>;
11
+ /** The serve record beside a world, when the process it names is alive; a stale record (its serving
12
+ * process gone) is removed and reads as none. */
13
+ export type ServeRecord = {
14
+ name: string;
15
+ url: string;
16
+ base: string;
17
+ port: number;
18
+ pid: number;
19
+ startedAt: string;
20
+ };
21
+ export declare function readServeRecord(worldRoot: string): ServeRecord | null;
22
+ export type ServedWorld = {
23
+ url: string;
24
+ base: string;
25
+ name: string;
26
+ port: number;
27
+ token: string;
28
+ readToken: string;
29
+ console: string | null;
30
+ stop: () => Promise<void>;
31
+ };
32
+ /** The served name: `bare.name` (`acme/team`), else `<id>/<id>`. */
33
+ export declare function servedName(worldRoot: string, configRef: string): string;
34
+ /** A world MOUNTED for serving: its doors, its tokens, and a boot that writes the serve record once the
35
+ * URL is known. `serveWorld` mounts one world on its own port; the host mounts many under one URL
36
+ * (contract "Just like Neon", 4: one URL per served world, solid and discoverable). */
37
+ /** A world mounted by a host. `token`/`readToken` read the CURRENT tokens (rotate changes them);
38
+ * `twins()` names the world's twins once booted; `rotate()` mints both tokens anew — the old die
39
+ * with the call — and keeps them beside the world like `boot` does. */
40
+ export type MountedWorld = {
41
+ name: string;
42
+ served: string;
43
+ root: string;
44
+ readonly token: string;
45
+ readonly readToken: string;
46
+ twins: () => string[];
47
+ rotate: () => {
48
+ token: string;
49
+ readToken: string;
50
+ };
51
+ handle: (request: Request) => Promise<Response>;
52
+ boot: (url: string) => Promise<void>;
53
+ stop: () => Promise<void>;
54
+ };
55
+ export declare function mountWorld(name: string, opts?: {
56
+ root?: string;
57
+ }): Promise<MountedWorld>;
58
+ /** Boot the world (state kept) and serve it on its own port. Announces and returns after boot; `stop` downs the world. */
59
+ export declare function serveWorld(name: string, opts?: {
60
+ root?: string;
61
+ port?: number;
62
+ host?: string;
63
+ consolePort?: number;
64
+ announce?: (info: {
65
+ name: string;
66
+ base: string;
67
+ token: string;
68
+ readToken: string;
69
+ console: string | null;
70
+ }) => void;
71
+ }): Promise<ServedWorld>;
72
+ /** What the doors need of a world: where each twin's state lives and which twins it has. A booted
73
+ * local instance is one; a hosted World describes itself. */
74
+ export type WorldLayout = {
75
+ dirs: {
76
+ data: string;
77
+ };
78
+ services: Record<string, {
79
+ url?: string;
80
+ protocol?: unknown;
81
+ }>;
82
+ };
83
+ /** The host a world's doors run in: its layout, and how a request reaches a twin's wire — a local
84
+ * host forwards to the twin's own port, a hosted World calls the pack in-process. */
85
+ export type DoorHost = {
86
+ ready: () => boolean;
87
+ layout: () => WorldLayout;
88
+ /** The layout re-read before a write lands (a local world may have been re-booted). */
89
+ reload: () => WorldLayout;
90
+ /** The twin's wire for a request whose path is the twin's own; null when the world has no such twin. */
91
+ twinFetch: (vendor: string) => ((request: Request) => Promise<Response>) | null;
92
+ /** The world's byte-stream doors (a TCP protocol a twin serves: smtp's own, planetscale's mysql),
93
+ * by the id a local World gives that listener's service, when this host carries bytes over a
94
+ * WebSocket (a hosted World takes no inbound TCP). */
95
+ streams?: () => Record<string, {
96
+ protocol: string;
97
+ }>;
98
+ openStream?: (id: string, sink: TwinStreamSink, peer: string) => TwinStreamConnection | null;
99
+ /** Where this host reads a twin's scenario (the handlers document a generative twin serves from,
100
+ * re-read on every request), or null when the twin takes none here. */
101
+ scenarioPath?: (vendor: string) => string | null;
102
+ };
103
+ export declare class WorldDoors {
104
+ readonly name: string;
105
+ readonly worldRoot: string;
106
+ readonly configRef: string;
107
+ readonly served: string;
108
+ private readonly host;
109
+ private readonly queues;
110
+ token: string;
111
+ readToken: string;
112
+ constructor(name: string, worldRoot: string, configRef: string, served: string, host: DoorHost, token: string, readToken: string);
113
+ /** New tokens; a request presenting the old ones is refused from the next call on. */
114
+ retoken(token: string, readToken: string): void;
115
+ /** The world's twins, by vendor, once booted. */
116
+ twins(): string[];
117
+ private up;
118
+ /** The world's token, presented the way the app's SDK presents a credential: the world's own header,
119
+ * the injector's `x-twins-key` (a zero-edit app keeps its SDK's own Authorization), `Bearer <token>`,
120
+ * GitHub's `token <token>`, or the password half of `Basic` (Jira's email:token). */
121
+ private scope;
122
+ /** The World token the request presented, in whichever form, and the scope it opens. */
123
+ private match;
124
+ /** Open one connection on a byte-stream door for the holder of the World's (write) token; null when
125
+ * the token is not the World's or the World has no such stream. */
126
+ openStream(token: string, id: string, sink: TwinStreamSink, peer: string): TwinStreamConnection | null;
127
+ private serialized;
128
+ private refresh;
129
+ private controlRoot;
130
+ private stateOf;
131
+ handle(request: Request): Promise<Response>;
132
+ /** The vendor wire: `/<org>/<world>/<vendor>/<rest>` → the twin's own URL. */
133
+ private wire;
134
+ /** Whether the twin's pack ships a mirror (its vendor's UI over this World's state). */
135
+ private hasMirror;
136
+ /** THE MIRROR MOUNT, as the hosted World serves it (apps/cloud supervisor.ts): `/<org>/<world>/<vendor>/mirror/`
137
+ * and `…/mirror/assets/*`, keyless, GET only — the pack's own shell and bundle. The shell's <base> is the
138
+ * twin's place under this World, so its reads go to the keyed wire with the browser's World session. */
139
+ private mirror;
140
+ private linksPath;
141
+ /** The World's links: name → the vendor origin it forwards to. */
142
+ links(): Record<string, {
143
+ origin: string;
144
+ }>;
145
+ private link;
146
+ /** Forward to the link's origin: the path under the link, the caller's headers with the World's
147
+ * token removed and the sealed credential's headers replacing any of the same name. The vendor's
148
+ * answer (status, headers, body) is streamed back as it arrives. */
149
+ private forward;
150
+ /** The instant of the twin's last completed refresh (its marker's `observedAt`), when it has a root. */
151
+ private observedAt;
152
+ /** The world's own doors under `/-/<org>/<world>/`. */
153
+ private door;
154
+ /** PUSH: see `landChangeset` — the door hands the body to it. */
155
+ private push;
156
+ }
157
+ /**
158
+ * LAND a pushed changeset in a world: its entries go onto the world's branch log for each twin, in
159
+ * order, each by its own id (landing twice is a no-op). Under `deploy: auto` each landed entry is
160
+ * performed at once and its receipt answered; under `gated`/`hold` the entry waits (`landed`). The
161
+ * changeset object is kept beside the world's own, so verify/approve/deploy can name it. The push
162
+ * door and the path transport both come here.
163
+ */
164
+ export declare function landChangeset(name: string, worldRoot: string, instance: WorldLayout, changeset: Changeset, expected?: Record<string, HistoryReference>): Promise<Array<{
165
+ actionId: string;
166
+ twin: string;
167
+ } & Receipt>>;
168
+ /** Confirm locally what a served world answered: each receipt lands the entry's copy on the parent
169
+ * log with that receipt, so `log --receipts` shows it and the entry stops being unpushed. */
170
+ export declare function landReceipts(controlRoot: string, state: string, receipts: Array<{
171
+ actionId: string;
172
+ } & Receipt>, at?: string): void;
173
+ /** The twins of a world that refresh on a cadence: each rooted twin with `root.refresh.every` ("15m",
174
+ * "1h", "30s"), else its pack's declared posture ("Refresh is the kernel's fold", 2). What a local
175
+ * host puts on timers and a hosted World on its object's alarm. */
176
+ export declare function refreshSchedule(worldRoot: string, layout: WorldLayout, log?: (line: string) => void): Promise<Array<{
177
+ vendor: string;
178
+ controlRoot: string;
179
+ root: NonNullable<ReturnType<typeof rootForControlRoot>>;
180
+ everyMs: number;
181
+ }>>;
182
+ /** Observe each scheduled twin's root on its cadence while the world serves locally. A failed refresh
183
+ * is logged, never fatal; the next tick tries again. */
184
+ export declare function scheduleRefreshes(name: string, worldRoot: string, instance: WorldInstance, log?: (line: string) => void): Promise<ReturnType<typeof setInterval>[]>;
185
+ /** A remote given as a PATH: the world in that directory, on its checked-out branch, as `fetch` and
186
+ * `push` reach it with no server between — git's file transport. The world must have booted at
187
+ * least once (its logs live in its instance); `serve` or `up` makes that so. */
188
+ export declare function isPathRemote(target: string): boolean;
189
+ export declare function localWorld(target: string): {
190
+ root: string;
191
+ name: string;
192
+ served: string;
193
+ instance: WorldInstance;
194
+ };