@volter/world-core 3.0.39 → 3.0.41

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.
@@ -127,8 +127,10 @@ function allowsWorldNetworkEgress(policy, value, method = 'GET') {
127
127
 
128
128
  function worldNetworkUsesPassthrough(policy, value) {
129
129
  const to = destination(value, true);
130
- return !!to && policy.phase === 'build' && policy.passthrough?.includes(to.url.origin) === true
131
- && policy.egress.includes(to.url.origin);
130
+ if (!to || policy.phase !== 'build') return false;
131
+ // public build artifacts tunnel unopened: native clients (Turbopack's next/font on macOS) trust only the OS store
132
+ if (policy.publicReads === true && PUBLIC_BUILD_READS.includes(to.url.origin) && !granted(policy.writes ?? [], to)) return true;
133
+ return policy.passthrough?.includes(to.url.origin) === true && policy.egress.includes(to.url.origin);
132
134
  }
133
135
 
134
136
  /** This authority must be mediated per request; CONNECT is only a path to the inspector. */
@@ -175,5 +175,12 @@ export type BoardFrame = {
175
175
  /** set by the kernel, never the pack: whether a built screen of the vendor's (any of its lanes') draws the url */
176
176
  drawn?: boolean;
177
177
  };
178
+ /** Host-side measurement of actual dispatch, including declared gaps. It changes no request or answer. */
179
+ export type DerivedDispatch = {
180
+ surface: DerivedSurface;
181
+ operation: DerivedOperation;
182
+ owner: DerivedOwner;
183
+ };
184
+ export declare function observeDerivedDispatch(observer: (dispatch: DerivedDispatch) => void): () => void;
178
185
  export declare function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch;
179
186
  export {};
@@ -144,6 +144,11 @@ export function pathParams(routes, pathname) {
144
144
  }
145
145
  /** The header the kernel carries a path prefix's named groups in, from routing to the call (never a client's). */
146
146
  export const PREFIX_PARAMS_HEADER = 'x-volter-path-prefix-params';
147
+ let dispatchObservers;
148
+ export function observeDerivedDispatch(observer) {
149
+ (dispatchObservers ??= new Set()).add(observer);
150
+ return () => { dispatchObservers?.delete(observer); };
151
+ }
147
152
  export function createDerivedFetch(options) {
148
153
  const handlers = options.handlers ?? {};
149
154
  const known = new Set(options.surface.operations.map((o) => o.id));
@@ -161,6 +166,8 @@ export function createDerivedFetch(options) {
161
166
  : matchOperation(routes, request.method, url.pathname, url.searchParams, request.headers);
162
167
  if (!matched)
163
168
  return fallback(request, undefined, 'no operation at this path');
169
+ for (const observer of dispatchObservers ?? [])
170
+ observer({ surface: options.surface, operation: matched.operation, owner: handlers[matched.operation.id] ? 'handler' : options.core?.owns(matched.operation) ? 'core' : 'gap' });
164
171
  // the body read once, as text, for everything the dispatch does with it (bodyTextOf)
165
172
  if (request.method !== 'GET' && request.method !== 'HEAD' && request.body && !(request.headers.get('content-type') ?? '').includes('multipart'))
166
173
  tagBody(request, await request.clone().text());
@@ -1,3 +1,8 @@
1
+ /** The vendor is published data, independent of its publisher's npm name. No package code is imported. */
2
+ export declare function packVendor(dir: string): string | undefined;
3
+ /** Nearest installed package wins only over another installation of the SAME package. A World's explicit
4
+ * package choice wins over a catalog recommendation; different publishers' versions never compete. */
5
+ export declare function installedVendorPacks(from: string): Map<string, string>;
1
6
  /** Node's nearest installed package, including linked packages and hoisted workspace dependencies. */
2
7
  export declare function installedPackageDir(from: string, name: string): string | undefined;
3
8
  /** A pack repository itself, or the P3 repository beside a platform checkout. Applications do not acquire a
@@ -10,6 +10,88 @@ function packageName(dir) {
10
10
  return undefined;
11
11
  }
12
12
  }
13
+ /** The vendor is published data, independent of its publisher's npm name. No package code is imported. */
14
+ export function packVendor(dir) {
15
+ const facts = join(dir, 'generated', 'pack-facts.json');
16
+ if (existsSync(facts)) {
17
+ const document = JSON.parse(readFileSync(facts, 'utf8'));
18
+ const vendors = Object.keys(document.packs ?? {});
19
+ if (vendors.length !== 1 || !/^[a-z][a-z0-9-]*$/.test(vendors[0]) || document.packs[vendors[0]].protocol?.declared !== '3')
20
+ throw new Error(`Invalid pack identity in ${facts}`);
21
+ return vendors[0];
22
+ }
23
+ // Source checkouts predate release facts; their conventional name remains sufficient for development.
24
+ const match = /^@[^/]+\/twin-([a-z][a-z0-9-]*)$/.exec(packageName(dir) ?? '');
25
+ return match?.[1] === 'standard' || match?.[1] === 'catalog' ? undefined : match?.[1];
26
+ }
27
+ /** Nearest installed package wins only over another installation of the SAME package. A World's explicit
28
+ * package choice wins over a catalog recommendation; different publishers' versions never compete. */
29
+ export function installedVendorPacks(from) {
30
+ const packages = new Map();
31
+ const seen = new Set();
32
+ const pins = new Map();
33
+ let at = resolve(from);
34
+ for (;;) {
35
+ const config = join(at, '.volter', 'world.json');
36
+ if (existsSync(config)) {
37
+ const document = JSON.parse(readFileSync(config, 'utf8'));
38
+ for (const service of document.services ?? []) {
39
+ const name = service.source?.package ?? service.package;
40
+ if (name && !pins.has(service.id))
41
+ pins.set(service.id, name);
42
+ }
43
+ }
44
+ const modules = join(at, 'node_modules');
45
+ if (existsSync(modules)) {
46
+ const directories = readdirSync(modules, { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith('.')).flatMap((e) => e.name.startsWith('@') ? readdirSync(join(modules, e.name)).map((n) => join(modules, e.name, n)) : [join(modules, e.name)]);
47
+ for (const dir of directories) {
48
+ const name = packageName(dir);
49
+ if (!name || seen.has(name))
50
+ continue;
51
+ seen.add(name);
52
+ if (!existsSync(join(dir, 'generated', 'pack-facts.json')) && !/^@[^/]+\/twin-/.test(name))
53
+ continue;
54
+ if (!isDerivedPack(dir))
55
+ continue;
56
+ const vendor = packVendor(dir);
57
+ if (vendor)
58
+ packages.set(name, { dir, vendor });
59
+ }
60
+ }
61
+ const parent = dirname(at);
62
+ if (parent === at)
63
+ break;
64
+ at = parent;
65
+ }
66
+ const index = installedPackageDir(from, '@volter/twin-catalog');
67
+ const file = index && join(index, 'recommendations.json');
68
+ const recommendations = file && existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};
69
+ const revokedFile = index && join(index, 'revocations.json');
70
+ const revocations = revokedFile && existsSync(revokedFile) ? JSON.parse(readFileSync(revokedFile, 'utf8')) : [];
71
+ for (const [id, name] of [...pins]) {
72
+ const vendor = packages.get(name)?.vendor;
73
+ if (vendor && vendor !== id) {
74
+ if (pins.has(vendor) && pins.get(vendor) !== name)
75
+ throw new Error(`${vendor}: a World must select one package implementation`);
76
+ pins.set(vendor, name);
77
+ }
78
+ }
79
+ const result = new Map();
80
+ for (const vendor of new Set([...packages.values()].map((p) => p.vendor))) {
81
+ const candidates = [...packages.entries()].filter(([, p]) => p.vendor === vendor);
82
+ const selected = pins.get(vendor) ?? recommendations[vendor];
83
+ const choice = selected ? candidates.find(([name]) => name === selected) : candidates.length === 1 ? candidates[0] : undefined;
84
+ if (!choice)
85
+ throw new Error(`${vendor}: ${selected ? `selected package ${selected} is not installed` : `multiple implementations installed (${candidates.map(([name]) => name).join(', ')})`}; name the chosen source.package in .volter/world.json`);
86
+ if (!pins.has(vendor)) {
87
+ const version = JSON.parse(readFileSync(join(choice[1].dir, 'package.json'), 'utf8')).version;
88
+ if (revocations.some((r) => r.package === choice[0] && r.version === version))
89
+ throw new Error(`${vendor}: installed ${choice[0]}@${version} is revoked; install an approved release or retain an existing explicit World pin`);
90
+ }
91
+ result.set(vendor, choice[1].dir);
92
+ }
93
+ return result;
94
+ }
13
95
  /** Node's nearest installed package, including linked packages and hoisted workspace dependencies. */
14
96
  export function installedPackageDir(from, name) {
15
97
  let dir = resolve(from);
@@ -45,14 +127,15 @@ export function packRepository(from) {
45
127
  export function vendorPackageDir(from, vendor) {
46
128
  if (!/^[a-z][a-z0-9-]*$/.test(vendor))
47
129
  return undefined;
48
- const candidate = installedPackageDir(from, `@volter/twin-${vendor}`);
49
- const installed = candidate && isDerivedPack(candidate) ? candidate : undefined;
130
+ const installed = installedVendorPacks(from).get(vendor);
50
131
  const repo = packRepository(from);
51
132
  const checkout = repo === undefined ? undefined : join(repo, vendor);
52
133
  if (!checkout || packageName(checkout) !== `@volter/twin-${vendor}` || !isDerivedPack(checkout))
53
134
  return installed;
54
135
  if (!installed)
55
136
  return checkout;
137
+ if (packageName(installed) !== packageName(checkout))
138
+ return installed;
56
139
  const major = (dir) => {
57
140
  try {
58
141
  return Number(/^(\d+)/.exec(JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).version ?? '')?.[1] ?? 0);
@@ -77,7 +160,7 @@ export function vendorOfPackModule(modulePath) {
77
160
  for (;;) {
78
161
  const name = packageName(dir);
79
162
  if (name !== undefined)
80
- return name.startsWith('@volter/twin-') ? name.slice('@volter/twin-'.length) : undefined;
163
+ return packVendor(dir);
81
164
  const up = dirname(dir);
82
165
  if (up === dir)
83
166
  return undefined;
@@ -1,4 +1,4 @@
1
- export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, protocolStanding } from './packRegistry.js';
1
+ export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, PACK_ARCHETYPES, protocolStanding } from './packRegistry.js';
2
2
  export type { PackTransport, PullPosture, PullTrigger, PullVendor, RoundTripWrite, TwinPack } from './packRegistry.js';
3
3
  export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError, statefulTwinManifest, twinManifest } from './scenario.js';
4
4
  export { WORLD_CLOCK_ENV, worldNow } from './world-clock.js';
@@ -6,10 +6,10 @@ export { WORLD_ENV_NAMES_ENV, worldEnvValue } from './world-env.js';
6
6
  export { ORIGINAL_PATH_HEADER } from './sigv4.js';
7
7
  export { createTwinFetchFromHandler, placedCookies, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, TWIN_SITE_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, twinVendorUrl, withRequestScopes } from './twin-fetch.js';
8
8
  export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from './request-scope.js';
9
- export { compileSurface, createDerivedFetch, matchOperation } from './derived.js';
9
+ export { compileSurface, createDerivedFetch, matchOperation, observeDerivedDispatch } from './derived.js';
10
10
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.js';
11
11
  export type { Traceparent } from './trace-context.js';
12
- export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.js';
12
+ export type { DerivedCall, DerivedCoreOutcome, DerivedDispatch, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.js';
13
13
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.js';
14
14
  export { deliverEvents, fillEnvelope, setDeliveryObserver, signEvent, signEventAll, verifyEvent } from './events.js';
15
15
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from './signing.js';
@@ -49,7 +49,7 @@ export type { ActionProjection, ProjectedDelivery, ProjectedResource, ProjectedR
49
49
  export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, approverOf, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from './changeset.js';
50
50
  export type { ApplyReceipt, RebaseActionResult, RebaseReport, RebaseTarget, Changeset, ChangesetAction, ChangesetApplication, CompensationEntry, ChangesetApproval, ChangesetReadiness, ChangesetVerification, ChangesetVerifier, ChangesetVerifierResult, LedgerDelta, LedgerPosition, LedgerRef, ReplayActionResult, ReplayReport, ReplayTarget, VendorSummary, WorldMarker, } from './changeset.js';
51
51
  export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets, type PackAssetStore } from './pack-assets.js';
52
- export { installedPackageDir, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from './pack-paths.js';
52
+ export { installedPackageDir, installedVendorPacks, packVendor, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from './pack-paths.js';
53
53
  export * as git from './git/index.js';
54
54
  export * as s3 from './s3/wire.js';
55
55
  export { PLACEHOLDER_REMOTE, beginPlaceholderPull, endPlaceholderPull, placeholderPullActive, placeholderPullMarkerPath, withPlaceholderPull, placeholderEventsFor } from './placeholder-remote.js';
@@ -5,7 +5,7 @@
5
5
  // contract: the kernel's root"). Removed v1 entry points fail explicitly. Conformance and validation tooling lives in
6
6
  // @volter/world-tooling, a dev dependency.
7
7
  // Pack registry — vendor twins self-describe (TwinPack) so tooling discovers them.
8
- export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, protocolStanding } from "./packRegistry.js";
8
+ export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, PACK_ARCHETYPES, protocolStanding } from "./packRegistry.js";
9
9
  // The DELIVER verb (`emit`) — vendor-agnostic engine + CLI glue; packs declare a TwinEmitter
10
10
  // (their event catalog, endpoints-from-state, and signed synthesis) on `TwinPack.emitter`.
11
11
  export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError, statefulTwinManifest, twinManifest } from "./scenario.js";
@@ -14,7 +14,7 @@ export { WORLD_ENV_NAMES_ENV, worldEnvValue } from "./world-env.js";
14
14
  export { ORIGINAL_PATH_HEADER } from "./sigv4.js";
15
15
  export { createTwinFetchFromHandler, placedCookies, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, TWIN_SITE_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, twinVendorUrl, withRequestScopes } from "./twin-fetch.js";
16
16
  export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from "./request-scope.js";
17
- export { compileSurface, createDerivedFetch, matchOperation } from "./derived.js";
17
+ export { compileSurface, createDerivedFetch, matchOperation, observeDerivedDispatch } from "./derived.js";
18
18
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from "./trace-context.js";
19
19
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from "./derived-core.js";
20
20
  export { deliverEvents, fillEnvelope, setDeliveryObserver, signEvent, signEventAll, verifyEvent } from "./events.js";
@@ -68,7 +68,7 @@ export { appendAction, appendTransactionCommit, checkPrecondition, confirmAction
68
68
  // world discovery and thin verbs on top.
69
69
  export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, approverOf, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from "./changeset.js";
70
70
  export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets } from "./pack-assets.js";
71
- export { installedPackageDir, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from "./pack-paths.js";
71
+ export { installedPackageDir, installedVendorPacks, packVendor, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from "./pack-paths.js";
72
72
  // The git plane (contract "The git plane is a kernel library"): objects, packs, refs, smart HTTP.
73
73
  export * as git from "./git/index.js";
74
74
  // S3's wire (contract "S3's wire is a kernel library too"): its XML, CORS, lifecycle, delete batches, ETags, body bytes.
@@ -127,8 +127,10 @@ function allowsWorldNetworkEgress(policy, value, method = 'GET') {
127
127
 
128
128
  function worldNetworkUsesPassthrough(policy, value) {
129
129
  const to = destination(value, true);
130
- return !!to && policy.phase === 'build' && policy.passthrough?.includes(to.url.origin) === true
131
- && policy.egress.includes(to.url.origin);
130
+ if (!to || policy.phase !== 'build') return false;
131
+ // public build artifacts tunnel unopened: native clients (Turbopack's next/font on macOS) trust only the OS store
132
+ if (policy.publicReads === true && PUBLIC_BUILD_READS.includes(to.url.origin) && !granted(policy.writes ?? [], to)) return true;
133
+ return policy.passthrough?.includes(to.url.origin) === true && policy.egress.includes(to.url.origin);
132
134
  }
133
135
 
134
136
  /** This authority must be mediated per request; CONNECT is only a path to the inspector. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-core",
3
- "version": "3.0.39",
3
+ "version": "3.0.41",
4
4
  "description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
5
5
  "keywords": [
6
6
  "twin",
package/src/derived.ts CHANGED
@@ -255,6 +255,14 @@ export type BoardFrame = {
255
255
  drawn?: boolean;
256
256
  };
257
257
 
258
+ /** Host-side measurement of actual dispatch, including declared gaps. It changes no request or answer. */
259
+ export type DerivedDispatch = { surface: DerivedSurface; operation: DerivedOperation; owner: DerivedOwner };
260
+ let dispatchObservers: Set<(dispatch: DerivedDispatch) => void> | undefined;
261
+ export function observeDerivedDispatch(observer: (dispatch: DerivedDispatch) => void): () => void {
262
+ (dispatchObservers ??= new Set()).add(observer);
263
+ return () => { dispatchObservers?.delete(observer); };
264
+ }
265
+
258
266
  export function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch {
259
267
  const handlers = options.handlers ?? {};
260
268
  const known = new Set(options.surface.operations.map((o) => o.id));
@@ -271,6 +279,7 @@ export function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch {
271
279
  ? [...routes.keys()].map((m) => matchOperation(routes, m, url.pathname, url.searchParams, request.headers)).find(Boolean)
272
280
  : matchOperation(routes, request.method, url.pathname, url.searchParams, request.headers);
273
281
  if (!matched) return fallback(request, undefined, 'no operation at this path');
282
+ for (const observer of dispatchObservers ?? []) observer({ surface: options.surface, operation: matched.operation, owner: handlers[matched.operation.id] ? 'handler' : options.core?.owns(matched.operation) ? 'core' : 'gap' });
274
283
  // the body read once, as text, for everything the dispatch does with it (bodyTextOf)
275
284
  if (request.method !== 'GET' && request.method !== 'HEAD' && request.body && !(request.headers.get('content-type') ?? '').includes('multipart')) tagBody(request, await request.clone().text());
276
285
  // the path prefix's named groups (pack-fetch.ts, `pathPrefix`) are the call's parameters too
package/src/pack-paths.ts CHANGED
@@ -8,6 +8,78 @@ function packageName(dir: string): string | undefined {
8
8
  catch { return undefined; }
9
9
  }
10
10
 
11
+ /** The vendor is published data, independent of its publisher's npm name. No package code is imported. */
12
+ export function packVendor(dir: string): string | undefined {
13
+ const facts = join(dir, 'generated', 'pack-facts.json');
14
+ if (existsSync(facts)) {
15
+ const document = JSON.parse(readFileSync(facts, 'utf8')) as { packs?: Record<string, { protocol?: { declared?: string } }> };
16
+ const vendors = Object.keys(document.packs ?? {});
17
+ if (vendors.length !== 1 || !/^[a-z][a-z0-9-]*$/.test(vendors[0]!) || document.packs![vendors[0]!]!.protocol?.declared !== '3') throw new Error(`Invalid pack identity in ${facts}`);
18
+ return vendors[0];
19
+ }
20
+ // Source checkouts predate release facts; their conventional name remains sufficient for development.
21
+ const match = /^@[^/]+\/twin-([a-z][a-z0-9-]*)$/.exec(packageName(dir) ?? '');
22
+ return match?.[1] === 'standard' || match?.[1] === 'catalog' ? undefined : match?.[1];
23
+ }
24
+
25
+ /** Nearest installed package wins only over another installation of the SAME package. A World's explicit
26
+ * package choice wins over a catalog recommendation; different publishers' versions never compete. */
27
+ export function installedVendorPacks(from: string): Map<string, string> {
28
+ const packages = new Map<string, { dir: string; vendor: string }>();
29
+ const seen = new Set<string>();
30
+ const pins = new Map<string, string>();
31
+ let at = resolve(from);
32
+ for (;;) {
33
+ const config = join(at, '.volter', 'world.json');
34
+ if (existsSync(config)) {
35
+ const document = JSON.parse(readFileSync(config, 'utf8')) as { services?: Array<{ id: string; source?: { package?: string }; package?: string }> };
36
+ for (const service of document.services ?? []) {
37
+ const name = service.source?.package ?? service.package;
38
+ if (name && !pins.has(service.id)) pins.set(service.id, name);
39
+ }
40
+ }
41
+ const modules = join(at, 'node_modules');
42
+ if (existsSync(modules)) {
43
+ const directories = readdirSync(modules, { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith('.')).flatMap((e) => e.name.startsWith('@') ? readdirSync(join(modules, e.name)).map((n) => join(modules, e.name, n)) : [join(modules, e.name)]);
44
+ for (const dir of directories) {
45
+ const name = packageName(dir);
46
+ if (!name || seen.has(name)) continue;
47
+ seen.add(name);
48
+ if (!existsSync(join(dir, 'generated', 'pack-facts.json')) && !/^@[^/]+\/twin-/.test(name)) continue;
49
+ if (!isDerivedPack(dir)) continue;
50
+ const vendor = packVendor(dir);
51
+ if (vendor) packages.set(name, { dir, vendor });
52
+ }
53
+ }
54
+ const parent = dirname(at); if (parent === at) break; at = parent;
55
+ }
56
+ const index = installedPackageDir(from, '@volter/twin-catalog');
57
+ const file = index && join(index, 'recommendations.json');
58
+ const recommendations = file && existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) as Record<string, string> : {};
59
+ const revokedFile = index && join(index, 'revocations.json');
60
+ const revocations = revokedFile && existsSync(revokedFile) ? JSON.parse(readFileSync(revokedFile, 'utf8')) as Array<{ package: string; version: string }> : [];
61
+ for (const [id, name] of [...pins]) {
62
+ const vendor = packages.get(name)?.vendor;
63
+ if (vendor && vendor !== id) {
64
+ if (pins.has(vendor) && pins.get(vendor) !== name) throw new Error(`${vendor}: a World must select one package implementation`);
65
+ pins.set(vendor, name);
66
+ }
67
+ }
68
+ const result = new Map<string, string>();
69
+ for (const vendor of new Set([...packages.values()].map((p) => p.vendor))) {
70
+ const candidates = [...packages.entries()].filter(([, p]) => p.vendor === vendor);
71
+ const selected = pins.get(vendor) ?? recommendations[vendor];
72
+ const choice = selected ? candidates.find(([name]) => name === selected) : candidates.length === 1 ? candidates[0] : undefined;
73
+ if (!choice) throw new Error(`${vendor}: ${selected ? `selected package ${selected} is not installed` : `multiple implementations installed (${candidates.map(([name]) => name).join(', ')})`}; name the chosen source.package in .volter/world.json`);
74
+ if (!pins.has(vendor)) {
75
+ const version = (JSON.parse(readFileSync(join(choice[1].dir, 'package.json'), 'utf8')) as { version?: string }).version;
76
+ if (revocations.some((r) => r.package === choice[0] && r.version === version)) throw new Error(`${vendor}: installed ${choice[0]}@${version} is revoked; install an approved release or retain an existing explicit World pin`);
77
+ }
78
+ result.set(vendor, choice[1].dir);
79
+ }
80
+ return result;
81
+ }
82
+
11
83
  /** Node's nearest installed package, including linked packages and hoisted workspace dependencies. */
12
84
  export function installedPackageDir(from: string, name: string): string | undefined {
13
85
  let dir = resolve(from);
@@ -39,12 +111,12 @@ export function packRepository(from: string): string | undefined {
39
111
  /** Resolve one vendor's package directory for host-side reads (assets, infrastructure launchers). */
40
112
  export function vendorPackageDir(from: string, vendor: string): string | undefined {
41
113
  if (!/^[a-z][a-z0-9-]*$/.test(vendor)) return undefined;
42
- const candidate = installedPackageDir(from, `@volter/twin-${vendor}`);
43
- const installed = candidate && isDerivedPack(candidate) ? candidate : undefined;
114
+ const installed = installedVendorPacks(from).get(vendor);
44
115
  const repo = packRepository(from);
45
116
  const checkout = repo === undefined ? undefined : join(repo, vendor);
46
117
  if (!checkout || packageName(checkout) !== `@volter/twin-${vendor}` || !isDerivedPack(checkout)) return installed;
47
118
  if (!installed) return checkout;
119
+ if (packageName(installed) !== packageName(checkout)) return installed;
48
120
  const major = (dir: string): number => {
49
121
  try { return Number(/^(\d+)/.exec((JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as { version?: string }).version ?? '')?.[1] ?? 0); } catch { return 0; }
50
122
  };
@@ -64,7 +136,7 @@ export function vendorOfPackModule(modulePath: string): string | undefined {
64
136
  let dir = dirname(resolve(modulePath));
65
137
  for (;;) {
66
138
  const name = packageName(dir);
67
- if (name !== undefined) return name.startsWith('@volter/twin-') ? name.slice('@volter/twin-'.length) : undefined;
139
+ if (name !== undefined) return packVendor(dir);
68
140
  const up = dirname(dir);
69
141
  if (up === dir) return undefined;
70
142
  dir = up;
package/src/runtime.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  // contract: the kernel's root"). Removed v1 entry points fail explicitly. Conformance and validation tooling lives in
6
6
  // @volter/world-tooling, a dev dependency.
7
7
  // Pack registry — vendor twins self-describe (TwinPack) so tooling discovers them.
8
- export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, protocolStanding } from './packRegistry.ts';
8
+ export { clearRegistry, getPack, hasPack, listPacks, packOf, registerPack, pullPosture, assertContinuousPullAllowed, pullOnSchedule, resolvePullVendor, DEFAULT_PULL_POSTURE, DEFAULT_PULL_TRIGGER, PROTOCOL_VERSION, PROTOCOL_MAJOR, PACK_ARCHETYPES, protocolStanding } from './packRegistry.ts';
9
9
  export type { PackTransport, PullPosture, PullTrigger, PullVendor, RoundTripWrite, TwinPack } from './packRegistry.ts';
10
10
  // The DELIVER verb (`emit`) — vendor-agnostic engine + CLI glue; packs declare a TwinEmitter
11
11
  // (their event catalog, endpoints-from-state, and signed synthesis) on `TwinPack.emitter`.
@@ -15,10 +15,10 @@ export { WORLD_ENV_NAMES_ENV, worldEnvValue } from './world-env.ts';
15
15
  export { ORIGINAL_PATH_HEADER } from './sigv4.ts';
16
16
  export { createTwinFetchFromHandler, placedCookies, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, TWIN_SITE_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, twinVendorUrl, withRequestScopes } from './twin-fetch.ts';
17
17
  export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from './request-scope.ts';
18
- export { compileSurface, createDerivedFetch, matchOperation } from './derived.ts';
18
+ export { compileSurface, createDerivedFetch, matchOperation, observeDerivedDispatch } from './derived.ts';
19
19
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.ts';
20
20
  export type { Traceparent } from './trace-context.ts';
21
- export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.ts';
21
+ export type { DerivedCall, DerivedCoreOutcome, DerivedDispatch, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.ts';
22
22
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.ts';
23
23
  export { deliverEvents, fillEnvelope, setDeliveryObserver, signEvent, signEventAll, verifyEvent } from './events.ts';
24
24
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from './signing.ts';
@@ -291,7 +291,7 @@ export type {
291
291
  WorldMarker,
292
292
  } from './changeset.ts';
293
293
  export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets, type PackAssetStore } from './pack-assets.ts';
294
- export { installedPackageDir, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from './pack-paths.ts';
294
+ export { installedPackageDir, installedVendorPacks, packVendor, packRepository, isDerivedPack, vendorPackageDir, vendorOfPackModule } from './pack-paths.ts';
295
295
 
296
296
  // The git plane (contract "The git plane is a kernel library"): objects, packs, refs, smart HTTP.
297
297
  export * as git from './git/index.ts';