depa-actor 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addressing.d.ts +100 -0
- package/dist/addressing.d.ts.map +1 -0
- package/dist/addressing.js +517 -0
- package/dist/addressing.js.map +1 -0
- package/dist/dispatch/ActorDispatchAdapter.d.ts +74 -17
- package/dist/dispatch/ActorDispatchAdapter.d.ts.map +1 -1
- package/dist/dispatch/ActorDispatchAdapter.js +109 -24
- package/dist/dispatch/ActorDispatchAdapter.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/ActorPipeline.d.ts +35 -8
- package/dist/pipeline/ActorPipeline.d.ts.map +1 -1
- package/dist/pipeline/ActorPipeline.js +26 -16
- package/dist/pipeline/ActorPipeline.js.map +1 -1
- package/dist-cjs/addressing.cjs +532 -0
- package/dist-cjs/dispatch/ActorDispatchAdapter.cjs +109 -24
- package/dist-cjs/index.cjs +26 -1
- package/dist-cjs/pipeline/ActorPipeline.cjs +26 -16
- package/package.json +4 -1
- package/src/addressing.ts +976 -0
- package/src/dispatch/ActorDispatchAdapter.ts +218 -47
- package/src/index.ts +55 -2
- package/src/pipeline/ActorPipeline.ts +103 -57
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export declare const ACTOR_ADDRESS_SCHEMA_VERSION: "depa-actor-address/v1";
|
|
2
|
+
export declare const ACTOR_OWNER_SNAPSHOT_SCHEMA_VERSION: "depa-actor-owner-snapshot/v1";
|
|
3
|
+
export declare const ACTOR_REGISTRATION_SCHEMA_VERSION: "depa-actor-registration/v1";
|
|
4
|
+
export type ActorAddressingErrorCode = 'invalid-address' | 'invalid-selector' | 'invalid-owner-snapshot' | 'duplicate-snapshot-address' | 'already-registered' | 'unresolved-selector' | 'registration-mismatch' | 'stale-registration';
|
|
5
|
+
export declare class ActorAddressingError extends Error {
|
|
6
|
+
readonly code: ActorAddressingErrorCode;
|
|
7
|
+
readonly name = "ActorAddressingError";
|
|
8
|
+
constructor(code: ActorAddressingErrorCode, message: string);
|
|
9
|
+
}
|
|
10
|
+
export interface ActorAddress {
|
|
11
|
+
readonly schemaVersion: typeof ACTOR_ADDRESS_SCHEMA_VERSION;
|
|
12
|
+
readonly namespace: string;
|
|
13
|
+
readonly deploymentId: string;
|
|
14
|
+
readonly actorKind: string;
|
|
15
|
+
readonly logicalKey: string;
|
|
16
|
+
}
|
|
17
|
+
export type ActorSelector = {
|
|
18
|
+
readonly byAddress: ActorAddress;
|
|
19
|
+
} | {
|
|
20
|
+
readonly byAlias: string;
|
|
21
|
+
};
|
|
22
|
+
export interface ActorOwnerSnapshotRegistration {
|
|
23
|
+
readonly address: ActorAddress;
|
|
24
|
+
readonly handlerIdentity: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ActorOwnerSnapshot {
|
|
27
|
+
readonly schemaVersion: typeof ACTOR_OWNER_SNAPSHOT_SCHEMA_VERSION;
|
|
28
|
+
readonly ownerRevision: string;
|
|
29
|
+
readonly snapshotReceipt: string;
|
|
30
|
+
readonly registrations: readonly ActorOwnerSnapshotRegistration[];
|
|
31
|
+
}
|
|
32
|
+
export interface ActorRegistrationReceipt {
|
|
33
|
+
readonly schemaVersion: typeof ACTOR_REGISTRATION_SCHEMA_VERSION;
|
|
34
|
+
readonly address: ActorAddress;
|
|
35
|
+
readonly ownerRevision: string;
|
|
36
|
+
readonly snapshotReceipt: string;
|
|
37
|
+
readonly handlerIdentity: string;
|
|
38
|
+
readonly registrationId: string;
|
|
39
|
+
}
|
|
40
|
+
export interface LocalActorEndpoint<TInvocation, TOutput> {
|
|
41
|
+
readonly handlerIdentity: string;
|
|
42
|
+
readonly dispatch: (invocation: TInvocation) => TOutput | Promise<TOutput>;
|
|
43
|
+
}
|
|
44
|
+
declare const localActorAddressingRuntimeBrand: unique symbol;
|
|
45
|
+
export interface LocalActorAddressingRuntime<TInvocation, TOutput> {
|
|
46
|
+
readonly runtimeInstanceId: string;
|
|
47
|
+
readonly [localActorAddressingRuntimeBrand]: {
|
|
48
|
+
readonly invocation: TInvocation;
|
|
49
|
+
readonly output: TOutput;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface LocalActorAddressingRuntimeConfig {
|
|
53
|
+
readonly runtimeInstanceId?: string;
|
|
54
|
+
readonly resolveAlias?: (alias: string) => ActorAddress | undefined;
|
|
55
|
+
readonly registrationIdFactory?: (input: {
|
|
56
|
+
readonly runtimeInstanceId: string;
|
|
57
|
+
readonly sequence: number;
|
|
58
|
+
readonly address: ActorAddress;
|
|
59
|
+
}) => string;
|
|
60
|
+
}
|
|
61
|
+
export interface RegisterActorInput<TInvocation, TOutput> {
|
|
62
|
+
readonly address: ActorAddress;
|
|
63
|
+
readonly ownerSnapshot: ActorOwnerSnapshot;
|
|
64
|
+
readonly endpoint: LocalActorEndpoint<TInvocation, TOutput>;
|
|
65
|
+
}
|
|
66
|
+
export type ActorProcessorConfig = Readonly<Record<string, never>>;
|
|
67
|
+
export interface ResolveActorInvocation {
|
|
68
|
+
readonly expectedRegistrationId?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface DispatchActorInvocation<TInvocation> extends ResolveActorInvocation {
|
|
71
|
+
readonly input: TInvocation;
|
|
72
|
+
}
|
|
73
|
+
export interface UnregisterActorInvocation {
|
|
74
|
+
readonly expectedRegistrationId: string;
|
|
75
|
+
}
|
|
76
|
+
export interface ResolvedActor {
|
|
77
|
+
readonly address: ActorAddress;
|
|
78
|
+
readonly receipt: ActorRegistrationReceipt;
|
|
79
|
+
}
|
|
80
|
+
export interface RebuildActorRegistrationsConfig<TInvocation, TOutput> {
|
|
81
|
+
readonly endpointFor: (registration: ActorOwnerSnapshotRegistration) => LocalActorEndpoint<TInvocation, TOutput>;
|
|
82
|
+
}
|
|
83
|
+
export type DirectActorProcessor<TRuntime, TInput, TConfig, TOutput> = (runtime: TRuntime, input: TInput, config: TConfig) => TOutput | Promise<TOutput>;
|
|
84
|
+
export type TargetedActorProcessor<TRuntime, TSelector, TInvocation, TConfig, TOutput> = (runtime: TRuntime, selector: TSelector, invocation: TInvocation, config: TConfig) => TOutput | Promise<TOutput>;
|
|
85
|
+
export declare function parseActorAddress(value: unknown): ActorAddress;
|
|
86
|
+
export declare function actorAddressKey(address: ActorAddress): string;
|
|
87
|
+
export declare function parseActorSelector(value: unknown): ActorSelector;
|
|
88
|
+
export declare function parseActorOwnerSnapshot(value: unknown): ActorOwnerSnapshot;
|
|
89
|
+
export declare function parseActorRegistrationReceipt(value: unknown): ActorRegistrationReceipt;
|
|
90
|
+
export declare function createLocalActorAddressingRuntime<TInvocation, TOutput>(config?: LocalActorAddressingRuntimeConfig): LocalActorAddressingRuntime<TInvocation, TOutput>;
|
|
91
|
+
export declare function registerActor<TInvocation, TOutput>(runtime: LocalActorAddressingRuntime<TInvocation, TOutput>, input: RegisterActorInput<TInvocation, TOutput>, config: ActorProcessorConfig): ActorRegistrationReceipt;
|
|
92
|
+
export declare function resolveActor<TInvocation, TOutput>(runtime: LocalActorAddressingRuntime<TInvocation, TOutput>, selector: ActorSelector, invocation: ResolveActorInvocation, config: ActorProcessorConfig): ResolvedActor;
|
|
93
|
+
export declare function dispatchActor<TInvocation, TOutput>(runtime: LocalActorAddressingRuntime<TInvocation, TOutput>, selector: ActorSelector, invocation: DispatchActorInvocation<TInvocation>, config: ActorProcessorConfig): Promise<TOutput>;
|
|
94
|
+
export declare function unregisterActor<TInvocation, TOutput>(runtime: LocalActorAddressingRuntime<TInvocation, TOutput>, selector: ActorSelector, invocation: UnregisterActorInvocation, config: ActorProcessorConfig): ActorRegistrationReceipt;
|
|
95
|
+
export declare function rebuildActorRegistrations<TInvocation, TOutput>(runtime: LocalActorAddressingRuntime<TInvocation, TOutput>, input: ActorOwnerSnapshot, config: RebuildActorRegistrationsConfig<TInvocation, TOutput>): readonly ActorRegistrationReceipt[];
|
|
96
|
+
export declare function createActorRefEndpoint<TSchema extends Record<string, unknown>, TTag extends keyof TSchema & string>(ref: {
|
|
97
|
+
readonly send: (tag: TTag, payload: TSchema[TTag]) => void;
|
|
98
|
+
}, tag: TTag, handlerIdentity: string): LocalActorEndpoint<TSchema[TTag], void>;
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=addressing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addressing.d.ts","sourceRoot":"","sources":["../src/addressing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
export const ACTOR_ADDRESS_SCHEMA_VERSION = 'depa-actor-address/v1';
|
|
2
|
+
export const ACTOR_OWNER_SNAPSHOT_SCHEMA_VERSION = 'depa-actor-owner-snapshot/v1';
|
|
3
|
+
export const ACTOR_REGISTRATION_SCHEMA_VERSION = 'depa-actor-registration/v1';
|
|
4
|
+
export class ActorAddressingError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
name = 'ActorAddressingError';
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const ADDRESS_KEYS = [
|
|
13
|
+
'schemaVersion',
|
|
14
|
+
'namespace',
|
|
15
|
+
'deploymentId',
|
|
16
|
+
'actorKind',
|
|
17
|
+
'logicalKey',
|
|
18
|
+
];
|
|
19
|
+
const OWNER_SNAPSHOT_KEYS = [
|
|
20
|
+
'schemaVersion',
|
|
21
|
+
'ownerRevision',
|
|
22
|
+
'snapshotReceipt',
|
|
23
|
+
'registrations',
|
|
24
|
+
];
|
|
25
|
+
const OWNER_REGISTRATION_KEYS = ['address', 'handlerIdentity'];
|
|
26
|
+
const REGISTRATION_RECEIPT_KEYS = [
|
|
27
|
+
'schemaVersion',
|
|
28
|
+
'address',
|
|
29
|
+
'ownerRevision',
|
|
30
|
+
'snapshotReceipt',
|
|
31
|
+
'handlerIdentity',
|
|
32
|
+
'registrationId',
|
|
33
|
+
];
|
|
34
|
+
const REGISTER_INPUT_KEYS = ['address', 'ownerSnapshot', 'endpoint'];
|
|
35
|
+
const ENDPOINT_KEYS = ['handlerIdentity', 'dispatch'];
|
|
36
|
+
const RUNTIME_CONFIG_KEYS = ['runtimeInstanceId', 'resolveAlias', 'registrationIdFactory'];
|
|
37
|
+
const EXPECTED_REGISTRATION_ID_KEYS = ['expectedRegistrationId'];
|
|
38
|
+
const DISPATCH_INVOCATION_REQUIRED_KEYS = ['input'];
|
|
39
|
+
const ADDRESS_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._~-]{0,126}[A-Za-z0-9])?$/;
|
|
40
|
+
const OPAQUE_TOKEN = /^[A-Za-z0-9](?:[A-Za-z0-9._~:/-]{0,254}[A-Za-z0-9])?$/;
|
|
41
|
+
const runtimeStates = new WeakMap();
|
|
42
|
+
let runtimeNonceSequence = 0;
|
|
43
|
+
function closedRecordError(code, label, detail) {
|
|
44
|
+
return new ActorAddressingError(code, `${label} ${detail}`);
|
|
45
|
+
}
|
|
46
|
+
function readClosedRecord(value, requiredKeys, optionalKeys, code, label) {
|
|
47
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
48
|
+
throw closedRecordError(code, label, 'must be an object');
|
|
49
|
+
}
|
|
50
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
51
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
52
|
+
throw closedRecordError(code, label, 'must use Object.prototype or a null prototype');
|
|
53
|
+
}
|
|
54
|
+
const allowedKeys = new Set([...requiredKeys, ...optionalKeys]);
|
|
55
|
+
const values = new Map();
|
|
56
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
57
|
+
if (typeof key !== 'string' || !allowedKeys.has(key)) {
|
|
58
|
+
throw closedRecordError(code, label, `must contain only: ${[...allowedKeys].sort().join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
|
|
61
|
+
if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) {
|
|
62
|
+
throw closedRecordError(code, label, `${key} must be an own enumerable data property`);
|
|
63
|
+
}
|
|
64
|
+
values.set(key, descriptor.value);
|
|
65
|
+
}
|
|
66
|
+
for (const key of requiredKeys) {
|
|
67
|
+
if (!values.has(key)) {
|
|
68
|
+
throw closedRecordError(code, label, `must contain required field: ${key}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
73
|
+
function readExactRecord(value, keys, code, label) {
|
|
74
|
+
return readClosedRecord(value, keys, [], code, label);
|
|
75
|
+
}
|
|
76
|
+
function readClosedArray(value, code, label) {
|
|
77
|
+
if (!Array.isArray(value) || Reflect.getPrototypeOf(value) !== Array.prototype) {
|
|
78
|
+
throw closedRecordError(code, label, 'must be a plain array');
|
|
79
|
+
}
|
|
80
|
+
const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, 'length');
|
|
81
|
+
const lengthValue = lengthDescriptor && 'value' in lengthDescriptor ? lengthDescriptor.value : undefined;
|
|
82
|
+
if (!lengthDescriptor ||
|
|
83
|
+
!('value' in lengthDescriptor) ||
|
|
84
|
+
lengthDescriptor.enumerable ||
|
|
85
|
+
typeof lengthValue !== 'number' ||
|
|
86
|
+
!Number.isSafeInteger(lengthValue) ||
|
|
87
|
+
lengthValue < 0) {
|
|
88
|
+
throw closedRecordError(code, label, 'must have the standard own data length property');
|
|
89
|
+
}
|
|
90
|
+
const length = lengthValue;
|
|
91
|
+
const expectedKeys = new Set(['length']);
|
|
92
|
+
for (let index = 0; index < length; index += 1) {
|
|
93
|
+
expectedKeys.add(String(index));
|
|
94
|
+
}
|
|
95
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
96
|
+
if (ownKeys.length !== expectedKeys.size ||
|
|
97
|
+
ownKeys.some((key) => typeof key !== 'string' || !expectedKeys.has(key))) {
|
|
98
|
+
throw closedRecordError(code, label, 'must be dense and contain no extra own keys');
|
|
99
|
+
}
|
|
100
|
+
const elements = [];
|
|
101
|
+
for (let index = 0; index < length; index += 1) {
|
|
102
|
+
const key = String(index);
|
|
103
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
|
|
104
|
+
if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) {
|
|
105
|
+
throw closedRecordError(code, label, `${key} must be an own enumerable data property`);
|
|
106
|
+
}
|
|
107
|
+
elements.push(descriptor.value);
|
|
108
|
+
}
|
|
109
|
+
return elements;
|
|
110
|
+
}
|
|
111
|
+
function parseAddressSegment(value, field, code = 'invalid-address') {
|
|
112
|
+
if (typeof value !== 'string' ||
|
|
113
|
+
value !== value.normalize('NFC') ||
|
|
114
|
+
!ADDRESS_SEGMENT.test(value)) {
|
|
115
|
+
throw new ActorAddressingError(code, `${field} must be a canonical actor-address segment`);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
function parseOpaqueToken(value, field, code) {
|
|
120
|
+
if (typeof value !== 'string' ||
|
|
121
|
+
value !== value.normalize('NFC') ||
|
|
122
|
+
!OPAQUE_TOKEN.test(value) ||
|
|
123
|
+
value.includes('..') ||
|
|
124
|
+
value.includes('//') ||
|
|
125
|
+
value.includes('%')) {
|
|
126
|
+
throw new ActorAddressingError(code, `${field} must be a canonical non-empty token`);
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
export function parseActorAddress(value) {
|
|
131
|
+
const record = readExactRecord(value, ADDRESS_KEYS, 'invalid-address', 'ActorAddress');
|
|
132
|
+
if (record.get('schemaVersion') !== ACTOR_ADDRESS_SCHEMA_VERSION) {
|
|
133
|
+
throw new ActorAddressingError('invalid-address', 'Unsupported ActorAddress schemaVersion');
|
|
134
|
+
}
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
schemaVersion: ACTOR_ADDRESS_SCHEMA_VERSION,
|
|
137
|
+
namespace: parseAddressSegment(record.get('namespace'), 'namespace'),
|
|
138
|
+
deploymentId: parseAddressSegment(record.get('deploymentId'), 'deploymentId'),
|
|
139
|
+
actorKind: parseAddressSegment(record.get('actorKind'), 'actorKind'),
|
|
140
|
+
logicalKey: parseAddressSegment(record.get('logicalKey'), 'logicalKey'),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
export function actorAddressKey(address) {
|
|
144
|
+
const parsed = parseActorAddress(address);
|
|
145
|
+
return [
|
|
146
|
+
parsed.schemaVersion,
|
|
147
|
+
parsed.namespace,
|
|
148
|
+
parsed.deploymentId,
|
|
149
|
+
parsed.actorKind,
|
|
150
|
+
parsed.logicalKey,
|
|
151
|
+
].join(':');
|
|
152
|
+
}
|
|
153
|
+
export function parseActorSelector(value) {
|
|
154
|
+
const record = readClosedRecord(value, [], ['byAddress', 'byAlias'], 'invalid-selector', 'ActorSelector');
|
|
155
|
+
if (record.size !== 1) {
|
|
156
|
+
throw new ActorAddressingError('invalid-selector', 'ActorSelector must contain exactly one of byAddress or byAlias');
|
|
157
|
+
}
|
|
158
|
+
if (record.has('byAddress')) {
|
|
159
|
+
try {
|
|
160
|
+
return Object.freeze({ byAddress: parseActorAddress(record.get('byAddress')) });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
if (error instanceof ActorAddressingError) {
|
|
164
|
+
throw new ActorAddressingError('invalid-selector', `Invalid byAddress: ${error.message}`);
|
|
165
|
+
}
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
byAlias: parseOpaqueToken(record.get('byAlias'), 'byAlias', 'invalid-selector'),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
export function parseActorOwnerSnapshot(value) {
|
|
174
|
+
const record = readExactRecord(value, OWNER_SNAPSHOT_KEYS, 'invalid-owner-snapshot', 'ActorOwnerSnapshot');
|
|
175
|
+
if (record.get('schemaVersion') !== ACTOR_OWNER_SNAPSHOT_SCHEMA_VERSION) {
|
|
176
|
+
throw new ActorAddressingError('invalid-owner-snapshot', 'Unsupported owner snapshot schemaVersion');
|
|
177
|
+
}
|
|
178
|
+
const sourceRegistrations = readClosedArray(record.get('registrations'), 'invalid-owner-snapshot', 'registrations');
|
|
179
|
+
const registrations = [];
|
|
180
|
+
const seen = new Set();
|
|
181
|
+
for (const registration of sourceRegistrations) {
|
|
182
|
+
const registrationRecord = readExactRecord(registration, OWNER_REGISTRATION_KEYS, 'invalid-owner-snapshot', 'owner snapshot registration');
|
|
183
|
+
let address;
|
|
184
|
+
try {
|
|
185
|
+
address = parseActorAddress(registrationRecord.get('address'));
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
if (error instanceof ActorAddressingError) {
|
|
189
|
+
throw new ActorAddressingError('invalid-owner-snapshot', error.message);
|
|
190
|
+
}
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
const key = actorAddressKey(address);
|
|
194
|
+
if (seen.has(key)) {
|
|
195
|
+
throw new ActorAddressingError('duplicate-snapshot-address', `Owner snapshot contains duplicate address: ${key}`);
|
|
196
|
+
}
|
|
197
|
+
seen.add(key);
|
|
198
|
+
registrations.push(Object.freeze({
|
|
199
|
+
address,
|
|
200
|
+
handlerIdentity: parseOpaqueToken(registrationRecord.get('handlerIdentity'), 'handlerIdentity', 'invalid-owner-snapshot'),
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
return Object.freeze({
|
|
204
|
+
schemaVersion: ACTOR_OWNER_SNAPSHOT_SCHEMA_VERSION,
|
|
205
|
+
ownerRevision: parseOpaqueToken(record.get('ownerRevision'), 'ownerRevision', 'invalid-owner-snapshot'),
|
|
206
|
+
snapshotReceipt: parseOpaqueToken(record.get('snapshotReceipt'), 'snapshotReceipt', 'invalid-owner-snapshot'),
|
|
207
|
+
registrations: Object.freeze(registrations),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
export function parseActorRegistrationReceipt(value) {
|
|
211
|
+
const record = readExactRecord(value, REGISTRATION_RECEIPT_KEYS, 'registration-mismatch', 'ActorRegistrationReceipt');
|
|
212
|
+
if (record.get('schemaVersion') !== ACTOR_REGISTRATION_SCHEMA_VERSION) {
|
|
213
|
+
throw new ActorAddressingError('registration-mismatch', 'Unsupported registration schemaVersion');
|
|
214
|
+
}
|
|
215
|
+
return Object.freeze({
|
|
216
|
+
schemaVersion: ACTOR_REGISTRATION_SCHEMA_VERSION,
|
|
217
|
+
address: parseActorAddress(record.get('address')),
|
|
218
|
+
ownerRevision: parseOpaqueToken(record.get('ownerRevision'), 'ownerRevision', 'registration-mismatch'),
|
|
219
|
+
snapshotReceipt: parseOpaqueToken(record.get('snapshotReceipt'), 'snapshotReceipt', 'registration-mismatch'),
|
|
220
|
+
handlerIdentity: parseOpaqueToken(record.get('handlerIdentity'), 'handlerIdentity', 'registration-mismatch'),
|
|
221
|
+
registrationId: parseOpaqueToken(record.get('registrationId'), 'registrationId', 'registration-mismatch'),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function assertEmptyConfig(config) {
|
|
225
|
+
readExactRecord(config, [], 'registration-mismatch', 'Processor config');
|
|
226
|
+
}
|
|
227
|
+
function runtimeState(runtime) {
|
|
228
|
+
const state = runtimeStates.get(runtime);
|
|
229
|
+
if (!state) {
|
|
230
|
+
throw new ActorAddressingError('registration-mismatch', 'runtime must be created by createLocalActorAddressingRuntime');
|
|
231
|
+
}
|
|
232
|
+
return state;
|
|
233
|
+
}
|
|
234
|
+
function createRuntimeNonce() {
|
|
235
|
+
runtimeNonceSequence += 1;
|
|
236
|
+
const randomPart = typeof globalThis.crypto?.randomUUID === 'function'
|
|
237
|
+
? globalThis.crypto.randomUUID().replaceAll('-', '')
|
|
238
|
+
: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2) || '0'}`;
|
|
239
|
+
return `runtime-${randomPart}-${runtimeNonceSequence.toString(36)}`;
|
|
240
|
+
}
|
|
241
|
+
function beginMutation(state, operation) {
|
|
242
|
+
if (state.mutationGuard !== undefined) {
|
|
243
|
+
throw new ActorAddressingError('registration-mismatch', `${operation} cannot mutate the runtime while ${state.mutationGuard} is in progress`);
|
|
244
|
+
}
|
|
245
|
+
state.mutationGuard = operation;
|
|
246
|
+
return state.mutationVersion;
|
|
247
|
+
}
|
|
248
|
+
function endMutation(state, operation) {
|
|
249
|
+
if (state.mutationGuard === operation) {
|
|
250
|
+
state.mutationGuard = undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
export function createLocalActorAddressingRuntime(config = {}) {
|
|
254
|
+
const record = readClosedRecord(config, [], RUNTIME_CONFIG_KEYS, 'registration-mismatch', 'runtime config');
|
|
255
|
+
const resolveAlias = record.get('resolveAlias');
|
|
256
|
+
const registrationIdFactory = record.get('registrationIdFactory');
|
|
257
|
+
if (resolveAlias !== undefined && typeof resolveAlias !== 'function') {
|
|
258
|
+
throw new ActorAddressingError('registration-mismatch', 'resolveAlias must be a function');
|
|
259
|
+
}
|
|
260
|
+
if (registrationIdFactory !== undefined && typeof registrationIdFactory !== 'function') {
|
|
261
|
+
throw new ActorAddressingError('registration-mismatch', 'registrationIdFactory must be a function');
|
|
262
|
+
}
|
|
263
|
+
const randomPart = Math.random().toString(36).slice(2) || '0';
|
|
264
|
+
const runtimeInstanceId = parseOpaqueToken(record.get('runtimeInstanceId') ?? `local-runtime-${Date.now().toString(36)}-${randomPart}`, 'runtimeInstanceId', 'registration-mismatch');
|
|
265
|
+
const runtime = Object.freeze({ runtimeInstanceId });
|
|
266
|
+
runtimeStates.set(runtime, {
|
|
267
|
+
registrations: new Map(),
|
|
268
|
+
usedRegistrationIds: new Set(),
|
|
269
|
+
runtimeNonce: createRuntimeNonce(),
|
|
270
|
+
resolveAlias: resolveAlias,
|
|
271
|
+
registrationIdFactory: registrationIdFactory ??
|
|
272
|
+
((input) => `${input.runtimeInstanceId}:registration-${input.sequence}`),
|
|
273
|
+
sequence: 0,
|
|
274
|
+
mutationVersion: 0,
|
|
275
|
+
mutationGuard: undefined,
|
|
276
|
+
});
|
|
277
|
+
return runtime;
|
|
278
|
+
}
|
|
279
|
+
function parseEndpoint(value) {
|
|
280
|
+
const record = readExactRecord(value, ENDPOINT_KEYS, 'registration-mismatch', 'LocalActorEndpoint');
|
|
281
|
+
const handlerIdentity = parseOpaqueToken(record.get('handlerIdentity'), 'handlerIdentity', 'registration-mismatch');
|
|
282
|
+
const dispatch = record.get('dispatch');
|
|
283
|
+
if (typeof dispatch !== 'function') {
|
|
284
|
+
throw new ActorAddressingError('registration-mismatch', 'endpoint.dispatch must be a function');
|
|
285
|
+
}
|
|
286
|
+
return Object.freeze({
|
|
287
|
+
handlerIdentity,
|
|
288
|
+
dispatch: dispatch,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
function parseRegisterInput(input) {
|
|
292
|
+
const record = readExactRecord(input, REGISTER_INPUT_KEYS, 'registration-mismatch', 'RegisterActorInput');
|
|
293
|
+
return {
|
|
294
|
+
address: parseActorAddress(record.get('address')),
|
|
295
|
+
ownerSnapshot: parseActorOwnerSnapshot(record.get('ownerSnapshot')),
|
|
296
|
+
endpoint: parseEndpoint(record.get('endpoint')),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function resolveRegistration(runtime, selector) {
|
|
300
|
+
const state = runtimeState(runtime);
|
|
301
|
+
const parsedSelector = parseActorSelector(selector);
|
|
302
|
+
let address;
|
|
303
|
+
if ('byAddress' in parsedSelector) {
|
|
304
|
+
address = parsedSelector.byAddress;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
const resolved = state.resolveAlias?.(parsedSelector.byAlias);
|
|
308
|
+
if (resolved === undefined) {
|
|
309
|
+
throw new ActorAddressingError('unresolved-selector', `Actor alias is unresolved: ${parsedSelector.byAlias}`);
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
address = parseActorAddress(resolved);
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
if (error instanceof ActorAddressingError) {
|
|
316
|
+
throw new ActorAddressingError('unresolved-selector', `Actor alias resolved to an invalid address: ${parsedSelector.byAlias}`);
|
|
317
|
+
}
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const registration = state.registrations.get(actorAddressKey(address));
|
|
322
|
+
if (!registration) {
|
|
323
|
+
throw new ActorAddressingError('unresolved-selector', `Actor address is not registered: ${actorAddressKey(address)}`);
|
|
324
|
+
}
|
|
325
|
+
return registration;
|
|
326
|
+
}
|
|
327
|
+
function expectedRegistrationId(value, required) {
|
|
328
|
+
const record = readClosedRecord(value, required ? EXPECTED_REGISTRATION_ID_KEYS : [], required ? [] : EXPECTED_REGISTRATION_ID_KEYS, 'stale-registration', 'invocation');
|
|
329
|
+
const valueToParse = record.get('expectedRegistrationId');
|
|
330
|
+
if (valueToParse === undefined && !required)
|
|
331
|
+
return undefined;
|
|
332
|
+
return parseOpaqueToken(valueToParse, 'expectedRegistrationId', 'stale-registration');
|
|
333
|
+
}
|
|
334
|
+
function assertCurrentRegistration(registration, expectedId) {
|
|
335
|
+
if (expectedId !== undefined && expectedId !== registration.registrationId) {
|
|
336
|
+
throw new ActorAddressingError('stale-registration', `Expected registration ${expectedId} is not current`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function hashRegistrationIdComponent(value) {
|
|
340
|
+
let hash = 0x811c9dc5;
|
|
341
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
342
|
+
hash = Math.imul(hash ^ value.charCodeAt(index), 0x01000193);
|
|
343
|
+
}
|
|
344
|
+
return (hash >>> 0).toString(36);
|
|
345
|
+
}
|
|
346
|
+
function mintRegistrationId(runtime, state, sequence, address, additionallyUsed = new Set()) {
|
|
347
|
+
const factoryValue = parseOpaqueToken(state.registrationIdFactory({
|
|
348
|
+
runtimeInstanceId: runtime.runtimeInstanceId,
|
|
349
|
+
sequence,
|
|
350
|
+
address,
|
|
351
|
+
}), 'registrationIdFactory result', 'registration-mismatch');
|
|
352
|
+
const factoryComponent = factoryValue.length <= 128
|
|
353
|
+
? factoryValue
|
|
354
|
+
: `factory-${hashRegistrationIdComponent(factoryValue)}`;
|
|
355
|
+
const registrationId = parseOpaqueToken(`${factoryComponent}:${state.runtimeNonce}:${sequence.toString(36)}`, 'registrationId', 'registration-mismatch');
|
|
356
|
+
if (state.usedRegistrationIds.has(registrationId) || additionallyUsed.has(registrationId)) {
|
|
357
|
+
throw new ActorAddressingError('registration-mismatch', `registrationIdFactory produced an already-used registration id: ${registrationId}`);
|
|
358
|
+
}
|
|
359
|
+
return registrationId;
|
|
360
|
+
}
|
|
361
|
+
export function registerActor(runtime, input, config) {
|
|
362
|
+
assertEmptyConfig(config);
|
|
363
|
+
const state = runtimeState(runtime);
|
|
364
|
+
const operation = 'registerActor';
|
|
365
|
+
const startingVersion = beginMutation(state, operation);
|
|
366
|
+
try {
|
|
367
|
+
const parsed = parseRegisterInput(input);
|
|
368
|
+
const key = actorAddressKey(parsed.address);
|
|
369
|
+
if (state.registrations.has(key)) {
|
|
370
|
+
throw new ActorAddressingError('already-registered', `Actor is already registered: ${key}`);
|
|
371
|
+
}
|
|
372
|
+
const ownerEntry = parsed.ownerSnapshot.registrations.find((entry) => actorAddressKey(entry.address) === key);
|
|
373
|
+
if (!ownerEntry || ownerEntry.handlerIdentity !== parsed.endpoint.handlerIdentity) {
|
|
374
|
+
throw new ActorAddressingError('registration-mismatch', 'Address and handler identity must be authorized by the owner snapshot');
|
|
375
|
+
}
|
|
376
|
+
const sequence = state.sequence + 1;
|
|
377
|
+
const registrationId = mintRegistrationId(runtime, state, sequence, parsed.address);
|
|
378
|
+
if (state.mutationVersion !== startingVersion) {
|
|
379
|
+
throw new ActorAddressingError('registration-mismatch', 'Runtime changed while registration was being constructed');
|
|
380
|
+
}
|
|
381
|
+
const receipt = Object.freeze({
|
|
382
|
+
schemaVersion: ACTOR_REGISTRATION_SCHEMA_VERSION,
|
|
383
|
+
address: parsed.address,
|
|
384
|
+
ownerRevision: parsed.ownerSnapshot.ownerRevision,
|
|
385
|
+
snapshotReceipt: parsed.ownerSnapshot.snapshotReceipt,
|
|
386
|
+
handlerIdentity: parsed.endpoint.handlerIdentity,
|
|
387
|
+
registrationId,
|
|
388
|
+
});
|
|
389
|
+
state.sequence = sequence;
|
|
390
|
+
state.registrations.set(key, {
|
|
391
|
+
address: parsed.address,
|
|
392
|
+
receipt,
|
|
393
|
+
endpoint: parsed.endpoint,
|
|
394
|
+
});
|
|
395
|
+
state.usedRegistrationIds.add(registrationId);
|
|
396
|
+
state.mutationVersion = startingVersion + 1;
|
|
397
|
+
return receipt;
|
|
398
|
+
}
|
|
399
|
+
finally {
|
|
400
|
+
endMutation(state, operation);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
export function resolveActor(runtime, selector, invocation, config) {
|
|
404
|
+
assertEmptyConfig(config);
|
|
405
|
+
const expectedId = expectedRegistrationId(invocation, false);
|
|
406
|
+
const registration = resolveRegistration(runtime, selector);
|
|
407
|
+
assertCurrentRegistration(registration.receipt, expectedId);
|
|
408
|
+
return Object.freeze({
|
|
409
|
+
address: registration.address,
|
|
410
|
+
receipt: registration.receipt,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
export async function dispatchActor(runtime, selector, invocation, config) {
|
|
414
|
+
assertEmptyConfig(config);
|
|
415
|
+
const invocationRecord = readClosedRecord(invocation, DISPATCH_INVOCATION_REQUIRED_KEYS, EXPECTED_REGISTRATION_ID_KEYS, 'stale-registration', 'dispatch invocation');
|
|
416
|
+
const registration = resolveRegistration(runtime, selector);
|
|
417
|
+
const expectedRegistrationIdValue = invocationRecord.get('expectedRegistrationId');
|
|
418
|
+
const expectedId = expectedRegistrationIdValue === undefined
|
|
419
|
+
? undefined
|
|
420
|
+
: parseOpaqueToken(expectedRegistrationIdValue, 'expectedRegistrationId', 'stale-registration');
|
|
421
|
+
assertCurrentRegistration(registration.receipt, expectedId);
|
|
422
|
+
return await registration.endpoint.dispatch(invocationRecord.get('input'));
|
|
423
|
+
}
|
|
424
|
+
export function unregisterActor(runtime, selector, invocation, config) {
|
|
425
|
+
assertEmptyConfig(config);
|
|
426
|
+
const expectedId = expectedRegistrationId(invocation, true);
|
|
427
|
+
const state = runtimeState(runtime);
|
|
428
|
+
const operation = 'unregisterActor';
|
|
429
|
+
const startingVersion = beginMutation(state, operation);
|
|
430
|
+
try {
|
|
431
|
+
const registration = resolveRegistration(runtime, selector);
|
|
432
|
+
assertCurrentRegistration(registration.receipt, expectedId);
|
|
433
|
+
if (state.mutationVersion !== startingVersion) {
|
|
434
|
+
throw new ActorAddressingError('registration-mismatch', 'Runtime changed while unregister was being resolved');
|
|
435
|
+
}
|
|
436
|
+
state.registrations.delete(actorAddressKey(registration.address));
|
|
437
|
+
state.mutationVersion = startingVersion + 1;
|
|
438
|
+
return registration.receipt;
|
|
439
|
+
}
|
|
440
|
+
finally {
|
|
441
|
+
endMutation(state, operation);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
export function rebuildActorRegistrations(runtime, input, config) {
|
|
445
|
+
const snapshot = parseActorOwnerSnapshot(input);
|
|
446
|
+
const configRecord = readExactRecord(config, ['endpointFor'], 'registration-mismatch', 'RebuildActorRegistrationsConfig');
|
|
447
|
+
const endpointFor = configRecord.get('endpointFor');
|
|
448
|
+
if (typeof endpointFor !== 'function') {
|
|
449
|
+
throw new ActorAddressingError('registration-mismatch', 'endpointFor must be a function');
|
|
450
|
+
}
|
|
451
|
+
const state = runtimeState(runtime);
|
|
452
|
+
const operation = 'rebuildActorRegistrations';
|
|
453
|
+
const startingVersion = beginMutation(state, operation);
|
|
454
|
+
try {
|
|
455
|
+
if (state.registrations.size !== 0) {
|
|
456
|
+
throw new ActorAddressingError('already-registered', 'Registration recovery requires a fresh empty local runtime');
|
|
457
|
+
}
|
|
458
|
+
const endpoints = snapshot.registrations.map((registration) => {
|
|
459
|
+
const endpoint = parseEndpoint(endpointFor(registration));
|
|
460
|
+
if (endpoint.handlerIdentity !== registration.handlerIdentity) {
|
|
461
|
+
throw new ActorAddressingError('registration-mismatch', `Recovered endpoint identity does not match snapshot for ${actorAddressKey(registration.address)}`);
|
|
462
|
+
}
|
|
463
|
+
return endpoint;
|
|
464
|
+
});
|
|
465
|
+
if (state.mutationVersion !== startingVersion || state.registrations.size !== 0) {
|
|
466
|
+
throw new ActorAddressingError('registration-mismatch', 'Runtime changed while recovery endpoints were being constructed');
|
|
467
|
+
}
|
|
468
|
+
let nextSequence = state.sequence;
|
|
469
|
+
const plannedIds = new Set();
|
|
470
|
+
const planned = snapshot.registrations.map((registration, index) => {
|
|
471
|
+
nextSequence += 1;
|
|
472
|
+
const registrationId = mintRegistrationId(runtime, state, nextSequence, registration.address, plannedIds);
|
|
473
|
+
plannedIds.add(registrationId);
|
|
474
|
+
const receipt = Object.freeze({
|
|
475
|
+
schemaVersion: ACTOR_REGISTRATION_SCHEMA_VERSION,
|
|
476
|
+
address: registration.address,
|
|
477
|
+
ownerRevision: snapshot.ownerRevision,
|
|
478
|
+
snapshotReceipt: snapshot.snapshotReceipt,
|
|
479
|
+
handlerIdentity: registration.handlerIdentity,
|
|
480
|
+
registrationId,
|
|
481
|
+
});
|
|
482
|
+
return {
|
|
483
|
+
key: actorAddressKey(registration.address),
|
|
484
|
+
registration: {
|
|
485
|
+
address: registration.address,
|
|
486
|
+
receipt,
|
|
487
|
+
endpoint: endpoints[index],
|
|
488
|
+
},
|
|
489
|
+
};
|
|
490
|
+
});
|
|
491
|
+
if (state.mutationVersion !== startingVersion || state.registrations.size !== 0) {
|
|
492
|
+
throw new ActorAddressingError('registration-mismatch', 'Runtime changed while recovery was being planned');
|
|
493
|
+
}
|
|
494
|
+
const nextRegistrations = new Map(planned.map((item) => [item.key, item.registration]));
|
|
495
|
+
const nextUsedRegistrationIds = new Set(state.usedRegistrationIds);
|
|
496
|
+
for (const registrationId of plannedIds) {
|
|
497
|
+
nextUsedRegistrationIds.add(registrationId);
|
|
498
|
+
}
|
|
499
|
+
const receipts = Object.freeze(planned.map((item) => item.registration.receipt));
|
|
500
|
+
state.registrations = nextRegistrations;
|
|
501
|
+
state.usedRegistrationIds = nextUsedRegistrationIds;
|
|
502
|
+
state.sequence = nextSequence;
|
|
503
|
+
state.mutationVersion = startingVersion + 1;
|
|
504
|
+
return receipts;
|
|
505
|
+
}
|
|
506
|
+
finally {
|
|
507
|
+
endMutation(state, operation);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
export function createActorRefEndpoint(ref, tag, handlerIdentity) {
|
|
511
|
+
const parsedHandlerIdentity = parseOpaqueToken(handlerIdentity, 'handlerIdentity', 'registration-mismatch');
|
|
512
|
+
return Object.freeze({
|
|
513
|
+
handlerIdentity: parsedHandlerIdentity,
|
|
514
|
+
dispatch: (input) => ref.send(tag, input),
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
//# sourceMappingURL=addressing.js.map
|