@volter/twin-world 0.1.0 → 0.1.2

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.
@@ -0,0 +1,207 @@
1
+ // World fixture env — STRUCTURALLY VALID fake credentials for the env a world hands the app
2
+ // under test.
3
+ //
4
+ // The failure this fixes (feature-sweep): fake env values in a world config are hand-authored
5
+ // scalars (`sk_test_fake_…`), which is exactly right for credentials an SDK treats as an opaque
6
+ // bearer token — the twin accepts anything, the value's SHAPE never matters. But some
7
+ // credentials are PARSED AND USED CLIENT-SIDE before any request leaves the process: a Google
8
+ // service-account JSON is loaded by google-auth-library, which signs a JWT assertion with its
9
+ // `private_key` locally and only then calls the (twin-served) token endpoint. A faked
10
+ // `GOOGLE_VERTEX_JSON` lacking `private_key` therefore throws inside the app and blocks every
11
+ // Google-auth path — no twin ever sees a request. The fix is not a smarter twin; it is a
12
+ // STRUCTURALLY VALID fake: all required fields, and a REAL throwaway RSA key the client library
13
+ // can genuinely sign with. The signature is verified by nothing (the twin's token endpoint
14
+ // accepts any well-formed assertion), so a throwaway key is safe by construction — it
15
+ // corresponds to no real account anywhere.
16
+ //
17
+ // THE PATTERN (document + reuse for any future structurally-parsed credential):
18
+ // 1. find what the CLIENT SDK does with the value before the first network call;
19
+ // 2. fake every field it reads, with material that genuinely works (a real keypair, a
20
+ // well-formed JWT, …) — never placeholder strings in cryptographic positions;
21
+ // 3. keep the fake obviously fake in the IDENTIFYING fields (project id, email) so it can
22
+ // never be mistaken for a real credential;
23
+ // 4. mint keys per process (throwaway), never commit them — a committed key looks real to
24
+ // scanners and to attackers alike.
25
+ // Precedents in-repo: gcs-sdk.integration.test.ts (throwaway RSA key lets the unmodified
26
+ // @google-cloud/storage SDK sign V4 URLs offline), clerk-jwt.ts / fal-webhooks.ts (generated
27
+ // signing keypairs).
28
+ import { generateKeyPairSync } from 'node:crypto';
29
+
30
+ export type FakeServiceAccountOptions = {
31
+ /** identifying project id — defaults to an unmistakably fake twin project. */
32
+ projectId?: string;
33
+ /** client_email — defaults to a twin address under the fake project. */
34
+ clientEmail?: string;
35
+ };
36
+
37
+ // RSA-2048 generation costs ~100ms — mint ONCE per process and reuse (the clerk-worker
38
+ // baked-key history is the cautionary precedent for per-call generation cost). Throwaway by
39
+ // design: never persisted, never committed, corresponds to no real account.
40
+ let cachedPrivateKeyPem: string | undefined;
41
+ function throwawayPrivateKeyPem(): string {
42
+ if (!cachedPrivateKeyPem) {
43
+ const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
44
+ cachedPrivateKeyPem = privateKey.export({ type: 'pkcs8', format: 'pem' }).toString();
45
+ }
46
+ return cachedPrivateKeyPem;
47
+ }
48
+
49
+ /**
50
+ * A STRUCTURALLY VALID fake Google service-account JSON: every field a real
51
+ * `service_account` key file carries, with a REAL throwaway RSA private key — so
52
+ * google-auth-library (and every SDK built on it: Vertex, GCS, @ai-sdk/google-vertex, …)
53
+ * loads it, signs its JWT assertion locally, and proceeds to the twin-served token
54
+ * endpoint instead of throwing before the first request.
55
+ */
56
+ export function fakeGoogleServiceAccountJson(opts: FakeServiceAccountOptions = {}): string {
57
+ const projectId = opts.projectId ?? 'twin-project';
58
+ const clientEmail = opts.clientEmail ?? `twin-fake@${projectId}.iam.gserviceaccount.com`;
59
+ return JSON.stringify(
60
+ {
61
+ type: 'service_account',
62
+ project_id: projectId,
63
+ private_key_id: 'twinfake0000000000000000000000000000dead',
64
+ private_key: throwawayPrivateKeyPem(),
65
+ client_email: clientEmail,
66
+ client_id: '000000000000000000000',
67
+ auth_uri: 'https://accounts.google.com/o/oauth2/auth',
68
+ token_uri: 'https://oauth2.googleapis.com/token',
69
+ auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
70
+ client_x509_cert_url: `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent(clientEmail)}`,
71
+ universe_domain: 'googleapis.com',
72
+ },
73
+ null,
74
+ 2,
75
+ );
76
+ }
77
+
78
+ /**
79
+ * A STRUCTURALLY VALID fake Google OAUTH WEB-CLIENT JSON — the `{"web":{...}}` shape a
80
+ * Google-Cloud-console "OAuth client" download has, which is what OAuth-APP consumers parse
81
+ * (cal.com: `JSON.parse(GOOGLE_API_CREDENTIALS)?.web`, then a zod schema over
82
+ * client_id/client_secret/redirect_uris). This is a DIFFERENT credential species from the
83
+ * service-account JSON above: faking the SA shape for these names passes the consumer's
84
+ * "valid JSON" check and then yields `?.web === undefined`, so the integration silently
85
+ * degrades instead of erroring — the worst failure mode for a fake credential (Cal.com blind
86
+ * run, friction #4). No cryptographic material is needed: the client secret is an opaque
87
+ * bearer the twin accepts; identifying fields are unmistakably fake.
88
+ */
89
+ export function fakeGoogleOAuthClientJson(): string {
90
+ return JSON.stringify(
91
+ {
92
+ web: {
93
+ client_id: '000000000000-twinfake.apps.googleusercontent.com',
94
+ project_id: 'twin-project',
95
+ auth_uri: 'https://accounts.google.com/o/oauth2/auth',
96
+ token_uri: 'https://oauth2.googleapis.com/token',
97
+ auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
98
+ client_secret: 'twin-fake-google-oauth-client-secret',
99
+ redirect_uris: ['http://localhost:3000/api/auth/callback/google'],
100
+ },
101
+ },
102
+ null,
103
+ 2,
104
+ );
105
+ }
106
+
107
+ /** Does this env NAME carry an INLINE Google OAUTH-CLIENT JSON (the `{"web":{...}}` shape)?
108
+ * Matches a GOOGLE stem combined with an OAuth-app marker: `API_CREDENTIALS` (cal.com's
109
+ * GOOGLE_API_CREDENTIALS — the name that motivated this), `OAUTH_*`, or `*_CLIENT_JSON` /
110
+ * `CLIENT_CREDENTIALS` forms. Deliberately NOT the SERVICE_ACCOUNT-marked names, NOT the
111
+ * GCP/GCLOUD/VERTEX stems (cloud-platform credentials are service accounts), and NOT bare
112
+ * GOOGLE_CREDENTIALS (ambiguous; historically ADC, i.e. SA-shaped — kept on the SA fake). */
113
+ export function isGoogleOAuthClientEnvName(name: string): boolean {
114
+ const n = name.toUpperCase();
115
+ if (!/(^|_)GOOGLE(_|$)/.test(n)) return false;
116
+ if (n === 'GOOGLE_APPLICATION_CREDENTIALS') return false; // a path, not inline JSON
117
+ if (/SERVICE_ACCOUNT/.test(n)) return false; // explicitly SA-shaped
118
+ return /(API_CREDENTIALS|OAUTH_(CLIENT|CREDENTIALS|JSON)|CLIENT_(JSON|CREDENTIALS))/.test(n);
119
+ }
120
+
121
+ /** Does this env NAME carry an INLINE Google service-account JSON (the structurally-parsed
122
+ * kind)? Matches a Google-ish stem (GOOGLE/GCP/GCLOUD/VERTEX) combined with a JSON/
123
+ * credentials/service-account marker — e.g. GOOGLE_VERTEX_JSON, GCP_SERVICE_ACCOUNT_JSON,
124
+ * GOOGLE_APPLICATION_CREDENTIALS_JSON. Deliberately NOT GOOGLE_MAPS_API_KEY (opaque scalar),
125
+ * NOT GOOGLE_APPLICATION_CREDENTIALS (a FILE PATH — point it at a file whose contents
126
+ * come from fakeGoogleServiceAccountJson instead), and NOT the OAuth-client names above —
127
+ * those need the `{"web":{...}}` shape, not SA JSON. */
128
+ export function isGoogleServiceAccountEnvName(name: string): boolean {
129
+ const n = name.toUpperCase();
130
+ if (!/(^|_)(GOOGLE|GCP|GCLOUD|VERTEX)(_|$)/.test(n)) return false;
131
+ if (n === 'GOOGLE_APPLICATION_CREDENTIALS') return false; // a path, not inline JSON
132
+ if (isGoogleOAuthClientEnvName(name)) return false; // OAuth-client shape, handled separately
133
+ return /(_JSON$|_JSON_|CREDENTIALS|SERVICE_ACCOUNT)/.test(n);
134
+ }
135
+
136
+ /**
137
+ * A structurally valid fake value for one env NAME. Google OAuth-client-shaped names get the
138
+ * `{"web":{...}}` client JSON; Google service-account-shaped names get the full SA JSON (real
139
+ * throwaway key); endpoint-shaped names get a parseable vendor-host URL that the injector can
140
+ * claim; everything else gets an unmistakably fake opaque scalar (`twin-fake-<name>`), which is
141
+ * sufficient for bearer-token credentials because the twin accepts any value — shape only
142
+ * matters when the CLIENT parses it (rule of thumb: if a blind adoption run shows an SDK throwing
143
+ * on a fake before any request is made, that env var needs a structural fake; add its rule here).
144
+ */
145
+ /** Endpoint values whose SHAPE is consumed before the first network call.
146
+ *
147
+ * `new URL(value)` runs inside each client SDK before the injector can see a request, so an opaque
148
+ * `twin-fake-*` scalar fails even though the vendor is otherwise perfectly intercepted. These
149
+ * values are deliberately real-vendor-HOST-SHAPED but credential-free: the injector claims the
150
+ * hostname and sends the request to the local twin, while the slug remains unmistakably fake.
151
+ *
152
+ * Like CREDENTIAL_SHAPES below, this is duplicated kernel data with an explicit canonical source:
153
+ * world-runtime must not import a pack, and the tests pin every value against the injector's actual
154
+ * VENDOR_HOSTS predicate so either side changing makes the contract fail loudly. */
155
+ const ENDPOINT_SHAPES: Array<{ match: RegExp; value: string; source: string }> = [
156
+ {
157
+ match: /(^|_)UPSTASH_REDIS_REST_URL$/,
158
+ value: 'https://twin-fake.upstash.io',
159
+ source: 'packages/twin/control-plane/inject.cjs VENDOR_HOSTS.upstashredis',
160
+ },
161
+ {
162
+ match: /(^|_)UPSTASH_VECTOR_REST_URL$/,
163
+ value: 'https://twin-fake-us1-vector.upstash.io',
164
+ source: 'packages/twin/control-plane/inject.cjs VENDOR_HOSTS.upstashvector',
165
+ },
166
+ {
167
+ match: /(^|_)TINYBIRD_API_URL$/,
168
+ value: 'https://api.tinybird.co',
169
+ source: 'packages/twin/control-plane/inject.cjs VENDOR_HOSTS.tinybird',
170
+ },
171
+ ];
172
+
173
+ /** Credentials whose SHAPE the receiving twin actually checks.
174
+ *
175
+ * The generic `twin-fake-<name>` value is inert everywhere it lands — except at a twin that
176
+ * validates its own vendor's key format. Then the world is fully covered and the app still gets a
177
+ * 401, which reads as "the twin doesn't work" and is the most confusing failure this system can
178
+ * produce (measured: it cost two of four subjects a clean boot in PROOF-2026-08-20.md, finding F3).
179
+ * A minted fake must satisfy the twin that will receive it — the minter and the twin are two halves
180
+ * of one contract.
181
+ *
182
+ * These literals are DUPLICATED from the packs on purpose: the kernel must not import a pack
183
+ * (ARCHITECTURE.md). Each entry names its source so the pair can be re-checked by hand. */
184
+ const CREDENTIAL_SHAPES: Array<{ match: RegExp; value: (name: string) => string; source: string }> = [
185
+ // A Discord bot token is three dot-separated base64 segments; a library parses the first for the
186
+ // application id, so a structurally wrong fake breaks before any call reaches the twin.
187
+ { match: /(^|_)DISCORD_[A-Z0-9_]*(TOKEN|SECRET)$/, value: () => `${btoa('1'.repeat(18)).replace(/=+$/, '')}.Gtwinf.${'t'.repeat(38)}`, source: 'a Discord bot token: three dot-separated base64 segments, the first the application id' },
188
+ // resend-twin.ts enforces bearer auth of the form `re_<...>` whenever a key is presented.
189
+ { match: /(^|_)RESEND_[A-Z0-9_]*(KEY|TOKEN|SECRET)$/, value: (name) => `re_twinfake_${name.toLowerCase().replace(/_/g, '')}`, source: 'packages/twin/resend/src/resend-twin.ts' },
190
+ // tinybird-twin.ts accepts exactly one admin token, TINYBIRD_ADMIN_TOKEN = 'p.twin_admin_token'.
191
+ { match: /(^|_)TINYBIRD_[A-Z0-9_]*(KEY|TOKEN)$/, value: () => 'p.twin_admin_token', source: 'packages/twin/tinybird/src/tinybird-twin.ts' },
192
+ ];
193
+
194
+ export function fakeEnvValue(name: string): string {
195
+ if (isGoogleOAuthClientEnvName(name)) return fakeGoogleOAuthClientJson();
196
+ if (isGoogleServiceAccountEnvName(name)) return fakeGoogleServiceAccountJson();
197
+ for (const shape of ENDPOINT_SHAPES) if (shape.match.test(name)) return shape.value;
198
+ for (const shape of CREDENTIAL_SHAPES) if (shape.match.test(name)) return shape.value(name);
199
+ const slug = name.toLowerCase().replace(/_/g, '-');
200
+ // A URL-shaped name must be faked as a URL (F4). An SDK handed `twin-fake-x` where it expects an
201
+ // endpoint throws while CONSTRUCTING its client — before it ever issues the request the world
202
+ // could have intercepted, so the failure looks like a twin bug and no ledger entry exists to
203
+ // contradict that. `.invalid` is reserved (RFC 2606) and never resolves, so an untwinned vendor
204
+ // still fails — but as an unreachable HOST, which the diagnostics can name.
205
+ if (/(^|_)(URL|URI|ENDPOINT|HOST)$/.test(name)) return `https://${slug}.invalid`;
206
+ return `twin-fake-${slug}`;
207
+ }
package/src/host-cli.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
+ import { keepProcessAlive } from '@volter/twin/lifecycle';
2
3
  // volter-world-host: run a set of twins co-located in this single process. The world
3
4
  // runtime spawns ONE of these (instead of one bin per twin) when a world selects
4
5
  // 'colocated'/'worker' isolation. Each twin is named by a module specifier + export so
@@ -83,4 +84,4 @@ process.stdout.write(`host ready (${specs.length} twins, isolation=${isolation})
83
84
  const shutdown = async () => { await host.stop(); process.exit(0); };
84
85
  process.on('SIGTERM', shutdown);
85
86
  process.on('SIGINT', shutdown);
86
- await new Promise(() => {});
87
+ await keepProcessAlive();
@@ -7,8 +7,8 @@ import type { ColocatedTwinSpec } from './host.ts';
7
7
 
8
8
  const spec = workerData as ColocatedTwinSpec;
9
9
 
10
- type TwinServer = { port: number; stop: () => void };
11
- type TwinServerFactory = (opts: { port?: number; root?: string; readOnly?: boolean }) => TwinServer;
10
+ type TwinServer = { port: number; stop: () => void | Promise<void> };
11
+ type TwinServerFactory = (opts: { port?: number; root?: string; readOnly?: boolean }) => TwinServer | Promise<TwinServer>;
12
12
 
13
13
  const mod = (await import(spec.module)) as Record<string, unknown>;
14
14
  const factory = mod[spec.export] as TwinServerFactory | undefined;
@@ -16,7 +16,8 @@ if (typeof factory !== 'function') {
16
16
  throw new Error(`Twin "${spec.id}": ${spec.module} has no factory export "${spec.export}"`);
17
17
  }
18
18
 
19
- const server = factory({ port: spec.port, root: spec.root, readOnly: spec.readOnly });
19
+ // Awaited: an async factory (fly) must post `ready` only once its listener is bound.
20
+ const server = await factory({ port: spec.port, root: spec.root, readOnly: spec.readOnly });
20
21
  parentPort?.postMessage({ type: 'ready', port: server.port });
21
22
 
22
23
  // The Bun.serve listener keeps this worker's event loop alive; nothing else to do.
package/src/host.ts CHANGED
@@ -42,8 +42,14 @@ export type ColocatedHost = {
42
42
  stop: () => Promise<void>;
43
43
  };
44
44
 
45
- type TwinServer = { port: number; stop: () => void };
46
- type TwinServerFactory = (opts: { port?: number; root?: string; readOnly?: boolean }) => TwinServer;
45
+ // `stop` returns void OR a promise (76 of 78 packs return Bun's async server.stop) and the
46
+ // factory itself may be async (fly's createFlyTwinServer) both shapes are awaited, so
47
+ // "resolves once every twin is listening" is true for async factories and shutdown actually
48
+ // WAITS instead of fire-and-forgetting (§9 skeptic finding M1, 2026-08-31: an async factory
49
+ // made host.stop() throw `s.stop is not a function`, turning every SIGTERM into downWorld's
50
+ // SIGKILL escalation for the whole world).
51
+ type TwinServer = { port: number; stop: () => void | Promise<void> };
52
+ type TwinServerFactory = (opts: { port?: number; root?: string; readOnly?: boolean }) => TwinServer | Promise<TwinServer>;
47
53
 
48
54
  async function loadFactory(spec: ColocatedTwinSpec): Promise<TwinServerFactory> {
49
55
  const mod = (await import(spec.module)) as Record<string, unknown>;
@@ -56,6 +62,11 @@ async function loadFactory(spec: ColocatedTwinSpec): Promise<TwinServerFactory>
56
62
 
57
63
  const workerEntry = new URL('./host-worker.ts', import.meta.url);
58
64
 
65
+ /** Per-twin stop budget inside host.stop(). Must stay comfortably under downWorld's 5s
66
+ * SIGTERM→SIGKILL grace (DOWN_GRACE_MS_DEFAULT): the host must reach process.exit(0) even
67
+ * when a twin's stop hangs, or the whole co-located world dies by SIGKILL. */
68
+ const STOP_TIMEOUT_MS = 3000;
69
+
59
70
  /**
60
71
  * Start a co-located host. Resolves once every twin is listening. The returned `stop()`
61
72
  * tears the whole host down (all servers / all workers).
@@ -86,7 +97,7 @@ export async function startColocatedHost(
86
97
  const servers: TwinServer[] = [];
87
98
  for (const spec of specs) {
88
99
  const factory = await loadFactory(spec);
89
- servers.push(factory({ port: spec.port, root: spec.root, readOnly: spec.readOnly }));
100
+ servers.push(await factory({ port: spec.port, root: spec.root, readOnly: spec.readOnly }));
90
101
  }
91
102
  return {
92
103
  isolation,
@@ -94,7 +105,18 @@ export async function startColocatedHost(
94
105
  stop: async () => {
95
106
  process.off('unhandledRejection', onRejection);
96
107
  process.off('uncaughtException', onUncaught);
97
- for (const s of servers) s.stop();
108
+ // EVERY stop is invoked, IN PARALLEL, each under its own timeout, and no outcome —
109
+ // rejection, hang, or slowness — can prevent the others or wedge host.stop() itself.
110
+ // The awaited-sequential first cut re-created the SIGKILL escalation it was fixing
111
+ // through a new door (§9 round two H2, 2026-08-31: one pending/throwing stop — fly's
112
+ // cleanup throws on a failed container removal — left siblings unstopped and the host
113
+ // ignoring SIGTERM forever). The bound stays under downWorld's 5s SIGKILL grace.
114
+ await Promise.allSettled(servers.map((s) =>
115
+ Promise.race([
116
+ Promise.resolve().then(() => s.stop()),
117
+ new Promise((resolveTimeout) => setTimeout(resolveTimeout, STOP_TIMEOUT_MS).unref?.()),
118
+ ]),
119
+ ));
98
120
  },
99
121
  };
100
122
  }
package/src/index.ts CHANGED
@@ -9,6 +9,9 @@ export type {
9
9
  WorldExternalDiscover,
10
10
  WorldExternalDiscoverSource,
11
11
  WorldExternalReadyWhen,
12
+ WorldRunOutcome,
13
+ WorldRunRecord,
14
+ WorldResourceRequirements,
12
15
  } from './schema.ts';
13
16
  export { loadWorldConfig, resolveConfigPath } from './configs.ts';
14
17
  export {
@@ -16,6 +19,8 @@ export {
16
19
  downWorld,
17
20
  listWorlds,
18
21
  statusWorld,
22
+ planWorldActions,
23
+ reviewWorldActions,
19
24
  doctorWorld,
20
25
  runWithWorldEnv,
21
26
  activateScript,
@@ -28,15 +33,106 @@ export {
28
33
  shareWorldServices,
29
34
  unshareWorld,
30
35
  urlsWorld,
36
+ urlWorld,
31
37
  } from './runtime.ts';
38
+ // `volter-world app-url` — the recorded, queryable app endpoint of an instance (see app-url.ts).
39
+ export { appUrlFile, appUrlUnsetMessage, detectAppUrl, readAppUrl, setAppUrl } from './app-url.ts';
40
+ export type { AppUrlRecord, AppUrlSource } from './app-url.ts';
41
+ export { tailWorldActions } from './tail.ts';
42
+ export type { TailWorldOptions } from './tail.ts';
43
+ // the changeset primitive + the diff verb (docs/OPERATIONAL_VCS.md v0) and the operational-PR
44
+ // contract over it (v1: verify/approve/status). World-side glue only — markers, deltas, content
45
+ // hashing, replay, verifier evaluation and approval binding live in @volter/twin's control plane.
32
46
  export {
33
- checkDockerRuntime,
47
+ approveWorldChangeset,
48
+ createWorldChangeset,
49
+ diffWorld,
50
+ EPHEMERAL_VERIFY_TARGET,
51
+ findWorldChangeset,
52
+ listWorldChangesets,
53
+ listWorldMarks,
54
+ markWorld,
55
+ replayWorldChangeset,
56
+ resolveBaseMarker,
57
+ statusWorldChangeset,
58
+ verifyWorldChangeset,
59
+ worldChangesetsDir,
60
+ worldLedgers,
61
+ worldMarksDir,
62
+ } from './changeset.ts';
63
+ export type { ApproveWorldOutcome, ChangesetLocation, VerifyWorldOutcome, WorldRootOptions } from './changeset.ts';
64
+ export {
65
+ checkLocalExecution,
34
66
  checkPrerequisites,
35
67
  formatPrerequisiteChecks,
36
68
  } from './prerequisites.ts';
69
+ export { inspectProject, formatProjectInspection, projectDependencies, projectEnvNames, SDK_TWINS, workspaceDirs } from './project-inspect.ts';
70
+ export type { ProjectInspection } from './project-inspect.ts';
71
+ // Structurally valid fake credentials for world configs (fixture env) — see fixture-env.ts
72
+ // for the pattern (a fake a client SDK parses/signs with must be structurally real).
73
+ export { fakeEnvValue, fakeGoogleOAuthClientJson, fakeGoogleServiceAccountJson, isGoogleOAuthClientEnvName, isGoogleServiceAccountEnvName } from './fixture-env.ts';
74
+ export type { FakeServiceAccountOptions } from './fixture-env.ts';
75
+ export {
76
+ coverWorld,
77
+ detectRepoVendors,
78
+ envNameVendor,
79
+ formatCoverageReport,
80
+ injectorVendorKeysFor,
81
+ isCredentialShapedEnvName,
82
+ worldTwinInventory,
83
+ } from './covers.ts';
84
+ export type { CoverageReport, CoverageRow, CoverageStatus, CoverageOptions, RepoVendorSignals } from './covers.ts';
85
+ // `volter-world init` — the deterministic front door: detect the repo's vendors (covers), emit a
86
+ // world config + env file OUTSIDE the repo (fixture-env), and prove the emission with `covers`.
87
+ export { formatInitReport, initWorld, packCatalog, planWorldInit, renderEnvFile, writeWorldInit } from './init.ts';
88
+ export type {
89
+ EnvDisposition,
90
+ InitEnvRow,
91
+ InitInfraStub,
92
+ InitOptions,
93
+ InitPlan,
94
+ InitResult,
95
+ InitVendorPlan,
96
+ InitWiring,
97
+ } from './init.ts';
98
+ export {
99
+ deriveWorldManifest,
100
+ findWorldRefFile,
101
+ isRemoteWorldRef,
102
+ resolveWorldRef,
103
+ WORLD_REF_FILE,
104
+ worldManifest,
105
+ } from './attach.ts';
106
+ export type { ResolvedWorldRef, WorldManifest, WorldRefSource } from './attach.ts';
107
+ export {
108
+ parseSni,
109
+ readReflectRoutes,
110
+ reflectRoutesPath,
111
+ reflectManifestPath,
112
+ readReflectManifest,
113
+ writeReflectManifest,
114
+ clearReflectManifest,
115
+ composeOverrideForReflect,
116
+ splitDockerComposeArgs,
117
+ dockerComposeWithOverride,
118
+ CA_TRUST_ENV,
119
+ ATTACHED_CA_PATH,
120
+ startReflectFront,
121
+ startReflectResolver,
122
+ writeReflectRoutes,
123
+ } from './reflect.ts';
124
+ export type { ReflectFrontHandle, ReflectFrontOptions, ReflectManifest, ReflectResolverHandle, ReflectResolverOptions } from './reflect.ts';
37
125
  export type {
38
126
  PrerequisiteCheck,
39
127
  PrerequisiteId,
40
128
  } from './prerequisites.ts';
41
129
  export { startColocatedHost } from './host.ts';
42
130
  export type { ColocatedTwinSpec, ColocatedHost, HostIsolation } from './host.ts';
131
+ export {
132
+ advertiseWorldManifest,
133
+ fetchRemoteManifest,
134
+ MANIFEST_PATH,
135
+ remoteAttachEnv,
136
+ startManifestServer,
137
+ } from './serve.ts';
138
+ export type { ManifestServerHandle, ManifestServerOptions } from './serve.ts';