@zlink-systems/framework 0.32.0 → 0.32.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.
@@ -59,7 +59,7 @@ class DefaultZLinkActorContext {
59
59
  return this.state.boundSession;
60
60
  }
61
61
  get objectGeneration() {
62
- return this.state.nativeActorRef?.generation ?? 1n;
62
+ return this.state.currentActorRef().generation;
63
63
  }
64
64
  get spotId() {
65
65
  return this.state.spotId;
@@ -116,7 +116,7 @@ class ZLinkActorCreationCoordinator {
116
116
  }
117
117
  }
118
118
  else if (nodeRid !== undefined && updateLocation) {
119
- await this.options.locationLifecycle?.setActorRef(actorType, actorId, { actorId, objectGeneration: 1n, meshName, nodeRid }, 0n);
119
+ await this.options.locationLifecycle?.setActorRef(actorType, actorId, (0, actor_runtime_state_1.toFrameworkActorRef)(state.currentActorRef(), meshName), 0n);
120
120
  }
121
121
  return { status: 'created', actor, reply: response.reply };
122
122
  }
@@ -76,6 +76,7 @@ export declare class ZLinkActorRuntimeState {
76
76
  private spotGenerationValue;
77
77
  private spotMembershipEpochValue;
78
78
  private nativeActorRefValue;
79
+ private nativeActorDestroyed;
79
80
  private entryNodeRidValue;
80
81
  boundSessionValue: ZLinkRemoteBoundSessionTarget | undefined;
81
82
  private remoteActorPacketTargetValue;
@@ -96,6 +97,7 @@ export declare class ZLinkActorRuntimeState {
96
97
  get spotMembershipEpoch(): bigint;
97
98
  get spotGeneration(): bigint | undefined;
98
99
  get nativeActorRef(): ZLinkBackendActorRef | undefined;
100
+ currentActorRef(): ZLinkBackendActorRef;
99
101
  get boundSessionBindingGeneration(): bigint;
100
102
  get entryNodeRid(): RoutingId | undefined;
101
103
  /** The one current Session binding of this Actor (Session–Actor binding §6). */
@@ -124,7 +126,6 @@ export declare class ZLinkActorRuntimeState {
124
126
  setOwnerLeaseGeneration(generation: bigint): void;
125
127
  getOrStartDestroy(entryNodeRid: RoutingId, destroy: (actorRef: ZLinkBackendActorRef | undefined) => Promise<void>): Promise<void>;
126
128
  markNativeActorDestroyed(actorRef: ZLinkBackendActorRef): void;
127
- clearFailedDestroy(task: Promise<void>): void;
128
129
  ensureContext(createContext: () => ZLinkActorContext): ZLinkActorContext;
129
130
  getOrStartCreation(actorType: string, failIfExists: boolean, createActor: () => Promise<ZLinkActorCreationAttemptResult>): ZLinkActorCreationOperation;
130
131
  clearFailedCreation(task: Promise<ZLinkActorCreationAttemptResult>): boolean;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkActorRuntimeState = void 0;
4
4
  exports.toFrameworkRoutingId = toFrameworkRoutingId;
5
5
  exports.toFrameworkActorRef = toFrameworkActorRef;
6
+ const configuration_1 = require("../configuration");
6
7
  const state_lane_1 = require("../execution/state-lane");
7
8
  const framework_errors_internal_1 = require("../framework-errors-internal");
8
9
  const routing_id_1 = require("../routing-id");
@@ -57,7 +58,9 @@ class ZLinkActorRuntimeState {
57
58
  spotIdValue;
58
59
  spotGenerationValue;
59
60
  spotMembershipEpochValue = 0n;
61
+ // Preserve the exact incarnation until teardown finalization, even after native removal.
60
62
  nativeActorRefValue;
63
+ nativeActorDestroyed = false;
61
64
  entryNodeRidValue;
62
65
  boundSessionValue;
63
66
  remoteActorPacketTargetValue;
@@ -103,6 +106,12 @@ class ZLinkActorRuntimeState {
103
106
  get nativeActorRef() {
104
107
  return this.nativeActorRefValue;
105
108
  }
109
+ currentActorRef() {
110
+ if (this.nativeActorRefValue === undefined) {
111
+ throw new configuration_1.ZLinkConfigurationException(`Actor '${this.actorId}' lifecycle identity is not initialized.`);
112
+ }
113
+ return this.nativeActorRefValue;
114
+ }
106
115
  get boundSessionBindingGeneration() {
107
116
  return this.boundSessionValue?.bindingGeneration ?? 0n;
108
117
  }
@@ -194,20 +203,23 @@ class ZLinkActorRuntimeState {
194
203
  !(0, routing_id_1.routingIdsEqual)(toFrameworkRoutingId(actorRef.nodeRid), entryNodeRid)) {
195
204
  throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorRouteNotFound, `Actor '${this.actorId}' is not owned by this Entry Spot.`);
196
205
  }
197
- const task = Promise.resolve().then(() => destroy(actorRef));
206
+ const task = Promise.resolve()
207
+ .then(() => destroy(this.nativeActorDestroyed ? undefined : actorRef))
208
+ .catch((error) => {
209
+ // A caller may start another attempt only after this attempt has failed.
210
+ if (this.destroyTask === task) {
211
+ this.destroyTask = undefined;
212
+ this.movingValue = false;
213
+ }
214
+ throw error;
215
+ });
198
216
  this.destroyTask = task;
199
217
  return task;
200
218
  }
201
219
  markNativeActorDestroyed(actorRef) {
202
220
  if (this.nativeActorRefValue === actorRef) {
203
- this.nativeActorRefValue = undefined;
204
- }
205
- }
206
- clearFailedDestroy(task) {
207
- if (this.destroyTask === task) {
208
- this.destroyTask = undefined;
221
+ this.nativeActorDestroyed = true;
209
222
  }
210
- this.movingValue = false;
211
223
  }
212
224
  ensureContext(createContext) {
213
225
  this.context ??= createContext();
@@ -243,6 +255,7 @@ class ZLinkActorRuntimeState {
243
255
  this.createRequestPayloadValue = undefined;
244
256
  this.configured = false;
245
257
  this.nativeActorRefValue = undefined;
258
+ this.nativeActorDestroyed = false;
246
259
  this.entryNodeRidValue = undefined;
247
260
  return true;
248
261
  }
@@ -278,6 +291,7 @@ class ZLinkActorRuntimeState {
278
291
  }
279
292
  setNativeActorRef(actorRef) {
280
293
  this.nativeActorRefValue = actorRef;
294
+ this.nativeActorDestroyed = false;
281
295
  this.entryNodeRidValue ??= toFrameworkRoutingId(actorRef.nodeRid);
282
296
  }
283
297
  /** @internal Installs one authority-confirmed binding inside its Actor owner turn. */
@@ -344,6 +358,7 @@ class ZLinkActorRuntimeState {
344
358
  this.spotGenerationValue = undefined;
345
359
  this.spotMembershipEpochValue = 0n;
346
360
  this.nativeActorRefValue = undefined;
361
+ this.nativeActorDestroyed = false;
347
362
  this.entryNodeRidValue = undefined;
348
363
  this.boundSessionValue = undefined;
349
364
  this.remoteActorPacketTargetValue = undefined;
@@ -366,6 +381,7 @@ class ZLinkActorRuntimeState {
366
381
  this.spotValue = undefined;
367
382
  this.spotIdValue = undefined;
368
383
  this.nativeActorRefValue = undefined;
384
+ this.nativeActorDestroyed = false;
369
385
  // The arriving relocation installs the binding it carries.
370
386
  this.boundSessionValue = undefined;
371
387
  this.remoteActorPacketTargetValue = undefined;
@@ -64,7 +64,7 @@ export declare class DefaultZLinkActorManager implements ZLinkActorManager {
64
64
  private awaitActorDestroy;
65
65
  getOrCreateActor(actorId: string, actorType: string, signal?: AbortSignal): Promise<ZLinkActor>;
66
66
  getOrCreateWithNativeRef(actorId: string, actorType: string, actorRef: ZLinkBackendActorRef, createRequest?: unknown, signal?: AbortSignal): Promise<ZLinkActor>;
67
- getOrCreateActorResult(actorId: string, actorType: string, createRequest?: unknown, signal?: AbortSignal): Promise<ZLinkActorLocalCreateResult>;
67
+ getOrCreateActorResult(actorId: string, actorType: string, createRequest?: unknown, signal?: AbortSignal): Promise<ZLinkActorLocalCreateResult<ActorRef | undefined>>;
68
68
  createReservedActorResult(actorId: string, actorType: string, createRequest: unknown, signal?: AbortSignal, nativeActorRef?: ZLinkBackendActorRef): Promise<ZLinkActorLocalCreateResult>;
69
69
  adoptCreatedAuthority(actorId: string, authorityOwnerGeneration: bigint, ownerLeaseGeneration: bigint): void;
70
70
  getState(actorId: string): ZLinkActorRuntimeState | undefined;
@@ -77,10 +77,10 @@ export declare class DefaultZLinkActorManager implements ZLinkActorManager {
77
77
  private getOrCreateState;
78
78
  private actorRefForState;
79
79
  }
80
- export type ZLinkActorLocalCreateResult = {
80
+ export type ZLinkActorLocalCreateResult<TActorRef extends ActorRef | undefined = ActorRef> = {
81
81
  readonly status: 'existing' | 'created';
82
82
  readonly actor: ZLinkActor;
83
- readonly actorRef: ActorRef;
83
+ readonly actorRef: TActorRef;
84
84
  readonly reply?: unknown;
85
85
  } | {
86
86
  readonly status: 'rejected';
@@ -17,7 +17,6 @@ const actor_creation_1 = require("./actor-creation");
17
17
  const actor_runtime_state_1 = require("./actor-runtime-state");
18
18
  const transferred_actor_rollback_1 = require("./transferred-actor-rollback");
19
19
  const ACTOR_CREATION_RETRY_INTERVAL_MS = 5;
20
- const LOCAL_DIAGNOSTIC_NODE_RID = 'local';
21
20
  var actor_client_1 = require("./actor-client");
22
21
  Object.defineProperty(exports, "DefaultZLinkActorClient", { enumerable: true, get: function () { return actor_client_1.DefaultZLinkActorClient; } });
23
22
  var actor_context_1 = require("./actor-context");
@@ -100,7 +99,7 @@ class DefaultZLinkActorManager {
100
99
  if (this.relocationStaged.has(actorId))
101
100
  return undefined;
102
101
  const state = this.states.get(actorId);
103
- if (state?.actor !== undefined) {
102
+ if (state?.actor !== undefined && state.nativeActorRef !== undefined) {
104
103
  return this.actorRefForState(state);
105
104
  }
106
105
  return await this.options.actorRefResolver?.resolveActorRef(actorId, signal);
@@ -111,7 +110,9 @@ class DefaultZLinkActorManager {
111
110
  async findSpot(actorId, signal) {
112
111
  (0, abort_1.throwIfAborted)(signal);
113
112
  const state = this.states.get(actorId);
114
- if (state?.actor === undefined || state.spotId === undefined)
113
+ if (state?.actor === undefined ||
114
+ state.spotId === undefined ||
115
+ state.nativeActorRef === undefined)
115
116
  return undefined;
116
117
  const spotId = state.spotId;
117
118
  const actorRef = this.actorRefForState(state);
@@ -162,13 +163,7 @@ class DefaultZLinkActorManager {
162
163
  }
163
164
  await this.finalizeDestroyedActor(actor.actorId, state);
164
165
  }));
165
- try {
166
- await this.awaitActorDestroy(state, destroyTask);
167
- }
168
- catch (error) {
169
- state.clearFailedDestroy(destroyTask);
170
- throw error;
171
- }
166
+ await this.awaitActorDestroy(state, destroyTask);
172
167
  return true;
173
168
  }
174
169
  async materializeTransferredActor(actorId, actorType, adapterKey, transferState, signal) {
@@ -235,9 +230,10 @@ class DefaultZLinkActorManager {
235
230
  if (result.status === 'failed') {
236
231
  throw actorApplicationFailure(actorId, result.error);
237
232
  }
233
+ const actorRef = result.actorRef ?? this.actorRefForState(this.states.get(actorId));
238
234
  return result.reply === undefined
239
- ? { status: result.status, actor: result.actorRef }
240
- : { status: result.status, actor: result.actorRef, reply: result.reply };
235
+ ? { status: result.status, actor: actorRef }
236
+ : { status: result.status, actor: actorRef, reply: result.reply };
241
237
  }
242
238
  ensureActorTypeBelongsToMesh(meshName, actorType) {
243
239
  const registeredMesh = this.options.actorMeshNameProvider?.(actorType);
@@ -442,7 +438,13 @@ class DefaultZLinkActorManager {
442
438
  }
443
439
  async createReservedActorResult(actorId, actorType, createRequest, signal, nativeActorRef) {
444
440
  this.rememberActorMeshFromType(actorId, actorType);
445
- return await this.createOrGet(actorId, actorType, false, createRequest, signal, false, Registration_1.DEFAULT_REQUEST_TIMEOUT_MS, nativeActorRef);
441
+ const result = await this.createOrGet(actorId, actorType, false, createRequest, signal, false, Registration_1.DEFAULT_REQUEST_TIMEOUT_MS, nativeActorRef);
442
+ if (result.status === 'failed' || result.status === 'rejected')
443
+ return result;
444
+ return {
445
+ ...result,
446
+ actorRef: this.actorRefForState(this.states.get(actorId))
447
+ };
446
448
  }
447
449
  adoptCreatedAuthority(actorId, authorityOwnerGeneration, ownerLeaseGeneration) {
448
450
  const state = this.states.get(actorId);
@@ -473,7 +475,7 @@ class DefaultZLinkActorManager {
473
475
  throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorRouteNotFound, `Actor '${actor.context.actorId}' must leave its current SPOT before destroy.`);
474
476
  }
475
477
  const destroyTask = state.getOrStartDestroy(entryNodeRid, (actorRef) => this.terminateActor(state, async () => {
476
- const destroyedActorRef = actorRef === undefined ? undefined : (0, actor_runtime_state_1.toFrameworkActorRef)(actorRef, state.meshName ?? '');
478
+ const destroyedActorRef = state.nativeActorRef === undefined ? undefined : this.actorRefForState(state);
477
479
  if (actorRef !== undefined) {
478
480
  await node.destroyActor(actorRef, 0, destroySignal);
479
481
  state.markNativeActorDestroyed(actorRef);
@@ -483,13 +485,7 @@ class DefaultZLinkActorManager {
483
485
  }
484
486
  await this.finalizeDestroyedActor(actor.context.actorId, state);
485
487
  }));
486
- try {
487
- await this.awaitActorDestroy(state, destroyTask);
488
- }
489
- catch (error) {
490
- state.clearFailedDestroy(destroyTask);
491
- throw error;
492
- }
488
+ await this.awaitActorDestroy(state, destroyTask);
493
489
  }
494
490
  async createOrGet(actorId, actorType, failIfExists, request, signal, claimLocation = true, timeoutMs = Registration_1.DEFAULT_REQUEST_TIMEOUT_MS, nativeActorRef) {
495
491
  const deadline = performance.now() + timeoutMs;
@@ -533,7 +529,7 @@ class DefaultZLinkActorManager {
533
529
  try {
534
530
  const result = await operation.task;
535
531
  if (result.status === 'created') {
536
- const actorRef = this.actorRefForState(state);
532
+ const actorRef = state.nativeActorRef === undefined ? undefined : this.actorRefForState(state);
537
533
  return {
538
534
  status: operation.created ? 'created' : 'existing',
539
535
  actor: result.actor,
@@ -602,16 +598,7 @@ class DefaultZLinkActorManager {
602
598
  return state;
603
599
  }
604
600
  actorRefForState(state) {
605
- const nativeActorRef = state.nativeActorRef;
606
- if (nativeActorRef !== undefined) {
607
- return (0, actor_runtime_state_1.toFrameworkActorRef)(nativeActorRef, state.meshName ?? '');
608
- }
609
- return {
610
- actorId: state.actorId,
611
- objectGeneration: 1n,
612
- meshName: state.meshName ?? '',
613
- nodeRid: this.options.actorCreatedNodeRidProvider?.() ?? LOCAL_DIAGNOSTIC_NODE_RID
614
- };
601
+ return (0, actor_runtime_state_1.toFrameworkActorRef)(state.currentActorRef(), state.meshName ?? '');
615
602
  }
616
603
  }
617
604
  exports.DefaultZLinkActorManager = DefaultZLinkActorManager;
@@ -311,24 +311,23 @@ class ZLinkActorLocationClaims {
311
311
  const current = await store.readAuthority(key);
312
312
  if (!matchesActorAuthority(current, actorRef, ownerToken))
313
313
  return;
314
- const result = await store.compareExchangeAuthority(key, current.storeVersion, {
314
+ let result = await store.compareExchangeAuthority(key, current.storeVersion, {
315
315
  kind: 'delete'
316
316
  });
317
- if (result.kind === 'deleted' ||
318
- (result.kind === 'conflict' && result.current.kind === 'missing')) {
319
- return;
320
- }
321
317
  if (result.kind === 'conflict' &&
322
318
  result.current.kind === 'snapshot' &&
323
319
  matchesActorAuthority(result.current, actorRef, ownerToken)) {
324
- const retry = await store.compareExchangeAuthority(key, result.current.storeVersion, {
320
+ result = await store.compareExchangeAuthority(key, result.current.storeVersion, {
325
321
  kind: 'delete'
326
322
  });
327
- if (retry.kind === 'deleted' ||
328
- (retry.kind === 'conflict' && retry.current.kind === 'missing')) {
329
- return;
330
- }
331
323
  }
324
+ if (result.kind === 'deleted' ||
325
+ (result.kind === 'conflict' && result.current.kind === 'missing')) {
326
+ return;
327
+ }
328
+ throw new Errors_1.ZLinkFrameworkException(result.kind === 'conflict'
329
+ ? classifyMembershipAuthorityFailure(result.current, actorRef)
330
+ : Errors_1.ZLinkFrameworkErrorKind.InternalFailure, `Actor '${actorId}' authority release was rejected with status ${result.kind}.`);
332
331
  }
333
332
  }
334
333
  exports.ZLinkActorLocationClaims = ZLinkActorLocationClaims;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zlink-systems/framework",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@opentelemetry/api": "^1.9.1",
21
21
  "@opentelemetry/api-logs": "^0.221.0",
22
- "@zlink-systems/stream-wire": "0.32.0",
22
+ "@zlink-systems/stream-wire": "0.32.1",
23
23
  "@zlink-systems/zlink": "1.23.0"
24
24
  }
25
25
  }
@@ -97,7 +97,7 @@ export class DefaultZLinkActorContext implements ZLinkActorContext {
97
97
  }
98
98
 
99
99
  get objectGeneration(): bigint {
100
- return this.state.nativeActorRef?.generation ?? 1n;
100
+ return this.state.currentActorRef().generation;
101
101
  }
102
102
 
103
103
  get spotId(): SpotId | undefined {
@@ -211,7 +211,7 @@ export class ZLinkActorCreationCoordinator {
211
211
  await this.options.locationLifecycle?.setActorRef(
212
212
  actorType,
213
213
  actorId,
214
- { actorId, objectGeneration: 1n, meshName, nodeRid },
214
+ toFrameworkActorRef(state.currentActorRef(), meshName),
215
215
  0n
216
216
  );
217
217
  }
@@ -9,6 +9,7 @@ import {
9
9
 
10
10
  import type { Message } from '../../contracts/Common/Message';
11
11
  import type { ZLinkBackendActorRef, ZLinkBackendMeshNode } from '../backend/contracts';
12
+ import { ZLinkConfigurationException } from '../configuration';
12
13
  import { isStructuralGuardEnabled } from '../execution/state-lane';
13
14
  import {
14
15
  ZLinkFrameworkInternalErrorKind,
@@ -172,7 +173,9 @@ export class ZLinkActorRuntimeState {
172
173
  private spotIdValue: RoutingId | undefined;
173
174
  private spotGenerationValue: bigint | undefined;
174
175
  private spotMembershipEpochValue = 0n;
176
+ // Preserve the exact incarnation until teardown finalization, even after native removal.
175
177
  private nativeActorRefValue: ZLinkBackendActorRef | undefined;
178
+ private nativeActorDestroyed = false;
176
179
  private entryNodeRidValue: RoutingId | undefined;
177
180
  boundSessionValue: ZLinkRemoteBoundSessionTarget | undefined;
178
181
  private remoteActorPacketTargetValue: ZLinkRemoteActorPacketTarget | undefined;
@@ -228,6 +231,15 @@ export class ZLinkActorRuntimeState {
228
231
  return this.nativeActorRefValue;
229
232
  }
230
233
 
234
+ currentActorRef(): ZLinkBackendActorRef {
235
+ if (this.nativeActorRefValue === undefined) {
236
+ throw new ZLinkConfigurationException(
237
+ `Actor '${this.actorId}' lifecycle identity is not initialized.`
238
+ );
239
+ }
240
+ return this.nativeActorRefValue;
241
+ }
242
+
231
243
  get boundSessionBindingGeneration(): bigint {
232
244
  return this.boundSessionValue?.bindingGeneration ?? 0n;
233
245
  }
@@ -355,24 +367,26 @@ export class ZLinkActorRuntimeState {
355
367
  );
356
368
  }
357
369
 
358
- const task = Promise.resolve().then(() => destroy(actorRef));
370
+ const task = Promise.resolve()
371
+ .then(() => destroy(this.nativeActorDestroyed ? undefined : actorRef))
372
+ .catch((error: unknown) => {
373
+ // A caller may start another attempt only after this attempt has failed.
374
+ if (this.destroyTask === task) {
375
+ this.destroyTask = undefined;
376
+ this.movingValue = false;
377
+ }
378
+ throw error;
379
+ });
359
380
  this.destroyTask = task;
360
381
  return task;
361
382
  }
362
383
 
363
384
  markNativeActorDestroyed(actorRef: ZLinkBackendActorRef): void {
364
385
  if (this.nativeActorRefValue === actorRef) {
365
- this.nativeActorRefValue = undefined;
386
+ this.nativeActorDestroyed = true;
366
387
  }
367
388
  }
368
389
 
369
- clearFailedDestroy(task: Promise<void>): void {
370
- if (this.destroyTask === task) {
371
- this.destroyTask = undefined;
372
- }
373
- this.movingValue = false;
374
- }
375
-
376
390
  ensureContext(createContext: () => ZLinkActorContext): ZLinkActorContext {
377
391
  this.context ??= createContext();
378
392
  return this.context;
@@ -425,6 +439,7 @@ export class ZLinkActorRuntimeState {
425
439
  this.createRequestPayloadValue = undefined;
426
440
  this.configured = false;
427
441
  this.nativeActorRefValue = undefined;
442
+ this.nativeActorDestroyed = false;
428
443
  this.entryNodeRidValue = undefined;
429
444
  return true;
430
445
  }
@@ -474,6 +489,7 @@ export class ZLinkActorRuntimeState {
474
489
 
475
490
  setNativeActorRef(actorRef: ZLinkBackendActorRef): void {
476
491
  this.nativeActorRefValue = actorRef;
492
+ this.nativeActorDestroyed = false;
477
493
  this.entryNodeRidValue ??= toFrameworkRoutingId(actorRef.nodeRid);
478
494
  }
479
495
 
@@ -556,6 +572,7 @@ export class ZLinkActorRuntimeState {
556
572
  this.spotGenerationValue = undefined;
557
573
  this.spotMembershipEpochValue = 0n;
558
574
  this.nativeActorRefValue = undefined;
575
+ this.nativeActorDestroyed = false;
559
576
  this.entryNodeRidValue = undefined;
560
577
  this.boundSessionValue = undefined;
561
578
  this.remoteActorPacketTargetValue = undefined;
@@ -578,6 +595,7 @@ export class ZLinkActorRuntimeState {
578
595
  this.spotValue = undefined;
579
596
  this.spotIdValue = undefined;
580
597
  this.nativeActorRefValue = undefined;
598
+ this.nativeActorDestroyed = false;
581
599
  // The arriving relocation installs the binding it carries.
582
600
  this.boundSessionValue = undefined;
583
601
  this.remoteActorPacketTargetValue = undefined;
@@ -40,7 +40,6 @@ import {
40
40
  } from './actor-runtime-state';
41
41
  import { ZLinkTransferredActorRollbackCoordinator } from './transferred-actor-rollback';
42
42
  const ACTOR_CREATION_RETRY_INTERVAL_MS = 5;
43
- const LOCAL_DIAGNOSTIC_NODE_RID = 'local';
44
43
 
45
44
  export { DefaultZLinkActorClient, type ZLinkActorClientOptions } from './actor-client';
46
45
  export { DefaultZLinkActorContext, ZLINK_ACTOR_JOIN_ENTRY_SPOT_RUNTIME } from './actor-context';
@@ -167,7 +166,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
167
166
  throwIfAborted(signal);
168
167
  if (this.relocationStaged.has(actorId)) return undefined;
169
168
  const state = this.states.get(actorId);
170
- if (state?.actor !== undefined) {
169
+ if (state?.actor !== undefined && state.nativeActorRef !== undefined) {
171
170
  return this.actorRefForState(state);
172
171
  }
173
172
  return await this.options.actorRefResolver?.resolveActorRef(actorId, signal);
@@ -182,7 +181,12 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
182
181
  async findSpot(actorId: string, signal?: AbortSignal): Promise<SpotRef | undefined> {
183
182
  throwIfAborted(signal);
184
183
  const state = this.states.get(actorId);
185
- if (state?.actor === undefined || state.spotId === undefined) return undefined;
184
+ if (
185
+ state?.actor === undefined ||
186
+ state.spotId === undefined ||
187
+ state.nativeActorRef === undefined
188
+ )
189
+ return undefined;
186
190
  const spotId = state.spotId;
187
191
  const actorRef = this.actorRefForState(state);
188
192
  return {
@@ -249,12 +253,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
249
253
  await this.finalizeDestroyedActor(actor.actorId, state);
250
254
  })
251
255
  );
252
- try {
253
- await this.awaitActorDestroy(state, destroyTask);
254
- } catch (error) {
255
- state.clearFailedDestroy(destroyTask);
256
- throw error;
257
- }
256
+ await this.awaitActorDestroy(state, destroyTask);
258
257
  return true;
259
258
  }
260
259
 
@@ -362,9 +361,10 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
362
361
  if (result.status === 'failed') {
363
362
  throw actorApplicationFailure(actorId, result.error);
364
363
  }
364
+ const actorRef = result.actorRef ?? this.actorRefForState(this.states.get(actorId)!);
365
365
  return result.reply === undefined
366
- ? { status: result.status, actor: result.actorRef }
367
- : { status: result.status, actor: result.actorRef, reply: result.reply };
366
+ ? { status: result.status, actor: actorRef }
367
+ : { status: result.status, actor: actorRef, reply: result.reply };
368
368
  }
369
369
 
370
370
  private ensureActorTypeBelongsToMesh(meshName: string, actorType: string): void {
@@ -638,7 +638,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
638
638
  actorType: string,
639
639
  createRequest?: unknown,
640
640
  signal?: AbortSignal
641
- ): Promise<ZLinkActorLocalCreateResult> {
641
+ ): Promise<ZLinkActorLocalCreateResult<ActorRef | undefined>> {
642
642
  this.rememberActorMeshFromType(actorId, actorType);
643
643
  return await this.createOrGet(actorId, actorType, false, createRequest, signal);
644
644
  }
@@ -651,7 +651,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
651
651
  nativeActorRef?: ZLinkBackendActorRef
652
652
  ): Promise<ZLinkActorLocalCreateResult> {
653
653
  this.rememberActorMeshFromType(actorId, actorType);
654
- return await this.createOrGet(
654
+ const result = await this.createOrGet(
655
655
  actorId,
656
656
  actorType,
657
657
  false,
@@ -661,6 +661,11 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
661
661
  DEFAULT_REQUEST_TIMEOUT_MS,
662
662
  nativeActorRef
663
663
  );
664
+ if (result.status === 'failed' || result.status === 'rejected') return result;
665
+ return {
666
+ ...result,
667
+ actorRef: this.actorRefForState(this.states.get(actorId)!)
668
+ };
664
669
  }
665
670
 
666
671
  adoptCreatedAuthority(
@@ -712,7 +717,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
712
717
  const destroyTask = state.getOrStartDestroy(entryNodeRid, (actorRef) =>
713
718
  this.terminateActor(state, async () => {
714
719
  const destroyedActorRef =
715
- actorRef === undefined ? undefined : toFrameworkActorRef(actorRef, state.meshName ?? '');
720
+ state.nativeActorRef === undefined ? undefined : this.actorRefForState(state);
716
721
  if (actorRef !== undefined) {
717
722
  await node.destroyActor(actorRef, 0, destroySignal);
718
723
  state.markNativeActorDestroyed(actorRef);
@@ -728,12 +733,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
728
733
  })
729
734
  );
730
735
 
731
- try {
732
- await this.awaitActorDestroy(state, destroyTask);
733
- } catch (error) {
734
- state.clearFailedDestroy(destroyTask);
735
- throw error;
736
- }
736
+ await this.awaitActorDestroy(state, destroyTask);
737
737
  }
738
738
 
739
739
  private async createOrGet(
@@ -745,7 +745,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
745
745
  claimLocation = true,
746
746
  timeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,
747
747
  nativeActorRef?: ZLinkBackendActorRef
748
- ): Promise<ZLinkActorLocalCreateResult> {
748
+ ): Promise<ZLinkActorLocalCreateResult<ActorRef | undefined>> {
749
749
  const deadline = performance.now() + timeoutMs;
750
750
  const requestedMeshName = this.actorMeshNames.get(actorId);
751
751
  for (;;) {
@@ -801,7 +801,8 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
801
801
  try {
802
802
  const result = await operation.task;
803
803
  if (result.status === 'created') {
804
- const actorRef = this.actorRefForState(state);
804
+ const actorRef =
805
+ state.nativeActorRef === undefined ? undefined : this.actorRefForState(state);
805
806
  return {
806
807
  status: operation.created ? 'created' : 'existing',
807
808
  actor: result.actor,
@@ -886,16 +887,7 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
886
887
  }
887
888
 
888
889
  private actorRefForState(state: ZLinkActorRuntimeState): ActorRef {
889
- const nativeActorRef = state.nativeActorRef;
890
- if (nativeActorRef !== undefined) {
891
- return toFrameworkActorRef(nativeActorRef, state.meshName ?? '');
892
- }
893
- return {
894
- actorId: state.actorId,
895
- objectGeneration: 1n,
896
- meshName: state.meshName ?? '',
897
- nodeRid: this.options.actorCreatedNodeRidProvider?.() ?? LOCAL_DIAGNOSTIC_NODE_RID
898
- };
890
+ return toFrameworkActorRef(state.currentActorRef(), state.meshName ?? '');
899
891
  }
900
892
  }
901
893
 
@@ -994,11 +986,11 @@ class ZLinkActorGetOrCreateCallRuntime
994
986
  extends ZLinkActorCreateCallRuntime
995
987
  implements ZLinkActorGetOrCreateCall {}
996
988
 
997
- export type ZLinkActorLocalCreateResult =
989
+ export type ZLinkActorLocalCreateResult<TActorRef extends ActorRef | undefined = ActorRef> =
998
990
  | {
999
991
  readonly status: 'existing' | 'created';
1000
992
  readonly actor: ZLinkActor;
1001
- readonly actorRef: ActorRef;
993
+ readonly actorRef: TActorRef;
1002
994
  readonly reply?: unknown;
1003
995
  }
1004
996
  | {
@@ -1010,7 +1002,10 @@ export type ZLinkActorLocalCreateResult =
1010
1002
  readonly error: unknown;
1011
1003
  };
1012
1004
 
1013
- function requireCreatedActor(result: ZLinkActorLocalCreateResult, actorId: string): ZLinkActor {
1005
+ function requireCreatedActor(
1006
+ result: ZLinkActorLocalCreateResult<ActorRef | undefined>,
1007
+ actorId: string
1008
+ ): ZLinkActor {
1014
1009
  if (result.status === 'existing' || result.status === 'created') return result.actor;
1015
1010
  if (result.status === 'failed') {
1016
1011
  throw actorApplicationFailure(actorId, result.error);
@@ -426,30 +426,30 @@ export class ZLinkActorLocationClaims {
426
426
  const current = await store.readAuthority(key);
427
427
  if (!matchesActorAuthority(current, actorRef, ownerToken)) return;
428
428
 
429
- const result = await store.compareExchangeAuthority(key, current.storeVersion, {
429
+ let result = await store.compareExchangeAuthority(key, current.storeVersion, {
430
430
  kind: 'delete'
431
431
  });
432
- if (
433
- result.kind === 'deleted' ||
434
- (result.kind === 'conflict' && result.current.kind === 'missing')
435
- ) {
436
- return;
437
- }
438
432
  if (
439
433
  result.kind === 'conflict' &&
440
434
  result.current.kind === 'snapshot' &&
441
435
  matchesActorAuthority(result.current, actorRef, ownerToken)
442
436
  ) {
443
- const retry = await store.compareExchangeAuthority(key, result.current.storeVersion, {
437
+ result = await store.compareExchangeAuthority(key, result.current.storeVersion, {
444
438
  kind: 'delete'
445
439
  });
446
- if (
447
- retry.kind === 'deleted' ||
448
- (retry.kind === 'conflict' && retry.current.kind === 'missing')
449
- ) {
450
- return;
451
- }
452
440
  }
441
+ if (
442
+ result.kind === 'deleted' ||
443
+ (result.kind === 'conflict' && result.current.kind === 'missing')
444
+ ) {
445
+ return;
446
+ }
447
+ throw new ZLinkFrameworkException(
448
+ result.kind === 'conflict'
449
+ ? classifyMembershipAuthorityFailure(result.current, actorRef)
450
+ : ZLinkFrameworkErrorKind.InternalFailure,
451
+ `Actor '${actorId}' authority release was rejected with status ${result.kind}.`
452
+ );
453
453
  }
454
454
  }
455
455