@volter/twin-standard 1.0.85 → 1.0.87

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.
@@ -18,6 +18,7 @@ import { createHostTable } from '@volter/world-core/host-routing';
18
18
  import packFactsDocument from '@volter/world-core/generated/pack-facts.json' with { type: 'json' };
19
19
  import { isMysql, isResp, at, captureAt, echoFailures, expandFills, expectFailures, fill, fillJson, formBody, isGit, isLine, isSql, isSocket, isWait, jwtAuthorization, oauth1Authorization, presignedPath, sigv4Headers, waitMs } from "./journey-kit.js";
20
20
  import { lanesOf, lineShape, shapeChecker } from "./shape.js";
21
+ import { walkPackDirectory } from "./pack-directory.js";
21
22
  import { xmlMembers } from "./xml-view.js";
22
23
  /** The pack repository the walk finds a vendor's pack in, set by the caller before its first walk. */
23
24
  let packsRoot;
@@ -31,6 +32,8 @@ function socketAt(open, host) {
31
32
  const baselineFacts = packFactsDocument.packs;
32
33
  let walkFacts = baselineFacts;
33
34
  let walkHosts = createHostTable(walkFacts).hosts;
35
+ const directories = new Map();
36
+ const installedFacts = new Set();
34
37
  export function usePacks(dir) {
35
38
  packsRoot = dir;
36
39
  const installed = {};
@@ -40,12 +43,34 @@ export function usePacks(dir) {
40
43
  Object.assign(installed, JSON.parse(readFileSync(file, 'utf8')).packs);
41
44
  }
42
45
  walkFacts = { ...baselineFacts, ...installed };
46
+ installedFacts.clear();
47
+ for (const vendor of Object.keys(installed))
48
+ installedFacts.add(vendor);
43
49
  walkHosts = createHostTable(walkFacts, Object.keys(installed)).hosts;
44
50
  shapes.clear();
45
51
  fieldsByVendor.clear();
52
+ directories.clear();
46
53
  }
47
54
  const packsDir = () => { if (packsRoot === undefined)
48
55
  throw new Error('usePacks(<packs dir>) first'); return packsRoot; };
56
+ function directoryFor(vendor) {
57
+ if (!directories.has(vendor)) {
58
+ const directory = walkPackDirectory(packsDir(), vendor);
59
+ directories.set(vendor, directory);
60
+ if (directory) {
61
+ const name = vendor.split('/')[0];
62
+ const root = vendor.includes('/') ? join(directory, '..') : directory;
63
+ const facts = join(root, 'generated', 'pack-facts.json');
64
+ if (existsSync(facts)) {
65
+ const document = JSON.parse(readFileSync(facts, 'utf8'));
66
+ walkFacts = { ...walkFacts, ...document.packs };
67
+ installedFacts.add(name);
68
+ walkHosts = createHostTable(walkFacts, [...installedFacts]).hosts;
69
+ }
70
+ }
71
+ }
72
+ return directories.get(vendor) ?? join(packsDir(), vendor);
73
+ }
49
74
  /** The walk's World: the twin's own code on its in-memory World and blob stores (the backends a serverless
50
75
  * entry runs on), so a walk of any length is state changes in memory and never touches the disk; the World
51
76
  * clock, pinned to 2026-01-01, is world state in the same store, and the World is sealed. Each root is a fresh key
@@ -97,10 +122,11 @@ function defaultType(body) {
97
122
  const vendorFetch = (vendor) => vendorFetchFrom(packsDir(), vendor);
98
123
  const shapes = new Map();
99
124
  const shapeOf = (vendor) => { if (!shapes.has(vendor))
100
- shapes.set(vendor, shapeChecker(join(packsDir(), vendor))); return shapes.get(vendor); };
125
+ shapes.set(vendor, shapeChecker(directoryFor(vendor))); return shapes.get(vendor); };
101
126
  /** The routing keys a pack answers under: its descriptor's host rules (pack-facts), each rule's `key` or the vendor's own
102
127
  * name, as vendor-hosts.cjs compiles them. */
103
128
  function routingKeys(vendor) {
129
+ directoryFor(vendor);
104
130
  const name = vendor.split('/')[0];
105
131
  const hosts = walkFacts[name]?.hosts ?? [];
106
132
  return [...new Set(hosts.map((rule) => rule.key ?? name))].filter((key) => walkHosts[key] !== undefined);
@@ -151,7 +177,8 @@ const fieldsByVendor = new Map();
151
177
  function specFields(vendor) {
152
178
  if (!fieldsByVendor.has(vendor)) {
153
179
  // the pack's surface and each of its lanes' (a walk reaches a lane through the pack's router)
154
- const files = [join(packsDir(), vendor), ...lanesOf(join(packsDir(), vendor))].map((dir) => join(dir, 'src', 'generated', 'surface.gen.json')).filter((f) => existsSync(f));
180
+ const directory = directoryFor(vendor);
181
+ const files = [directory, ...lanesOf(directory)].map((dir) => join(dir, 'src', 'generated', 'surface.gen.json')).filter((f) => existsSync(f));
155
182
  const surfaces = files.map((f) => parseExactJson(readFileSync(f, 'utf8')));
156
183
  fieldsByVendor.set(vendor, new Set(surfaces.flatMap((surface) => (surface.resources ?? []).flatMap((r) => r.fields.map((f) => f.name)))));
157
184
  }
@@ -213,7 +240,7 @@ export async function walk(journey, root, collect, opts) {
213
240
  const companionOf = (url) => (claims(ownKeys, url) ? undefined : companions.find((c) => claims(c.keys, url)));
214
241
  // the life's scenario is the World's: written into the walk's World store, which the pack reads it from as a World's
215
242
  // handlers/<vendor>.json is read
216
- const scenarioPath = journey.scenario ? join(packsDir(), journey.vendor, 'journeys', journey.scenario) : undefined;
243
+ const scenarioPath = journey.scenario ? join(directoryFor(journey.vendor), 'journeys', journey.scenario) : undefined;
217
244
  if (scenarioPath)
218
245
  getActiveWorldStore().write(scenarioPath, readFileSync(scenarioPath, 'utf8'));
219
246
  // the application the vendor asks (ctx.ask) is the life's stand-in, this walk's fetch's alone: its answers, in order,
@@ -311,7 +338,7 @@ export async function walk(journey, root, collect, opts) {
311
338
  // replies each line drew; its answer is checked as a request's is (status, SHAPE, captures, expectations).
312
339
  const connections = new Map();
313
340
  let streams;
314
- const lines = lineShape(join(packsDir(), journey.vendor));
341
+ const lines = lineShape(directoryFor(journey.vendor));
315
342
  const encoder = new TextEncoder();
316
343
  const decoder = new TextDecoder();
317
344
  const speak = async (step) => {
@@ -953,7 +980,7 @@ export async function walk(journey, root, collect, opts) {
953
980
  }
954
981
  }
955
982
  const serving = companionOf(path)?.vendor ?? journey.vendor;
956
- const graphqlBody = existsSync(join(packsDir(), serving, 'src', 'generated', 'graphql-sdl.gen.json'));
983
+ const graphqlBody = existsSync(join(directoryFor(serving), 'src', 'generated', 'graphql-sdl.gen.json'));
957
984
  let body;
958
985
  let headers;
959
986
  // a form's bytes, built before anything signs the request, so a signature covers what is sent
@@ -0,0 +1 @@
1
+ export declare function walkPackDirectory(from: string, vendor: string): string | undefined;
@@ -0,0 +1,15 @@
1
+ // Source siblings and installed companions use the kernel's existing package identity and selection rules.
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { installedVendorPacks, isDerivedPack, packVendor } from '@volter/world-core/runtime';
5
+ export function walkPackDirectory(from, vendor) {
6
+ if (!/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(vendor))
7
+ return undefined;
8
+ const [name, lane] = vendor.split('/');
9
+ const sibling = join(from, name);
10
+ const root = isDerivedPack(sibling) && packVendor(sibling) === name
11
+ ? sibling
12
+ : installedVendorPacks(from, { vendors: [name] }).get(name);
13
+ const unit = root && (lane ? join(root, lane) : root);
14
+ return unit && existsSync(join(unit, 'src', 'index.ts')) ? unit : undefined;
15
+ }
@@ -12,10 +12,14 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
12
12
  import { join } from 'node:path';
13
13
  import { startPgliteHost } from "./walk-database.js";
14
14
  import { worldNow } from '@volter/world-core/runtime';
15
+ import { walkPackDirectory } from "./pack-directory.js";
15
16
  export async function vendorFetch(twinDir, vendor) {
17
+ const directory = walkPackDirectory(twinDir, vendor);
18
+ if (!directory)
19
+ return undefined;
16
20
  let mod;
17
21
  try {
18
- mod = (await import(__rewriteRelativeImportExtension(join(twinDir, vendor, 'src', 'index.ts'))));
22
+ mod = (await import(__rewriteRelativeImportExtension(join(directory, 'src', 'index.ts'))));
19
23
  }
20
24
  catch {
21
25
  return undefined;
@@ -57,16 +61,21 @@ const jwtView = (field) => (body) => {
57
61
  };
58
62
  export async function vendorAnswerViews(twinDir, vendor) {
59
63
  let own = {};
64
+ const directory = walkPackDirectory(twinDir, vendor);
60
65
  try {
61
- own = (await import(__rewriteRelativeImportExtension(join(twinDir, vendor, 'src', 'index.ts')))).answerViews ?? {};
66
+ if (directory)
67
+ own = (await import(__rewriteRelativeImportExtension(join(directory, 'src', 'index.ts')))).answerViews ?? {};
62
68
  }
63
69
  catch { /* none of its own */ }
64
70
  return new Proxy(own, { get: (views, name) => (typeof name === 'string' && name.startsWith('jwt:') ? jwtView(name.slice(4)) : views[name]) });
65
71
  }
66
72
  export async function vendorStream(twinDir, vendor) {
73
+ const directory = walkPackDirectory(twinDir, vendor);
74
+ if (!directory)
75
+ return undefined;
67
76
  let mod;
68
77
  try {
69
- mod = (await import(__rewriteRelativeImportExtension(join(twinDir, vendor, 'src', 'index.ts'))));
78
+ mod = (await import(__rewriteRelativeImportExtension(join(directory, 'src', 'index.ts'))));
70
79
  }
71
80
  catch {
72
81
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-standard",
3
- "version": "1.0.85",
3
+ "version": "1.0.87",
4
4
  "description": "The Protocol 3 standard for Volter twin packs: the criteria a pack is graded by, the grader, the gate a pack repository and the twin catalog run on every change and submission, and the spec derivation the grade checks against. Pin a version: every place a pack is judged judges by that standard.",
5
5
  "keywords": [
6
6
  "twin",
@@ -75,7 +75,7 @@
75
75
  "yaml": "2.9.0"
76
76
  },
77
77
  "peerDependencies": {
78
- "@volter/world-core": "3.0.93",
78
+ "@volter/world-core": "3.0.95",
79
79
  "@volter/world-runtime": "*",
80
80
  "playwright": "^1.63.0"
81
81
  },
@@ -19,6 +19,7 @@ import { createHostTable, type HostFacts } from '@volter/world-core/host-routing
19
19
  import packFactsDocument from '@volter/world-core/generated/pack-facts.json' with { type: 'json' };
20
20
  import { type Captured, type GitStep, type Journey, type JourneyStep, type LineStep, type SocketStep, type SqlStep, type RespStep, type MysqlStep, isMysql, isResp, at, captureAt, echoFailures, expandFills, expectFailures, fill, fillJson, formBody, isGit, isLine, isSql, isSocket, isWait, jwtAuthorization, oauth1Authorization, presignedPath, sigv4Headers, waitMs } from './journey-kit.ts';
21
21
  import { lanesOf, lineShape, shapeChecker, type LineConnection, type ShapeChecker } from './shape.ts';
22
+ import { walkPackDirectory } from './pack-directory.ts';
22
23
  import { xmlMembers } from './xml-view.ts';
23
24
 
24
25
  /** The pack repository the walk finds a vendor's pack in, set by the caller before its first walk. */
@@ -33,6 +34,8 @@ function socketAt(open: string, host: string): { host: string; path: string } {
33
34
  const baselineFacts = packFactsDocument.packs as unknown as HostFacts;
34
35
  let walkFacts: HostFacts = baselineFacts;
35
36
  let walkHosts = createHostTable(walkFacts).hosts;
37
+ const directories = new Map<string, string | undefined>();
38
+ const installedFacts = new Set<string>();
36
39
  export function usePacks(dir: string): void {
37
40
  packsRoot = dir;
38
41
  const installed: Record<string, HostFacts[string]> = {};
@@ -41,10 +44,31 @@ export function usePacks(dir: string): void {
41
44
  if (existsSync(file)) Object.assign(installed, JSON.parse(readFileSync(file, 'utf8')).packs);
42
45
  }
43
46
  walkFacts = { ...baselineFacts, ...installed };
47
+ installedFacts.clear();
48
+ for (const vendor of Object.keys(installed)) installedFacts.add(vendor);
44
49
  walkHosts = createHostTable(walkFacts, Object.keys(installed)).hosts;
45
50
  shapes.clear(); fieldsByVendor.clear();
51
+ directories.clear();
46
52
  }
47
53
  const packsDir = (): string => { if (packsRoot === undefined) throw new Error('usePacks(<packs dir>) first'); return packsRoot; };
54
+ function directoryFor(vendor: string): string {
55
+ if (!directories.has(vendor)) {
56
+ const directory = walkPackDirectory(packsDir(), vendor);
57
+ directories.set(vendor, directory);
58
+ if (directory) {
59
+ const name = vendor.split('/')[0]!;
60
+ const root = vendor.includes('/') ? join(directory, '..') : directory;
61
+ const facts = join(root, 'generated', 'pack-facts.json');
62
+ if (existsSync(facts)) {
63
+ const document = JSON.parse(readFileSync(facts, 'utf8')) as { packs: HostFacts };
64
+ walkFacts = { ...walkFacts, ...document.packs };
65
+ installedFacts.add(name);
66
+ walkHosts = createHostTable(walkFacts, [...installedFacts]).hosts;
67
+ }
68
+ }
69
+ }
70
+ return directories.get(vendor) ?? join(packsDir(), vendor);
71
+ }
48
72
 
49
73
  /** The walk's World: the twin's own code on its in-memory World and blob stores (the backends a serverless
50
74
  * entry runs on), so a walk of any length is state changes in memory and never touches the disk; the World
@@ -85,11 +109,12 @@ function defaultType(body: unknown): string {
85
109
  }
86
110
  const vendorFetch = (vendor: string) => vendorFetchFrom(packsDir(), vendor);
87
111
  const shapes = new Map<string, Promise<ShapeChecker | undefined>>();
88
- const shapeOf = (vendor: string): Promise<ShapeChecker | undefined> => { if (!shapes.has(vendor)) shapes.set(vendor, shapeChecker(join(packsDir(), vendor))); return shapes.get(vendor)!; };
112
+ const shapeOf = (vendor: string): Promise<ShapeChecker | undefined> => { if (!shapes.has(vendor)) shapes.set(vendor, shapeChecker(directoryFor(vendor))); return shapes.get(vendor)!; };
89
113
 
90
114
  /** The routing keys a pack answers under: its descriptor's host rules (pack-facts), each rule's `key` or the vendor's own
91
115
  * name, as vendor-hosts.cjs compiles them. */
92
116
  function routingKeys(vendor: string): string[] {
117
+ directoryFor(vendor);
93
118
  const name = vendor.split('/')[0]!;
94
119
  const hosts = walkFacts[name]?.hosts ?? [];
95
120
  return [...new Set(hosts.map((rule) => rule.key ?? name))].filter((key) => walkHosts[key] !== undefined);
@@ -132,7 +157,8 @@ const fieldsByVendor = new Map<string, Set<string>>();
132
157
  function specFields(vendor: string): Set<string> {
133
158
  if (!fieldsByVendor.has(vendor)) {
134
159
  // the pack's surface and each of its lanes' (a walk reaches a lane through the pack's router)
135
- const files = [join(packsDir(), vendor), ...lanesOf(join(packsDir(), vendor))].map((dir) => join(dir, 'src', 'generated', 'surface.gen.json')).filter((f) => existsSync(f));
160
+ const directory = directoryFor(vendor);
161
+ const files = [directory, ...lanesOf(directory)].map((dir) => join(dir, 'src', 'generated', 'surface.gen.json')).filter((f) => existsSync(f));
136
162
  const surfaces = files.map((f) => parseExactJson(readFileSync(f, 'utf8')) as { resources?: Array<{ fields: Array<{ name: string }> }> });
137
163
  fieldsByVendor.set(vendor, new Set(surfaces.flatMap((surface) => (surface.resources ?? []).flatMap((r) => r.fields.map((f) => f.name)))));
138
164
  }
@@ -200,7 +226,7 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
200
226
  const companionOf = (url: string) => (claims(ownKeys, url) ? undefined : companions.find((c) => claims(c.keys, url)));
201
227
  // the life's scenario is the World's: written into the walk's World store, which the pack reads it from as a World's
202
228
  // handlers/<vendor>.json is read
203
- const scenarioPath = journey.scenario ? join(packsDir(), journey.vendor, 'journeys', journey.scenario) : undefined;
229
+ const scenarioPath = journey.scenario ? join(directoryFor(journey.vendor), 'journeys', journey.scenario) : undefined;
204
230
  if (scenarioPath) getActiveWorldStore().write(scenarioPath, readFileSync(scenarioPath, 'utf8'));
205
231
  // the application the vendor asks (ctx.ask) is the life's stand-in, this walk's fetch's alone: its answers, in order,
206
232
  // by method and URL prefix, each request header it declares checked as sent; a question none takes is unreachable, as
@@ -276,7 +302,7 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
276
302
  // replies each line drew; its answer is checked as a request's is (status, SHAPE, captures, expectations).
277
303
  const connections = new Map<string, Connection>();
278
304
  let streams: VendorStreamFactory | undefined;
279
- const lines = lineShape(join(packsDir(), journey.vendor));
305
+ const lines = lineShape(directoryFor(journey.vendor));
280
306
  const encoder = new TextEncoder();
281
307
  const decoder = new TextDecoder();
282
308
  const speak = async (step: LineStep): Promise<void> => {
@@ -662,7 +688,7 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
662
688
  // a presigned URL is signed again with the key that presigned it, as its client's SDK signed it
663
689
  if (step.presign) { try { path = presignedPath(step.presign, captured, step.method, path, host, fillJson({ ...(step.bodyBase64 === undefined ? { 'content-type': defaultType(step.body) } : {}), ...(journey.headers ?? {}), ...(step.headers ?? {}) }, captured) as Record<string, string>); } catch (e) { collect.push({ step: step.name, beat: 'CAPTURE', detail: (e as Error).message }); continue; } }
664
690
  const serving = companionOf(path)?.vendor ?? journey.vendor;
665
- const graphqlBody = existsSync(join(packsDir(), serving, 'src', 'generated', 'graphql-sdl.gen.json'));
691
+ const graphqlBody = existsSync(join(directoryFor(serving), 'src', 'generated', 'graphql-sdl.gen.json'));
666
692
  let body: unknown;
667
693
  let headers: Record<string, string> | undefined;
668
694
  // a form's bytes, built before anything signs the request, so a signature covers what is sent
@@ -0,0 +1,15 @@
1
+ // Source siblings and installed companions use the kernel's existing package identity and selection rules.
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { installedVendorPacks, isDerivedPack, packVendor } from '@volter/world-core/runtime';
5
+
6
+ export function walkPackDirectory(from: string, vendor: string): string | undefined {
7
+ if (!/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(vendor)) return undefined;
8
+ const [name, lane] = vendor.split('/');
9
+ const sibling = join(from, name!);
10
+ const root = isDerivedPack(sibling) && packVendor(sibling) === name
11
+ ? sibling
12
+ : installedVendorPacks(from, { vendors: [name!] }).get(name!);
13
+ const unit = root && (lane ? join(root, lane) : root);
14
+ return unit && existsSync(join(unit, 'src', 'index.ts')) ? unit : undefined;
15
+ }
@@ -5,6 +5,7 @@ import { join } from 'node:path';
5
5
  import { type PgliteHost, startPgliteHost } from './walk-database.ts';
6
6
  import { type TwinStream, worldNow } from '@volter/world-core/runtime';
7
7
  import type { PackFetchOptions } from '@volter/world-core';
8
+ import { walkPackDirectory } from './pack-directory.ts';
8
9
 
9
10
  type ApplicationStandIn = NonNullable<PackFetchOptions['application']>;
10
11
 
@@ -13,8 +14,10 @@ type ApplicationStandIn = NonNullable<PackFetchOptions['application']>;
13
14
  export type VendorFetchFactory = (root: string, options?: { scenarioPath?: string; application?: ApplicationStandIn }) => (request: Request) => Response | Promise<Response>;
14
15
 
15
16
  export async function vendorFetch(twinDir: string, vendor: string): Promise<VendorFetchFactory | undefined> {
17
+ const directory = walkPackDirectory(twinDir, vendor);
18
+ if (!directory) return undefined;
16
19
  let mod: Record<string, unknown>;
17
- try { mod = (await import(join(twinDir, vendor, 'src', 'index.ts'))) as Record<string, unknown>; } catch { return undefined; }
20
+ try { mod = (await import(join(directory, 'src', 'index.ts'))) as Record<string, unknown>; } catch { return undefined; }
18
21
  // a pack exports create<Name>Fetch (its generated fetch.ts)
19
22
  const name = Object.keys(mod).find((k) => /^create\w+?Fetch$/.test(k) && !/TwinFetch$/.test(k) && typeof mod[k] === 'function');
20
23
  if (!name) return undefined;
@@ -51,8 +54,9 @@ const jwtView = (field: string) => (body: unknown): unknown => {
51
54
 
52
55
  export async function vendorAnswerViews(twinDir: string, vendor: string): Promise<AnswerViews> {
53
56
  let own: AnswerViews = {};
57
+ const directory = walkPackDirectory(twinDir, vendor);
54
58
  try {
55
- own = ((await import(join(twinDir, vendor, 'src', 'index.ts'))) as { answerViews?: AnswerViews }).answerViews ?? {};
59
+ if (directory) own = ((await import(join(directory, 'src', 'index.ts'))) as { answerViews?: AnswerViews }).answerViews ?? {};
56
60
  } catch { /* none of its own */ }
57
61
  return new Proxy(own, { get: (views, name) => (typeof name === 'string' && name.startsWith('jwt:') ? jwtView(name.slice(4)) : views[name as string]) });
58
62
  }
@@ -62,8 +66,10 @@ export async function vendorAnswerViews(twinDir: string, vendor: string): Promis
62
66
  export type VendorStreamFactory = (root: string, options?: Record<string, unknown>) => TwinStream;
63
67
 
64
68
  export async function vendorStream(twinDir: string, vendor: string): Promise<VendorStreamFactory | undefined> {
69
+ const directory = walkPackDirectory(twinDir, vendor);
70
+ if (!directory) return undefined;
65
71
  let mod: Record<string, unknown>;
66
- try { mod = (await import(join(twinDir, vendor, 'src', 'index.ts'))) as Record<string, unknown>; } catch { return undefined; }
72
+ try { mod = (await import(join(directory, 'src', 'index.ts'))) as Record<string, unknown>; } catch { return undefined; }
67
73
  const name = Object.keys(mod).find((k) => /^create\w+TwinStream$/.test(k) && typeof mod[k] === 'function');
68
74
  if (!name) return undefined;
69
75
  const factory = mod[name] as (options: Record<string, unknown>) => TwinStream;