@peerbit/trusted-network 6.0.128 → 6.0.129

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.
@@ -16,11 +16,14 @@ import type {
16
16
  PolicyHeadProjectionV2,
17
17
  PolicyReducerDurableStateV2,
18
18
  PolicySnapshotResolverV2,
19
+ PreparedExactPolicyCandidateV2,
19
20
  } from "./v2-policy-engine.js";
20
21
  import {
21
22
  TRUSTED_NETWORK_V2_MAX_PENDING_POLICIES,
22
23
  TrustedNetworkV2PolicyReducer,
23
24
  authenticatePolicySnapshotEntryV2,
25
+ captureCanonicalPolicyEntryCidV2,
26
+ observeAbortSignalV2,
24
27
  } from "./v2-policy-engine.js";
25
28
  import {
26
29
  NetworkDescriptorV2,
@@ -59,6 +62,9 @@ export const TRUSTED_NETWORK_V2_MAX_POLICY_ANCHOR_CHECKPOINT_PAYLOAD_BYTES =
59
62
  const MAX_QUEUED_POLICY_INPUT_BYTES_V2 =
60
63
  TRUSTED_NETWORK_V2_MAX_POLICY_ENTRY_BYTES * 2;
61
64
  const MAX_TIMER_DELAY_MS_V2 = 0x7fffffff;
65
+ const DEFAULT_EXACT_POLICY_HEAD_TIMEOUT_MS_V2 = 10 * 1000;
66
+ const DEFAULT_EXACT_POLICY_HEAD_MAX_ANCESTRY_STEPS_V2 =
67
+ TRUSTED_NETWORK_V2_MAX_PENDING_POLICIES;
62
68
  const ZERO_DIGEST = new Uint8Array(32);
63
69
  const textEncoder = new TextEncoder();
64
70
  const CHECKPOINT_SCOPE_DOMAIN = textEncoder.encode(
@@ -84,11 +90,18 @@ const isAbortSignalV2 = (value: unknown): value is AbortSignal => {
84
90
  }
85
91
  };
86
92
 
93
+ const boundedDependencyReasonV2 = (error: unknown): string =>
94
+ (error instanceof Error ? error.message : String(error)).slice(
95
+ 0,
96
+ MAX_UNAVAILABLE_REASON_LENGTH,
97
+ );
98
+
87
99
  export type CrashSafePolicyAnchorStoreV2 = CrashSafeAtomicReplaceStore;
88
100
 
89
101
  type DurableReducerOptionsV2 = {
90
102
  descriptor: NetworkDescriptorV2;
91
103
  resolvePolicyEntry: PolicySnapshotResolverV2;
104
+ resolvePolicyEntryByCid?: PolicyEntryCidResolverV2;
92
105
  resolveTimeoutMs?: number;
93
106
  signal?: AbortSignal;
94
107
  maxPending?: number;
@@ -100,6 +113,25 @@ export type TrustedNetworkV2DurablePolicyReducerOptions =
100
113
  store: CrashSafePolicyAnchorStoreV2;
101
114
  };
102
115
 
116
+ export type PolicyEntryCidResolverV2 = (
117
+ policyEntryCid: string,
118
+ options: { signal: AbortSignal },
119
+ ) => Uint8Array | undefined | Promise<Uint8Array | undefined>;
120
+
121
+ export type ExactPolicyHeadRequirementV2 = {
122
+ policyEntryCid: string;
123
+ maxAncestrySteps?: number;
124
+ /** Queue-inclusive relative deadline; callers may only shorten the 10s cap. */
125
+ timeoutMs?: number;
126
+ deadline?: number;
127
+ signal?: AbortSignal;
128
+ };
129
+
130
+ export type ExactPolicyHeadLeaseV2 = {
131
+ policyEntryCid: string;
132
+ policy: PolicyHeadProjectionV2;
133
+ };
134
+
103
135
  export type PolicyLeaseReferenceV2 = {
104
136
  sequence: bigint;
105
137
  digest: Uint8Array;
@@ -127,6 +159,15 @@ export type PolicyLeaseResultV2<T> =
127
159
  reason: string;
128
160
  };
129
161
 
162
+ type PolicyLeaseFailureV2 = Exclude<
163
+ PolicyLeaseResultV2<never>,
164
+ { status: "completed" }
165
+ >;
166
+
167
+ type PolicyLeaseAcquisitionV2<T> =
168
+ | { status: "resolved"; lease: T }
169
+ | PolicyLeaseFailureV2;
170
+
130
171
  /**
131
172
  * One self-contained application snapshot. The enclosing generic checkpoint
132
173
  * supplies generation, scope, predecessor, and checksum authentication.
@@ -740,6 +781,11 @@ export class TrustedNetworkV2DurablePolicyReducer {
740
781
  private checkpoint?: CrashSafeTwoSlotCheckpoint;
741
782
  private core: TrustedNetworkV2PolicyReducer;
742
783
  private published: PublishedProjectionV2;
784
+ private readonly descriptor: NetworkDescriptorV2;
785
+ private readonly resolvePolicyEntryByCid?: PolicyEntryCidResolverV2;
786
+ private readonly leaseLifecycleController: AbortController;
787
+ private readonly disposeLifecycleObservation: () => void;
788
+ private exactAuthenticationInFlight?: Promise<PreparedExactPolicyCandidateV2>;
743
789
  private durableCoreIdentityBytes?: Uint8Array;
744
790
  private operationTail: Promise<void> = Promise.resolve();
745
791
  private authorizationFences = 0;
@@ -750,11 +796,18 @@ export class TrustedNetworkV2DurablePolicyReducer {
750
796
  private constructor(properties: {
751
797
  checkpoint?: CrashSafeTwoSlotCheckpoint;
752
798
  core: TrustedNetworkV2PolicyReducer;
799
+ descriptor: NetworkDescriptorV2;
800
+ resolvePolicyEntryByCid?: PolicyEntryCidResolverV2;
801
+ lifecycle: ReturnType<typeof observeAbortSignalV2>;
753
802
  durableCoreIdentityBytes?: Uint8Array;
754
803
  }) {
755
804
  this.checkpoint = properties.checkpoint;
756
805
  this.core = properties.core;
757
806
  this.published = publishedFromReducer(this.core);
807
+ this.descriptor = properties.descriptor;
808
+ this.resolvePolicyEntryByCid = properties.resolvePolicyEntryByCid;
809
+ this.leaseLifecycleController = properties.lifecycle[0];
810
+ this.disposeLifecycleObservation = properties.lifecycle[1];
758
811
  this.durableCoreIdentityBytes =
759
812
  properties.durableCoreIdentityBytes === undefined
760
813
  ? undefined
@@ -765,11 +818,18 @@ export class TrustedNetworkV2DurablePolicyReducer {
765
818
  options: TrustedNetworkV2DurablePolicyReducerOptions,
766
819
  ): Promise<TrustedNetworkV2DurablePolicyReducer> {
767
820
  assertNetworkDescriptorV2(options.descriptor);
821
+ if (
822
+ options.resolvePolicyEntryByCid !== undefined &&
823
+ typeof options.resolvePolicyEntryByCid !== "function"
824
+ ) {
825
+ throw new TypeError("Policy CID resolver must be a function");
826
+ }
768
827
  const descriptor = deserialize(
769
828
  serialize(options.descriptor),
770
829
  NetworkDescriptorV2,
771
830
  );
772
- const signal = options.signal;
831
+ const lifecycle = observeAbortSignalV2(options.signal);
832
+ const signal = lifecycle[0].signal;
773
833
  const store = options.store;
774
834
  const coreProperties: DurableReducerOptionsV2 = {
775
835
  descriptor,
@@ -779,39 +839,41 @@ export class TrustedNetworkV2DurablePolicyReducer {
779
839
  maxPending: options.maxPending,
780
840
  maxPendingPolicyBytes: options.maxPendingPolicyBytes,
781
841
  };
782
- assertOpenNotAborted(signal);
783
- const checkpoint = await CrashSafeTwoSlotCheckpoint.open({
784
- store,
785
- scope: checkpointScope(descriptor),
786
- maxPayloadBytes:
787
- TRUSTED_NETWORK_V2_MAX_POLICY_ANCHOR_CHECKPOINT_PAYLOAD_BYTES,
788
- });
789
- assertOpenNotAborted(signal);
790
-
791
- // Never let the old append-only format look like an empty or newer
792
- // checkpoint. It was internal and never activated, so migration or fallback
793
- // would add rollback surface without preserving a public compatibility need.
794
- for await (const [key] of store.iterator()) {
795
- assertOpenNotAborted(signal);
796
- if (
797
- key === TRUSTED_NETWORK_V2_POLICY_ANCHOR_STORE_OWNER ||
798
- key.startsWith(`${TRUSTED_NETWORK_V2_POLICY_ANCHOR_STORE_OWNER}/`)
799
- ) {
800
- throw new Error(
801
- "Legacy append-only policy-anchor records are not supported; reset the dedicated store",
802
- );
803
- }
804
- }
805
- assertOpenNotAborted(signal);
806
-
807
- const current = checkpoint.current;
808
842
  let core: TrustedNetworkV2PolicyReducer | undefined;
809
843
  try {
844
+ assertOpenNotAborted(signal);
845
+ const checkpoint = await CrashSafeTwoSlotCheckpoint.open({
846
+ store,
847
+ scope: checkpointScope(descriptor),
848
+ maxPayloadBytes:
849
+ TRUSTED_NETWORK_V2_MAX_POLICY_ANCHOR_CHECKPOINT_PAYLOAD_BYTES,
850
+ });
851
+ assertOpenNotAborted(signal);
852
+
853
+ // Never let the old append-only format look like an empty or newer
854
+ // checkpoint. It was internal and never activated, so migration or fallback
855
+ // would add rollback surface without preserving a public compatibility need.
856
+ for await (const [key] of store.iterator()) {
857
+ assertOpenNotAborted(signal);
858
+ if (
859
+ key === TRUSTED_NETWORK_V2_POLICY_ANCHOR_STORE_OWNER ||
860
+ key.startsWith(`${TRUSTED_NETWORK_V2_POLICY_ANCHOR_STORE_OWNER}/`)
861
+ ) {
862
+ throw new Error(
863
+ "Legacy append-only policy-anchor records are not supported; reset the dedicated store",
864
+ );
865
+ }
866
+ }
867
+ assertOpenNotAborted(signal);
868
+ const current = checkpoint.current;
810
869
  if (current === undefined) {
811
870
  core = new TrustedNetworkV2PolicyReducer(coreProperties);
812
871
  return new TrustedNetworkV2DurablePolicyReducer({
813
872
  checkpoint,
814
873
  core,
874
+ descriptor,
875
+ resolvePolicyEntryByCid: options.resolvePolicyEntryByCid,
876
+ lifecycle,
815
877
  });
816
878
  }
817
879
 
@@ -834,10 +896,14 @@ export class TrustedNetworkV2DurablePolicyReducer {
834
896
  // storage, so release that potentially 8.78 MiB snapshot immediately.
835
897
  checkpoint: forked ? undefined : checkpoint,
836
898
  core,
899
+ descriptor,
900
+ resolvePolicyEntryByCid: options.resolvePolicyEntryByCid,
901
+ lifecycle,
837
902
  durableCoreIdentityBytes: decoded.coreIdentityBytes,
838
903
  });
839
904
  } catch (error) {
840
905
  core?.abort();
906
+ lifecycle[1]();
841
907
  throw error;
842
908
  }
843
909
  }
@@ -916,6 +982,7 @@ export class TrustedNetworkV2DurablePolicyReducer {
916
982
 
917
983
  abort(): void {
918
984
  this.core.abort();
985
+ this.disposeLifecycleObservation();
919
986
  }
920
987
 
921
988
  ingest(entryBytes: Uint8Array): Promise<PolicyAdmissionResultV2> {
@@ -1110,38 +1177,242 @@ export class TrustedNetworkV2DurablePolicyReducer {
1110
1177
  });
1111
1178
  }
1112
1179
 
1113
- const retainedReferenceBytes = 32;
1114
- if (!this.reserveOperation(retainedReferenceBytes)) {
1180
+ let digest: Uint8Array;
1181
+ try {
1182
+ digest = copyBytes(suppliedDigest);
1183
+ } catch {
1184
+ return Promise.resolve({
1185
+ status: "rejected",
1186
+ reason: "Policy reference digest must contain exactly 32 bytes",
1187
+ });
1188
+ }
1189
+
1190
+ return this.withSerializedPolicyLease(
1191
+ 32,
1192
+ deadline,
1193
+ signal,
1194
+ async (leaseSignal) => {
1195
+ const resolution = await this.core.resolveAcceptedPolicyPrefix(
1196
+ { sequence, digest },
1197
+ { maxSteps, deadline, signal: leaseSignal },
1198
+ );
1199
+ return resolution.status === "resolved"
1200
+ ? {
1201
+ status: "resolved",
1202
+ lease: {
1203
+ policy: resolution.policy,
1204
+ acceptedHead: resolution.acceptedHead,
1205
+ },
1206
+ }
1207
+ : resolution;
1208
+ },
1209
+ use,
1210
+ );
1211
+ }
1212
+
1213
+ /**
1214
+ * Run one callback while a CID-addressed policy wrapper is authenticated and
1215
+ * its policy-body identity is the stable durable current head.
1216
+ *
1217
+ * Exact fetch, prepared admission, crash-safe publication, and callback share
1218
+ * one bounded budget and serialized queue slot. No digest-resolver fallback is
1219
+ * allowed when the CID resolver is absent or unavailable.
1220
+ */
1221
+ withExactPolicyHead<T>(
1222
+ requirement: ExactPolicyHeadRequirementV2,
1223
+ use: (lease: ExactPolicyHeadLeaseV2) => T | Promise<T>,
1224
+ ): Promise<PolicyLeaseResultV2<T>> {
1225
+ const halted = this.immediateLeaseHaltedResult();
1226
+ if (halted !== undefined) return Promise.resolve(halted);
1227
+
1228
+ let policyEntryCid: string;
1229
+ let maxAncestrySteps: number;
1230
+ let deadline: number;
1231
+ let signal: AbortSignal | undefined;
1232
+ try {
1233
+ policyEntryCid = captureCanonicalPolicyEntryCidV2(
1234
+ requirement.policyEntryCid,
1235
+ );
1236
+ maxAncestrySteps =
1237
+ requirement.maxAncestrySteps ??
1238
+ DEFAULT_EXACT_POLICY_HEAD_MAX_ANCESTRY_STEPS_V2;
1239
+ if (
1240
+ !Number.isSafeInteger(maxAncestrySteps) ||
1241
+ maxAncestrySteps < 0 ||
1242
+ maxAncestrySteps > TRUSTED_NETWORK_V2_MAX_PENDING_POLICIES
1243
+ ) {
1244
+ return Promise.resolve({
1245
+ status: "rejected",
1246
+ reason: `Exact policy maxAncestrySteps must be between 0 and ${TRUSTED_NETWORK_V2_MAX_PENDING_POLICIES}`,
1247
+ });
1248
+ }
1249
+ const suppliedDeadline = requirement.deadline;
1250
+ if (
1251
+ suppliedDeadline !== undefined &&
1252
+ (!Number.isSafeInteger(suppliedDeadline) || suppliedDeadline < 0)
1253
+ ) {
1254
+ return Promise.resolve({
1255
+ status: "rejected",
1256
+ reason: "Exact policy deadline must be a non-negative safe integer",
1257
+ });
1258
+ }
1259
+ const timeoutMs =
1260
+ requirement.timeoutMs ?? DEFAULT_EXACT_POLICY_HEAD_TIMEOUT_MS_V2;
1261
+ if (
1262
+ !Number.isSafeInteger(timeoutMs) ||
1263
+ timeoutMs < 0 ||
1264
+ timeoutMs > DEFAULT_EXACT_POLICY_HEAD_TIMEOUT_MS_V2
1265
+ ) {
1266
+ return Promise.resolve({
1267
+ status: "rejected",
1268
+ reason: `Exact policy timeoutMs must be between 0 and ${DEFAULT_EXACT_POLICY_HEAD_TIMEOUT_MS_V2}`,
1269
+ });
1270
+ }
1271
+ const relativeDeadline = Math.min(
1272
+ Number.MAX_SAFE_INTEGER,
1273
+ Date.now() + timeoutMs,
1274
+ );
1275
+ deadline =
1276
+ suppliedDeadline === undefined
1277
+ ? relativeDeadline
1278
+ : Math.min(suppliedDeadline, relativeDeadline);
1279
+ signal = requirement.signal;
1280
+ if (signal !== undefined && !isAbortSignalV2(signal)) {
1281
+ return Promise.resolve({
1282
+ status: "rejected",
1283
+ reason: "Exact policy signal must be an AbortSignal",
1284
+ });
1285
+ }
1286
+ } catch {
1287
+ return Promise.resolve({
1288
+ status: "rejected",
1289
+ reason: "Exact policy-head requirement is invalid",
1290
+ });
1291
+ }
1292
+ if (typeof use !== "function") {
1293
+ return Promise.resolve({
1294
+ status: "rejected",
1295
+ reason: "Exact policy-head callback must be a function",
1296
+ });
1297
+ }
1298
+
1299
+ return this.withSerializedPolicyLease(
1300
+ textEncoder.encode(policyEntryCid).byteLength,
1301
+ deadline,
1302
+ signal,
1303
+ async (leaseSignal, mutationCompleted) => {
1304
+ const exact = await this.resolveExactPolicyEntry(
1305
+ policyEntryCid,
1306
+ deadline,
1307
+ leaseSignal,
1308
+ );
1309
+ if (exact.status !== "resolved") return exact;
1310
+ this.authorizationFences += 1;
1311
+ try {
1312
+ const admission = await this.core.ingestPreparedExactPolicy(
1313
+ exact.lease,
1314
+ {
1315
+ maxParentEdges: maxAncestrySteps,
1316
+ deadline,
1317
+ signal: leaseSignal,
1318
+ },
1319
+ );
1320
+ // Core admission may now be mutated. From here through checkpoint
1321
+ // settlement, cancellation may settle outward but cannot release the slot.
1322
+ mutationCompleted();
1323
+ await this.persistCorePublication(admission);
1324
+ const halted = this.immediateLeaseHaltedResult();
1325
+ if (halted !== undefined) return halted;
1326
+ if (
1327
+ admission.status !== "accepted" &&
1328
+ admission.status !== "duplicate"
1329
+ ) {
1330
+ return {
1331
+ status:
1332
+ admission.status === "rejected" ||
1333
+ admission.status === "capacity"
1334
+ ? admission.status
1335
+ : "unavailable",
1336
+ reason:
1337
+ admission.reason ?? "Exact policy admission is unavailable",
1338
+ };
1339
+ }
1340
+ const head = this.published.head;
1341
+ if (
1342
+ this.published.state !== "ACTIVE" ||
1343
+ head === undefined ||
1344
+ head.sequence !== exact.lease.policy.sequence ||
1345
+ !equals(head.digest, exact.lease.policy.digest)
1346
+ ) {
1347
+ return {
1348
+ status: "unavailable",
1349
+ reason:
1350
+ "Exact policy entry is not the durable current policy head",
1351
+ };
1352
+ }
1353
+ return {
1354
+ status: "resolved",
1355
+ lease: { policyEntryCid, policy: copyHead(head)! },
1356
+ };
1357
+ } catch (error) {
1358
+ throw this.halt(error);
1359
+ } finally {
1360
+ this.authorizationFences -= 1;
1361
+ }
1362
+ },
1363
+ use,
1364
+ );
1365
+ }
1366
+
1367
+ private withSerializedPolicyLease<T, Lease>(
1368
+ retainedInputBytes: number,
1369
+ deadline: number | undefined,
1370
+ signal: AbortSignal | undefined,
1371
+ acquire: (
1372
+ signal: AbortSignal,
1373
+ mutationCompleted: () => void,
1374
+ ) => Promise<PolicyLeaseAcquisitionV2<Lease>>,
1375
+ use: (lease: Lease) => T | Promise<T>,
1376
+ ): Promise<PolicyLeaseResultV2<T>> {
1377
+ if (!this.reserveOperation(retainedInputBytes)) {
1115
1378
  return Promise.resolve({
1116
1379
  status: "capacity",
1117
1380
  reason: "Durable policy operation queue is at its fixed capacity",
1118
1381
  });
1119
1382
  }
1120
- let digest: Uint8Array;
1383
+ let observedSignal: ReturnType<typeof observeAbortSignalV2>;
1121
1384
  try {
1122
- digest = copyBytes(suppliedDigest);
1385
+ observedSignal = observeAbortSignalV2(signal);
1123
1386
  } catch {
1124
- this.releaseOperation(retainedReferenceBytes);
1387
+ this.releaseOperation(retainedInputBytes);
1125
1388
  return Promise.resolve({
1126
1389
  status: "rejected",
1127
- reason: "Policy reference digest must contain exactly 32 bytes",
1390
+ reason: "Policy lease signal could not be observed",
1128
1391
  });
1129
1392
  }
1130
1393
 
1131
1394
  let queueAcquired = false;
1132
1395
  let callbackAcquired = false;
1396
+ let mutationCompleted = false;
1397
+ const acquisitionController = observedSignal[0];
1398
+ const interruptionSignal = AbortSignal.any([
1399
+ acquisitionController.signal,
1400
+ this.leaseLifecycleController.signal,
1401
+ ]);
1133
1402
  let preAcquisitionResult: PolicyLeaseResultV2<T> | undefined;
1134
1403
  let resolveEarly!: (result: PolicyLeaseResultV2<T>) => void;
1135
1404
  const earlyResult = new Promise<PolicyLeaseResultV2<T>>((resolve) => {
1136
1405
  resolveEarly = resolve;
1137
1406
  });
1138
1407
  let deadlineTimer: ReturnType<typeof setTimeout> | undefined;
1139
- let signalListenerInstalled = false;
1140
1408
 
1141
- const abortBeforeAcquisition = (): void => {
1409
+ const interruptBeforeAcquisition = (): void => {
1410
+ const halted = this.leaseLifecycleController.signal.aborted;
1142
1411
  settleBeforeAcquisition({
1143
- status: "unavailable",
1144
- reason: "Policy lease acquisition was aborted by the caller",
1412
+ status: halted ? "halted" : "unavailable",
1413
+ reason: halted
1414
+ ? "Policy reducer lifecycle is aborted"
1415
+ : "Policy lease acquisition was aborted by the caller",
1145
1416
  });
1146
1417
  };
1147
1418
  const cleanupWakeups = (): void => {
@@ -1149,31 +1420,29 @@ export class TrustedNetworkV2DurablePolicyReducer {
1149
1420
  clearTimeout(deadlineTimer);
1150
1421
  deadlineTimer = undefined;
1151
1422
  }
1152
- if (signalListenerInstalled) {
1153
- signalListenerInstalled = false;
1154
- try {
1155
- signal?.removeEventListener("abort", abortBeforeAcquisition);
1156
- } catch {
1157
- // A structurally valid hostile signal must not break queue cleanup.
1158
- }
1159
- }
1423
+ interruptionSignal.removeEventListener(
1424
+ "abort",
1425
+ interruptBeforeAcquisition,
1426
+ );
1427
+ observedSignal[1]();
1160
1428
  };
1161
1429
  function settleBeforeAcquisition(result: PolicyLeaseResultV2<T>): void {
1162
- if (
1163
- queueAcquired ||
1164
- callbackAcquired ||
1165
- preAcquisitionResult !== undefined
1166
- ) {
1430
+ if (callbackAcquired || preAcquisitionResult !== undefined) {
1167
1431
  return;
1168
1432
  }
1169
1433
  preAcquisitionResult = result;
1434
+ acquisitionController.abort();
1170
1435
  cleanupWakeups();
1171
- resolveEarly(result);
1436
+ if (!queueAcquired || mutationCompleted) resolveEarly(result);
1172
1437
  }
1438
+ const completeMutation = (): void => {
1439
+ mutationCompleted = true;
1440
+ if (preAcquisitionResult !== undefined)
1441
+ resolveEarly(preAcquisitionResult);
1442
+ };
1173
1443
  const armDeadlineWakeup = (): void => {
1174
1444
  if (
1175
1445
  deadline === undefined ||
1176
- queueAcquired ||
1177
1446
  callbackAcquired ||
1178
1447
  preAcquisitionResult !== undefined
1179
1448
  ) {
@@ -1209,26 +1478,22 @@ export class TrustedNetworkV2DurablePolicyReducer {
1209
1478
  return preAcquisitionResult;
1210
1479
  }
1211
1480
  queueAcquired = true;
1212
- cleanupWakeups();
1213
1481
  const queuedHalt = this.immediateLeaseHaltedResult();
1214
1482
  if (queuedHalt !== undefined) return queuedHalt;
1215
- const resolution = await this.core.resolveAcceptedPolicyPrefix(
1216
- {
1217
- sequence,
1218
- digest,
1219
- },
1220
- { maxSteps, deadline, signal },
1483
+ const acquisition = await acquire(
1484
+ acquisitionController.signal,
1485
+ completeMutation,
1221
1486
  );
1222
1487
  if (preAcquisitionResult !== undefined) {
1223
1488
  return preAcquisitionResult;
1224
1489
  }
1225
- if (resolution.status !== "resolved") return resolution;
1490
+ if (acquisition.status !== "resolved") return acquisition;
1226
1491
  // Lifecycle abort before callback invocation loses acquisition. There is
1227
1492
  // no await between this check and invoking user code, which is the lease's
1228
1493
  // linearization point.
1229
1494
  const resolvedHalt = this.immediateLeaseHaltedResult();
1230
1495
  if (resolvedHalt !== undefined) return resolvedHalt;
1231
- if (signal?.aborted) {
1496
+ if (acquisitionController.signal.aborted) {
1232
1497
  return {
1233
1498
  status: "unavailable",
1234
1499
  reason: "Policy lease acquisition was aborted by the caller",
@@ -1242,39 +1507,161 @@ export class TrustedNetworkV2DurablePolicyReducer {
1242
1507
  }
1243
1508
  callbackAcquired = true;
1244
1509
  cleanupWakeups();
1245
- const value = await use({
1246
- // The core created these two projections independently and retains
1247
- // neither, including when the requested policy is the current head.
1248
- policy: resolution.policy,
1249
- acceptedHead: resolution.acceptedHead,
1250
- });
1510
+ const value = await use(acquisition.lease);
1251
1511
  return { status: "completed", value };
1252
1512
  });
1253
1513
  const retainedResult = queuedResult.finally(() => {
1254
1514
  cleanupWakeups();
1255
- this.releaseOperation(retainedReferenceBytes);
1515
+ this.releaseOperation(retainedInputBytes);
1256
1516
  });
1257
1517
  this.operationTail = retainedResult.then(
1258
1518
  (): void => {},
1259
1519
  (): void => {},
1260
1520
  );
1261
1521
 
1262
- if (signal !== undefined) {
1263
- signalListenerInstalled = true;
1522
+ interruptionSignal.addEventListener("abort", interruptBeforeAcquisition, {
1523
+ once: true,
1524
+ });
1525
+ if (interruptionSignal.aborted) interruptBeforeAcquisition();
1526
+ armDeadlineWakeup();
1527
+ return Promise.race([retainedResult, earlyResult]);
1528
+ }
1529
+
1530
+ private async resolveExactPolicyEntry(
1531
+ policyEntryCid: string,
1532
+ deadline: number,
1533
+ callerSignal: AbortSignal,
1534
+ ): Promise<PolicyLeaseAcquisitionV2<PreparedExactPolicyCandidateV2>> {
1535
+ const resolver = this.resolvePolicyEntryByCid;
1536
+ if (resolver === undefined) {
1537
+ return {
1538
+ status: "unavailable",
1539
+ reason: "Exact policy-head readiness has no policy CID resolver",
1540
+ };
1541
+ }
1542
+ if (this.core.state === "HALTED") {
1543
+ return {
1544
+ status: "halted",
1545
+ reason: "Policy reducer lifecycle is aborted",
1546
+ };
1547
+ }
1548
+ if (callerSignal.aborted) {
1549
+ return {
1550
+ status: "unavailable",
1551
+ reason: "Exact policy-head acquisition was aborted by the caller",
1552
+ };
1553
+ }
1554
+ if (Date.now() >= deadline) {
1555
+ return {
1556
+ status: "unavailable",
1557
+ reason: "Exact policy-head acquisition deadline elapsed",
1558
+ };
1559
+ }
1560
+
1561
+ const interrupted = new Promise<never>((_resolve, reject) => {
1562
+ callerSignal.addEventListener(
1563
+ "abort",
1564
+ () => reject(new Error("Exact policy-head resolution interrupted")),
1565
+ { once: true },
1566
+ );
1567
+ });
1568
+ const interruptionFailure = (): PolicyLeaseFailureV2 | undefined => {
1569
+ const halted = this.immediateLeaseHaltedResult();
1570
+ if (halted !== undefined) return halted;
1571
+ if (callerSignal.aborted) {
1572
+ return {
1573
+ status: "unavailable",
1574
+ reason: "Exact policy-head acquisition was aborted by the caller",
1575
+ };
1576
+ }
1577
+ if (Date.now() >= deadline) {
1578
+ return {
1579
+ status: "unavailable",
1580
+ reason: "Exact policy-head acquisition deadline elapsed",
1581
+ };
1582
+ }
1583
+ return undefined;
1584
+ };
1585
+
1586
+ const priorAuthentication = this.exactAuthenticationInFlight;
1587
+ if (priorAuthentication !== undefined) {
1264
1588
  try {
1265
- signal.addEventListener("abort", abortBeforeAcquisition, {
1266
- once: true,
1267
- });
1589
+ await Promise.race([
1590
+ priorAuthentication.catch((): void => {}),
1591
+ interrupted,
1592
+ ]);
1268
1593
  } catch {
1269
- settleBeforeAcquisition({
1270
- status: "rejected",
1271
- reason: "Policy lease signal could not be observed",
1272
- });
1594
+ return (
1595
+ interruptionFailure() ?? {
1596
+ status: "unavailable",
1597
+ reason: "Exact policy authentication slot is unavailable",
1598
+ }
1599
+ );
1273
1600
  }
1274
- if (signal.aborted) abortBeforeAcquisition();
1601
+ const interruptedResult = interruptionFailure();
1602
+ if (interruptedResult !== undefined) return interruptedResult;
1275
1603
  }
1276
- armDeadlineWakeup();
1277
- return Promise.race([retainedResult, earlyResult]);
1604
+ let entryBytes: Uint8Array | undefined;
1605
+ try {
1606
+ entryBytes = await Promise.race([
1607
+ Promise.resolve().then(() =>
1608
+ resolver(policyEntryCid, { signal: callerSignal }),
1609
+ ),
1610
+ interrupted,
1611
+ ]);
1612
+ } catch (error) {
1613
+ const interruptedResult = interruptionFailure();
1614
+ if (interruptedResult !== undefined) return interruptedResult;
1615
+ return {
1616
+ status: "unavailable",
1617
+ reason: `Policy CID resolver dependency is unavailable: ${boundedDependencyReasonV2(error)}`,
1618
+ };
1619
+ }
1620
+ if (entryBytes === undefined) {
1621
+ return {
1622
+ status: "unavailable",
1623
+ reason: "Exact policy entry is unavailable from its CID resolver",
1624
+ };
1625
+ }
1626
+ const authentication = Promise.resolve().then(() =>
1627
+ this.authenticateExactPolicyEntry({
1628
+ policyEntryCid,
1629
+ entryBytes,
1630
+ descriptor: this.descriptor,
1631
+ }),
1632
+ );
1633
+ this.exactAuthenticationInFlight = authentication;
1634
+ const clearAuthentication = (): void => {
1635
+ if (this.exactAuthenticationInFlight === authentication) {
1636
+ this.exactAuthenticationInFlight = undefined;
1637
+ }
1638
+ };
1639
+ void authentication.then(clearAuthentication, clearAuthentication);
1640
+ try {
1641
+ const authenticated = await Promise.race([authentication, interrupted]);
1642
+ const completedInterruption = interruptionFailure();
1643
+ return (
1644
+ completedInterruption ?? { status: "resolved", lease: authenticated }
1645
+ );
1646
+ } catch (error) {
1647
+ const interruptedResult = interruptionFailure();
1648
+ if (interruptedResult !== undefined) return interruptedResult;
1649
+ return {
1650
+ status: "rejected",
1651
+ reason: `Exact policy entry is invalid: ${boundedDependencyReasonV2(error)}`,
1652
+ };
1653
+ }
1654
+ }
1655
+
1656
+ private authenticateExactPolicyEntry(properties: {
1657
+ policyEntryCid: string;
1658
+ entryBytes: Uint8Array;
1659
+ descriptor: NetworkDescriptorV2;
1660
+ }): Promise<PreparedExactPolicyCandidateV2> {
1661
+ return this.core.prepareExactPolicyEntry(
1662
+ properties.policyEntryCid,
1663
+ properties.entryBytes,
1664
+ );
1278
1665
  }
1279
1666
 
1280
1667
  private forkFailStopResult(): PolicyAdmissionResultV2 {
@@ -1297,7 +1684,7 @@ export class TrustedNetworkV2DurablePolicyReducer {
1297
1684
  };
1298
1685
  }
1299
1686
 
1300
- private immediateLeaseHaltedResult(): PolicyLeaseResultV2<never> | undefined {
1687
+ private immediateLeaseHaltedResult(): PolicyLeaseFailureV2 | undefined {
1301
1688
  if (this.terminalError !== undefined) {
1302
1689
  return {
1303
1690
  status: "halted",
@@ -1440,6 +1827,10 @@ export class TrustedNetworkV2DurablePolicyReducer {
1440
1827
  throw new Error("Policy-anchor checkpoint is unavailable");
1441
1828
  }
1442
1829
  await checkpoint.commit(payloadBytes);
1830
+ // Atomic replacement is not cancellable. A lifecycle that ended while it
1831
+ // was in flight may leave durable recovery state, but cannot publish it into
1832
+ // the stale in-memory instance.
1833
+ if (this.core.state === "HALTED") return;
1443
1834
 
1444
1835
  this.durableCoreIdentityBytes = nextDurableCoreIdentityBytes;
1445
1836
  this.published = nextPublished;