@volter/world-core 3.0.156 → 3.0.157

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 (74) hide show
  1. package/attach.cjs +2 -0
  2. package/capability-decision.cjs +6 -4
  3. package/dist/attach.cjs +2 -0
  4. package/dist/capability-decision.cjs +6 -4
  5. package/dist/generated/pack-facts.json +77 -8
  6. package/dist/network-policy.cjs +11 -1
  7. package/dist/network-policy.d.cts +1 -0
  8. package/dist/pack-facts.d.cts +3 -0
  9. package/dist/required-credential-transport.cjs +29 -0
  10. package/dist/required-credential-transport.d.cts +3 -0
  11. package/dist/src/blob-store.d.ts +16 -0
  12. package/dist/src/blob-store.js +76 -1
  13. package/dist/src/derived-core.d.ts +72 -6
  14. package/dist/src/derived-core.js +192 -51
  15. package/dist/src/derived-real.js +97 -15
  16. package/dist/src/derived.d.ts +5 -0
  17. package/dist/src/executor.d.ts +7 -0
  18. package/dist/src/executor.js +15 -1
  19. package/dist/src/git/lfs.d.ts +13 -3
  20. package/dist/src/git/lfs.js +41 -9
  21. package/dist/src/head.d.ts +2 -0
  22. package/dist/src/head.js +6 -0
  23. package/dist/src/index.d.ts +1 -0
  24. package/dist/src/index.js +1 -0
  25. package/dist/src/live/ingest.js +9 -13
  26. package/dist/src/live/rtmp.js +7 -5
  27. package/dist/src/live/segmenter.js +7 -1
  28. package/dist/src/machines.js +5 -1
  29. package/dist/src/managed-go-programs.d.ts +55 -0
  30. package/dist/src/managed-go-programs.js +133 -0
  31. package/dist/src/mongodb/stream.d.ts +23 -0
  32. package/dist/src/pack-fetch.d.ts +6 -1
  33. package/dist/src/pack-fetch.js +49 -6
  34. package/dist/src/pack-paths.d.ts +2 -1
  35. package/dist/src/pack-paths.js +6 -1
  36. package/dist/src/resource-blob.d.ts +4 -0
  37. package/dist/src/resource-blob.js +8 -1
  38. package/dist/src/runtime.d.ts +3 -3
  39. package/dist/src/runtime.js +2 -2
  40. package/dist/src/serve-http.js +53 -3
  41. package/dist/src/sockets.d.ts +4 -1
  42. package/dist/src/sockets.js +59 -6
  43. package/dist/src/vendor-call.js +58 -0
  44. package/dist/src/world-store.d.ts +15 -1
  45. package/dist/src/world-store.js +78 -2
  46. package/generated/pack-facts.json +77 -8
  47. package/network-policy.cjs +11 -1
  48. package/network-policy.d.cts +1 -0
  49. package/pack-facts.d.cts +3 -0
  50. package/package.json +8 -1
  51. package/required-credential-transport.cjs +29 -0
  52. package/required-credential-transport.d.cts +3 -0
  53. package/src/blob-store.ts +59 -1
  54. package/src/derived-core.ts +215 -51
  55. package/src/derived-real.ts +80 -14
  56. package/src/derived.ts +6 -1
  57. package/src/executor.ts +17 -3
  58. package/src/git/lfs.ts +40 -9
  59. package/src/head.ts +6 -0
  60. package/src/index.ts +1 -0
  61. package/src/live/ingest.ts +7 -3
  62. package/src/live/rtmp.ts +7 -5
  63. package/src/live/segmenter.ts +7 -1
  64. package/src/machines.ts +5 -1
  65. package/src/managed-go-programs.ts +146 -0
  66. package/src/mongodb/stream.ts +10 -0
  67. package/src/pack-fetch.ts +46 -8
  68. package/src/pack-paths.ts +5 -1
  69. package/src/resource-blob.ts +9 -1
  70. package/src/runtime.ts +4 -2
  71. package/src/serve-http.ts +43 -3
  72. package/src/sockets.ts +39 -8
  73. package/src/vendor-call.ts +54 -0
  74. package/src/world-store.ts +66 -2
@@ -1,3 +1,12 @@
1
+ // A vendor's persistent wire (architecture, "Other wires: sockets"): a WebSocket its clients hold open, on which the
2
+ // vendor sends what happens as it happens (Discord's Gateway: a bot identifies, is told the guilds it is in, and is sent
3
+ // each message, member and interaction as it lands). The manifest declares the socket (`sockets`); the pack's engine
4
+ // (`semantics/sockets.ts`, one export per socket id) speaks its protocol: what a session is sent when it opens, what it
5
+ // answers each frame, and which frames a write of the World sends it. The kernel holds the open sessions, serves the
6
+ // upgrade through the serve seam, and offers every write to every open session of the vendor, after the write's
7
+ // webhooks. A session's own counters (a sequence number, a heartbeat) are the connection's, never the World's state.
8
+ // Nothing here runs at module scope beyond the empty registry.
9
+ import { worldNow } from "./world-clock.js";
1
10
  const sessions = new Map();
2
11
  /** A World's next session number, per World (its service and root): a session's id is the World's, never the
3
12
  * process's, so a life replayed on a fresh World numbers its sessions as it did the first time. */
@@ -7,6 +16,21 @@ const keyOf = (service, root) => `${service}\0${root ?? ''}`;
7
16
  export function openSessions(service, root, socket) {
8
17
  return [...(sessions.get(keyOf(service, root)) ?? [])].filter((o) => o.session.socket === socket).map((o) => o.session);
9
18
  }
19
+ /** What a session awaits that the World's clock has run out (a life's `wait` past a relay's timeout), rejected as the
20
+ * machine's clock would reject it; called as the vendor serves a request ("A request answered by a session"). */
21
+ export function expireSocketWaits(service, root) {
22
+ const open = sessions.get(keyOf(service, root));
23
+ if (!open?.size)
24
+ return;
25
+ const now = Date.parse(worldNow());
26
+ for (const o of open)
27
+ for (const [k, p] of o.pending)
28
+ if (p.due <= now) {
29
+ clearTimeout(p.timer);
30
+ o.pending.delete(k);
31
+ p.reject(new Error('no reply in time'));
32
+ }
33
+ }
10
34
  /** Offer a write to every open session of the vendor, each in its turn after what it is already doing. Queued, never
11
35
  * awaited: the write may be one a session's own frame made, which that session finishes before it is told. */
12
36
  export function socketWrite(service, root, write) {
@@ -20,12 +44,41 @@ export function socketWrite(service, root, write) {
20
44
  o.queue = o.queue.then(async () => engine.write(o.session, write, await o.context())).catch((error) => o.session.close(1011, String(error.message ?? error).slice(0, 120)));
21
45
  }
22
46
  }
47
+ /** A declared socket path's parameters for a request's path, or undefined when it does not match: a `{name}` segment
48
+ * matches one segment, as an operation's path parameter does (architecture, sockets). */
49
+ function socketParams(declared, path) {
50
+ const names = [];
51
+ const pattern = (declared.replace(/\/+$/, '') || '/').split(/(\{[^}/]+\})/).map((part) => {
52
+ const name = /^\{([^}/]+)\}$/.exec(part)?.[1];
53
+ if (name === undefined)
54
+ return part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
55
+ names.push(name);
56
+ return '([^/]+)';
57
+ }).join('');
58
+ const hit = new RegExp(`^${pattern}$`).exec(path);
59
+ if (!hit)
60
+ return undefined;
61
+ try {
62
+ return Object.fromEntries(names.map((name, i) => [name, decodeURIComponent(hit[i + 1])]));
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ }
23
68
  /** The upgrade the serve seam takes: a request to a declared socket's path (and host) opens a session of its engine. */
24
69
  export function socketUpgrade(service, root, decls, engines, context, hostOf, pathOf = (request) => new URL(request.url).pathname, decide = async () => undefined) {
25
- const declFor = (request) => decls.find((d) => {
70
+ const matchFor = (request) => {
26
71
  const path = pathOf(request).replace(/\/+$/, '') || '/';
27
- return (d.path.replace(/\/+$/, '') || '/') === path && (!d.host || d.host.toLowerCase() === hostOf(request)) && engines[d.id] !== undefined;
28
- });
72
+ for (const d of decls) {
73
+ if ((d.host && d.host.toLowerCase() !== hostOf(request)) || engines[d.id] === undefined)
74
+ continue;
75
+ const params = socketParams(d.path, path);
76
+ if (params)
77
+ return { decl: d, params };
78
+ }
79
+ return undefined;
80
+ };
81
+ const declFor = (request) => matchFor(request)?.decl;
29
82
  const byPeer = new WeakMap();
30
83
  const key = keyOf(service, root);
31
84
  return {
@@ -38,7 +91,7 @@ export function socketUpgrade(service, root, decls, engines, context, hostOf, pa
38
91
  return declared ? offered.find((p) => declared.includes(p)) : offered[0];
39
92
  },
40
93
  open: (peer, request) => {
41
- const decl = declFor(request);
94
+ const { decl, params } = matchFor(request);
42
95
  const engine = engines[decl.id];
43
96
  const pending = new Map();
44
97
  const session = {
@@ -47,7 +100,7 @@ export function socketUpgrade(service, root, decls, engines, context, hostOf, pa
47
100
  close: (code, reason) => { peer.close(code, reason); },
48
101
  expect: (key, ms) => new Promise((resolve, reject) => {
49
102
  const timer = setTimeout(() => { pending.delete(key); reject(new Error('no reply in time')); }, ms);
50
- pending.set(key, { resolve, reject, timer });
103
+ pending.set(key, { resolve, reject, timer, due: Date.parse(worldNow()) + ms });
51
104
  }),
52
105
  fulfil: (key, value) => {
53
106
  const p = pending.get(key);
@@ -60,7 +113,7 @@ export function socketUpgrade(service, root, decls, engines, context, hostOf, pa
60
113
  },
61
114
  decide,
62
115
  };
63
- const o = { session, engine, context: () => context(request.clone(), decl), queue: Promise.resolve(), pending };
116
+ const o = { session, engine, context: () => context(request.clone(), decl, params), queue: Promise.resolve(), pending };
64
117
  byPeer.set(peer, o);
65
118
  (sessions.get(key) ?? sessions.set(key, new Set()).get(key)).add(o);
66
119
  if (engine.open)
@@ -34,6 +34,52 @@ async function worldTwins() {
34
34
  }
35
35
  return { ...twinOrigins(env), ...twinOrigins(instanceEnv) };
36
36
  }
37
+ /** The hosts each claiming twin last listed at its `hostsClaimed` door, by the door's address, and when; read again
38
+ * after CLAIMS_TTL_MS or for a host it lacks, as the injector polls the doors every five seconds (inject.cjs, "HOSTS A TWIN CLAIMS WHILE IT
39
+ * RUNS"). */
40
+ const claimsRead = new Map();
41
+ const CLAIMS_TTL_MS = 5_000;
42
+ /** The hosts a twin claims at its door: in process (a journey walk's companion) or at its address, within the injector's
43
+ * first-read deadline (inject.cjs CLAIMS_WAIT_MS, 1500 ms, measured beside it); a door that does not answer claims
44
+ * nothing. */
45
+ async function claimedHosts(at, ask, host) {
46
+ const held = claimsRead.get(at);
47
+ // a host the held list lacks is asked for again once, as the injector refreshes before it refuses: a domain claimed a
48
+ // moment ago is found
49
+ if (held && Date.now() - held.at < CLAIMS_TTL_MS && held.hosts.has(host))
50
+ return held.hosts;
51
+ let hosts = new Set();
52
+ try {
53
+ const r = await ask();
54
+ const body = r.ok ? await r.json() : null;
55
+ hosts = new Set((body?.hosts ?? []).map((h) => String(h).toLowerCase()));
56
+ }
57
+ catch { /* an unanswered door claims nothing */ }
58
+ claimsRead.set(at, { hosts, at: Date.now() });
59
+ return hosts;
60
+ }
61
+ /** The twin that claims a host at its `hostsClaimed` door (an R2 bucket's custom domain, a Worker's), as the injector
62
+ * routes it: a twin this process answers first, the World's twins after. */
63
+ async function claimingTwin(target, twins) {
64
+ const { packFacts } = await import('../pack-facts.cjs');
65
+ const host = target.hostname.toLowerCase();
66
+ const key = process.env.VOLTER_TWINS_KEY;
67
+ const doors = Object.entries(packFacts().packs).flatMap(([vendor, facts]) => (facts.hostsClaimed?.door ? [[vendor, facts.hostsClaimed.door]] : []));
68
+ for (const [vendor, door] of doors) {
69
+ const twin = inProcessTwins[vendor];
70
+ if (twin && (await claimedHosts(`in-process:${vendor}${door}`, async () => twin(new Request(`http://${vendor}.twin${door}`)), host)).has(host))
71
+ return { vendor, local: true };
72
+ }
73
+ for (const [vendor, door] of doors) {
74
+ const origin = twins[vendor];
75
+ if (origin === undefined)
76
+ continue;
77
+ const at = `${origin.replace(/\/$/, '')}${door}`;
78
+ if ((await claimedHosts(at, () => fetch(at, { headers: key ? { 'x-twins-key': key } : {}, signal: AbortSignal.timeout(1500) }), host)).has(host))
79
+ return { vendor, local: false };
80
+ }
81
+ return undefined;
82
+ }
37
83
  /** One URL answered only by a World-held application or vendor twin: the fetch's application stand-in first (its answer
38
84
  * is the application's; `'unreachable'` leaves no application to reach, the World's twins still reachable). */
39
85
  async function worldResponse(target, init, standIn) {
@@ -61,9 +107,21 @@ async function worldResponse(target, init, standIn) {
61
107
  headers.set('x-twins-key', key);
62
108
  return fetch(`${twins[vendor].replace(/\/$/, '')}${target.pathname}${target.search}`, { ...init, headers, redirect: 'manual' });
63
109
  }
110
+ // the application's own hosts before any twin's claimed ones: a call to the application asks no door
64
111
  const { appDestination, appFetch } = await import('../app-route.cjs');
65
112
  if (scripted !== 'unreachable' && appDestination(target))
66
113
  return appFetch(target, { ...init, redirect: 'manual' });
114
+ const claimer = await claimingTwin(target, twins);
115
+ if (claimer !== undefined) {
116
+ const headers = new Headers(init.headers);
117
+ headers.set('x-volter-twin-original-host', target.host);
118
+ if (claimer.local)
119
+ return inProcessTwins[claimer.vendor](new Request(target, { ...init, headers, redirect: 'manual' }));
120
+ const key = process.env.VOLTER_TWINS_KEY;
121
+ if (key && !headers.has('x-twins-key'))
122
+ headers.set('x-twins-key', key);
123
+ return fetch(`${twins[claimer.vendor].replace(/\/$/, '')}${target.pathname}${target.search}`, { ...init, headers, redirect: 'manual' });
124
+ }
67
125
  throw new VendorUnreachableError(`${target.host}${target.pathname}: this World holds no application or vendor twin at this URL`);
68
126
  }
69
127
  /** A vendor URL (or the World's application), including redirects, always answered inside the World; `standIn` is the
@@ -13,7 +13,21 @@ export type WorldLockOptions = {
13
13
  operation?: string;
14
14
  caller?: string;
15
15
  };
16
- /** Capture at the outermost lock helper, then carry the same caller through nested helpers. */
16
+ /**
17
+ * Capture at the outermost lock helper, then carry the same caller through nested helpers.
18
+ * LIMIT THE CAPTURE TO THE FRAMES READ (browser-substrate S2 R44, AC-LC3): V8's third frame supplies the caller,
19
+ * while new Error().stack normally collects up to Error.stackTraceLimit frames (ten by default).
20
+ * Retained browser-substrate LibreChat World-realm warm-up profiles 73/74 from runs 36c6d279 and 991f63e7e
21
+ * attributed about 10-57 ms self/inclusive to storageLockScope over each full 13.3-13.4 second profile window.
22
+ * Samples are about 5 ms apart. Those totals include this helper's capture, string and regex work; they are
23
+ * neither isolated capture time nor the credential doors' share. The co-located host serves doors on one loop.
24
+ * Original profiles are under /Users/aaronclaw/heavy-lead/librechat/logs-kept/:
25
+ * librechat-sn-36c6d279-e9e2632a-004051/cpuprofile/ (SHA256 prefixes 04dfc4fe, 77df6e8e) and
26
+ * librechat-sn-991f63e7e/cpuprofile/ (be6c6a93, 2fe80e7c), realms 73 and 74 respectively.
27
+ * The limit is lowered to three only for Error's own writable numeric data property above three, and restored
28
+ * only when lowered. Absent, accessor, non-writable and lower limits receive no writes. Existing constructor
29
+ * and user stack-formatter failure paths remain; this diagnostic optimization changes no lock ownership rule.
30
+ */
17
31
  export declare function storageLockScope(options?: WorldLockOptions): WorldLockOptions & {
18
32
  operation: string;
19
33
  caller: string;
@@ -28,9 +28,77 @@ import { hostname } from 'node:os';
28
28
  import { randomUUID } from 'node:crypto';
29
29
  import { refuseReadOnlyWrite } from "./request-scope.js";
30
30
  import { basename, dirname, join, resolve } from 'node:path';
31
- /** Capture at the outermost lock helper, then carry the same caller through nested helpers. */
31
+ // WHAT A LOCK HOLD ASKS (architecture, "What a hold asks is counted"): the file
32
+ // store's questions counted inside an outermost lock hold and outside one, said at each outermost release where
33
+ // VOLTER_TWIN_LOG=1 (storage.ts twinLog's gate and line), and not counted otherwise. Each counter counts the calls of
34
+ // its own method: a readKept that misses its kept text, or meets a link, also counts the read it makes. A hold's
35
+ // `heldMs` is the time of the hold's body, run once the lock is taken and before it is released, as the lock's release
36
+ // line times its hold; the wait before the take is the wait line's `waitedMs`.
37
+ const QUESTION_KINDS = ['generation', 'read', 'readKept', 'stat', 'exists', 'list', 'append'];
38
+ // Read once, where a process is: a realm with none counts nothing.
39
+ const questionsCounted = typeof process !== 'undefined' && process.env?.VOLTER_TWIN_LOG === '1';
40
+ const noQuestions = () => ({ generation: 0, read: 0, readKept: 0, stat: 0, exists: 0, list: 0, append: 0 });
41
+ let lockHoldDepth = 0;
42
+ let questionsHeld = noQuestions();
43
+ let questionsUnheld = noQuestions();
44
+ function asked(kind) {
45
+ if (questionsCounted)
46
+ (lockHoldDepth > 0 ? questionsHeld : questionsUnheld)[kind] += 1;
47
+ }
48
+ function countedHold(operation, fn) {
49
+ if (!questionsCounted)
50
+ return fn;
51
+ return () => {
52
+ const began = Date.now();
53
+ lockHoldDepth += 1;
54
+ try {
55
+ return fn();
56
+ }
57
+ finally {
58
+ lockHoldDepth -= 1;
59
+ if (lockHoldDepth === 0) {
60
+ const held = questionsHeld, before = questionsUnheld;
61
+ questionsHeld = noQuestions();
62
+ questionsUnheld = noQuestions();
63
+ try {
64
+ console.error('[twin:store-lock]', JSON.stringify({ operation, heldMs: Date.now() - began, held, before }));
65
+ }
66
+ catch { /* an instrument */ }
67
+ }
68
+ }
69
+ };
70
+ }
71
+ /**
72
+ * Capture at the outermost lock helper, then carry the same caller through nested helpers.
73
+ * LIMIT THE CAPTURE TO THE FRAMES READ (browser-substrate S2 R44, AC-LC3): V8's third frame supplies the caller,
74
+ * while new Error().stack normally collects up to Error.stackTraceLimit frames (ten by default).
75
+ * Retained browser-substrate LibreChat World-realm warm-up profiles 73/74 from runs 36c6d279 and 991f63e7e
76
+ * attributed about 10-57 ms self/inclusive to storageLockScope over each full 13.3-13.4 second profile window.
77
+ * Samples are about 5 ms apart. Those totals include this helper's capture, string and regex work; they are
78
+ * neither isolated capture time nor the credential doors' share. The co-located host serves doors on one loop.
79
+ * Original profiles are under /Users/aaronclaw/heavy-lead/librechat/logs-kept/:
80
+ * librechat-sn-36c6d279-e9e2632a-004051/cpuprofile/ (SHA256 prefixes 04dfc4fe, 77df6e8e) and
81
+ * librechat-sn-991f63e7e/cpuprofile/ (be6c6a93, 2fe80e7c), realms 73 and 74 respectively.
82
+ * The limit is lowered to three only for Error's own writable numeric data property above three, and restored
83
+ * only when lowered. Absent, accessor, non-writable and lower limits receive no writes. Existing constructor
84
+ * and user stack-formatter failure paths remain; this diagnostic optimization changes no lock ownership rule.
85
+ */
32
86
  export function storageLockScope(options = {}) {
33
- const frame = options.caller ? undefined : new Error().stack?.split('\n')[3];
87
+ let frame;
88
+ if (!options.caller) {
89
+ const held = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit');
90
+ const lowered = held !== undefined && 'value' in held && held.writable === true
91
+ && typeof held.value === 'number' && held.value > 3;
92
+ if (lowered)
93
+ Error.stackTraceLimit = 3;
94
+ try {
95
+ frame = new Error().stack?.split('\n')[3];
96
+ }
97
+ finally {
98
+ if (lowered)
99
+ Error.stackTraceLimit = held.value;
100
+ }
101
+ }
34
102
  const location = frame?.slice(frame.lastIndexOf('(') + 1).trim().replace(/^at\s+/, '');
35
103
  const site = location?.match(/^(.*):(\d+):\d+\)?$/);
36
104
  const caller = options.caller ?? (site ? `${site[1].replace(/^file:\/\//, '')}:${site[2]}` : 'unknown:0');
@@ -564,6 +632,7 @@ export class FsWorldStore {
564
632
  // pays a kernel exchange for each, and a tree's stamp is a handful of these on every operation: Twenty's Redis twin
565
633
  // spent 54 s of 136 in `existsSync` and `statSync` under `treeStamp`, and its server's requests waited on it.
566
634
  read(path) {
635
+ asked('read');
567
636
  try {
568
637
  return readFileSync(path, 'utf8');
569
638
  }
@@ -586,6 +655,7 @@ export class FsWorldStore {
586
655
  */
587
656
  kept = new Map();
588
657
  readKept(path) {
658
+ asked('readKept');
589
659
  // A missing file is asked for without an error being made of it: a World with no parent has no branch.json, and
590
660
  // every stamp asks.
591
661
  let own;
@@ -639,6 +709,7 @@ export class FsWorldStore {
639
709
  * World with a parent: its view and its ancestors' logs) is never kept under a generation (log.ts).
640
710
  */
641
711
  generation(dirPath) {
712
+ asked('generation');
642
713
  let own;
643
714
  try {
644
715
  own = lstatSync(join(dirPath, TREE_GENERATION), { throwIfNoEntry: false });
@@ -721,6 +792,7 @@ export class FsWorldStore {
721
792
  }
722
793
  }
723
794
  append(path, data) {
795
+ asked('append');
724
796
  refuseReadOnlyWrite('the World'); // a read-only request writes nothing, whatever path it takes to the store
725
797
  this.kept.delete(path);
726
798
  // A tree's file in a tab: the generation's byte, the append and the byte again as one request of the kernel
@@ -774,6 +846,7 @@ export class FsWorldStore {
774
846
  });
775
847
  }
776
848
  exists(path) {
849
+ asked('exists');
777
850
  return existsSync(path);
778
851
  }
779
852
  remove(path) {
@@ -787,6 +860,7 @@ export class FsWorldStore {
787
860
  mkdirSync(dirPath, { recursive: true });
788
861
  }
789
862
  list(dirPath) {
863
+ asked('list');
790
864
  try {
791
865
  return readdirSync(dirPath);
792
866
  }
@@ -818,6 +892,7 @@ export class FsWorldStore {
818
892
  }
819
893
  }
820
894
  stat(path) {
895
+ asked('stat');
821
896
  // The path itself first: where it is no link, that is the whole answer. A link is followed by a second call,
822
897
  // and one that leads nowhere is absent, as it was.
823
898
  // Asked without an error being made of a missing path (a tree's parent log is absent in a World with no parent).
@@ -852,6 +927,7 @@ export class FsWorldStore {
852
927
  withLock(lockPath, fn, options = {}) {
853
928
  const started = Date.now();
854
929
  const scope = storageLockScope(options);
930
+ fn = countedHold(scope.operation, fn);
855
931
  let fd = null;
856
932
  // A kernel's file step takes the lock with its record in one request and keeps no descriptor (fileSteps).
857
933
  const steps = fileSteps();
@@ -221,6 +221,50 @@
221
221
  },
222
222
  "serveExport": "createAxiomTwinServer"
223
223
  },
224
+ "bitly": {
225
+ "adoption": {
226
+ "sdks": [],
227
+ "envStems": [
228
+ "BITLY",
229
+ "BUFFER_BITLY"
230
+ ]
231
+ },
232
+ "hosts": [
233
+ {
234
+ "host": "api-ssl.bitly.com"
235
+ },
236
+ {
237
+ "host": "bitly.com",
238
+ "pathPattern": "^/oauth/authorize/?$"
239
+ }
240
+ ],
241
+ "archetype": "crud",
242
+ "protocol": {
243
+ "declared": "3",
244
+ "major": 3,
245
+ "standing": "current"
246
+ },
247
+ "transport": "rest",
248
+ "resources": [
249
+ "group",
250
+ "bitlink"
251
+ ],
252
+ "endpointEnvNone": "Dub uses literal vendor URLs and native fetch; the World routes them by host.",
253
+ "credentialDoor": {
254
+ "path": "/_twin/signup",
255
+ "body": {
256
+ "email": "publisher@example.test",
257
+ "password": "throwaway-bitly-password",
258
+ "login": "publisher"
259
+ },
260
+ "fill": {
261
+ "BITLY_CLIENT_ID": "client_id",
262
+ "BITLY_CLIENT_SECRET": "client_secret",
263
+ "BUFFER_BITLY_API_KEY": "access_token"
264
+ }
265
+ },
266
+ "serveExport": "createBitlyTwinServer"
267
+ },
224
268
  "cerebras": {
225
269
  "adoption": {
226
270
  "sdks": [
@@ -270,6 +314,9 @@
270
314
  {
271
315
  "host": "api.clerk.com"
272
316
  },
317
+ {
318
+ "host": "dashboard.clerk.com"
319
+ },
273
320
  {
274
321
  "suffix": ".clerk.accounts.dev"
275
322
  },
@@ -594,7 +641,7 @@
594
641
  },
595
642
  "transport": "rest",
596
643
  "resources": [],
597
- "endpointEnvNone": "Postiz calls https://api.deepgram.com/v1/listen; the World claims the host",
644
+ "endpointEnvNone": "No scanned application calls Deepgram; the World claims api.deepgram.com",
598
645
  "serveExport": "createDeepgramTwinServer"
599
646
  },
600
647
  "discord": {
@@ -842,7 +889,7 @@
842
889
  },
843
890
  "transport": "rest",
844
891
  "resources": [],
845
- "endpointEnvNone": "Postiz calls https://fal.run/fal-ai/<model>; the World claims the hosts",
892
+ "endpointEnvNone": "the customer life calls https://fal.run/fal-ai/<model>; the World claims the hosts",
846
893
  "credentialDoor": {
847
894
  "path": "/_twin/app-credentials",
848
895
  "body": {},
@@ -1012,7 +1059,7 @@
1012
1059
  },
1013
1060
  {
1014
1061
  "host": "github.com",
1015
- "pathPattern": "^/login|^/session|^/settings/|^/organizations/|^/apps/|^/[^/]+/[^/]+/(?:info/refs|git-upload-pack|git-receive-pack)$|^/[^/]+/[^/]+\\.git/"
1062
+ "pathPattern": "^/login|^/session|^/settings/|^/organizations/|^/apps/|^/[^/]+/[^/]+/(?:info/refs|git-upload-pack|git-receive-pack)$|^/[^/]+/[^/]+\\.git/|^/[^/]+/[^/]+/?$|^/[^/]+/[^/]+/(?:issues|pulls?|blob|raw|tree|commits?|compare)(?:/|$)"
1016
1063
  }
1017
1064
  ],
1018
1065
  "archetype": "crud",
@@ -1088,7 +1135,7 @@
1088
1135
  },
1089
1136
  {
1090
1137
  "host": "fonts.googleapis.com",
1091
- "pathPattern": "^/css$"
1138
+ "pathPattern": "^/css2?$"
1092
1139
  },
1093
1140
  {
1094
1141
  "host": "fonts.gstatic.com",
@@ -1417,8 +1464,7 @@
1417
1464
  "host": "api.linear.app"
1418
1465
  },
1419
1466
  {
1420
- "host": "linear.app",
1421
- "pathPattern": "^/oauth/"
1467
+ "host": "linear.app"
1422
1468
  }
1423
1469
  ],
1424
1470
  "archetype": "crud",
@@ -1438,7 +1484,7 @@
1438
1484
  "comment",
1439
1485
  "issue_label"
1440
1486
  ],
1441
- "endpointEnvNone": "Linear uses api.linear.app/graphql and linear.app/oauth/authorize; the World claims the documented hosts",
1487
+ "endpointEnvNone": "Linear uses api.linear.app/graphql and linear.app for its workspace and OAuth authorize page; the World claims those hosts",
1442
1488
  "credentialDoor": {
1443
1489
  "path": "/_twin/local-credentials",
1444
1490
  "body": {},
@@ -2048,6 +2094,10 @@
2048
2094
  "host": "reddit.com",
2049
2095
  "demandPathPattern": "^/api/"
2050
2096
  },
2097
+ {
2098
+ "host": "old.reddit.com",
2099
+ "demandPathPattern": "^/api/"
2100
+ },
2051
2101
  {
2052
2102
  "host": "reddit-uploaded-media.s3-accelerate.amazonaws.com"
2053
2103
  },
@@ -2163,6 +2213,10 @@
2163
2213
  },
2164
2214
  {
2165
2215
  "host": "inbound-cdn.resend.com"
2216
+ },
2217
+ {
2218
+ "host": "resend.com",
2219
+ "pathPattern": "^/emails(?:/|$)"
2166
2220
  }
2167
2221
  ],
2168
2222
  "archetype": "crud",
@@ -2319,6 +2373,9 @@
2319
2373
  ]
2320
2374
  },
2321
2375
  "hosts": [
2376
+ {
2377
+ "host": "app.slack.com"
2378
+ },
2322
2379
  {
2323
2380
  "host": "slack.com"
2324
2381
  },
@@ -2697,7 +2754,7 @@
2697
2754
  "publish",
2698
2755
  "video"
2699
2756
  ],
2700
- "endpointEnvNone": "Postiz calls open.tiktokapis.com and sends people to www.tiktok.com; the World claims the hosts",
2757
+ "endpointEnvNone": "an app calls open.tiktokapis.com and sends people to www.tiktok.com; the World claims the hosts",
2701
2758
  "credentialDoor": {
2702
2759
  "path": "/_twin/app-credentials",
2703
2760
  "body": {},
@@ -3280,6 +3337,18 @@
3280
3337
  "_code_challenge",
3281
3338
  "upload"
3282
3339
  ],
3340
+ "credentialDoor": {
3341
+ "path": "/_twin/app-credentials",
3342
+ "body": {},
3343
+ "fill": {
3344
+ "TWITTER_API_KEY": "consumer_key",
3345
+ "TWITTER_API_SECRET": "consumer_secret",
3346
+ "TWITTER_ACCESS_TOKEN": "access_token",
3347
+ "TWITTER_ACCESS_SECRET": "access_token_secret",
3348
+ "TWITTER_CLIENT_ID": "client_id",
3349
+ "TWITTER_CLIENT_SECRET": "client_secret"
3350
+ }
3351
+ },
3283
3352
  "serveExport": "createXTwinServer"
3284
3353
  },
3285
3354
  "xai": {
@@ -140,6 +140,16 @@ function allowsWorldNetworkEgress(policy, value, method = 'GET') {
140
140
  return granted(policy.egress, to) || (policy.phase === 'build' && policy.publicReads === true && PUBLIC_BUILD_READS.includes(to.url.origin));
141
141
  }
142
142
 
143
+ /** Whether the config grants this request by name (`egress` for a read, `writes` for any method): the grant that takes a
144
+ * build World's request past a twinned host's twin to its real origin. The unlisted public build reads are not one:
145
+ * on a twinned host the twin answers them (architecture, "Reads are granted generously, writes narrowly"). */
146
+ function explicitlyGrantsWorldNetworkEgress(policy, value, method = 'GET') {
147
+ const to = destination(value, true);
148
+ if (!to) return false;
149
+ if (granted(policy.writes ?? [], to)) return true;
150
+ return READ_METHODS.includes(String(method).toUpperCase()) && granted(policy.egress, to);
151
+ }
152
+
143
153
  function worldNetworkUsesPassthrough(policy, value) {
144
154
  const to = destination(value, true);
145
155
  if (!to || policy.phase !== 'build') return false;
@@ -222,4 +232,4 @@ function worldEgressRefusal(value, env = process.env, method = 'GET') {
222
232
  return answer.outcome === 'refuse' ? `${answer.reason} (${refusalSide(answer)})` : null;
223
233
  }
224
234
 
225
- module.exports = { worldAttachmentNetworkEnv, worldStrictEgress, worldGrantFromEnv, PUBLIC_BUILD_READS, READ_METHODS, intersectWorldNetwork, worldNetworkNeedsPathInspection, worldNetworkUsesPassthrough, isWorldInternalHost, worldEgressRefusal, WORLD_NETWORK_POLICY_ENV, normalizeWorldNetwork, createWorldNetworkPolicy, parseWorldNetworkPolicy, worldNetworkPolicyFromEnv, allowsWorldNetworkEgress };
235
+ module.exports = { worldAttachmentNetworkEnv, worldStrictEgress, worldGrantFromEnv, PUBLIC_BUILD_READS, READ_METHODS, intersectWorldNetwork, worldNetworkNeedsPathInspection, worldNetworkUsesPassthrough, isWorldInternalHost, worldEgressRefusal, WORLD_NETWORK_POLICY_ENV, normalizeWorldNetwork, createWorldNetworkPolicy, parseWorldNetworkPolicy, worldNetworkPolicyFromEnv, allowsWorldNetworkEgress, explicitlyGrantsWorldNetworkEgress };
@@ -10,6 +10,7 @@ export function worldNetworkPolicyFromEnv(env: Readonly<Record<string, string |
10
10
  export const READ_METHODS: readonly string[];
11
11
  export const PUBLIC_BUILD_READS: readonly string[];
12
12
  export function allowsWorldNetworkEgress(policy: WorldNetworkPolicy, value: string | URL, method?: string): boolean;
13
+ export function explicitlyGrantsWorldNetworkEgress(policy: WorldNetworkPolicy, value: string | URL, method?: string): boolean;
13
14
  export function isWorldInternalHost(hostname: string): boolean;
14
15
  export function worldEgressRefusal(value: string | URL, env?: Readonly<Record<string, string | undefined>>, method?: string): string | null;
15
16
  export function worldNetworkNeedsPathInspection(policy: WorldNetworkPolicy, value: string | URL): boolean;
@@ -0,0 +1,3 @@
1
+ export type PackFacts = { packs: Record<string, Record<string, unknown>>; installed: string[]; [key: string]: unknown };
2
+ export function packFacts(): PackFacts;
3
+ export function extendPackFacts(files: string[] | undefined): PackFacts;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-core",
3
- "version": "3.0.156",
3
+ "version": "3.0.157",
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",
@@ -25,6 +25,8 @@
25
25
  "attach.cjs",
26
26
  "stream-bridge.cjs",
27
27
  "http-bridge.cjs",
28
+ "required-credential-transport.cjs",
29
+ "required-credential-transport.d.cts",
28
30
  "network-policy.cjs",
29
31
  "network-policy.d.cts",
30
32
  "capability-decision.cjs",
@@ -34,6 +36,7 @@
34
36
  "host-routing.cjs",
35
37
  "host-routing.d.cts",
36
38
  "pack-facts.cjs",
39
+ "pack-facts.d.cts",
37
40
  "vendor-hosts.d.cts",
38
41
  "world-clock.cjs",
39
42
  "world-clock.d.cts",
@@ -89,6 +92,10 @@
89
92
  "./attach": "./attach.cjs",
90
93
  "./stream-bridge": "./stream-bridge.cjs",
91
94
  "./http-bridge": "./http-bridge.cjs",
95
+ "./required-credential-transport": {
96
+ "types": "./required-credential-transport.d.cts",
97
+ "default": "./required-credential-transport.cjs"
98
+ },
92
99
  "./network-policy": {
93
100
  "types": "./network-policy.d.cts",
94
101
  "default": "./network-policy.cjs"
@@ -0,0 +1,29 @@
1
+ // Metadata-only admission for native machine backings. Imports start no process and read no file.
2
+ 'use strict';
3
+
4
+ exports.refuseRequiredMachineTransport = function refuseRequiredMachineTransport(source, transport) {
5
+ const path = source.VOLTER_WORLD_INSTANCE;
6
+ if (!path) {
7
+ if (source.VOLTER_WORLD) throw new Error('World machine execution has no retained credential declaration');
8
+ return; // No registered World declaration is asserted by the standalone provider.
9
+ }
10
+ const instance = JSON.parse(require('node:fs').readFileSync(path, 'utf8'));
11
+ if (!instance || typeof instance !== 'object' || Array.isArray(instance)
12
+ || !instance.env || instance.env.VOLTER_WORLD_INSTANCE !== path || instance.env.VOLTER_WORLD !== source.VOLTER_WORLD
13
+ || !Object.hasOwn(instance, 'requiredCredentials')) throw new Error('World machine boot lacks its own retained credential declaration');
14
+ const record = instance.requiredCredentials;
15
+ if (!record || typeof record !== 'object' || Array.isArray(record)
16
+ || Object.keys(record).some(key => !['version', 'owners', 'valuesSha256'].includes(key))
17
+ || !Object.hasOwn(record, 'version') || record.version !== 1 || !Object.hasOwn(record, 'owners')
18
+ || !record.owners || typeof record.owners !== 'object' || Array.isArray(record.owners))
19
+ throw new Error('World machine credential declaration has an unsupported version or shape');
20
+ if (Object.keys(record.owners).length) {
21
+ const error = new Error(`${transport} does not carry required credential bindings`);
22
+ error.code = 'WORLD_MACHINE_CAPABILITY_GAP';
23
+ throw error;
24
+ }
25
+ if (Object.hasOwn(record, 'valuesSha256')) {
26
+ const empty = require('node:crypto').createHash('sha256').update('[]').digest('hex');
27
+ if (record.valuesSha256 !== empty) throw new Error('World machine empty credential declaration changed');
28
+ }
29
+ };
@@ -0,0 +1,3 @@
1
+ /** Refuse a registered World's required declarations before a backing with no credential transport acts.
2
+ * Reads only the actual instance named by the provider's own environment; standalone providers assert no World proof. */
3
+ export declare function refuseRequiredMachineTransport(source: Readonly<Record<string, string | undefined>>, transport: string): void;