dsh-lcx-codex 0.4.3 → 0.4.4-pre.1
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/lib/abort-error.js +47 -0
- package/lib/client.js +97 -98
- package/lib/dsh-responses.js +70 -33
- package/lib/index.js +27 -11
- package/lib/invocation-policy-scope.js +4 -8
- package/lib/native-checkpoint.js +42 -3
- package/lib/pi-responses-runtime.js +251 -97
- package/lib/responses-request.js +2 -2
- package/lib/responses-stream.js +35 -8
- package/lib/search-usage.js +5 -13
- package/lib/service-mutex.js +4 -8
- package/lib/transport.js +6 -6
- package/package.json +28 -27
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { abortError } from "./abort-error.js";
|
|
2
3
|
const activePolicy = new AsyncLocalStorage();
|
|
3
4
|
const projections = new WeakMap();
|
|
4
5
|
function scopedValue(values, target, key) {
|
|
@@ -118,11 +119,6 @@ function restoreProjection(record) {
|
|
|
118
119
|
}
|
|
119
120
|
catch { }
|
|
120
121
|
}
|
|
121
|
-
function operationError(signal) {
|
|
122
|
-
if (signal?.reason instanceof Error)
|
|
123
|
-
return signal.reason;
|
|
124
|
-
return new DOMException("The operation was aborted", "AbortError");
|
|
125
|
-
}
|
|
126
122
|
export class InvocationPolicyScope {
|
|
127
123
|
records = new Set();
|
|
128
124
|
queue = [];
|
|
@@ -147,7 +143,7 @@ export class InvocationPolicyScope {
|
|
|
147
143
|
if (this.closed)
|
|
148
144
|
return Promise.reject(this.closeReason ?? new Error("invocation policy scope closed"));
|
|
149
145
|
if (signal?.aborted)
|
|
150
|
-
return Promise.reject(
|
|
146
|
+
return Promise.reject(abortError(signal));
|
|
151
147
|
if (this.queue.length === 0 &&
|
|
152
148
|
!this.exclusiveActive &&
|
|
153
149
|
(mode === "shared" || this.sharedActive === 0)) {
|
|
@@ -165,7 +161,7 @@ export class InvocationPolicyScope {
|
|
|
165
161
|
if (index >= 0)
|
|
166
162
|
this.queue.splice(index, 1);
|
|
167
163
|
signal.removeEventListener("abort", onAbort);
|
|
168
|
-
reject(
|
|
164
|
+
reject(abortError(signal));
|
|
169
165
|
this.flushQueue();
|
|
170
166
|
};
|
|
171
167
|
waiter.onAbort = onAbort;
|
|
@@ -193,7 +189,7 @@ export class InvocationPolicyScope {
|
|
|
193
189
|
this.queue.shift();
|
|
194
190
|
if (waiter.onAbort)
|
|
195
191
|
waiter.signal.removeEventListener("abort", waiter.onAbort);
|
|
196
|
-
waiter.reject(
|
|
192
|
+
waiter.reject(abortError(waiter.signal));
|
|
197
193
|
continue;
|
|
198
194
|
}
|
|
199
195
|
if (waiter.mode === "exclusive") {
|
package/lib/native-checkpoint.js
CHANGED
|
@@ -485,16 +485,55 @@ export function checkpointStateForMessage(session, message) {
|
|
|
485
485
|
export function stateRouteCompatible(state, route, ctx) {
|
|
486
486
|
return routeCompatible(state, route, ctx);
|
|
487
487
|
}
|
|
488
|
+
const DSH_PROJECTION_UNAVAILABLE_PREFIX = 'session message projection "';
|
|
489
|
+
const DSH_PROJECTION_UNAVAILABLE_SUFFIX = '" was removed or replaced; restore the session with its owning plugin';
|
|
488
490
|
/**
|
|
491
|
+
* DSH 0.1.6 attaches no error code or subclass to this failure and exposes no
|
|
492
|
+
* public inventory of required or active projections, so message shape is the
|
|
493
|
+
* only available signal. Both classes fail closed, so a misclassification
|
|
494
|
+
* costs precision in the error code, not correctness.
|
|
495
|
+
* @param {unknown} cause
|
|
496
|
+
*/
|
|
497
|
+
function isMissingOrReplacedProjectionError(cause) {
|
|
498
|
+
if (!(cause instanceof Error))
|
|
499
|
+
return false;
|
|
500
|
+
const { message } = cause;
|
|
501
|
+
if (!message.startsWith(DSH_PROJECTION_UNAVAILABLE_PREFIX) ||
|
|
502
|
+
!message.endsWith(DSH_PROJECTION_UNAVAILABLE_SUFFIX))
|
|
503
|
+
return false;
|
|
504
|
+
const projectionType = message.slice(DSH_PROJECTION_UNAVAILABLE_PREFIX.length, message.length - DSH_PROJECTION_UNAVAILABLE_SUFFIX.length);
|
|
505
|
+
return projectionType.length > 0;
|
|
506
|
+
}
|
|
507
|
+
function checkpointHistoryReadError(cause) {
|
|
508
|
+
return Object.assign(new Error("Unsupported or invalid LCX checkpoint history; start a new session", {
|
|
509
|
+
cause,
|
|
510
|
+
}), { code: "LCX_CHECKPOINT_UNSUPPORTED" });
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* DSH 0.1.6 derives a message only while every `SessionMessageProjection` the
|
|
514
|
+
* durable log committed is still registered; an absent or replaced owner throws
|
|
515
|
+
* instead of yielding pre-projection content. Reconstructing the shadowed
|
|
516
|
+
* transcript without that owner would resurrect content a durable decision
|
|
517
|
+
* (for example `image/offload`) removed, so this is a checkpoint
|
|
518
|
+
* incompatibility rather than a recoverable read.
|
|
489
519
|
* @param {Session} session
|
|
490
520
|
* @param {number} seq
|
|
491
521
|
* @returns {Message | undefined}
|
|
492
522
|
*/
|
|
493
523
|
function eventMessage(session, seq) {
|
|
494
524
|
if (!Number.isSafeInteger(seq) || seq < 0)
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
525
|
+
throw checkpointHistoryReadError(new Error("Portable checkpoint history contains an invalid event sequence"));
|
|
526
|
+
try {
|
|
527
|
+
const event = session.eventAt(SessionSeq(seq));
|
|
528
|
+
if (!event)
|
|
529
|
+
throw new Error(`Portable checkpoint history is missing event at seq ${seq}`);
|
|
530
|
+
return session.deriveEventMessage(event) ?? undefined;
|
|
531
|
+
}
|
|
532
|
+
catch (cause) {
|
|
533
|
+
if (isMissingOrReplacedProjectionError(cause))
|
|
534
|
+
throw Object.assign(new Error("Session history requires a message projection this runtime does not provide; restore the owning plugin to reuse this checkpoint", { cause }), { code: "LCX_CHECKPOINT_PROJECTION_UNAVAILABLE" });
|
|
535
|
+
throw checkpointHistoryReadError(cause);
|
|
536
|
+
}
|
|
498
537
|
}
|
|
499
538
|
/** @param {Message} message */
|
|
500
539
|
function estimateChars(message) {
|