@volter/world-core 2.0.0 → 2.0.2
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/app-route.cjs +95 -6
- package/app-route.d.cts +2 -1
- package/dist/app-route.cjs +95 -6
- package/dist/app-route.d.cts +2 -1
- package/dist/generated/pack-facts.json +127 -8
- package/dist/inject.cjs +46 -1
- package/dist/src/actions.d.ts +27 -0
- package/dist/src/actions.js +62 -4
- package/dist/src/blob-store.d.ts +3 -0
- package/dist/src/blob-store.js +15 -1
- package/dist/src/client-bundle.d.ts +4 -0
- package/dist/src/client-bundle.js +13 -2
- package/dist/src/derived-core.d.ts +6 -0
- package/dist/src/derived-core.js +17 -3
- package/dist/src/derived.js +5 -2
- package/dist/src/git/refs.js +5 -3
- package/dist/src/head.js +12 -2
- package/dist/src/index.d.ts +8 -5
- package/dist/src/index.js +9 -5
- package/dist/src/log.d.ts +2 -0
- package/dist/src/packRegistry.d.ts +8 -6
- package/dist/src/redis/engine.d.ts +308 -0
- package/dist/src/redis/engine.js +1663 -0
- package/dist/src/redis/index.d.ts +2 -0
- package/dist/src/redis/index.js +6 -0
- package/dist/src/redis/lua.d.ts +153 -0
- package/dist/src/redis/lua.js +1373 -0
- package/dist/src/request-scope.d.ts +28 -0
- package/dist/src/request-scope.js +70 -0
- package/dist/src/storage.d.ts +22 -1
- package/dist/src/storage.js +57 -1
- package/dist/src/trace-context.d.ts +31 -0
- package/dist/src/trace-context.js +78 -0
- package/dist/src/twin-fetch.d.ts +16 -0
- package/dist/src/twin-fetch.js +66 -3
- package/dist/src/world-clock.d.ts +2 -2
- package/dist/src/world-clock.js +18 -17
- package/dist/src/world-store.js +9 -0
- package/dist/vendor-hosts.cjs +2 -2
- package/dist/world-clock.cjs +40 -0
- package/dist/world-clock.d.cts +4 -0
- package/generated/pack-facts.json +127 -8
- package/inject.cjs +46 -1
- package/package.json +11 -1
- package/src/actions.ts +69 -4
- package/src/blob-store.ts +15 -1
- package/src/client-bundle.ts +15 -2
- package/src/derived-core.ts +17 -3
- package/src/derived.ts +5 -2
- package/src/git/refs.ts +5 -3
- package/src/head.ts +11 -2
- package/src/index.ts +11 -3
- package/src/log.ts +2 -0
- package/src/packRegistry.ts +8 -6
- package/src/redis/engine.ts +1468 -0
- package/src/redis/index.ts +6 -0
- package/src/redis/lua.ts +1250 -0
- package/src/request-scope.ts +74 -0
- package/src/storage.ts +54 -2
- package/src/trace-context.ts +87 -0
- package/src/twin-fetch.ts +69 -3
- package/src/world-clock.ts +19 -16
- package/src/world-store.ts +9 -0
- package/vendor-hosts.cjs +2 -2
- package/world-clock.cjs +40 -0
- package/world-clock.d.cts +4 -0
package/src/derived.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// existing fetch, which keeps serving everything not yet moved (and every route outside the spec, such
|
|
6
6
|
// as the `/twin` door). `owners` says, per operation, which of the two serves it: the count a pack's
|
|
7
7
|
// move is measured by. Workerd-clean: no fs, no clock, nothing at import.
|
|
8
|
+
import { runWithRequestTrace } from './trace-context.ts';
|
|
8
9
|
|
|
9
10
|
/** The slice of a generated surface the dispatch reads. */
|
|
10
11
|
export type DerivedOperation = {
|
|
@@ -141,7 +142,9 @@ export function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch {
|
|
|
141
142
|
const routes = compileSurface(options.surface);
|
|
142
143
|
const fallback = (request: Request, operation: DerivedOperation | undefined, reason: string): Promise<Response> =>
|
|
143
144
|
options.legacy ? options.legacy(request) : Promise.resolve(options.gap(request, operation, reason));
|
|
144
|
-
|
|
145
|
+
// a valid incoming W3C traceparent scopes the dispatch, so every entry it appends records it (trace-context.ts)
|
|
146
|
+
const fetch = ((request: Request): Promise<Response> => runWithRequestTrace(request, () => dispatch(request))) as DerivedFetch;
|
|
147
|
+
const dispatch = async (request: Request): Promise<Response> => {
|
|
145
148
|
const url = new URL(request.url);
|
|
146
149
|
const matched = options.anyMethod
|
|
147
150
|
? [...routes.keys()].map((m) => matchOperation(routes, m, url.pathname, url.searchParams, request.headers)).find(Boolean)
|
|
@@ -167,7 +170,7 @@ export function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch {
|
|
|
167
170
|
}
|
|
168
171
|
}
|
|
169
172
|
return fallback(request, matched.operation, 'no handler');
|
|
170
|
-
}
|
|
173
|
+
};
|
|
171
174
|
fetch.owners = () =>
|
|
172
175
|
Object.fromEntries(
|
|
173
176
|
options.surface.operations.map((o) => [o.id, handlers[o.id] ? 'handler' : options.core?.owns(o) ? 'core' : options.legacy ? 'legacy' : 'gap'] as const),
|
package/src/git/refs.ts
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
// state a snapshot carries, a projection can read, and (through the action log the plane keeps
|
|
4
4
|
// beside it) a push policy can gate. No packed-refs: the store lists directories.
|
|
5
5
|
import type { WorldStore } from '../world-store.ts';
|
|
6
|
+
import { refuseReadOnlyWrite } from '../request-scope.ts';
|
|
6
7
|
|
|
7
8
|
export class GitRefs {
|
|
8
9
|
constructor(private readonly store: WorldStore, private readonly prefix: string) {}
|
|
9
10
|
private path(name: string): string { return `${this.prefix}/${name}`; }
|
|
10
11
|
get(name: string): string | null { const v = this.store.read(this.path(name)); return v === null ? null : v.trim(); }
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// a read-only request moves no ref (request-scope.ts): refused before the store is touched
|
|
13
|
+
set(name: string, sha: string): void { refuseReadOnlyWrite('git'); this.store.write(this.path(name), `${sha}\n`); }
|
|
14
|
+
delete(name: string): void { refuseReadOnlyWrite('git'); if (this.store.exists(this.path(name))) this.store.remove(this.path(name)); }
|
|
13
15
|
head(): string { const v = this.store.read(this.path('HEAD')); return v === null ? 'refs/heads/main' : v.trim().replace(/^ref: /, ''); }
|
|
14
|
-
setHead(target: string): void { this.store.write(this.path('HEAD'), `ref: ${target}\n`); }
|
|
16
|
+
setHead(target: string): void { refuseReadOnlyWrite('git'); this.store.write(this.path('HEAD'), `ref: ${target}\n`); }
|
|
15
17
|
/** Run `fn` holding the repository's ref lock (the world store's exclusive lock). */
|
|
16
18
|
withLock<T>(fn: () => T): T { return this.store.withLock(this.path('refs.lock'), fn); }
|
|
17
19
|
/** Every `refs/...` name with its sha, sorted by name. */
|
package/src/head.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// record: a `deployed` copy is never performed again, a `failed` one is retried.
|
|
10
10
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { homedir } from 'node:os';
|
|
12
|
-
import { basename, dirname, join, resolve } from 'node:path';
|
|
12
|
+
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
13
13
|
import { confirmAction, isTwinBookkeeping, resolveSubjectId, revertAction, type TwinAction } from './actions.ts';
|
|
14
14
|
import { openSealedCredential, sealCredential, type CredentialPayload, type SealedCredential } from './credential.ts';
|
|
15
15
|
import { buildRemoteExecute, validateRemoteOrigin, type CredentialCustody } from './executor.ts';
|
|
@@ -116,11 +116,20 @@ export async function loadChecks(worldRoot: string): Promise<Check[]> {
|
|
|
116
116
|
* loader that runs the check in an isolate of its own, with no network and nothing of the World's. */
|
|
117
117
|
export type CheckLoader = (path: string, name: string) => Promise<Check>;
|
|
118
118
|
const importCheck: CheckLoader = async (path, name) => {
|
|
119
|
-
|
|
119
|
+
// Node's ESM loader takes an absolute path only as a file URL (on Windows `C:\…` reads as the scheme `c:`); Bun takes either
|
|
120
|
+
const mod = (await import(isAbsolute(path) ? fileUrlOf(path) : path)) as { check?: Check; default?: Check };
|
|
120
121
|
const check = mod.check ?? mod.default;
|
|
121
122
|
if (!check || typeof check.run !== 'function') throw new Error(`${path} must export a check { name, run }`);
|
|
122
123
|
return { name: check.name ?? name, run: check.run };
|
|
123
124
|
};
|
|
125
|
+
/** An absolute path's file URL, built here: `node:url` is not in the browser bundles that also reach this module. */
|
|
126
|
+
const fileUrlOf = (path: string): string => {
|
|
127
|
+
// a long path (`\\?\C:\…`) is the drive path it names; a UNC path (`\\server\share\…`) puts the server in the URL's host
|
|
128
|
+
const long = /^\\\\\?\\(?:UNC\\)?/i.exec(path); const unc = /^\\\\\?\\UNC\\/i.test(path) || (!long && /^\\\\[^\\?]/.test(path));
|
|
129
|
+
const rest = (long ? path.slice(long[0].length) : unc ? path.slice(2) : path).replace(/\\/g, '/');
|
|
130
|
+
const encoded = rest.split('/').map((seg) => encodeURIComponent(seg).replace(/%3A/g, ':')).join('/');
|
|
131
|
+
return unc ? `file://${encoded}` : `file://${rest.startsWith('/') ? '' : '/'}${encoded}`;
|
|
132
|
+
};
|
|
124
133
|
let checkLoader: CheckLoader = importCheck;
|
|
125
134
|
export function setCheckLoader(loader: CheckLoader | null): void { checkLoader = loader ?? importCheck; }
|
|
126
135
|
/** One check file through the host's loader: what placing a check validates with. */
|
package/src/index.ts
CHANGED
|
@@ -15,10 +15,13 @@ export type { PackTransport, PullPosture, PullTrigger, PullVendor, RoundTripWrit
|
|
|
15
15
|
export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError, statefulTwinManifest, twinManifest } from './scenario.ts';
|
|
16
16
|
export { WORLD_CLOCK_ENV, worldNow } from './world-clock.ts';
|
|
17
17
|
export { WORLD_ENV_NAMES_ENV, worldEnvValue } from './world-env.ts';
|
|
18
|
-
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, twinPublicBase } from './twin-fetch.ts';
|
|
18
|
+
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, twinPublicBase, withRequestScopes } from './twin-fetch.ts';
|
|
19
|
+
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from './request-scope.ts';
|
|
19
20
|
export { compileSurface, createDerivedFetch, matchOperation } from './derived.ts';
|
|
21
|
+
export { currentTraceparent, deliveryTraceHeaders, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.ts';
|
|
22
|
+
export type { Traceparent } from './trace-context.ts';
|
|
20
23
|
export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface } from './derived.ts';
|
|
21
|
-
export { bindSemantics, coreFor, crossCutting, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.ts';
|
|
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';
|
|
22
25
|
export type { Actor, CoreScope, DerivedManifest, ErrorSpec, FieldRule, ResourceDecl, ScreenDecl, Semantics, SemanticsContext, StateField, Transition, TransitionObserver } from './derived-core.ts';
|
|
23
26
|
export type { RemoteExecute, RemoteExecuteRequest, RemoteExecuteResponse } from './remote-execute.ts';
|
|
24
27
|
export type { TwinFetchAdapterConfig, TwinFetchHandlerRequest, TwinFetchHandlerResult, TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.ts';
|
|
@@ -111,6 +114,9 @@ export {
|
|
|
111
114
|
withFileLock,
|
|
112
115
|
worldPaths,
|
|
113
116
|
worldStateRoot,
|
|
117
|
+
// Where another pack's store is in a World (architecture A3), and the variable the runtime names its data directory in.
|
|
118
|
+
ownerStoreRoots,
|
|
119
|
+
WORLD_DATA_ENV,
|
|
114
120
|
} from './storage.ts';
|
|
115
121
|
export type {
|
|
116
122
|
AppendEventResult,
|
|
@@ -190,6 +196,8 @@ export {
|
|
|
190
196
|
isTwinBookkeeping,
|
|
191
197
|
pendingTransactionCommits,
|
|
192
198
|
projectResources,
|
|
199
|
+
projectOwnerResources,
|
|
200
|
+
OwnerStoreAmbiguousError,
|
|
193
201
|
revertAction,
|
|
194
202
|
TwinActionPreconditionError, subjectAliases, resolveSubjectId, runWithCorrelationId, currentCorrelationId } from './actions.ts';
|
|
195
203
|
export type {
|
|
@@ -308,7 +316,7 @@ export { referenceField, registerReferences, packReferences, resolveReferences,
|
|
|
308
316
|
export { serveHttp, nodeBuiltin, WORLD_BOOT_PATH, type HttpServer, type ServeHttpOptions, type HttpHandler } from './serve-http.ts';
|
|
309
317
|
// two runtime-neutral helpers for a pack's serve path: a file as a Response, a mirror's client bundle
|
|
310
318
|
export { fileResponse, contentTypeOf } from './file-response.ts';
|
|
311
|
-
export { bundleClient } from './client-bundle.ts';
|
|
319
|
+
export { bundleClient, filePathOf } from './client-bundle.ts';
|
|
312
320
|
// the brand's tokens and faces for a Volter page (the console, the site, the UI kit), fetched at build
|
|
313
321
|
export { brandTokensResponse } from './brand-tokens.ts';
|
|
314
322
|
|
package/src/log.ts
CHANGED
|
@@ -71,6 +71,8 @@ export type Entry = {
|
|
|
71
71
|
/** a landed copy under the vendor's id: the local subject id it stands for */
|
|
72
72
|
aliasOf?: string;
|
|
73
73
|
receipt?: Receipt;
|
|
74
|
+
/** the W3C traceparent of the request that wrote this entry (trace-context.ts); never part of its identity */
|
|
75
|
+
traceparent?: string;
|
|
74
76
|
/** a v1 observed row kept verbatim for `listEvents`; folds nothing unless `fields` was derived */
|
|
75
77
|
event?: WorldServiceEvent;
|
|
76
78
|
[extra: string]: unknown;
|
package/src/packRegistry.ts
CHANGED
|
@@ -15,12 +15,14 @@ import { registerAuthStrategy, registerStateSystem, type StateSystemAdapters } f
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* How a pack's clients ADDRESS it. The first three are HTTP API styles; `raw-tcp` is the
|
|
18
|
-
* RAW-PROTOCOL class — a pack whose clients speak
|
|
19
|
-
* rather than HTTP, so none of the HTTP machinery applies: no
|
|
20
|
-
* the injector's `VENDOR_HOSTS` host map is possible (the
|
|
21
|
-
* sees the traffic). Such a pack is wired into a world
|
|
22
|
-
* and this value is what tells a reader that "no injector
|
|
23
|
-
* missing wiring point. `packages/twin/smtp`
|
|
18
|
+
* RAW-PROTOCOL class — a pack whose clients speak their protocol directly over a TCP socket
|
|
19
|
+
* rather than through the HTTP/1 fetch machinery, so none of the HTTP machinery applies: no
|
|
20
|
+
* `browserRouting`, and no entry in the injector's `VENDOR_HOSTS` host map is possible (the
|
|
21
|
+
* injector patches http/fetch and never sees the traffic). Such a pack is wired into a world
|
|
22
|
+
* through app-read host/port env instead, and this value is what tells a reader that "no injector
|
|
23
|
+
* entry" is STRUCTURAL rather than a missing wiring point. `packages/twin/smtp` (a line protocol)
|
|
24
|
+
* is the first; `packages/twin/temporal` (gRPC: HTTP/2 framing its clients drive themselves) the
|
|
25
|
+
* second.
|
|
24
26
|
*
|
|
25
27
|
* Deliberately the transport CLASS, not the protocol name: naming the wire protocol would put a
|
|
26
28
|
* vendor id in the kernel the moment a pack is named after its protocol, which is exactly what
|