@volter/world-core 2.0.13 → 2.0.15
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.
- package/dist/src/derived-core.d.ts +22 -0
- package/dist/src/derived-core.js +5 -2
- package/dist/src/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/derived-core.ts +31 -3
- package/src/index.ts +1 -1
|
@@ -296,6 +296,9 @@ export type DerivedManifest = {
|
|
|
296
296
|
root?: string;
|
|
297
297
|
occurredAt: string;
|
|
298
298
|
request: Request;
|
|
299
|
+
/** the writing call's context, narrow as a handler's, at the write's moment: what the hook reads to render the event
|
|
300
|
+
* it sends (until `declared-semantics` makes events data the kernel renders) */
|
|
301
|
+
context(): Promise<WriteHookContext>;
|
|
299
302
|
}) => Promise<void>;
|
|
300
303
|
};
|
|
301
304
|
/** A form body's bracket notation (`a[b][0][c]=v`, `expand[]=x`) as nested objects and arrays. A form carries only
|
|
@@ -428,12 +431,31 @@ export type SemanticsContext = {
|
|
|
428
431
|
expand(resource: string, body: Record<string, unknown>): Record<string, unknown>;
|
|
429
432
|
/** This context at another moment of the World clock (ISO): a move time makes is written at the moment it fell due. */
|
|
430
433
|
at(when: string): Promise<SemanticsContext>;
|
|
434
|
+
/** This call's context over another manifest of the same service, at the same moment: a lane over its vendor's
|
|
435
|
+
* state reads and writes the vendor's resources through the vendor's manifest ("Pack layout"). */
|
|
436
|
+
over(other: DerivedManifest): Promise<SemanticsContext>;
|
|
431
437
|
/** The generic core's answer to this call, or undefined where the core does not serve it. */
|
|
432
438
|
core(): Promise<Response | undefined>;
|
|
433
439
|
/** A stored row's own fields, as the vendor's object carries them (an `id`, `type` or `updatedAt` of its own restored). */
|
|
434
440
|
own(row: Record<string, unknown>): Record<string, unknown>;
|
|
435
441
|
};
|
|
436
442
|
export type Semantics = (ctx: SemanticsContext) => Promise<Response>;
|
|
443
|
+
/** The context a derived pack's handler is given ("What an author writes, and how"): the kernel's own members
|
|
444
|
+
* (`now`, `core`, `atomically`, `tree`, `writeDetailed`) and the tree's location (`root`) are not on it, so a handler
|
|
445
|
+
* typed `Handler` cannot reach them. Its reads are those the contract lists (`row`, `rowsRaw`, `rows`, `get`,
|
|
446
|
+
* `history`, `resolve`, `expand`); `at` and `over` give the same narrow context at another moment or over the
|
|
447
|
+
* vendor's manifest. */
|
|
448
|
+
export type HandlerContext = Omit<SemanticsContext, 'now' | 'core' | 'atomically' | 'tree' | 'writeDetailed' | 'root' | 'at' | 'over'> & {
|
|
449
|
+
/** This context at another moment of the World clock (ISO): a move time makes is written at the moment it fell due. */
|
|
450
|
+
at(when: string): Promise<HandlerContext>;
|
|
451
|
+
/** This call's context over the manifest of the vendor whose state a lane shares, at the same moment. */
|
|
452
|
+
over(other: DerivedManifest): Promise<HandlerContext>;
|
|
453
|
+
};
|
|
454
|
+
/** What a write hook reads: the writing call's context without its ways to write, so a hook that renders an event
|
|
455
|
+
* cannot write again (and run itself again). */
|
|
456
|
+
export type WriteHookContext = Omit<HandlerContext, 'write' | 'record' | 'at' | 'over'>;
|
|
457
|
+
/** A derived pack's handler: one operation, by its operationId, over the contract's context. */
|
|
458
|
+
export type Handler = (ctx: HandlerContext) => Promise<Response>;
|
|
437
459
|
/** A pack's semantics handlers as the dispatch's handlers. */
|
|
438
460
|
export declare function bindSemantics(m: DerivedManifest, handlers: Record<string, Semantics>, scope?: CoreScope): Record<string, DerivedHandler>;
|
|
439
461
|
/** The derived core as the dispatch's core: it owns every operation on a resource the manifest declares. */
|
package/dist/src/derived-core.js
CHANGED
|
@@ -311,7 +311,7 @@ async function writeDetailed(m, call, resource, id, fields, operation, params, r
|
|
|
311
311
|
{ operation, subjectType: storedType(m, resource), subjectId: id, fields, input: { operationId: call.operation.id, params: call.params, body: params }, occurredAt, actor: { kind: 'agent', ...(m.identity ? { id: m.identity(call.request.headers.get('authorization'), root) } : {}) } }, root);
|
|
312
312
|
const body = view(m, resource, row);
|
|
313
313
|
if (m.onWrite)
|
|
314
|
-
await m.onWrite({ operation, storedType: storedType(m, resource), body, ...(root !== undefined ? { root } : {}), occurredAt, request: call.request });
|
|
314
|
+
await m.onWrite({ operation, storedType: storedType(m, resource), body, ...(root !== undefined ? { root } : {}), occurredAt, request: call.request, context: () => contextFor(m, { ...call, request: call.request.clone() }, { ...(root !== undefined ? { root } : {}), clock: () => occurredAt }) });
|
|
315
315
|
// the subject's id as it stands after the write: the vendor's, when a live head minted one
|
|
316
316
|
return { body, id: result.externalId ?? row.id, ...(result.vendorData !== undefined ? { vendorData: result.vendorData } : {}) };
|
|
317
317
|
}
|
|
@@ -428,7 +428,8 @@ export async function serveCore(m, call, scope = {}) {
|
|
|
428
428
|
if (!resource || !decl)
|
|
429
429
|
return { unmodeled: `no manifest entry for resource ${resource ?? '(none)'}` };
|
|
430
430
|
call = adoptedPath(m, call, root);
|
|
431
|
-
|
|
431
|
+
// the body is read from a copy, so the call's own request is still unread for the write hook's context
|
|
432
|
+
const params = await boundaryParams(m, { ...call, request: call.request.clone() }, root);
|
|
432
433
|
const idParam = subjectOf(m, resource, call);
|
|
433
434
|
const orphan = missingParent(m, resource, call, root);
|
|
434
435
|
if (orphan)
|
|
@@ -601,6 +602,7 @@ export function sse(m, events, operationId) {
|
|
|
601
602
|
}
|
|
602
603
|
async function contextFor(m, call, scope) {
|
|
603
604
|
const root = scope.root;
|
|
605
|
+
const asAsked = call;
|
|
604
606
|
call = adoptedPath(m, call, root);
|
|
605
607
|
const at = (scope.clock ?? worldNow)();
|
|
606
608
|
const text = await call.request.clone().text().catch(() => '');
|
|
@@ -680,6 +682,7 @@ async function contextFor(m, call, scope) {
|
|
|
680
682
|
sse: (events) => sse(m, events, call.operation.id),
|
|
681
683
|
expand: (resource, body) => (paths.length ? expand(m, resource, body, paths, root) : body),
|
|
682
684
|
at: (when) => contextFor(m, { ...call, request: new Request(call.request.url) }, { ...scope, clock: () => when }),
|
|
685
|
+
over: (other) => contextFor(other, { ...asAsked, request: asAsked.request.clone() }, { ...scope, clock: () => at }),
|
|
683
686
|
core: async () => { const out = await serveCore(m, { ...call, request: pristine.clone() }, { ...scope, clock: () => at }); return 'served' in out ? out.served : undefined; },
|
|
684
687
|
own: (row) => ownFields(row),
|
|
685
688
|
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { currentTraceparent, deliveryTraceHeaders, parseTraceparent, runWithRequ
|
|
|
10
10
|
export type { Traceparent } from './trace-context.js';
|
|
11
11
|
export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface } from './derived.js';
|
|
12
12
|
export { bindSemantics, coreFor, crossCutting, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.js';
|
|
13
|
-
export type { Actor, CoreScope, DerivedManifest, ErrorSpec, FieldRule, ResourceDecl, ScreenDecl, Semantics, SemanticsContext, StateField, Transition, TransitionObserver } from './derived-core.js';
|
|
13
|
+
export type { Actor, CoreScope, DerivedManifest, ErrorSpec, FieldRule, Handler, HandlerContext, ResourceDecl, WriteHookContext, ScreenDecl, Semantics, SemanticsContext, StateField, Transition, TransitionObserver } from './derived-core.js';
|
|
14
14
|
export type { RemoteExecute, RemoteExecuteRequest, RemoteExecuteResponse } from './remote-execute.js';
|
|
15
15
|
export type { TwinFetchAdapterConfig, TwinFetchHandlerRequest, TwinFetchHandlerResult, TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.js';
|
|
16
16
|
export type { PackScenarioAdapter, ScenarioDecision, ScenarioDocument, ScenarioExtractorSpec, ScenarioFault, ScenarioFaultResult, ScenarioFeatures, ScenarioHandler, ScenarioMatcher, ScenarioMissRecord, ScenarioStatus } from './scenario.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
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",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"url": "git+https://github.com/volter-ai/twin.git",
|
|
49
49
|
"directory": "packages/world-core"
|
|
50
50
|
},
|
|
51
|
-
"homepage": "https://
|
|
51
|
+
"homepage": "https://world.volter.ai/docs/README",
|
|
52
52
|
"type": "module",
|
|
53
53
|
"exports": {
|
|
54
54
|
".": {
|
package/src/derived-core.ts
CHANGED
|
@@ -226,7 +226,12 @@ export type DerivedManifest = {
|
|
|
226
226
|
/** the vendor's screens this pack serves or owes (demand decides which exist) */
|
|
227
227
|
screens?: ScreenDecl[];
|
|
228
228
|
/** called after every stored write with the rendered resource, its stored type and the kernel operation name */
|
|
229
|
-
onWrite?: (write: {
|
|
229
|
+
onWrite?: (write: {
|
|
230
|
+
operation: string; storedType: string; body: Record<string, unknown>; root?: string; occurredAt: string; request: Request;
|
|
231
|
+
/** the writing call's context, narrow as a handler's, at the write's moment: what the hook reads to render the event
|
|
232
|
+
* it sends (until `declared-semantics` makes events data the kernel renders) */
|
|
233
|
+
context(): Promise<WriteHookContext>;
|
|
234
|
+
}) => Promise<void>;
|
|
230
235
|
};
|
|
231
236
|
|
|
232
237
|
// ── request parsing ──────────────────────────────────────────────────────────────────────────
|
|
@@ -504,7 +509,7 @@ async function writeDetailed(m: DerivedManifest, call: DerivedCall, resource: st
|
|
|
504
509
|
root,
|
|
505
510
|
);
|
|
506
511
|
const body = view(m, resource, row);
|
|
507
|
-
if (m.onWrite) await m.onWrite({ operation, storedType: storedType(m, resource), body, ...(root !== undefined ? { root } : {}), occurredAt, request: call.request });
|
|
512
|
+
if (m.onWrite) await m.onWrite({ operation, storedType: storedType(m, resource), body, ...(root !== undefined ? { root } : {}), occurredAt, request: call.request, context: () => contextFor(m, { ...call, request: call.request.clone() }, { ...(root !== undefined ? { root } : {}), clock: () => occurredAt }) });
|
|
508
513
|
// the subject's id as it stands after the write: the vendor's, when a live head minted one
|
|
509
514
|
return { body, id: result.externalId ?? row.id, ...(result.vendorData !== undefined ? { vendorData: result.vendorData } : {}) };
|
|
510
515
|
}
|
|
@@ -620,7 +625,8 @@ export async function serveCore(m: DerivedManifest, call: DerivedCall, scope: Co
|
|
|
620
625
|
const decl = resource ? m.resources[resource] : undefined;
|
|
621
626
|
if (!resource || !decl) return { unmodeled: `no manifest entry for resource ${resource ?? '(none)'}` };
|
|
622
627
|
call = adoptedPath(m, call, root);
|
|
623
|
-
|
|
628
|
+
// the body is read from a copy, so the call's own request is still unread for the write hook's context
|
|
629
|
+
const params = await boundaryParams(m, { ...call, request: call.request.clone() }, root);
|
|
624
630
|
const idParam = subjectOf(m, resource, call);
|
|
625
631
|
const orphan = missingParent(m, resource, call, root);
|
|
626
632
|
if (orphan) return { served: orphan };
|
|
@@ -834,6 +840,9 @@ export type SemanticsContext = {
|
|
|
834
840
|
expand(resource: string, body: Record<string, unknown>): Record<string, unknown>;
|
|
835
841
|
/** This context at another moment of the World clock (ISO): a move time makes is written at the moment it fell due. */
|
|
836
842
|
at(when: string): Promise<SemanticsContext>;
|
|
843
|
+
/** This call's context over another manifest of the same service, at the same moment: a lane over its vendor's
|
|
844
|
+
* state reads and writes the vendor's resources through the vendor's manifest ("Pack layout"). */
|
|
845
|
+
over(other: DerivedManifest): Promise<SemanticsContext>;
|
|
837
846
|
/** The generic core's answer to this call, or undefined where the core does not serve it. */
|
|
838
847
|
core(): Promise<Response | undefined>;
|
|
839
848
|
/** A stored row's own fields, as the vendor's object carries them (an `id`, `type` or `updatedAt` of its own restored). */
|
|
@@ -841,8 +850,26 @@ export type SemanticsContext = {
|
|
|
841
850
|
};
|
|
842
851
|
export type Semantics = (ctx: SemanticsContext) => Promise<Response>;
|
|
843
852
|
|
|
853
|
+
/** The context a derived pack's handler is given ("What an author writes, and how"): the kernel's own members
|
|
854
|
+
* (`now`, `core`, `atomically`, `tree`, `writeDetailed`) and the tree's location (`root`) are not on it, so a handler
|
|
855
|
+
* typed `Handler` cannot reach them. Its reads are those the contract lists (`row`, `rowsRaw`, `rows`, `get`,
|
|
856
|
+
* `history`, `resolve`, `expand`); `at` and `over` give the same narrow context at another moment or over the
|
|
857
|
+
* vendor's manifest. */
|
|
858
|
+
export type HandlerContext = Omit<SemanticsContext, 'now' | 'core' | 'atomically' | 'tree' | 'writeDetailed' | 'root' | 'at' | 'over'> & {
|
|
859
|
+
/** This context at another moment of the World clock (ISO): a move time makes is written at the moment it fell due. */
|
|
860
|
+
at(when: string): Promise<HandlerContext>;
|
|
861
|
+
/** This call's context over the manifest of the vendor whose state a lane shares, at the same moment. */
|
|
862
|
+
over(other: DerivedManifest): Promise<HandlerContext>;
|
|
863
|
+
};
|
|
864
|
+
/** What a write hook reads: the writing call's context without its ways to write, so a hook that renders an event
|
|
865
|
+
* cannot write again (and run itself again). */
|
|
866
|
+
export type WriteHookContext = Omit<HandlerContext, 'write' | 'record' | 'at' | 'over'>;
|
|
867
|
+
/** A derived pack's handler: one operation, by its operationId, over the contract's context. */
|
|
868
|
+
export type Handler = (ctx: HandlerContext) => Promise<Response>;
|
|
869
|
+
|
|
844
870
|
async function contextFor(m: DerivedManifest, call: DerivedCall, scope: CoreScope): Promise<SemanticsContext> {
|
|
845
871
|
const root = scope.root;
|
|
872
|
+
const asAsked = call;
|
|
846
873
|
call = adoptedPath(m, call, root);
|
|
847
874
|
const at = (scope.clock ?? worldNow)();
|
|
848
875
|
const text = await call.request.clone().text().catch(() => '');
|
|
@@ -915,6 +942,7 @@ async function contextFor(m: DerivedManifest, call: DerivedCall, scope: CoreScop
|
|
|
915
942
|
sse: (events) => sse(m, events, call.operation.id),
|
|
916
943
|
expand: (resource, body) => (paths.length ? expand(m, resource, body, paths, root) : body),
|
|
917
944
|
at: (when) => contextFor(m, { ...call, request: new Request(call.request.url) }, { ...scope, clock: () => when }),
|
|
945
|
+
over: (other) => contextFor(other, { ...asAsked, request: asAsked.request.clone() }, { ...scope, clock: () => at }),
|
|
918
946
|
core: async () => { const out = await serveCore(m, { ...call, request: pristine.clone() }, { ...scope, clock: () => at }); return 'served' in out ? out.served : undefined; },
|
|
919
947
|
own: (row) => ownFields(row as unknown as TwinResource),
|
|
920
948
|
};
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { currentTraceparent, deliveryTraceHeaders, parseTraceparent, runWithRequ
|
|
|
22
22
|
export type { Traceparent } from './trace-context.ts';
|
|
23
23
|
export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface } from './derived.ts';
|
|
24
24
|
export { bindSemantics, coreFor, crossCutting, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.ts';
|
|
25
|
-
export type { Actor, CoreScope, DerivedManifest, ErrorSpec, FieldRule, ResourceDecl, ScreenDecl, Semantics, SemanticsContext, StateField, Transition, TransitionObserver } from './derived-core.ts';
|
|
25
|
+
export type { Actor, CoreScope, DerivedManifest, ErrorSpec, FieldRule, Handler, HandlerContext, ResourceDecl, WriteHookContext, ScreenDecl, Semantics, SemanticsContext, StateField, Transition, TransitionObserver } from './derived-core.ts';
|
|
26
26
|
export type { RemoteExecute, RemoteExecuteRequest, RemoteExecuteResponse } from './remote-execute.ts';
|
|
27
27
|
export type { TwinFetchAdapterConfig, TwinFetchHandlerRequest, TwinFetchHandlerResult, TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.ts';
|
|
28
28
|
export type { PackScenarioAdapter, ScenarioDecision, ScenarioDocument, ScenarioExtractorSpec, ScenarioFault, ScenarioFaultResult, ScenarioFeatures, ScenarioHandler, ScenarioMatcher, ScenarioMissRecord, ScenarioStatus } from './scenario.ts';
|