@plurnk/plurnk-service 1.4.0 → 1.5.0
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/.env.defaults +20 -23
- package/INSTALL.md +6 -5
- package/README.md +1 -0
- package/SPEC.md +250 -149
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +2 -3
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/index.d.ts +1 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-marker.d.ts +7 -3
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +2 -1
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +1 -1
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +2 -2
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/read-projector.d.ts +14 -0
- package/dist/content/read-projector.d.ts.map +1 -0
- package/dist/content/read-projector.js +86 -0
- package/dist/content/read-projector.js.map +1 -0
- package/dist/content/read-resolve.d.ts +2 -7
- package/dist/content/read-resolve.d.ts.map +1 -1
- package/dist/content/read-resolve.js +32 -107
- package/dist/content/read-resolve.js.map +1 -1
- package/dist/core/BranchReceipt.d.ts +0 -1
- package/dist/core/BranchReceipt.d.ts.map +1 -1
- package/dist/core/BranchReceipt.js +0 -3
- package/dist/core/BranchReceipt.js.map +1 -1
- package/dist/core/BudgetOverflow.d.ts +0 -3
- package/dist/core/BudgetOverflow.d.ts.map +1 -1
- package/dist/core/BudgetOverflow.js +3 -15
- package/dist/core/BudgetOverflow.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +3 -0
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +2 -2
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +4 -3
- package/dist/core/CoreSchemeServices.d.ts +10 -2
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +3 -7
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +283 -217
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +19 -12
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +261 -167
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +66 -63
- package/dist/core/LogBody.d.ts +2 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +33 -1
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LoopLifecycle.d.ts +1 -2
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +1 -4
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +1 -4
- package/dist/core/PacketBuilder.d.ts +3 -2
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +16 -16
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/StrikeRail.d.ts +5 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +4 -3
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TerminalResult.d.ts +16 -0
- package/dist/core/TerminalResult.d.ts.map +1 -0
- package/dist/core/TerminalResult.js +49 -0
- package/dist/core/TerminalResult.js.map +1 -0
- package/dist/core/caps/CapsResolve.d.ts +5 -1
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js +8 -4
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +6 -4
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +14 -4
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +6 -4
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +27 -13
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/DbTagCaps.d.ts +1 -1
- package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
- package/dist/core/caps/DbTagCaps.js +6 -4
- package/dist/core/caps/DbTagCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +6 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +6 -6
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/fork.sql +2 -2
- package/dist/core/git-iso.d.ts +3 -2
- package/dist/core/git-iso.d.ts.map +1 -1
- package/dist/core/git-iso.js +27 -12
- package/dist/core/git-iso.js.map +1 -1
- package/dist/core/git-membership.d.ts +1 -0
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +86 -24
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +8 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +35 -16
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/namespace.d.ts +1 -0
- package/dist/core/namespace.d.ts.map +1 -1
- package/dist/core/namespace.js +20 -0
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/optimistic-settlement.d.ts +2 -0
- package/dist/core/optimistic-settlement.d.ts.map +1 -0
- package/dist/core/optimistic-settlement.js +14 -0
- package/dist/core/optimistic-settlement.js.map +1 -0
- package/dist/core/packet-wire.d.ts +1 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +81 -35
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/results.d.ts +4 -2
- package/dist/core/results.d.ts.map +1 -1
- package/dist/core/results.js +6 -0
- package/dist/core/results.js.map +1 -1
- package/dist/core/scheme-types.d.ts +0 -12
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/worker-ops.sql +4 -4
- package/dist/core/workspace-settings.js +1 -1
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +236 -74
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +9 -5
- package/dist/schemes/Exec.d.ts +4 -4
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +56 -33
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +4 -5
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +12 -20
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +1 -3
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +11 -19
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +5 -5
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +74 -172
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +20 -13
- package/dist/schemes/Prompt.d.ts +2 -3
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +1 -4
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Skill.d.ts +2 -3
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +0 -3
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts +5 -5
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +92 -81
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +2 -1
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +14 -1
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +9 -3
- package/dist/schemes/_entry-find.d.ts +37 -11
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +141 -153
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +9 -5
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +12 -73
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +1 -2
- package/dist/schemes/_entry-semantic.d.ts +5 -7
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +10 -31
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +2 -2
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +6 -4
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/server/BranchBatches.d.ts +1 -0
- package/dist/server/BranchBatches.d.ts.map +1 -1
- package/dist/server/BranchBatches.js +1 -0
- package/dist/server/BranchBatches.js.map +1 -1
- package/dist/server/Daemon.d.ts +5 -7
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +222 -54
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +3 -3
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/branch-batch.sql +3 -1
- package/dist/server/client-input.d.ts +2 -1
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +7 -1
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/drain.sql +6 -5
- package/dist/server/envelope.d.ts +2 -2
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +0 -1
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +1 -2
- package/dist/server/lifecycle-recovery.sql +34 -1
- package/dist/server/logEntry.d.ts +1 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +2 -1
- package/dist/server/logEntry.js.map +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +13 -1
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +238 -125
- package/package.json +48 -46
- package/dist/matrix/live-specimen.d.ts +0 -9
- package/dist/matrix/live-specimen.d.ts.map +0 -1
- package/dist/matrix/live-specimen.js +0 -37
- package/dist/matrix/live-specimen.js.map +0 -1
package/dist/core/Dispatcher.js
CHANGED
|
@@ -5,27 +5,29 @@ import WorkerControlAddress from "./WorkerControlAddress.js";
|
|
|
5
5
|
import { entryPathnameOf, foldAuthorityIntoPath, renderAddress, renderTarget, schemeNameOf } from "./plurnk-uri.js";
|
|
6
6
|
import Fork from "./fork.js";
|
|
7
7
|
import WorkerCap from "./worker-cap.js";
|
|
8
|
-
import {
|
|
8
|
+
import { PathSyntax } from "@plurnk/plurnk-contracts";
|
|
9
9
|
import Namespace from "./namespace.js";
|
|
10
10
|
import LoopFlagsReader from "./LoopFlagsReader.js";
|
|
11
11
|
import ChannelWrite from "./ChannelWrite.js";
|
|
12
|
-
import { assertEditBatchReceipt, assertEditReceipt, assertResourceEffects, editReceipt, LineMarkerOps, MimetypeBinary, PathMimetype, projectEditReceipt, } from "../content/index.js";
|
|
12
|
+
import { assertEditBatchReceipt, assertEditReceipt, assertResourceEffects, editReceipt, LineMarkerOps, MimetypeBinary, PathMimetype, ReadProjector, projectEditReceipt, } from "../content/index.js";
|
|
13
13
|
import SchemeCtxImpl from "./caps/SchemeCtxImpl.js";
|
|
14
14
|
import EntryCrud from "../schemes/_entry-crud.js";
|
|
15
15
|
import EntryOps from "../schemes/_entry-ops.js";
|
|
16
|
+
import EntryFind from "../schemes/_entry-find.js";
|
|
16
17
|
import WorkspaceSettings from "./workspace-settings.js";
|
|
17
18
|
import LoopLifecycle from "./LoopLifecycle.js";
|
|
19
|
+
import TerminalResult from "./TerminalResult.js";
|
|
18
20
|
import Results from "./results.js";
|
|
19
21
|
import { OperationFailureError } from "./results.js";
|
|
20
22
|
import EffectPolicy from "../schemes/EffectPolicy.js";
|
|
21
|
-
import { CoreSchemeAdapterBase } from "./CoreSchemeServices.js";
|
|
23
|
+
import { CoreSchemeAdapterBase, } from "./CoreSchemeServices.js";
|
|
22
24
|
import { InvalidOperationResultError, NetworkAddress, } from "@plurnk/plurnk-schemes";
|
|
23
25
|
import DurableStatement from "./DurableStatement.js";
|
|
24
26
|
// SPEC {§scheme-surface}: writer must be in target scheme's manifest.writableBy.
|
|
25
27
|
// OPEN/FOLD/READ/FIND are not gated — they curate the log or read, never mutating an entry.
|
|
26
28
|
const MUTATING_OPS = new Set(["EDIT", "SEND", "COPY", "MOVE", "EXEC", "KILL", "FORK", "WORK"]);
|
|
27
29
|
// Op dispatch ({§op-methods-op-dispatch}): gates (writableBy, loop flags), the
|
|
28
|
-
// engine-owned op orchestrations (COPY/MOVE/KILL/SEND
|
|
30
|
+
// engine-owned op orchestrations (COPY/MOVE/KILL/SEND), scheme
|
|
29
31
|
// routing, the durable log write, and the proposal pause.
|
|
30
32
|
class Dispatcher {
|
|
31
33
|
static #failure(code, status, detail, fields = {}, extensions = {}) {
|
|
@@ -95,8 +97,14 @@ class Dispatcher {
|
|
|
95
97
|
const handlerCtx = this.#handlerContext(scheme, ctx);
|
|
96
98
|
return this.#schemes.manifestFor(scheme)?.category === "data" ? handlerCtx : null;
|
|
97
99
|
}
|
|
98
|
-
|
|
100
|
+
#coreCrud(scheme) {
|
|
99
101
|
const handler = this.#schemes.get(scheme);
|
|
102
|
+
return handler instanceof CoreSchemeAdapterBase
|
|
103
|
+
? handler
|
|
104
|
+
: undefined;
|
|
105
|
+
}
|
|
106
|
+
async #readEntry(scheme, pathname, ctx) {
|
|
107
|
+
const handler = this.#coreCrud(scheme);
|
|
100
108
|
const handlerCtx = this.#entryContext(scheme, ctx);
|
|
101
109
|
if (typeof handler?.readEntry === "function" && handlerCtx !== null) {
|
|
102
110
|
return Results.assert(await handler.readEntry(pathname, handlerCtx));
|
|
@@ -120,7 +128,7 @@ class Dispatcher {
|
|
|
120
128
|
});
|
|
121
129
|
}
|
|
122
130
|
async #writeEntry(scheme, pathname, entry, ctx) {
|
|
123
|
-
const handler = this.#
|
|
131
|
+
const handler = this.#coreCrud(scheme);
|
|
124
132
|
const handlerCtx = this.#entryContext(scheme, ctx);
|
|
125
133
|
if (typeof handler?.writeEntry === "function" && handlerCtx !== null) {
|
|
126
134
|
return Results.assert(await handler.writeEntry(pathname, entry, handlerCtx));
|
|
@@ -137,7 +145,7 @@ class Dispatcher {
|
|
|
137
145
|
return Results.assert(await caps.write(pathname, entry, scheme === "prompt" ? "worker" : "commons"));
|
|
138
146
|
}
|
|
139
147
|
async #deleteEntry(scheme, pathname, ctx) {
|
|
140
|
-
const handler = this.#
|
|
148
|
+
const handler = this.#coreCrud(scheme);
|
|
141
149
|
const handlerCtx = this.#entryContext(scheme, ctx);
|
|
142
150
|
if (typeof handler?.deleteEntry === "function" && handlerCtx !== null) {
|
|
143
151
|
return Results.assert(await handler.deleteEntry(pathname, handlerCtx));
|
|
@@ -154,7 +162,7 @@ class Dispatcher {
|
|
|
154
162
|
return Results.assert(await caps.delete(pathname, scheme === "prompt" ? "worker" : "commons"));
|
|
155
163
|
}
|
|
156
164
|
async #deleteChannel(scheme, pathname, channel, ctx) {
|
|
157
|
-
const handler = this.#
|
|
165
|
+
const handler = this.#coreCrud(scheme);
|
|
158
166
|
const handlerCtx = this.#entryContext(scheme, ctx);
|
|
159
167
|
if (typeof handler?.deleteChannel === "function" && handlerCtx !== null) {
|
|
160
168
|
return Results.assert(await handler.deleteChannel(pathname, channel, handlerCtx));
|
|
@@ -241,7 +249,10 @@ class Dispatcher {
|
|
|
241
249
|
else {
|
|
242
250
|
try {
|
|
243
251
|
const addressedScheme = first.target?.kind === "url" ? first.target.scheme : schemeName;
|
|
244
|
-
|
|
252
|
+
const publishedChannel = first.target?.kind === "url"
|
|
253
|
+
? first.target.fragment ?? manifest.defaultChannel
|
|
254
|
+
: manifest.defaultChannel;
|
|
255
|
+
initial = Results.assert(await method.call(handler, group, new SchemeCtxImpl(schemeCtx, addressedScheme ?? schemeName, manifest, this.#liveSubscriptions, { publishedChannel })));
|
|
245
256
|
}
|
|
246
257
|
catch (err) {
|
|
247
258
|
if (err instanceof InvalidOperationResultError)
|
|
@@ -297,31 +308,15 @@ class Dispatcher {
|
|
|
297
308
|
return result;
|
|
298
309
|
}
|
|
299
310
|
async #dispatchOne(context) {
|
|
300
|
-
const { statement, workspaceId, workerId, loopId, turnId, sequence, origin, onDispatch,
|
|
311
|
+
const { statement, workspaceId, workerId, loopId, turnId, sequence, origin, onDispatch, } = context;
|
|
301
312
|
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, loopId, turnId, origin });
|
|
302
313
|
let result;
|
|
303
|
-
let denial =
|
|
304
|
-
&& !operationConstraint.allowedOperations.includes(statement.op)
|
|
305
|
-
? _a.#failure("operation-not-allowed", 409, `${statement.op} was not executed because ${operationConstraint.detail}.`, {}, {
|
|
306
|
-
constraint: operationConstraint.code,
|
|
307
|
-
allowedOperations: [...operationConstraint.allowedOperations],
|
|
308
|
-
retryable: false,
|
|
309
|
-
})
|
|
310
|
-
: null;
|
|
311
|
-
if (denial === null)
|
|
312
|
-
denial = this.#checkWritable(statement, origin);
|
|
314
|
+
let denial = this.#checkWritable(statement, origin);
|
|
313
315
|
if (denial === null)
|
|
314
316
|
denial = await this.#checkFlagsGate(statement, loopId);
|
|
315
317
|
if (denial !== null) {
|
|
316
318
|
result = denial;
|
|
317
319
|
}
|
|
318
|
-
else if (this.#readFansOut(statement)) {
|
|
319
|
-
// Multi-resource scopes, relation matchers, and acquisition-scheme
|
|
320
|
-
// matchers use FIND for selection and write their own rows. An exact
|
|
321
|
-
// stored-resource content matcher remains a direct READ, preserving
|
|
322
|
-
// content-level outcomes such as 203.
|
|
323
|
-
return await this.#handleReadFanout(statement, schemeCtx, { workerId, loopId, turnId, sequence, origin, onDispatch });
|
|
324
|
-
}
|
|
325
320
|
else {
|
|
326
321
|
// {§scheme-surface-exception-500} Scheme-handler
|
|
327
322
|
// exceptions become the action-entry's outcome (status 500), not a
|
|
@@ -531,11 +526,49 @@ class Dispatcher {
|
|
|
531
526
|
origin: "client",
|
|
532
527
|
});
|
|
533
528
|
const schemeCtx = new SchemeCtxImpl(coreCtx, addressedScheme, manifest, this.#liveSubscriptions);
|
|
529
|
+
const resolved = await this.#resolveDataEntryAddress({
|
|
530
|
+
target,
|
|
531
|
+
routedScheme,
|
|
532
|
+
handler,
|
|
533
|
+
manifest,
|
|
534
|
+
ctx: coreCtx,
|
|
535
|
+
schemeCtx,
|
|
536
|
+
});
|
|
537
|
+
if (resolved.address === null)
|
|
538
|
+
return null;
|
|
539
|
+
const rendered = target.kind === "url"
|
|
540
|
+
? renderTarget({ ...target, fragment: null })
|
|
541
|
+
: renderTarget({ scheme: null, pathname: target.raw, fragment: null });
|
|
542
|
+
if (rendered === null)
|
|
543
|
+
throw new TypeError("Resolved entry target did not render.");
|
|
544
|
+
return {
|
|
545
|
+
ownerId: resolved.address.ownerId,
|
|
546
|
+
scheme: resolved.address.scheme,
|
|
547
|
+
pathname: resolved.address.pathname,
|
|
548
|
+
target: rendered,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
async #resolveDataEntryAddress({ target, routedScheme, handler, manifest, ctx, schemeCtx, }) {
|
|
552
|
+
const addressedScheme = target.kind === "url" ? target.scheme : routedScheme;
|
|
553
|
+
const identityTarget = target.kind === "url"
|
|
554
|
+
? {
|
|
555
|
+
...target,
|
|
556
|
+
pathname: PathSyntax.decodeParens(target.pathname),
|
|
557
|
+
fragment: null,
|
|
558
|
+
}
|
|
559
|
+
: { ...target, raw: PathSyntax.decodeParens(target.raw) };
|
|
534
560
|
const resolved = handler.resolveEntryAddress === undefined
|
|
535
|
-
? { pathname: entryPathnameOf(
|
|
536
|
-
: await handler.resolveEntryAddress(
|
|
561
|
+
? { pathname: entryPathnameOf(identityTarget), owner: "commons" }
|
|
562
|
+
: await handler.resolveEntryAddress(identityTarget, schemeCtx);
|
|
537
563
|
if (resolved === null)
|
|
538
|
-
return null;
|
|
564
|
+
return { address: null, result: null };
|
|
565
|
+
if ("status" in resolved) {
|
|
566
|
+
const result = Results.assert(resolved);
|
|
567
|
+
if (result.status < 300) {
|
|
568
|
+
throw new InvalidOperationResultError(`Scheme '${routedScheme}' returned a successful operation result instead of an entry address.`);
|
|
569
|
+
}
|
|
570
|
+
return { address: null, result };
|
|
571
|
+
}
|
|
539
572
|
if (typeof resolved.pathname !== "string") {
|
|
540
573
|
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry pathname.`);
|
|
541
574
|
}
|
|
@@ -547,10 +580,10 @@ class Dispatcher {
|
|
|
547
580
|
ownerId = resolved.ownerId;
|
|
548
581
|
}
|
|
549
582
|
else if (resolved.owner === "worker") {
|
|
550
|
-
ownerId = workerId;
|
|
583
|
+
ownerId = ctx.workerId;
|
|
551
584
|
}
|
|
552
585
|
else if (resolved.owner === "commons") {
|
|
553
|
-
ownerId = await Owner.commonsId(this.#db, workspaceId);
|
|
586
|
+
ownerId = await Owner.commonsId(this.#db, ctx.workspaceId);
|
|
554
587
|
}
|
|
555
588
|
else {
|
|
556
589
|
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry owner.`);
|
|
@@ -558,16 +591,48 @@ class Dispatcher {
|
|
|
558
591
|
if (!Number.isSafeInteger(ownerId) || ownerId < 1) {
|
|
559
592
|
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry owner id.`);
|
|
560
593
|
}
|
|
561
|
-
const rendered = target.kind === "url"
|
|
562
|
-
? renderTarget({ ...target, fragment: null })
|
|
563
|
-
: renderTarget({ scheme: null, pathname: target.raw, fragment: null });
|
|
564
|
-
if (rendered === null)
|
|
565
|
-
throw new TypeError("Resolved entry target did not render.");
|
|
566
594
|
return {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
595
|
+
address: {
|
|
596
|
+
ownerId,
|
|
597
|
+
scheme: manifest.storedScheme ?? addressedScheme,
|
|
598
|
+
pathname: resolved.pathname,
|
|
599
|
+
},
|
|
600
|
+
result: null,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
async #prepareDataRepresentation({ target, routedScheme, handler, manifest, ctx, schemeCtx, publishedChannel, }) {
|
|
604
|
+
const resolved = await this.#resolveDataEntryAddress({
|
|
605
|
+
target,
|
|
606
|
+
routedScheme,
|
|
607
|
+
handler,
|
|
608
|
+
manifest,
|
|
609
|
+
ctx,
|
|
610
|
+
schemeCtx,
|
|
611
|
+
});
|
|
612
|
+
if (resolved.address === null
|
|
613
|
+
|| resolved.result !== null
|
|
614
|
+
|| typeof handler.prepareRepresentation !== "function") {
|
|
615
|
+
return resolved;
|
|
616
|
+
}
|
|
617
|
+
const address = resolved.address;
|
|
618
|
+
const selectionNeutralTarget = target.kind === "url"
|
|
619
|
+
? {
|
|
620
|
+
...target,
|
|
621
|
+
raw: renderTarget({ ...target, fragment: null }) ?? target.raw,
|
|
622
|
+
fragment: null,
|
|
623
|
+
}
|
|
624
|
+
: target;
|
|
625
|
+
const preparationCtx = new SchemeCtxImpl(ctx, target.kind === "url" ? target.scheme : routedScheme, manifest, this.#liveSubscriptions, {
|
|
626
|
+
ownerId: address.ownerId,
|
|
627
|
+
publishedChannel,
|
|
628
|
+
});
|
|
629
|
+
const prepared = Results.assertRepresentationPreparation(await handler.prepareRepresentation({
|
|
630
|
+
target: selectionNeutralTarget,
|
|
631
|
+
pathname: address.pathname,
|
|
632
|
+
}, preparationCtx));
|
|
633
|
+
return {
|
|
634
|
+
address,
|
|
635
|
+
result: prepared.status === 200 ? null : prepared,
|
|
571
636
|
};
|
|
572
637
|
}
|
|
573
638
|
// An accepted EXEC reads a non-file source through the same registered
|
|
@@ -829,7 +894,7 @@ class Dispatcher {
|
|
|
829
894
|
if (statement.op === "FORK") {
|
|
830
895
|
// Branch the current worker's log into a named sister.
|
|
831
896
|
const branchWorkerId = await Fork.fork(this.#db, ctx.workerId, name);
|
|
832
|
-
await ctx.injectWorker({ workspaceId: ctx.workspaceId, workerId: branchWorkerId, prompt, flags });
|
|
897
|
+
await ctx.injectWorker({ workspaceId: ctx.workspaceId, workerId: branchWorkerId, prompt, flags, parentLoopId: ctx.loopId });
|
|
833
898
|
return { status: 200, body: name };
|
|
834
899
|
}
|
|
835
900
|
// WORK — a fresh worker sister named <name>.
|
|
@@ -838,7 +903,7 @@ class Dispatcher {
|
|
|
838
903
|
});
|
|
839
904
|
if (row === undefined)
|
|
840
905
|
throw new Error("worker spawn: worker insert returned no row");
|
|
841
|
-
await ctx.injectWorker({ workspaceId: ctx.workspaceId, workerId: row.id, prompt, flags });
|
|
906
|
+
await ctx.injectWorker({ workspaceId: ctx.workspaceId, workerId: row.id, prompt, flags, parentLoopId: ctx.loopId });
|
|
842
907
|
return { status: 200, body: name };
|
|
843
908
|
}
|
|
844
909
|
async #handleCopy(statement, ctx) {
|
|
@@ -949,178 +1014,28 @@ class Dispatcher {
|
|
|
949
1014
|
// carries the delete target to review (#isProposal fires on 202). Plurnk-internal deletes execute inline.
|
|
950
1015
|
return this.#deleteEntry(schemeName, entryPathnameOf(path), ctx);
|
|
951
1016
|
}
|
|
952
|
-
//
|
|
953
|
-
//
|
|
954
|
-
//
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
return false;
|
|
958
|
-
const body = statement.body;
|
|
959
|
-
if (body?.dialect === "semantic" || body?.dialect === "graph")
|
|
960
|
-
return true;
|
|
961
|
-
const schemeName = schemeNameOf(statement.target);
|
|
962
|
-
const handler = schemeName === null
|
|
963
|
-
? undefined
|
|
964
|
-
: this.#schemes.get(schemeName);
|
|
965
|
-
if (body !== null && typeof handler?.prepareFind === "function")
|
|
966
|
-
return true;
|
|
967
|
-
const t = statement.target;
|
|
968
|
-
const p = t === null ? "" : (t.kind === "url" ? t.pathname : t.raw);
|
|
969
|
-
if (PathSyntax.hasGlob(p))
|
|
970
|
-
return true;
|
|
971
|
-
return p.endsWith("/") && schemeName !== null && this.#schemes.manifestFor(schemeName)?.folderScopes === true;
|
|
972
|
-
}
|
|
973
|
-
static #retargetRead(statement, pathname, lineMarker, body) {
|
|
974
|
-
const t = statement.target;
|
|
975
|
-
const target = t !== null && t.kind === "url"
|
|
976
|
-
? { ...t, pathname, raw: `${t.scheme}://${pathname}` }
|
|
977
|
-
: { ...t, raw: pathname };
|
|
978
|
-
return { ...statement, target: target, lineMarker, body };
|
|
979
|
-
}
|
|
980
|
-
// READ scope always projects text. Semantic READ reserves a leading decimal
|
|
981
|
-
// for similarity selection; any remaining integers are the text projection.
|
|
982
|
-
// FIND retains its own public result-range interpretation.
|
|
983
|
-
static #readMarkers(statement) {
|
|
984
|
-
const marker = statement.lineMarker;
|
|
985
|
-
if (statement.body?.dialect !== "semantic") {
|
|
986
|
-
return { selection: null, projection: marker };
|
|
987
|
-
}
|
|
988
|
-
if (marker === null)
|
|
989
|
-
return { selection: null, projection: null };
|
|
990
|
-
const [first, ...rest] = marker.marks;
|
|
991
|
-
if (Number.isInteger(first)) {
|
|
992
|
-
return { selection: null, projection: marker };
|
|
993
|
-
}
|
|
994
|
-
return {
|
|
995
|
-
selection: { marks: [first] },
|
|
996
|
-
projection: rest.length === 0 ? null : { marks: rest },
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
#standardEntryManifest(schemeName, statement) {
|
|
1000
|
-
const handler = this.#schemes.get(schemeName);
|
|
1001
|
-
if (typeof handler?.find === "function")
|
|
1002
|
-
return null;
|
|
1003
|
-
const target = statement.target;
|
|
1004
|
-
if (target === null || target.kind !== "url" || target.scheme === null)
|
|
1005
|
-
return null;
|
|
1006
|
-
const manifest = this.#schemes.manifestFor(schemeName);
|
|
1007
|
-
return manifest === undefined ? null : { ...manifest, name: target.scheme };
|
|
1008
|
-
}
|
|
1009
|
-
static #storedEntryRead(statement, pathname, lineMarker, body, storage) {
|
|
1010
|
-
const target = statement.target;
|
|
1011
|
-
if (target === null || target.kind !== "url")
|
|
1012
|
-
return _a.#retargetRead(statement, pathname, lineMarker, body);
|
|
1013
|
-
if (NetworkAddress.supports(target.scheme)) {
|
|
1014
|
-
const parsed = parsePath(renderAddress(target.scheme, pathname));
|
|
1015
|
-
if (parsed === null || parsed.kind !== "url") {
|
|
1016
|
-
throw new Error(`failed to reconstruct network entry target for ${target.scheme}:${pathname}`);
|
|
1017
|
-
}
|
|
1018
|
-
const reconstructed = { ...parsed, fragment: target.fragment };
|
|
1019
|
-
const raw = renderTarget(reconstructed);
|
|
1020
|
-
if (raw === null)
|
|
1021
|
-
throw new Error(`failed to render network entry target for ${target.scheme}:${pathname}`);
|
|
1022
|
-
return {
|
|
1023
|
-
...statement,
|
|
1024
|
-
target: { ...reconstructed, raw },
|
|
1025
|
-
lineMarker,
|
|
1026
|
-
body,
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
const hostPrefix = target.hostname === null ? null : `/${target.hostname}`;
|
|
1030
|
-
const displayPath = hostPrefix !== null && pathname.startsWith(`${hostPrefix}/`)
|
|
1031
|
-
? pathname.slice(hostPrefix.length)
|
|
1032
|
-
: pathname;
|
|
1033
|
-
return {
|
|
1034
|
-
...statement,
|
|
1035
|
-
target: storage
|
|
1036
|
-
? { ...target, hostname: null, pathname, raw: `${target.scheme}://${pathname}` }
|
|
1037
|
-
: { ...target, pathname: displayPath, raw: `${target.scheme}://${target.hostname ?? ""}${displayPath}` },
|
|
1038
|
-
lineMarker,
|
|
1039
|
-
body,
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
async #handleReadFanout(statement, ctx, ids) {
|
|
1043
|
-
const { workerId, loopId, turnId, sequence, origin, onDispatch } = ids;
|
|
1044
|
-
const schemeName = schemeNameOf(statement.target);
|
|
1045
|
-
const read = statement;
|
|
1046
|
-
const markers = _a.#readMarkers(read);
|
|
1047
|
-
const findStatement = {
|
|
1048
|
-
...statement,
|
|
1049
|
-
op: "FIND",
|
|
1050
|
-
lineMarker: markers.selection,
|
|
1051
|
-
};
|
|
1052
|
-
const standardEntryManifest = schemeName === null ? null : this.#standardEntryManifest(schemeName, statement);
|
|
1053
|
-
const found = await this.#run(schemeName, findStatement, ctx);
|
|
1054
|
-
const matches = found.matches ?? [];
|
|
1055
|
-
const omittedItems = typeof found.omittedItems === "number" ? found.omittedItems : null;
|
|
1056
|
-
if (omittedItems !== null) {
|
|
1057
|
-
const maximumItems = typeof found.maximumItems === "number" ? found.maximumItems : null;
|
|
1058
|
-
const result = _a.#failure("read-materialization-too-large", 413, `READ selected ${omittedItems} resources, exceeding the materialization limit${maximumItems === null ? "" : ` of ${maximumItems}`}.`, {}, {
|
|
1059
|
-
resources: omittedItems,
|
|
1060
|
-
...(maximumItems === null ? {} : { maximumResources: maximumItems }),
|
|
1061
|
-
stage: "materialization",
|
|
1062
|
-
recovery: "Narrow the target or matcher.",
|
|
1063
|
-
retryable: false,
|
|
1064
|
-
});
|
|
1065
|
-
const readRowId = await this.#writeLog({ statement, result, workspaceId: ctx.workspaceId, workerId, loopId, turnId, sequence, origin });
|
|
1066
|
-
onDispatch?.(readRowId);
|
|
1067
|
-
return { ...result, rowsWritten: 1 };
|
|
1068
|
-
}
|
|
1069
|
-
// Find-less scheme, a matcher/scope error, or zero matches → a single row carrying the
|
|
1070
|
-
// status, exactly like a non-fanned READ. The model sees the empty/failed result, not silence.
|
|
1071
|
-
if (found.status !== 200 || matches.length === 0) {
|
|
1072
|
-
const result = found.status === 200
|
|
1073
|
-
? { status: 204, ...(read.body === null ? {} : { matches: [] }) }
|
|
1074
|
-
: found;
|
|
1075
|
-
const id = await this.#writeLog({ statement, result, workspaceId: ctx.workspaceId, workerId, loopId, turnId, sequence, origin });
|
|
1076
|
-
onDispatch?.(id);
|
|
1077
|
-
return { ...result, rowsWritten: 1 };
|
|
1078
|
-
}
|
|
1079
|
-
const fannedStatuses = [];
|
|
1080
|
-
const scopeNormalizations = [];
|
|
1081
|
-
let written = 0;
|
|
1082
|
-
for (const match of matches) {
|
|
1083
|
-
ctx.signal?.throwIfAborted();
|
|
1084
|
-
const executionStatement = standardEntryManifest === null
|
|
1085
|
-
? _a.#retargetRead(statement, match.pathname, markers.projection, null)
|
|
1086
|
-
: _a.#storedEntryRead(statement, match.pathname, markers.projection, null, true);
|
|
1087
|
-
const readResult = standardEntryManifest === null
|
|
1088
|
-
? await this.#run(schemeName, executionStatement, ctx)
|
|
1089
|
-
: await EntryOps.readWorkspaceEntry(executionStatement, ctx, standardEntryManifest);
|
|
1090
|
-
const result = read.body === null
|
|
1091
|
-
? readResult
|
|
1092
|
-
: { ...readResult, matches: match.matches };
|
|
1093
|
-
const loggedStatement = standardEntryManifest === null
|
|
1094
|
-
? _a.#retargetRead(statement, match.pathname, statement.lineMarker, read.body)
|
|
1095
|
-
: _a.#storedEntryRead(statement, match.pathname, statement.lineMarker, read.body, false);
|
|
1096
|
-
const id = await this.#writeLog({ statement: loggedStatement, result, workspaceId: ctx.workspaceId, workerId, loopId, turnId, sequence: sequence + written, origin });
|
|
1097
|
-
onDispatch?.(id);
|
|
1098
|
-
fannedStatuses.push(result.status);
|
|
1099
|
-
scopeNormalizations.push(...(result.scopeNormalizations ?? []));
|
|
1100
|
-
written++;
|
|
1101
|
-
}
|
|
1102
|
-
return {
|
|
1103
|
-
status: 200,
|
|
1104
|
-
rowsWritten: written,
|
|
1105
|
-
fannedStatuses,
|
|
1106
|
-
...(scopeNormalizations.length === 0 ? {} : { scopeNormalizations }),
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
// {§model-entry} — mirror an admitted model emission back as an actionless `model` log row, so
|
|
1110
|
-
// the model can inspect and curate its own prior behavior.
|
|
1017
|
+
// {§model-entry} — mirror a model emission back as an actionless log row, so
|
|
1018
|
+
// the model can inspect and curate its own prior behavior. Ordinary admitted
|
|
1019
|
+
// emissions are folded; the bounded invalid-emission lifeline is the one
|
|
1020
|
+
// born-open rejected item under {§invalid-emission-attempts} and labels
|
|
1021
|
+
// that admission fact structurally.
|
|
1111
1022
|
// Born FOLDED by default (budget-neutral until OPENed); the turn-0 exemplar passes folded:false
|
|
1112
1023
|
// (born open — the one worked example the model orients on, thinning the grammar). text/vnd.plurnk.
|
|
1113
|
-
async writeModelEntry({ verbatim, workerId, loopId, turnId, sequence, folded, origin = "model", reasoningItems }) {
|
|
1024
|
+
async writeModelEntry({ verbatim, workerId, loopId, turnId, sequence, folded, origin = "model", admission = "accepted", reasoningItems }) {
|
|
1114
1025
|
const row = await this.#db.engine_insert_log_entry.get({
|
|
1115
1026
|
worker_id: workerId, loop_id: loopId, turn_id: turnId, sequence,
|
|
1116
|
-
origin, source: null, op:
|
|
1027
|
+
origin, source: null, op: null, suffix: "", signal: null,
|
|
1117
1028
|
scheme: null, username: null, password: null, hostname: null, port: null,
|
|
1118
1029
|
pathname: null, query: null, fragment: null, lineMarker: null,
|
|
1119
1030
|
tx: "", mimetype_tx: "text/vnd.plurnk",
|
|
1120
1031
|
rx: JSON.stringify({ content: verbatim, mimetype: "text/vnd.plurnk" }),
|
|
1121
1032
|
mimetype_rx: "application/json",
|
|
1122
1033
|
status_rx: 200, tokens: this.#tokenize(verbatim), state: "resolved", outcome: null,
|
|
1123
|
-
attrs:
|
|
1034
|
+
attrs: JSON.stringify({
|
|
1035
|
+
kind: "model_emission",
|
|
1036
|
+
...(admission === "rejected" ? { admission } : {}),
|
|
1037
|
+
...(reasoningItems !== undefined && reasoningItems.length > 0 ? { reasoning: reasoningItems } : {}),
|
|
1038
|
+
}),
|
|
1124
1039
|
});
|
|
1125
1040
|
if (row === undefined)
|
|
1126
1041
|
throw new Error("Dispatcher.writeModelEntry: insert returned no row");
|
|
@@ -1202,7 +1117,30 @@ class Dispatcher {
|
|
|
1202
1117
|
};
|
|
1203
1118
|
}
|
|
1204
1119
|
async #selectSource(selection, ctx) {
|
|
1205
|
-
const
|
|
1120
|
+
const handler = this.#schemes.get(selection.scheme);
|
|
1121
|
+
if (handler === undefined) {
|
|
1122
|
+
throw new InvalidOperationResultError(`Resolved COPY/MOVE source scheme '${selection.scheme}' is no longer registered.`);
|
|
1123
|
+
}
|
|
1124
|
+
const addressedScheme = selection.target.kind === "url"
|
|
1125
|
+
? selection.target.scheme
|
|
1126
|
+
: selection.scheme;
|
|
1127
|
+
const schemeCtx = new SchemeCtxImpl(ctx, addressedScheme, selection.manifest, this.#liveSubscriptions, { publishedChannel: selection.channel });
|
|
1128
|
+
const prepared = await this.#prepareDataRepresentation({
|
|
1129
|
+
target: selection.target,
|
|
1130
|
+
routedScheme: selection.scheme,
|
|
1131
|
+
handler,
|
|
1132
|
+
manifest: selection.manifest,
|
|
1133
|
+
ctx,
|
|
1134
|
+
schemeCtx,
|
|
1135
|
+
publishedChannel: selection.channel,
|
|
1136
|
+
});
|
|
1137
|
+
if (prepared.result !== null)
|
|
1138
|
+
return prepared.result;
|
|
1139
|
+
if (prepared.address === null) {
|
|
1140
|
+
return _a.#failure("entry-not-found", 404, `No entry exists at ${this.#resourceAddress(selection)}.`, {}, { target: this.#resourceAddress(selection) });
|
|
1141
|
+
}
|
|
1142
|
+
const storageAddress = prepared.address;
|
|
1143
|
+
const read = await EntryCrud.readEntry(storageAddress.pathname, ctx, storageAddress.scheme, storageAddress.ownerId);
|
|
1206
1144
|
if (read.status >= 400)
|
|
1207
1145
|
return read;
|
|
1208
1146
|
if (read.status !== 200 || read.entry === null) {
|
|
@@ -1210,8 +1148,8 @@ class Dispatcher {
|
|
|
1210
1148
|
}
|
|
1211
1149
|
const selected = read.entry.channels[selection.channel];
|
|
1212
1150
|
if (selected === undefined) {
|
|
1213
|
-
return _a.#failure("channel-not-found", 404, `No channel named #${selection.channel} exists at ${renderAddress(
|
|
1214
|
-
target: renderAddress(
|
|
1151
|
+
return _a.#failure("channel-not-found", 404, `No channel named #${selection.channel} exists at ${renderAddress(storageAddress.scheme, storageAddress.pathname)}.`, {}, {
|
|
1152
|
+
target: renderAddress(storageAddress.scheme, storageAddress.pathname),
|
|
1215
1153
|
requestedChannel: selection.channel,
|
|
1216
1154
|
availableChannels: Object.keys(read.entry.channels),
|
|
1217
1155
|
retryable: false,
|
|
@@ -1234,8 +1172,12 @@ class Dispatcher {
|
|
|
1234
1172
|
content = sliced.text ?? "";
|
|
1235
1173
|
scopeNormalizations = sliced.scopeNormalizations;
|
|
1236
1174
|
}
|
|
1175
|
+
if (selected.producerResult !== undefined && selected.producerResult.status >= 400) {
|
|
1176
|
+
return Results.assert(selected.producerResult);
|
|
1177
|
+
}
|
|
1237
1178
|
return {
|
|
1238
1179
|
...selection,
|
|
1180
|
+
storageAddress,
|
|
1239
1181
|
content,
|
|
1240
1182
|
mimetype: selected.mimetype,
|
|
1241
1183
|
...(scopeNormalizations === undefined ? {} : { scopeNormalizations }),
|
|
@@ -1911,7 +1853,7 @@ class Dispatcher {
|
|
|
1911
1853
|
if (status === null) {
|
|
1912
1854
|
return _a.#failure("send-status-required", 400, "SEND requires a numeric status.", {}, { retryable: false });
|
|
1913
1855
|
}
|
|
1914
|
-
const raw = statement.body === null ? "" :
|
|
1856
|
+
const raw = statement.body === null ? "" : statement.body.raw;
|
|
1915
1857
|
// The park rides SEND[202] only ({§park-202-only}). A scoped SEND[102] is neither
|
|
1916
1858
|
// a wait nor a meaningful continuation, so reject it instead of preserving the
|
|
1917
1859
|
// retired dual spelling.
|
|
@@ -1927,7 +1869,7 @@ class Dispatcher {
|
|
|
1927
1869
|
// indefinite park. {§join-blocking-collect}
|
|
1928
1870
|
const joinArmed = this.#joinTargets.delete(loopId);
|
|
1929
1871
|
if (status === 102 && statement.lineMarker === null && joinArmed) {
|
|
1930
|
-
if (!await this.#lifecycle.park(loopId
|
|
1872
|
+
if (!await this.#lifecycle.park(loopId)) {
|
|
1931
1873
|
return _a.#statusResult(await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to park it.");
|
|
1932
1874
|
}
|
|
1933
1875
|
this.#parkDeadlines.set(loopId, -1); // indefinite: the bounded child's terminal is the wake edge
|
|
@@ -1942,7 +1884,7 @@ class Dispatcher {
|
|
|
1942
1884
|
const marks = statement.lineMarker?.marks[0];
|
|
1943
1885
|
const seconds = typeof marks === "number" ? marks : -1; // bare 202 / absent T = indefinite, bounded by the join
|
|
1944
1886
|
if (await this.#hasLiveWork(workerId)) {
|
|
1945
|
-
if (!await this.#lifecycle.park(loopId
|
|
1887
|
+
if (!await this.#lifecycle.park(loopId)) {
|
|
1946
1888
|
return _a.#statusResult(await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to wait.");
|
|
1947
1889
|
}
|
|
1948
1890
|
this.#parkDeadlines.set(loopId, seconds);
|
|
@@ -1964,7 +1906,7 @@ class Dispatcher {
|
|
|
1964
1906
|
return branchDenial;
|
|
1965
1907
|
// The joined set is already drained. Awaiting an empty task group completes
|
|
1966
1908
|
// immediately; it never parks and needs no corrective model turn.
|
|
1967
|
-
const finished = await this.#lifecycle.finish(loopId,
|
|
1909
|
+
const finished = await this.#lifecycle.finish(loopId, TerminalResult.success(raw));
|
|
1968
1910
|
return {
|
|
1969
1911
|
status: finished !== null ? 200 : await this.#lifecycle.status(loopId),
|
|
1970
1912
|
attrs: { joined: true, pending: 0 },
|
|
@@ -2022,7 +1964,7 @@ class Dispatcher {
|
|
|
2022
1964
|
const branchDenial = await this.#branchCompletionGate?.(workerId) ?? null;
|
|
2023
1965
|
if (branchDenial !== null)
|
|
2024
1966
|
return branchDenial;
|
|
2025
|
-
const finished = await this.#lifecycle.finish(loopId,
|
|
1967
|
+
const finished = await this.#lifecycle.finish(loopId, TerminalResult.success(raw));
|
|
2026
1968
|
return _a.#statusResult(finished !== null ? 200 : await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to conclude it.");
|
|
2027
1969
|
}
|
|
2028
1970
|
if (status === 499) {
|
|
@@ -2050,7 +1992,20 @@ class Dispatcher {
|
|
|
2050
1992
|
}
|
|
2051
1993
|
async #run(schemeName, statement, ctx) {
|
|
2052
1994
|
if (schemeName === null) {
|
|
2053
|
-
|
|
1995
|
+
const fields = statement.op === "READ"
|
|
1996
|
+
? { content: null, mimetype: null, channel: null }
|
|
1997
|
+
: statement.op === "FIND"
|
|
1998
|
+
? {
|
|
1999
|
+
content: null,
|
|
2000
|
+
mimetype: null,
|
|
2001
|
+
results: [],
|
|
2002
|
+
itemsTokenTotal: 0,
|
|
2003
|
+
returnedItemsTokenTotal: 0,
|
|
2004
|
+
matchingPathCount: 0,
|
|
2005
|
+
matchLocationCount: 0,
|
|
2006
|
+
}
|
|
2007
|
+
: {};
|
|
2008
|
+
return _a.#failure("target-scheme-required", 400, `${statement.op} requires a target scheme.`, fields, { operation: statement.op, retryable: false });
|
|
2054
2009
|
}
|
|
2055
2010
|
if (statement.op === "SEND" && statement.signal === 499 && statement.target?.kind === "url") {
|
|
2056
2011
|
const addressedScheme = statement.target.scheme;
|
|
@@ -2084,16 +2039,127 @@ class Dispatcher {
|
|
|
2084
2039
|
const manifest = this.#schemes.manifestFor(schemeName);
|
|
2085
2040
|
if (manifest === undefined)
|
|
2086
2041
|
throw new Error(`scheme '${schemeName}' has no manifest`);
|
|
2087
|
-
const
|
|
2088
|
-
|
|
2089
|
-
|
|
2042
|
+
const publishedChannel = statement.target?.kind === "url"
|
|
2043
|
+
? statement.target.fragment ?? manifest.defaultChannel
|
|
2044
|
+
: manifest.defaultChannel;
|
|
2045
|
+
const schemeCtx = new SchemeCtxImpl(ctx, addressedScheme ?? schemeName, manifest, this.#liveSubscriptions, { publishedChannel });
|
|
2046
|
+
if (statement.op === "READ"
|
|
2047
|
+
&& handler instanceof CoreSchemeAdapterBase
|
|
2048
|
+
&& typeof handler.resolveCoreRepresentation === "function") {
|
|
2049
|
+
const selectionNeutralTarget = statement.target?.kind === "url"
|
|
2050
|
+
? {
|
|
2051
|
+
...statement.target,
|
|
2052
|
+
raw: renderTarget({ ...statement.target, fragment: null }) ?? statement.target.raw,
|
|
2053
|
+
fragment: null,
|
|
2054
|
+
}
|
|
2055
|
+
: statement.target;
|
|
2056
|
+
const resolved = await handler
|
|
2057
|
+
.resolveCoreRepresentation(selectionNeutralTarget, schemeCtx);
|
|
2058
|
+
if ("result" in resolved)
|
|
2059
|
+
return Results.assertReadResult(resolved.result);
|
|
2060
|
+
if (selectionNeutralTarget === null) {
|
|
2061
|
+
throw new InvalidOperationResultError(`Core scheme '${schemeName}' resolved a targetless READ representation.`);
|
|
2062
|
+
}
|
|
2063
|
+
const target = renderTarget(selectionNeutralTarget.kind === "url"
|
|
2064
|
+
? selectionNeutralTarget
|
|
2065
|
+
: { scheme: null, pathname: selectionNeutralTarget.raw });
|
|
2066
|
+
if (target === null) {
|
|
2067
|
+
throw new TypeError(`Core scheme '${schemeName}' resolved an unrenderable READ target.`);
|
|
2068
|
+
}
|
|
2069
|
+
return Results.assertReadResult(await ReadProjector.project({
|
|
2070
|
+
statement,
|
|
2071
|
+
manifest,
|
|
2072
|
+
target,
|
|
2073
|
+
representation: resolved.representation,
|
|
2074
|
+
mimetypes: ctx.mimetypes,
|
|
2075
|
+
}));
|
|
2076
|
+
}
|
|
2077
|
+
if (statement.op === "READ" && manifest.category === "data") {
|
|
2078
|
+
const prepared = statement.target === null
|
|
2079
|
+
? { address: null, result: null }
|
|
2080
|
+
: await this.#prepareDataRepresentation({
|
|
2081
|
+
target: statement.target,
|
|
2082
|
+
routedScheme: schemeName,
|
|
2083
|
+
handler: handler,
|
|
2084
|
+
manifest,
|
|
2085
|
+
ctx,
|
|
2086
|
+
schemeCtx,
|
|
2087
|
+
publishedChannel,
|
|
2088
|
+
});
|
|
2089
|
+
if (prepared.result !== null)
|
|
2090
|
+
return prepared.result;
|
|
2091
|
+
const resolved = prepared.address;
|
|
2092
|
+
if (statement.target !== null && resolved === null) {
|
|
2093
|
+
const target = renderTarget(statement.target.kind === "url"
|
|
2094
|
+
? statement.target
|
|
2095
|
+
: { scheme: null, pathname: statement.target.raw });
|
|
2096
|
+
return Results.failure(`scheme:${schemeName}`, "entry-not-found", 404, `No entry exists at ${target ?? "the requested address"}.`, { content: null, mimetype: null, channel: null }, { target });
|
|
2097
|
+
}
|
|
2098
|
+
const storageScheme = resolved?.scheme ?? manifest.storedScheme ?? addressedScheme ?? schemeName;
|
|
2099
|
+
const projected = Results.assertReadResult(await EntryOps.readWorkspaceEntry(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, resolved === null
|
|
2100
|
+
? {}
|
|
2101
|
+
: {
|
|
2102
|
+
ownerId: resolved.ownerId,
|
|
2103
|
+
pathname: resolved.pathname,
|
|
2104
|
+
}));
|
|
2105
|
+
return projected;
|
|
2106
|
+
}
|
|
2090
2107
|
if (statement.op !== "FIND" || manifest.category !== "data") {
|
|
2108
|
+
if (typeof method === "function") {
|
|
2109
|
+
return Results.assert(await method.call(handler, statement, schemeCtx));
|
|
2110
|
+
}
|
|
2091
2111
|
return _a.#failure("operation-not-implemented", 501, `Scheme '${schemeName}' does not implement ${statement.op}.`, {}, {
|
|
2092
2112
|
scheme: schemeName,
|
|
2093
2113
|
operation: statement.op,
|
|
2094
2114
|
retryable: false,
|
|
2095
2115
|
});
|
|
2096
2116
|
}
|
|
2117
|
+
const targetPathname = statement.target?.kind === "url"
|
|
2118
|
+
? statement.target.pathname
|
|
2119
|
+
: statement.target?.raw ?? "";
|
|
2120
|
+
const collectionTarget = manifest.folderScopes === true
|
|
2121
|
+
&& (targetPathname === "" || targetPathname.endsWith("/"));
|
|
2122
|
+
const exactTarget = statement.target !== null
|
|
2123
|
+
&& !collectionTarget
|
|
2124
|
+
&& !PathSyntax.hasGlob(entryPathnameOf(statement.target));
|
|
2125
|
+
if (exactTarget && statement.target !== null) {
|
|
2126
|
+
const prepared = await this.#prepareDataRepresentation({
|
|
2127
|
+
target: statement.target,
|
|
2128
|
+
routedScheme: schemeName,
|
|
2129
|
+
handler: handler,
|
|
2130
|
+
manifest,
|
|
2131
|
+
ctx,
|
|
2132
|
+
schemeCtx,
|
|
2133
|
+
publishedChannel,
|
|
2134
|
+
});
|
|
2135
|
+
if (prepared.result !== null)
|
|
2136
|
+
return prepared.result;
|
|
2137
|
+
if (prepared.address === null) {
|
|
2138
|
+
const target = renderTarget(statement.target.kind === "url"
|
|
2139
|
+
? statement.target
|
|
2140
|
+
: { scheme: null, pathname: statement.target.raw });
|
|
2141
|
+
return Results.failure(`scheme:${schemeName}`, "entry-not-found", 404, `No entry exists at ${target ?? "the requested address"}.`, {
|
|
2142
|
+
content: null,
|
|
2143
|
+
mimetype: null,
|
|
2144
|
+
results: [],
|
|
2145
|
+
itemsTokenTotal: 0,
|
|
2146
|
+
returnedItemsTokenTotal: 0,
|
|
2147
|
+
matchingPathCount: 0,
|
|
2148
|
+
matchLocationCount: 0,
|
|
2149
|
+
}, { target });
|
|
2150
|
+
}
|
|
2151
|
+
const storageScheme = prepared.address.scheme
|
|
2152
|
+
?? manifest.storedScheme
|
|
2153
|
+
?? addressedScheme
|
|
2154
|
+
?? schemeName;
|
|
2155
|
+
return Results.assert(await EntryFind.findWorkspaceEntries(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, {
|
|
2156
|
+
ownerId: prepared.address.ownerId,
|
|
2157
|
+
pathname: prepared.address.pathname,
|
|
2158
|
+
}));
|
|
2159
|
+
}
|
|
2160
|
+
if (typeof method === "function") {
|
|
2161
|
+
return Results.assert(await method.call(handler, statement, schemeCtx));
|
|
2162
|
+
}
|
|
2097
2163
|
const prepareFind = handler.prepareFind;
|
|
2098
2164
|
if (typeof prepareFind === "function") {
|
|
2099
2165
|
const prepared = await prepareFind.call(handler, statement, schemeCtx);
|