@volter/world-core 3.0.30 → 3.0.32

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 (45) hide show
  1. package/dist/host-routing.cjs +106 -0
  2. package/dist/host-routing.d.cts +7 -0
  3. package/dist/inject.cjs +5 -8
  4. package/dist/src/board-keys.d.ts +6 -0
  5. package/dist/src/board-keys.js +4 -0
  6. package/dist/src/browser-cookie-jar.d.ts +9 -0
  7. package/dist/src/browser-cookie-jar.js +104 -0
  8. package/dist/src/browser-state.d.ts +52 -0
  9. package/dist/src/browser-state.js +105 -0
  10. package/dist/src/browser.d.ts +12 -0
  11. package/dist/src/browser.js +197 -0
  12. package/dist/src/derived-core.d.ts +3 -7
  13. package/dist/src/derived.d.ts +1 -0
  14. package/dist/src/index.d.ts +1 -0
  15. package/dist/src/index.js +1 -0
  16. package/dist/src/pack-fetch.d.ts +0 -3
  17. package/dist/src/pack-fetch.js +5 -26
  18. package/dist/src/public-suffixes.json +1 -0
  19. package/dist/src/runtime.d.ts +1 -1
  20. package/dist/src/runtime.js +1 -1
  21. package/dist/src/twin-fetch.d.ts +1 -1
  22. package/dist/src/twin-fetch.js +23 -4
  23. package/dist/vendor-hosts.cjs +13 -105
  24. package/dist/vendor-hosts.d.cts +3 -0
  25. package/host-routing.cjs +106 -0
  26. package/host-routing.d.cts +7 -0
  27. package/inject.cjs +5 -8
  28. package/package.json +11 -1
  29. package/src/board-keys.ts +4 -0
  30. package/src/browser-cookie-jar.ts +77 -0
  31. package/src/browser-session.ts +1 -1
  32. package/src/browser-state.ts +89 -0
  33. package/src/browser.ts +164 -0
  34. package/src/derived-core.ts +4 -5
  35. package/src/derived.ts +1 -1
  36. package/src/index.ts +2 -0
  37. package/src/pack-fetch.ts +6 -24
  38. package/src/public-suffixes.json +1 -0
  39. package/src/runtime.ts +2 -1
  40. package/src/twin-fetch.ts +9 -4
  41. package/vendor-hosts.cjs +13 -105
  42. package/vendor-hosts.d.cts +3 -0
  43. package/dist/src/browser-session-permit.d.ts +0 -13
  44. package/dist/src/browser-session-permit.js +0 -51
  45. package/src/browser-session-permit.ts +0 -43
@@ -268,7 +268,6 @@ export type VendorManifest = {
268
268
  descriptor: Omit<PackDescriptor, 'vendor'>;
269
269
  ingest?: IngestDecl;
270
270
  rateBudget?: RateBudgetDeclaration;
271
- browserSession?: DerivedManifest['browserSession'];
272
271
  /** the vendor has no vendor-backed half (architecture, "The descriptor"): packOf copies it, and derives no state system */
273
272
  vendorBacked?: DerivedManifest['vendorBacked'];
274
273
  };
@@ -544,11 +543,6 @@ export type DerivedManifest = {
544
543
  owner: string;
545
544
  resource: string;
546
545
  }>;
547
- /** The browser session of a World's person, issued with world-ui's kit. Declaring it lets the World offer View as. */
548
- browserSession?: {
549
- cookie: string;
550
- scope?: string;
551
- };
552
546
  /** the vendor's screens this pack serves or owes (demand decides which exist) */
553
547
  screens?: ScreenDecl[];
554
548
  /** The discovery door's facts (`GET /twin`): what the twin is of, what it stores, and how it is authenticated. */
@@ -689,8 +683,10 @@ export declare function render(r: TwinResource): Record<string, unknown>;
689
683
  * a caller that pins an instant passes its own). */
690
684
  /** One call of a protocol-3 pack's default data (`src/semantics/seed.ts` exports `seed: SeedCall[]`): a request to the
691
685
  * vendor's own operation (or the pack's door), made in order against the twin by the runner `volter-world init` writes
692
- * beside the copied data. */
686
+ * beside the copied data. An ordinary path is relative to the twin base. A call naming a browser uses the
687
+ * vendor's absolute URL and is exported separately as `browserSeed`, after the ordinary `seed` calls. */
693
688
  export type SeedCall = {
689
+ browser?: string;
694
690
  method: string;
695
691
  path: string;
696
692
  body?: unknown;
@@ -125,6 +125,7 @@ export type DerivedFetch = ((request: Request) => Promise<Response>) & {
125
125
  export type Workspace = {
126
126
  id: string;
127
127
  path: string;
128
+ host?: string;
128
129
  };
129
130
  /** A page of the World's board (architecture, "The board"): a page there is to see at the vendor, a record's own (an
130
131
  * account's profile, each of its posts, a site and each page it serves), as the vendor's pack lists them from its state
@@ -65,3 +65,4 @@ export * as git from './git/index.js';
65
65
  export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError } from './scenario.js';
66
66
  export type { PackScenarioAdapter, ScenarioDecision, ScenarioDocument, ScenarioExtractorSpec, ScenarioFault, ScenarioFaultResult, ScenarioFeatures, ScenarioHandler, ScenarioMatcher, ScenarioMissRecord, ScenarioStatus } from './scenario.js';
67
67
  export { browserSessionToken, startBrowserSession, endBrowserSession } from './browser-session.js';
68
+ export { assertBrowserName, browserOrigin, validateBrowserState, cookieMatchesHost, type BrowserCookie, type BrowserState, type BrowserIndexedDB } from './browser-state.js';
package/dist/src/index.js CHANGED
@@ -60,3 +60,4 @@ export * as git from "./git/index.js";
60
60
  // ── the scenario grammar (architecture, "Behaviour") ───────────────────────────────────────────
61
61
  export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError } from "./scenario.js";
62
62
  export { browserSessionToken, startBrowserSession, endBrowserSession } from "./browser-session.js";
63
+ export { assertBrowserName, browserOrigin, validateBrowserState, cookieMatchesHost } from "./browser-state.js";
@@ -56,12 +56,9 @@ export type LanePart = {
56
56
  fetch: ((request: Request) => Promise<Response>) & {
57
57
  serves?: (method: string, path: string) => boolean;
58
58
  boards?: boolean;
59
- drawsScreens?: boolean;
60
59
  draws?: (url: string) => boolean;
61
60
  /** the hosts the lane's built content screens name: its vendor's router sends `<base>/@<host>/` there */
62
61
  contentHosts?: ReadonlyArray<string>;
63
- /** A vendor's browser session applies to its lanes without a lane importing its parent's manifest. */
64
- sessionDeclaration?: (session: NonNullable<DerivedManifest['browserSession']>) => void;
65
62
  };
66
63
  manifest: {
67
64
  doors?: ReadonlyArray<{
@@ -5,8 +5,6 @@
5
5
  // `screens/<id>.tsx`), and the API (the derived dispatch over the generated surface, the handlers and the core). Every
6
6
  // one of them is answered over the contract's context, which the kernel opens: a pack opens none, reads the tree and
7
7
  // writes it only through one.
8
- import { startBrowserSession, endBrowserSession } from "./browser-session.js";
9
- import { BROWSER_SESSION_PATH, takeBrowserSessionPermit } from "./browser-session-permit.js";
10
8
  import { ORIGINAL_PATH_HEADER } from "./sigv4.js";
11
9
  import { placedCookies, TWIN_PREFIX_HEADER } from "./twin-fetch.js";
12
10
  import { PREFIX_PARAMS_HEADER } from "./derived.js";
@@ -21,7 +19,7 @@ import { deferPerform, performRequestGroup, RefusedWriteError, VendorWriteError
21
19
  import { withCors } from "./cors.js";
22
20
  import { contentAddressOf } from "./content-route.js";
23
21
  import { getPack } from "./packRegistry.js";
24
- import { hostRules } from '../vendor-hosts.cjs';
22
+ import { hostRules } from '../host-routing.cjs';
25
23
  import { socketUpgrade } from "./sockets.js";
26
24
  import { MACHINE_POOL, POOL_KINDS } from "./machines.js";
27
25
  import { applyTwinWrite } from "./serve.js";
@@ -112,7 +110,6 @@ async function encoded(m, request, res) {
112
110
  /** A pack's HTTP surface, as the kernel serves it from the pack's parts. */
113
111
  export function createPackFetch(parts, options = {}) {
114
112
  const m = parts.manifest;
115
- let browserSession = m.browserSession;
116
113
  const scope = {
117
114
  ...(options.root !== undefined ? { root: options.root } : {}),
118
115
  ...(options.clock ? { clock: options.clock } : {}),
@@ -223,7 +220,7 @@ export function createPackFetch(parts, options = {}) {
223
220
  });
224
221
  // the workspaces a person can be shown (Viewing a World): each built workspace screen's id and path, the pack's own
225
222
  // and its lanes'
226
- const workspaces = () => [...(m.screens ?? []).filter((s) => s.kind === 'workspace' && s.status === 'done' && parts.screens?.[s.id]).map((s) => ({ id: s.id, path: s.path })), ...lanesWorkspaces(parts.lanes ?? {})];
223
+ const workspaces = () => [...(m.screens ?? []).filter((s) => s.kind === 'workspace' && s.status === 'done' && parts.screens?.[s.id]).map((s) => ({ id: s.id, path: s.path, host: s.host })), ...lanesWorkspaces(parts.lanes ?? {})];
227
224
  /** Whether a built screen a person views (a workspace or a flow, never content an API client reads) draws a url: its host
228
225
  * one the screen names, its path the screen's or under it (a root screen draws its root alone). */
229
226
  // by what the pack declares built (a screen drawn by another's handler, as X's profile is by its web pages, is built)
@@ -231,7 +228,6 @@ export function createPackFetch(parts, options = {}) {
231
228
  const hosts = [s.host, ...(s.hosts ?? [])].map(hostMatcher);
232
229
  return { root: s.path.replace(/\/+$/, '') === '', host: (h) => hosts.some((match) => match(h)), path: pathMatcher(s.path, true) };
233
230
  });
234
- const drawsScreens = viewed.length > 0 || Object.values(parts.lanes ?? {}).some((l) => l.fetch.drawsScreens);
235
231
  const drawsUrl = (at) => {
236
232
  try {
237
233
  const u = new URL(at);
@@ -381,7 +377,7 @@ export function createPackFetch(parts, options = {}) {
381
377
  if (request.method === 'GET' && path === '/twin' && m.discovery) {
382
378
  const d = m.discovery;
383
379
  // the workspaces a person can be shown (Viewing a World): each built workspace screen's id and path
384
- const shown = { drawsScreens, ...(workspaces().length ? { screens: workspaces() } : {}), ...(browserSession ? { browserSession } : {}) };
380
+ const shown = workspaces().length ? { screens: workspaces() } : {};
385
381
  // a model vendor's: its state, and what its scenario scripts, with the scenario's live counts
386
382
  if (parts.scenario && d.behavior) {
387
383
  return Response.json({ ...shown, ...twinManifest({
@@ -399,20 +395,6 @@ export function createPackFetch(parts, options = {}) {
399
395
  // header would make a payout time makes the caller's), but a tenant's, when the vendor keeps tenants apart
400
396
  if (parts.clock)
401
397
  await runAsVendorMove(async () => parts.clock(await open(new Request(request.url, m.tenant ? { headers: request.headers } : {}), 'clock', 'POST', '/_twin/clock', {})));
402
- if (path === BROWSER_SESSION_PATH && browserSession) {
403
- if (request.method !== 'POST' || readOnly)
404
- return Response.json({ error: 'a browser session needs a permitted write' }, { status: 403 });
405
- const choice = takeBrowserSessionPermit(request, m.service, options.root);
406
- if (!choice)
407
- return Response.json({ error: 'only the World can change this browser session' }, { status: 403 });
408
- const ctx = await open(request, 'browser-session', 'POST', BROWSER_SESSION_PATH, {});
409
- const person = choice.person === null ? null : ctx.rowsRaw('_person').find((p) => p.id === choice.person && typeof p.email === 'string');
410
- if (person === undefined)
411
- return Response.json({ error: 'that person is no longer in the World' }, { status: 404 });
412
- const cleared = await endBrowserSession(ctx, browserSession.cookie);
413
- const cookie = person ? await startBrowserSession(ctx, String(person.email), browserSession.cookie, browserSession.scope) : cleared;
414
- return new Response(null, { status: 303, headers: { location: choice.land, 'set-cookie': cookie } });
415
- }
416
398
  if (path.startsWith('/_twin/')) {
417
399
  // the World's machine pool, enrolled by the kernel for a vendor that runs images (machines.ts)
418
400
  if (m.machines && path === '/_twin/machine-pool' && request.method === 'POST') {
@@ -531,7 +513,7 @@ export function createPackFetch(parts, options = {}) {
531
513
  async (asked) => engineOf()?.serve(asked)) : undefined;
532
514
  // what serves each operation: the pack's own, and each lane's
533
515
  const owners = () => ({ ...api.owners(), ...lanesOwners(parts.lanes ?? {}) });
534
- return derivedRequestScopes(m, Object.assign(served, { sessionDeclaration: (session) => { browserSession ??= session; }, owners, serves, workspaces, boards: Boolean(parts.board), drawsScreens, draws: drawsUrl, contentHosts, ...(upgrade ? { upgrade } : {}) }));
516
+ return derivedRequestScopes(m, Object.assign(served, { owners, serves, workspaces, boards: Boolean(parts.board), draws: drawsUrl, contentHosts, ...(upgrade ? { upgrade } : {}) }));
535
517
  }
536
518
  /** The vendor's gateway over its lanes: the lane a request goes to (a door to the lane that declares it, then the first
537
519
  * route whose conditions all hold, then the default), behind the gateway's CORS; undefined when none takes it. */
@@ -591,9 +573,6 @@ const lanesOwners = (lanes) => Object.assign({}, ...Object.values(lanes).map((l)
591
573
  /** The workspaces a vendor's lanes draw, as one list. */
592
574
  const lanesWorkspaces = (lanes) => Object.values(lanes).flatMap((l) => l.fetch.workspaces?.() ?? []);
593
575
  export function createVendorFetch(manifest, lanes) {
594
- if (manifest.browserSession)
595
- for (const part of Object.values(lanes))
596
- part.fetch.sessionDeclaration?.(manifest.browserSession);
597
576
  const lane = laneRouter(manifest.vendor, manifest.lanes, lanes);
598
577
  return Object.assign(async (request) => {
599
578
  const path = new URL(request.url).pathname.replace(/\/+$/, '') || '/';
@@ -616,7 +595,7 @@ export function createVendorFetch(manifest, lanes) {
616
595
  if (request.method === 'GET' && path === '/twin' && manifest.discovery) {
617
596
  // the vendor's screens are its lanes' (a dashboard drawn by one lane is the vendor's)
618
597
  const screens = lanesWorkspaces(lanes);
619
- return Response.json({ ...statefulTwinManifest({ vendor: manifest.vendor, ...manifest.discovery }), drawsScreens: Object.values(lanes).some((l) => l.fetch.drawsScreens), ...(manifest.browserSession ? { browserSession: manifest.browserSession } : {}), ...(screens.length ? { screens } : {}) });
598
+ return Response.json({ ...statefulTwinManifest({ vendor: manifest.vendor, ...manifest.discovery }), ...(screens.length ? { screens } : {}) });
620
599
  }
621
600
  const to = lane(request);
622
601
  return to ? to(request) : Response.json({ error: `${manifest.vendor}: no lane serves ${request.method} ${path}` }, { status: 404 });