@opetope/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/README.ru.md +246 -0
- package/dist/abort-compat.d.ts +10 -0
- package/dist/abort-compat.js +2 -0
- package/dist/abort-compat.js.map +1 -0
- package/dist/adapter-method.d.ts +27 -0
- package/dist/attachment-lifecycle-cleanup.d.ts +3 -0
- package/dist/attachment-lifecycle-cleanup.js +2 -0
- package/dist/attachment-lifecycle-cleanup.js.map +1 -0
- package/dist/attachment-lifecycle-contract.d.ts +260 -0
- package/dist/attachment-lifecycle-contract.js +2 -0
- package/dist/attachment-lifecycle-contract.js.map +1 -0
- package/dist/attachment-lifecycle-helpers.d.ts +34 -0
- package/dist/attachment-lifecycle-helpers.js +2 -0
- package/dist/attachment-lifecycle-helpers.js.map +1 -0
- package/dist/attachment-lifecycle-machine.d.ts +3 -0
- package/dist/attachment-lifecycle-machine.js +2 -0
- package/dist/attachment-lifecycle-machine.js.map +1 -0
- package/dist/attachment-lifecycle-mailbox.d.ts +10 -0
- package/dist/attachment-lifecycle-mailbox.js +2 -0
- package/dist/attachment-lifecycle-mailbox.js.map +1 -0
- package/dist/attachment-lifecycle-open.d.ts +3 -0
- package/dist/attachment-lifecycle-open.js +2 -0
- package/dist/attachment-lifecycle-open.js.map +1 -0
- package/dist/attachment-lifecycle.d.ts +4 -0
- package/dist/attachment-lifecycle.js +2 -0
- package/dist/attachment-lifecycle.js.map +1 -0
- package/dist/attachment.d.ts +49 -0
- package/dist/attachment.js +2 -0
- package/dist/attachment.js.map +1 -0
- package/dist/call-authority.d.ts +26 -0
- package/dist/call-controller-support.d.ts +77 -0
- package/dist/call-controller-support.js +2 -0
- package/dist/call-controller-support.js.map +1 -0
- package/dist/call-controller.d.ts +49 -0
- package/dist/call-controller.js +2 -0
- package/dist/call-controller.js.map +1 -0
- package/dist/call-execution-inspection.d.ts +26 -0
- package/dist/call-execution-inspection.js +2 -0
- package/dist/call-execution-inspection.js.map +1 -0
- package/dist/call-executor-factory.d.ts +5 -0
- package/dist/call-executor-factory.js +2 -0
- package/dist/call-executor-factory.js.map +1 -0
- package/dist/call-executor-record.d.ts +66 -0
- package/dist/call-executor-record.js +2 -0
- package/dist/call-executor-record.js.map +1 -0
- package/dist/call-executor-support.d.ts +25 -0
- package/dist/call-executor-support.js +2 -0
- package/dist/call-executor-support.js.map +1 -0
- package/dist/call-executor-types.d.ts +56 -0
- package/dist/call-executor-waiters.d.ts +23 -0
- package/dist/call-executor-waiters.js +2 -0
- package/dist/call-executor-waiters.js.map +1 -0
- package/dist/call-executor.d.ts +6 -0
- package/dist/call-executor.js +2 -0
- package/dist/call-executor.js.map +1 -0
- package/dist/call-invocation.d.ts +61 -0
- package/dist/call-invocation.js +2 -0
- package/dist/call-invocation.js.map +1 -0
- package/dist/call-lane.d.ts +28 -0
- package/dist/call-lane.js +2 -0
- package/dist/call-lane.js.map +1 -0
- package/dist/call-target-result.d.ts +22 -0
- package/dist/call-target-result.js +2 -0
- package/dist/call-target-result.js.map +1 -0
- package/dist/call-target.d.ts +42 -0
- package/dist/call-target.js +2 -0
- package/dist/call-target.js.map +1 -0
- package/dist/call.d.ts +11 -0
- package/dist/call.js +2 -0
- package/dist/call.js.map +1 -0
- package/dist/contribution-hub.d.ts +100 -0
- package/dist/contribution-hub.js +2 -0
- package/dist/contribution-hub.js.map +1 -0
- package/dist/contribution-transaction.d.ts +20 -0
- package/dist/contribution-transaction.js +2 -0
- package/dist/contribution-transaction.js.map +1 -0
- package/dist/contribution.d.ts +64 -0
- package/dist/contribution.js +2 -0
- package/dist/contribution.js.map +1 -0
- package/dist/data-scheduler.d.ts +4 -0
- package/dist/data-scheduler.js +2 -0
- package/dist/data-scheduler.js.map +1 -0
- package/dist/errors.d.ts +56 -0
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -0
- package/dist/identity.d.ts +6 -0
- package/dist/identity.js +2 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +46 -0
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -0
- package/dist/lifetime.d.ts +19 -0
- package/dist/lifetime.js +2 -0
- package/dist/lifetime.js.map +1 -0
- package/dist/model-context.d.ts +155 -0
- package/dist/model.d.ts +21 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/platform-compat.d.ts +9 -0
- package/dist/platform-compat.js +2 -0
- package/dist/platform-compat.js.map +1 -0
- package/dist/port.d.ts +26 -0
- package/dist/port.js +2 -0
- package/dist/port.js.map +1 -0
- package/dist/reactive-collection.d.ts +27 -0
- package/dist/reactive-collection.js +2 -0
- package/dist/reactive-collection.js.map +1 -0
- package/dist/reactive-node.d.ts +62 -0
- package/dist/reactive-node.js +2 -0
- package/dist/reactive-node.js.map +1 -0
- package/dist/reactive-scheduler-control.d.ts +34 -0
- package/dist/reactive-scheduler-control.js +2 -0
- package/dist/reactive-scheduler-control.js.map +1 -0
- package/dist/reactive-scheduler.d.ts +18 -0
- package/dist/reactive-scheduler.js +2 -0
- package/dist/reactive-scheduler.js.map +1 -0
- package/dist/reactive.d.ts +41 -0
- package/dist/reactive.js +2 -0
- package/dist/reactive.js.map +1 -0
- package/dist/readable.d.ts +13 -0
- package/dist/readable.js +2 -0
- package/dist/readable.js.map +1 -0
- package/dist/resource.d.ts +82 -0
- package/dist/type-helpers.d.ts +14 -0
- package/package.json +66 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { AttachmentReadinessController, AttachmentReadinessRef } from './attachment.js';
|
|
2
|
+
import type { ReadableListener } from './readable.js';
|
|
3
|
+
import type { Awaitable } from './type-helpers.js';
|
|
4
|
+
type NonEmptyReadonlyArray<Value> = readonly [Value, ...Value[]];
|
|
5
|
+
declare const attachmentLifecycleControllerBrand: unique symbol;
|
|
6
|
+
declare const attachmentRetirementBrand: unique symbol;
|
|
7
|
+
declare const retiredAttachmentKey: unique symbol;
|
|
8
|
+
interface AttachmentLifecycleIntent<Key extends object, Value> {
|
|
9
|
+
readonly key: Key;
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
readonly value: Value;
|
|
12
|
+
}
|
|
13
|
+
interface AttachmentCleanupContext {
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
interface AttachmentOpenStep<Value> {
|
|
17
|
+
readonly cleanup: (context: AttachmentCleanupContext) => Awaitable<void>;
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly run: () => Awaitable<Value>;
|
|
20
|
+
}
|
|
21
|
+
interface AttachmentOpenContext<Value> {
|
|
22
|
+
readonly signal: AbortSignal;
|
|
23
|
+
readonly step: <Result>(step: AttachmentOpenStep<Result>) => Promise<Result>;
|
|
24
|
+
readonly value: Value;
|
|
25
|
+
}
|
|
26
|
+
interface AttachmentLifecycleOptions<Value> {
|
|
27
|
+
readonly close: (context: AttachmentCleanupContext) => Awaitable<void>;
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly open: (context: AttachmentOpenContext<Value>) => Awaitable<void>;
|
|
30
|
+
}
|
|
31
|
+
interface AttachmentCleanupFailure {
|
|
32
|
+
readonly error: unknown;
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly ordinal: number;
|
|
35
|
+
}
|
|
36
|
+
interface AttachmentCleanupCompleted {
|
|
37
|
+
readonly kind: 'completed';
|
|
38
|
+
}
|
|
39
|
+
interface AttachmentCleanupFailed {
|
|
40
|
+
readonly error: AggregateError;
|
|
41
|
+
readonly failures: NonEmptyReadonlyArray<AttachmentCleanupFailure>;
|
|
42
|
+
readonly kind: 'failed';
|
|
43
|
+
}
|
|
44
|
+
type AttachmentCleanupOutcome = AttachmentCleanupCompleted | AttachmentCleanupFailed;
|
|
45
|
+
interface AttachmentOpeningFailure {
|
|
46
|
+
readonly error: unknown;
|
|
47
|
+
readonly failedStep: string;
|
|
48
|
+
}
|
|
49
|
+
interface AttachmentOpenRolledBackFailureRecord {
|
|
50
|
+
readonly generation: number;
|
|
51
|
+
readonly kind: 'open-failed';
|
|
52
|
+
readonly opening: AttachmentOpeningFailure;
|
|
53
|
+
readonly rollback: AttachmentCleanupCompleted;
|
|
54
|
+
}
|
|
55
|
+
interface AttachmentOpenRollbackFailureRecord {
|
|
56
|
+
readonly generation: number;
|
|
57
|
+
readonly kind: 'open-failed';
|
|
58
|
+
readonly opening: AttachmentOpeningFailure;
|
|
59
|
+
readonly rollback: AttachmentCleanupFailed;
|
|
60
|
+
}
|
|
61
|
+
interface AttachmentRollbackFailureRecord {
|
|
62
|
+
readonly cleanup: AttachmentCleanupFailed;
|
|
63
|
+
readonly generation: number;
|
|
64
|
+
readonly kind: 'rollback-failed';
|
|
65
|
+
}
|
|
66
|
+
type AttachmentFailureOrigin = {
|
|
67
|
+
readonly cleanup: AttachmentCleanupFailed;
|
|
68
|
+
readonly generation: number;
|
|
69
|
+
readonly kind: 'close';
|
|
70
|
+
} | {
|
|
71
|
+
readonly cleanup: AttachmentCleanupFailed;
|
|
72
|
+
readonly generation: number;
|
|
73
|
+
readonly kind: 'rollback';
|
|
74
|
+
} | {
|
|
75
|
+
readonly generation: number;
|
|
76
|
+
readonly kind: 'open';
|
|
77
|
+
readonly opening: AttachmentOpeningFailure;
|
|
78
|
+
readonly rollback: AttachmentCleanupFailed;
|
|
79
|
+
};
|
|
80
|
+
interface AttachmentCloseFailureRecord {
|
|
81
|
+
readonly cleanup: AttachmentCleanupFailed;
|
|
82
|
+
readonly generation: number;
|
|
83
|
+
readonly kind: 'close-failed';
|
|
84
|
+
readonly origin: AttachmentFailureOrigin;
|
|
85
|
+
readonly phase: 'close' | 'retry';
|
|
86
|
+
}
|
|
87
|
+
type AttachmentQuarantineFailureRecord = AttachmentCloseFailureRecord | AttachmentOpenRollbackFailureRecord | AttachmentRollbackFailureRecord;
|
|
88
|
+
type AttachmentFailureRecord = AttachmentOpenRolledBackFailureRecord | AttachmentQuarantineFailureRecord;
|
|
89
|
+
interface AttachmentClosedSnapshot {
|
|
90
|
+
readonly kind: 'closed';
|
|
91
|
+
readonly lastFailure: AttachmentFailureRecord | null;
|
|
92
|
+
readonly revision: number;
|
|
93
|
+
}
|
|
94
|
+
interface AttachmentClosingSnapshot {
|
|
95
|
+
readonly generation: number;
|
|
96
|
+
readonly kind: 'closing';
|
|
97
|
+
readonly phase: 'close' | 'retry' | 'rollback';
|
|
98
|
+
readonly revision: number;
|
|
99
|
+
}
|
|
100
|
+
interface AttachmentFailedCloseSnapshot {
|
|
101
|
+
readonly failure: AttachmentQuarantineFailureRecord;
|
|
102
|
+
readonly generation: number;
|
|
103
|
+
readonly kind: 'failed-close';
|
|
104
|
+
readonly revision: number;
|
|
105
|
+
}
|
|
106
|
+
interface AttachmentOpeningSnapshot {
|
|
107
|
+
readonly generation: number;
|
|
108
|
+
readonly kind: 'opening';
|
|
109
|
+
readonly revision: number;
|
|
110
|
+
}
|
|
111
|
+
interface AttachmentReadySnapshot {
|
|
112
|
+
readonly generation: number;
|
|
113
|
+
readonly kind: 'ready';
|
|
114
|
+
readonly revision: number;
|
|
115
|
+
}
|
|
116
|
+
type AttachmentLifecycleSnapshot = AttachmentClosedSnapshot | AttachmentClosingSnapshot | AttachmentFailedCloseSnapshot | AttachmentOpeningSnapshot | AttachmentReadySnapshot;
|
|
117
|
+
type AttachmentIntentOutcome = {
|
|
118
|
+
readonly failure: AttachmentOpenRolledBackFailureRecord;
|
|
119
|
+
readonly kind: 'failed';
|
|
120
|
+
} | {
|
|
121
|
+
readonly failure: AttachmentQuarantineFailureRecord;
|
|
122
|
+
readonly kind: 'quarantined';
|
|
123
|
+
} | {
|
|
124
|
+
readonly kind: 'cancelled';
|
|
125
|
+
} | {
|
|
126
|
+
readonly kind: 'committed';
|
|
127
|
+
readonly state: 'closed' | 'ready';
|
|
128
|
+
} | {
|
|
129
|
+
readonly kind: 'superseded';
|
|
130
|
+
};
|
|
131
|
+
type AttachmentDrainOutcome = {
|
|
132
|
+
readonly failure: AttachmentQuarantineFailureRecord;
|
|
133
|
+
readonly kind: 'quarantined';
|
|
134
|
+
} | {
|
|
135
|
+
readonly kind: 'committed';
|
|
136
|
+
readonly state: 'closed';
|
|
137
|
+
};
|
|
138
|
+
type AttachmentRetryOutcome = {
|
|
139
|
+
readonly failure: AttachmentQuarantineFailureRecord;
|
|
140
|
+
readonly kind: 'quarantined';
|
|
141
|
+
} | {
|
|
142
|
+
readonly kind: 'interrupted';
|
|
143
|
+
readonly outcome: 'superseded';
|
|
144
|
+
} | {
|
|
145
|
+
readonly kind: 'not-needed';
|
|
146
|
+
readonly state: AttachmentLifecycleSnapshot['kind'];
|
|
147
|
+
} | {
|
|
148
|
+
readonly kind: 'recovered';
|
|
149
|
+
};
|
|
150
|
+
interface AttachmentLifecycleDiagnostics {
|
|
151
|
+
readonly activeIntent: boolean;
|
|
152
|
+
readonly awaitingDrain: boolean;
|
|
153
|
+
readonly cleanupHandles: number;
|
|
154
|
+
readonly disposed: boolean;
|
|
155
|
+
readonly disposeRequested: boolean;
|
|
156
|
+
readonly generation: number;
|
|
157
|
+
readonly listeners: number;
|
|
158
|
+
readonly queuedIntent: boolean;
|
|
159
|
+
readonly state: AttachmentLifecycleSnapshot['kind'];
|
|
160
|
+
}
|
|
161
|
+
interface AttachmentLifecycleController<Key extends object, Value> {
|
|
162
|
+
readonly assertRetirable: (expectedKey: Key) => void;
|
|
163
|
+
readonly [attachmentLifecycleControllerBrand]: true;
|
|
164
|
+
readonly diagnostics: () => AttachmentLifecycleDiagnostics;
|
|
165
|
+
readonly dispose: () => Promise<AttachmentIntentOutcome>;
|
|
166
|
+
readonly getSnapshot: () => AttachmentLifecycleSnapshot;
|
|
167
|
+
readonly ref: AttachmentReadinessRef;
|
|
168
|
+
readonly request: (intent: AttachmentLifecycleIntent<Key, Value> | null) => Promise<AttachmentIntentOutcome>;
|
|
169
|
+
readonly retire: () => AttachmentRetirement;
|
|
170
|
+
readonly retireExpected: (expectedKey: Key) => AttachmentRetirement;
|
|
171
|
+
readonly retryClose: () => Promise<AttachmentRetryOutcome>;
|
|
172
|
+
readonly subscribe: (listener: ReadableListener) => () => void;
|
|
173
|
+
}
|
|
174
|
+
interface AttachmentRetirement {
|
|
175
|
+
readonly [attachmentRetirementBrand]: true;
|
|
176
|
+
readonly drain: () => Promise<AttachmentDrainOutcome>;
|
|
177
|
+
}
|
|
178
|
+
interface AttachmentRetirementHandleState {
|
|
179
|
+
action: (() => Promise<AttachmentDrainOutcome>) | undefined;
|
|
180
|
+
outcome: Promise<AttachmentDrainOutcome> | undefined;
|
|
181
|
+
}
|
|
182
|
+
type AttachmentRetirementRequestResult = {
|
|
183
|
+
readonly error: unknown;
|
|
184
|
+
readonly kind: 'failed';
|
|
185
|
+
} | {
|
|
186
|
+
readonly kind: 'succeeded';
|
|
187
|
+
readonly outcome: AttachmentDrainOutcome;
|
|
188
|
+
};
|
|
189
|
+
interface ActiveAttachmentRetirement<Key extends object> {
|
|
190
|
+
allowDrain: () => void;
|
|
191
|
+
drainAllowed: boolean;
|
|
192
|
+
drainPermission: Promise<void> | undefined;
|
|
193
|
+
readonly handle: AttachmentRetirement;
|
|
194
|
+
requestOutcome: Promise<AttachmentIntentOutcome> | undefined;
|
|
195
|
+
targetAttempt: AttachmentAttempt<Key> | undefined;
|
|
196
|
+
targetKeys: WeakSet<Key> | undefined;
|
|
197
|
+
}
|
|
198
|
+
interface OwnedCleanup {
|
|
199
|
+
cleanup: ((context: AttachmentCleanupContext) => Awaitable<void>) | undefined;
|
|
200
|
+
readonly id: string;
|
|
201
|
+
}
|
|
202
|
+
interface AttachmentAttempt<Key extends object> {
|
|
203
|
+
acceptingSteps: boolean;
|
|
204
|
+
cleanups: OwnedCleanup[];
|
|
205
|
+
readonly generation: number;
|
|
206
|
+
key: typeof retiredAttachmentKey | Key;
|
|
207
|
+
openAbort: AbortController | undefined;
|
|
208
|
+
readonly originKeys: WeakSet<Key>;
|
|
209
|
+
}
|
|
210
|
+
interface OpenStepCoordinator {
|
|
211
|
+
readonly fail: (id: string, error: unknown) => void;
|
|
212
|
+
readonly firstFailure: () => Promise<AttachmentOpeningFailure | undefined>;
|
|
213
|
+
readonly seal: () => void;
|
|
214
|
+
readonly step: <Result>(step: AttachmentOpenStep<Result>) => Promise<Result>;
|
|
215
|
+
}
|
|
216
|
+
interface StartedAttachmentOpen {
|
|
217
|
+
readonly completion: Promise<void>;
|
|
218
|
+
readonly firstFailure: () => Promise<AttachmentOpeningFailure | undefined>;
|
|
219
|
+
}
|
|
220
|
+
interface IntentEntry<Key extends object, Value> {
|
|
221
|
+
cancelled: boolean;
|
|
222
|
+
intent: AttachmentLifecycleIntent<Key, Value> | null | undefined;
|
|
223
|
+
joinable: boolean;
|
|
224
|
+
readonly promise: Promise<AttachmentIntentOutcome>;
|
|
225
|
+
readonly resolve: (outcome: AttachmentIntentOutcome) => void;
|
|
226
|
+
settled: boolean;
|
|
227
|
+
started: boolean;
|
|
228
|
+
}
|
|
229
|
+
interface LifecycleStatusStore {
|
|
230
|
+
readonly close: () => void;
|
|
231
|
+
readonly getSnapshot: () => AttachmentLifecycleSnapshot;
|
|
232
|
+
readonly listenerCount: () => number;
|
|
233
|
+
readonly notify: () => void;
|
|
234
|
+
readonly replace: (create: (revision: number) => AttachmentLifecycleSnapshot, notify?: boolean) => AttachmentLifecycleSnapshot;
|
|
235
|
+
readonly subscribe: (listener: ReadableListener) => () => void;
|
|
236
|
+
}
|
|
237
|
+
interface AttachmentLifecycleState<Key extends object, Value> {
|
|
238
|
+
activeEntry: IntentEntry<Key, Value> | undefined;
|
|
239
|
+
activeRetirement: ActiveAttachmentRetirement<Key> | undefined;
|
|
240
|
+
currentAttempt: AttachmentAttempt<Key> | undefined;
|
|
241
|
+
disposed: boolean;
|
|
242
|
+
disposeRequested: boolean;
|
|
243
|
+
generation: number;
|
|
244
|
+
queuedEntry: IntentEntry<Key, Value> | undefined;
|
|
245
|
+
}
|
|
246
|
+
interface AttachmentLifecycleMachine<Key extends object, Value> {
|
|
247
|
+
readonly beginLogicalClose: (phase: AttachmentClosingSnapshot['phase']) => void;
|
|
248
|
+
readonly finishDisposal: () => void;
|
|
249
|
+
readonly reconcile: (entry: IntentEntry<Key, Value>) => Promise<AttachmentIntentOutcome>;
|
|
250
|
+
readonly recoverUnexpected: (error: unknown) => Promise<AttachmentIntentOutcome>;
|
|
251
|
+
}
|
|
252
|
+
interface AttachmentLifecycleMachineOptions<Key extends object, Value> {
|
|
253
|
+
readonly close: AttachmentLifecycleOptions<Value>['close'];
|
|
254
|
+
readonly open: AttachmentLifecycleOptions<Value>['open'];
|
|
255
|
+
readonly readiness: AttachmentReadinessController;
|
|
256
|
+
readonly state: AttachmentLifecycleState<Key, Value>;
|
|
257
|
+
readonly status: LifecycleStatusStore;
|
|
258
|
+
}
|
|
259
|
+
export { attachmentLifecycleControllerBrand, attachmentRetirementBrand, retiredAttachmentKey };
|
|
260
|
+
export type { ActiveAttachmentRetirement, AttachmentAttempt, AttachmentCleanupContext, AttachmentCleanupFailure, AttachmentCleanupOutcome, AttachmentCloseFailureRecord, AttachmentDrainOutcome, AttachmentFailureOrigin, AttachmentFailureRecord, AttachmentIntentOutcome, AttachmentLifecycleController, AttachmentLifecycleDiagnostics, AttachmentLifecycleIntent, AttachmentLifecycleMachine, AttachmentLifecycleMachineOptions, AttachmentLifecycleOptions, AttachmentLifecycleSnapshot, AttachmentLifecycleState, AttachmentOpenContext, AttachmentOpeningFailure, AttachmentOpenRolledBackFailureRecord, AttachmentOpenStep, AttachmentQuarantineFailureRecord, AttachmentRetirement, AttachmentRetirementHandleState, AttachmentRetirementRequestResult, AttachmentRetryOutcome, Awaitable, IntentEntry, LifecycleStatusStore, NonEmptyReadonlyArray, OpenStepCoordinator, OwnedCleanup, StartedAttachmentOpen, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const t=Symbol("opetope.attachment-lifecycle-controller"),e=Symbol("opetope.attachment-retirement"),o=Symbol("opetope.retired-attachment-key");export{t as attachmentLifecycleControllerBrand,e as attachmentRetirementBrand,o as retiredAttachmentKey};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle-contract.js","sources":["../src/attachment-lifecycle-contract.ts"],"sourcesContent":["import type { AttachmentReadinessController, AttachmentReadinessRef } from './attachment';\nimport type { ReadableListener } from './readable';\nimport type { Awaitable } from './type-helpers';\n\ntype NonEmptyReadonlyArray<Value> = readonly [Value, ...Value[]];\n\nconst attachmentLifecycleControllerBrand = Symbol('opetope.attachment-lifecycle-controller');\nconst attachmentRetirementBrand = Symbol('opetope.attachment-retirement');\nconst retiredAttachmentKey = Symbol('opetope.retired-attachment-key');\n\ninterface AttachmentLifecycleIntent<Key extends object, Value> {\n readonly key: Key;\n readonly signal?: AbortSignal;\n readonly value: Value;\n}\n\ninterface AttachmentCleanupContext {\n readonly signal: AbortSignal;\n}\n\ninterface AttachmentOpenStep<Value> {\n readonly cleanup: (context: AttachmentCleanupContext) => Awaitable<void>;\n readonly id: string;\n readonly run: () => Awaitable<Value>;\n}\n\ninterface AttachmentOpenContext<Value> {\n readonly signal: AbortSignal;\n readonly step: <Result>(step: AttachmentOpenStep<Result>) => Promise<Result>;\n readonly value: Value;\n}\n\ninterface AttachmentLifecycleOptions<Value> {\n readonly close: (context: AttachmentCleanupContext) => Awaitable<void>;\n readonly id: string;\n readonly open: (context: AttachmentOpenContext<Value>) => Awaitable<void>;\n}\n\ninterface AttachmentCleanupFailure {\n readonly error: unknown;\n readonly id: string;\n readonly ordinal: number;\n}\n\ninterface AttachmentCleanupCompleted {\n readonly kind: 'completed';\n}\n\ninterface AttachmentCleanupFailed {\n readonly error: AggregateError;\n readonly failures: NonEmptyReadonlyArray<AttachmentCleanupFailure>;\n readonly kind: 'failed';\n}\n\ntype AttachmentCleanupOutcome = AttachmentCleanupCompleted | AttachmentCleanupFailed;\n\ninterface AttachmentOpeningFailure {\n readonly error: unknown;\n readonly failedStep: string;\n}\n\ninterface AttachmentOpenRolledBackFailureRecord {\n readonly generation: number;\n readonly kind: 'open-failed';\n readonly opening: AttachmentOpeningFailure;\n readonly rollback: AttachmentCleanupCompleted;\n}\n\ninterface AttachmentOpenRollbackFailureRecord {\n readonly generation: number;\n readonly kind: 'open-failed';\n readonly opening: AttachmentOpeningFailure;\n readonly rollback: AttachmentCleanupFailed;\n}\n\ninterface AttachmentRollbackFailureRecord {\n readonly cleanup: AttachmentCleanupFailed;\n readonly generation: number;\n readonly kind: 'rollback-failed';\n}\n\ntype AttachmentFailureOrigin =\n | {\n readonly cleanup: AttachmentCleanupFailed;\n readonly generation: number;\n readonly kind: 'close';\n }\n | {\n readonly cleanup: AttachmentCleanupFailed;\n readonly generation: number;\n readonly kind: 'rollback';\n }\n | {\n readonly generation: number;\n readonly kind: 'open';\n readonly opening: AttachmentOpeningFailure;\n readonly rollback: AttachmentCleanupFailed;\n };\n\ninterface AttachmentCloseFailureRecord {\n readonly cleanup: AttachmentCleanupFailed;\n readonly generation: number;\n readonly kind: 'close-failed';\n readonly origin: AttachmentFailureOrigin;\n readonly phase: 'close' | 'retry';\n}\n\ntype AttachmentQuarantineFailureRecord =\n | AttachmentCloseFailureRecord\n | AttachmentOpenRollbackFailureRecord\n | AttachmentRollbackFailureRecord;\n\ntype AttachmentFailureRecord = AttachmentOpenRolledBackFailureRecord | AttachmentQuarantineFailureRecord;\n\ninterface AttachmentClosedSnapshot {\n readonly kind: 'closed';\n readonly lastFailure: AttachmentFailureRecord | null;\n readonly revision: number;\n}\n\ninterface AttachmentClosingSnapshot {\n readonly generation: number;\n readonly kind: 'closing';\n readonly phase: 'close' | 'retry' | 'rollback';\n readonly revision: number;\n}\n\ninterface AttachmentFailedCloseSnapshot {\n readonly failure: AttachmentQuarantineFailureRecord;\n readonly generation: number;\n readonly kind: 'failed-close';\n readonly revision: number;\n}\n\ninterface AttachmentOpeningSnapshot {\n readonly generation: number;\n readonly kind: 'opening';\n readonly revision: number;\n}\n\ninterface AttachmentReadySnapshot {\n readonly generation: number;\n readonly kind: 'ready';\n readonly revision: number;\n}\n\ntype AttachmentLifecycleSnapshot =\n | AttachmentClosedSnapshot\n | AttachmentClosingSnapshot\n | AttachmentFailedCloseSnapshot\n | AttachmentOpeningSnapshot\n | AttachmentReadySnapshot;\n\ntype AttachmentIntentOutcome =\n | { readonly failure: AttachmentOpenRolledBackFailureRecord; readonly kind: 'failed' }\n | { readonly failure: AttachmentQuarantineFailureRecord; readonly kind: 'quarantined' }\n | { readonly kind: 'cancelled' }\n | { readonly kind: 'committed'; readonly state: 'closed' | 'ready' }\n | { readonly kind: 'superseded' };\n\ntype AttachmentDrainOutcome =\n | { readonly failure: AttachmentQuarantineFailureRecord; readonly kind: 'quarantined' }\n | { readonly kind: 'committed'; readonly state: 'closed' };\n\ntype AttachmentRetryOutcome =\n | { readonly failure: AttachmentQuarantineFailureRecord; readonly kind: 'quarantined' }\n | { readonly kind: 'interrupted'; readonly outcome: 'superseded' }\n | { readonly kind: 'not-needed'; readonly state: AttachmentLifecycleSnapshot['kind'] }\n | { readonly kind: 'recovered' };\n\ninterface AttachmentLifecycleDiagnostics {\n readonly activeIntent: boolean;\n readonly awaitingDrain: boolean;\n readonly cleanupHandles: number;\n readonly disposed: boolean;\n readonly disposeRequested: boolean;\n readonly generation: number;\n readonly listeners: number;\n readonly queuedIntent: boolean;\n readonly state: AttachmentLifecycleSnapshot['kind'];\n}\n\ninterface AttachmentLifecycleController<Key extends object, Value> {\n readonly assertRetirable: (expectedKey: Key) => void;\n readonly [attachmentLifecycleControllerBrand]: true;\n readonly diagnostics: () => AttachmentLifecycleDiagnostics;\n readonly dispose: () => Promise<AttachmentIntentOutcome>;\n readonly getSnapshot: () => AttachmentLifecycleSnapshot;\n readonly ref: AttachmentReadinessRef;\n readonly request: (intent: AttachmentLifecycleIntent<Key, Value> | null) => Promise<AttachmentIntentOutcome>;\n readonly retire: () => AttachmentRetirement;\n readonly retireExpected: (expectedKey: Key) => AttachmentRetirement;\n readonly retryClose: () => Promise<AttachmentRetryOutcome>;\n readonly subscribe: (listener: ReadableListener) => () => void;\n}\n\ninterface AttachmentRetirement {\n readonly [attachmentRetirementBrand]: true;\n readonly drain: () => Promise<AttachmentDrainOutcome>;\n}\n\ninterface AttachmentRetirementHandleState {\n action: (() => Promise<AttachmentDrainOutcome>) | undefined;\n outcome: Promise<AttachmentDrainOutcome> | undefined;\n}\n\ntype AttachmentRetirementRequestResult =\n | { readonly error: unknown; readonly kind: 'failed' }\n | { readonly kind: 'succeeded'; readonly outcome: AttachmentDrainOutcome };\n\ninterface ActiveAttachmentRetirement<Key extends object> {\n allowDrain: () => void;\n drainAllowed: boolean;\n drainPermission: Promise<void> | undefined;\n readonly handle: AttachmentRetirement;\n requestOutcome: Promise<AttachmentIntentOutcome> | undefined;\n targetAttempt: AttachmentAttempt<Key> | undefined;\n targetKeys: WeakSet<Key> | undefined;\n}\n\ninterface OwnedCleanup {\n cleanup: ((context: AttachmentCleanupContext) => Awaitable<void>) | undefined;\n readonly id: string;\n}\n\ninterface AttachmentAttempt<Key extends object> {\n acceptingSteps: boolean;\n cleanups: OwnedCleanup[];\n readonly generation: number;\n key: typeof retiredAttachmentKey | Key;\n openAbort: AbortController | undefined;\n readonly originKeys: WeakSet<Key>;\n}\n\ninterface OpenStepCoordinator {\n readonly fail: (id: string, error: unknown) => void;\n readonly firstFailure: () => Promise<AttachmentOpeningFailure | undefined>;\n readonly seal: () => void;\n readonly step: <Result>(step: AttachmentOpenStep<Result>) => Promise<Result>;\n}\n\ninterface StartedAttachmentOpen {\n readonly completion: Promise<void>;\n readonly firstFailure: () => Promise<AttachmentOpeningFailure | undefined>;\n}\n\ninterface IntentEntry<Key extends object, Value> {\n cancelled: boolean;\n intent: AttachmentLifecycleIntent<Key, Value> | null | undefined;\n joinable: boolean;\n readonly promise: Promise<AttachmentIntentOutcome>;\n readonly resolve: (outcome: AttachmentIntentOutcome) => void;\n settled: boolean;\n started: boolean;\n}\n\ninterface LifecycleStatusStore {\n readonly close: () => void;\n readonly getSnapshot: () => AttachmentLifecycleSnapshot;\n readonly listenerCount: () => number;\n readonly notify: () => void;\n readonly replace: (\n create: (revision: number) => AttachmentLifecycleSnapshot,\n notify?: boolean,\n ) => AttachmentLifecycleSnapshot;\n readonly subscribe: (listener: ReadableListener) => () => void;\n}\n\ninterface AttachmentLifecycleState<Key extends object, Value> {\n activeEntry: IntentEntry<Key, Value> | undefined;\n activeRetirement: ActiveAttachmentRetirement<Key> | undefined;\n currentAttempt: AttachmentAttempt<Key> | undefined;\n disposed: boolean;\n disposeRequested: boolean;\n generation: number;\n queuedEntry: IntentEntry<Key, Value> | undefined;\n}\n\ninterface AttachmentLifecycleMachine<Key extends object, Value> {\n readonly beginLogicalClose: (phase: AttachmentClosingSnapshot['phase']) => void;\n readonly finishDisposal: () => void;\n readonly reconcile: (entry: IntentEntry<Key, Value>) => Promise<AttachmentIntentOutcome>;\n readonly recoverUnexpected: (error: unknown) => Promise<AttachmentIntentOutcome>;\n}\n\ninterface AttachmentLifecycleMachineOptions<Key extends object, Value> {\n readonly close: AttachmentLifecycleOptions<Value>['close'];\n readonly open: AttachmentLifecycleOptions<Value>['open'];\n readonly readiness: AttachmentReadinessController;\n readonly state: AttachmentLifecycleState<Key, Value>;\n readonly status: LifecycleStatusStore;\n}\n\nexport { attachmentLifecycleControllerBrand, attachmentRetirementBrand, retiredAttachmentKey };\nexport type {\n ActiveAttachmentRetirement,\n AttachmentAttempt,\n AttachmentCleanupContext,\n AttachmentCleanupFailure,\n AttachmentCleanupOutcome,\n AttachmentCloseFailureRecord,\n AttachmentDrainOutcome,\n AttachmentFailureOrigin,\n AttachmentFailureRecord,\n AttachmentIntentOutcome,\n AttachmentLifecycleController,\n AttachmentLifecycleDiagnostics,\n AttachmentLifecycleIntent,\n AttachmentLifecycleMachine,\n AttachmentLifecycleMachineOptions,\n AttachmentLifecycleOptions,\n AttachmentLifecycleSnapshot,\n AttachmentLifecycleState,\n AttachmentOpenContext,\n AttachmentOpeningFailure,\n AttachmentOpenRolledBackFailureRecord,\n AttachmentOpenStep,\n AttachmentQuarantineFailureRecord,\n AttachmentRetirement,\n AttachmentRetirementHandleState,\n AttachmentRetirementRequestResult,\n AttachmentRetryOutcome,\n Awaitable,\n IntentEntry,\n LifecycleStatusStore,\n NonEmptyReadonlyArray,\n OpenStepCoordinator,\n OwnedCleanup,\n StartedAttachmentOpen,\n};\n"],"names":["attachmentLifecycleControllerBrand","attachmentRetirementBrand","retiredAttachmentKey"],"mappings":"AAMA,MAAMA,EAAqC,OAAO,yCAAyC,EACrFC,EAA4B,OAAO,+BAA+B,EAClEC,EAAuB,OAAO,gCAAgC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AttachmentAttempt, AttachmentCleanupFailure, AttachmentCleanupOutcome, AttachmentDrainOutcome, AttachmentFailureOrigin, AttachmentIntentOutcome, AttachmentLifecycleIntent, AttachmentLifecycleSnapshot, AttachmentOpeningFailure, AttachmentQuarantineFailureRecord, AttachmentRetirement, AttachmentRetirementHandleState, IntentEntry, LifecycleStatusStore } from './attachment-lifecycle-contract.js';
|
|
2
|
+
declare const cancelledOutcome: Readonly<{
|
|
3
|
+
kind: "cancelled";
|
|
4
|
+
}>;
|
|
5
|
+
declare const cleanupCompleted: Readonly<{
|
|
6
|
+
kind: "completed";
|
|
7
|
+
}>;
|
|
8
|
+
declare const closedOutcome: Readonly<{
|
|
9
|
+
kind: "committed";
|
|
10
|
+
state: "closed";
|
|
11
|
+
}>;
|
|
12
|
+
declare const noop: () => void;
|
|
13
|
+
declare const readyOutcome: Readonly<{
|
|
14
|
+
kind: "committed";
|
|
15
|
+
state: "ready";
|
|
16
|
+
}>;
|
|
17
|
+
declare const supersededOutcome: Readonly<{
|
|
18
|
+
kind: "superseded";
|
|
19
|
+
}>;
|
|
20
|
+
declare function selectRetirementKeys<Key extends object>(targetKey: Key | undefined, attemptKeys: WeakSet<Key> | undefined): WeakSet<Key> | undefined;
|
|
21
|
+
declare function toAttachmentDrainOutcome(outcome: AttachmentIntentOutcome): AttachmentDrainOutcome;
|
|
22
|
+
declare function createAttachmentRetirementHandle(state: AttachmentRetirementHandleState): AttachmentRetirement;
|
|
23
|
+
declare function createStatusStore(): LifecycleStatusStore;
|
|
24
|
+
declare function createIntentEntry<Key extends object, Value>(intent: AttachmentLifecycleIntent<Key, Value> | null): IntentEntry<Key, Value>;
|
|
25
|
+
declare function retireEntryIntent<Key extends object, Value>(entry: IntentEntry<Key, Value>): void;
|
|
26
|
+
declare function settleIntentEntry<Key extends object, Value>(entry: IntentEntry<Key, Value>, outcome: AttachmentIntentOutcome): void;
|
|
27
|
+
declare function requestedOpenIntent<Key extends object, Value>(entry: IntentEntry<Key, Value>): AttachmentLifecycleIntent<Key, Value> | undefined;
|
|
28
|
+
declare function findJoinableEntry<Key extends object, Value>(entry: IntentEntry<Key, Value> | undefined, intent: AttachmentLifecycleIntent<Key, Value> | null): IntentEntry<Key, Value> | undefined;
|
|
29
|
+
declare function keepsCurrentAttempt<Key extends object, Value>(entry: IntentEntry<Key, Value>, attempt: AttachmentAttempt<Key>, state: AttachmentLifecycleSnapshot['kind']): boolean;
|
|
30
|
+
declare function countCleanupHandles<Key extends object>(attempt: AttachmentAttempt<Key> | undefined): number;
|
|
31
|
+
declare function makeCleanupOutcome(ownerId: string, failures: AttachmentCleanupFailure[]): AttachmentCleanupOutcome;
|
|
32
|
+
declare function openingFailure(id: string, error: unknown): AttachmentOpeningFailure;
|
|
33
|
+
declare function failureOrigin(failure: AttachmentQuarantineFailureRecord): AttachmentFailureOrigin;
|
|
34
|
+
export { cancelledOutcome, cleanupCompleted, closedOutcome, countCleanupHandles, createAttachmentRetirementHandle, createIntentEntry, createStatusStore, failureOrigin, findJoinableEntry, keepsCurrentAttempt, makeCleanupOutcome, noop, openingFailure, readyOutcome, requestedOpenIntent, retireEntryIntent, selectRetirementKeys, settleIntentEntry, supersededOutcome, toAttachmentDrainOutcome, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{reportDetachedError as m}from"./attachment.js";import{attachmentRetirementBrand as p}from"./attachment-lifecycle-contract.js";import{createAggregateError as k}from"./platform-compat.js";const O=Object.freeze({kind:"cancelled"}),l=Object.freeze({kind:"completed"}),a=Object.freeze({kind:"committed",state:"closed"}),s=()=>{},j=Object.freeze({kind:"committed",state:"ready"}),z=Object.freeze({kind:"superseded"});function h(e,n){return e===void 0||n!=null&&n.has(e)?n:new WeakSet().add(e)}function g(e){switch(e.kind){case"cancelled":break;case"committed":if(e.state==="closed")return a;break;case"failed":break;case"quarantined":return e}throw new TypeError(`Attachment retirement produced invalid ${e.kind} outcome.`)}function w(e){return Object.freeze({[p]:!0,drain(){if(e.outcome!==void 0)return e.outcome;const n=e.action;if(n===void 0)throw new TypeError("Attachment retirement is not drainable.");return n()}})}function E(){let e=!1,n=Object.freeze({kind:"closed",lastFailure:null,revision:0});const t=new Set;let r=!1,c=!1;const u=()=>{if(r=!0,!c){c=!0;try{for(;r;){r=!1;const i=n.revision;for(const{listener:o}of[...t]){if(n.revision!==i){r=!0;break}try{o()}catch(d){m(d)}}}}finally{c=!1}}};return Object.freeze({close(){e=!0,t.clear()},getSnapshot(){return n},listenerCount(){return t.size},notify:u,replace(i,o=!0){return n=Object.freeze(i(n.revision+1)),o&&u(),n},subscribe(i){if(e)return s;const o={listener:i};t.add(o);let d=!0;return()=>{d&&(d=!1,t.delete(o))}}})}function v(e){let n;const t=new Promise(r=>{n=r});return{cancelled:!1,intent:e,joinable:!0,promise:t,resolve:n,settled:!1,started:!1}}function f(e){e.intent=void 0,e.joinable=!1}function A(e,n){e.settled||(f(e),e.settled=!0,e.resolve(n))}function S(e,n){return e===null||n===null?e===n:Object.is(e.key,n.key)}function b(e){if(!(e.cancelled||e.intent===null))return e.intent}function C(e,n){if(!(e===void 0||!e.joinable||e.cancelled||e.intent===void 0))return S(e.intent,n)?e:void 0}function I(e,n,t){const r=b(e);return r!==void 0&&t==="ready"&&Object.is(n.key,r.key)}function F(e){if(e===void 0)return 0;let n=0;for(const t of e.cleanups)t.cleanup!==void 0&&(n+=1);return n}function R(e,n){const[t,...r]=n;if(t===void 0)return l;const c=Object.freeze([t,...r]),u=k(c.map(i=>i.error),`Attachment ${e} cleanup failed.`);return Object.freeze({error:u,failures:c,kind:"failed"})}function q(e,n){return Object.freeze({error:n,failedStep:e})}function D(e){return e.kind==="close-failed"?e.origin:e.kind==="open-failed"?Object.freeze({generation:e.generation,kind:"open",opening:e.opening,rollback:e.rollback}):Object.freeze({cleanup:e.cleanup,generation:e.generation,kind:"rollback"})}export{O as cancelledOutcome,l as cleanupCompleted,a as closedOutcome,F as countCleanupHandles,w as createAttachmentRetirementHandle,v as createIntentEntry,E as createStatusStore,D as failureOrigin,C as findJoinableEntry,I as keepsCurrentAttempt,R as makeCleanupOutcome,s as noop,q as openingFailure,j as readyOutcome,b as requestedOpenIntent,f as retireEntryIntent,h as selectRetirementKeys,A as settleIntentEntry,z as supersededOutcome,g as toAttachmentDrainOutcome};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle-helpers.js","sources":["../src/attachment-lifecycle-helpers.ts"],"sourcesContent":["import { reportDetachedError } from './attachment';\nimport { attachmentRetirementBrand } from './attachment-lifecycle-contract';\nimport type {\n AttachmentAttempt,\n AttachmentCleanupFailure,\n AttachmentCleanupOutcome,\n AttachmentDrainOutcome,\n AttachmentFailureOrigin,\n AttachmentIntentOutcome,\n AttachmentLifecycleIntent,\n AttachmentLifecycleSnapshot,\n AttachmentOpeningFailure,\n AttachmentQuarantineFailureRecord,\n AttachmentRetirement,\n AttachmentRetirementHandleState,\n IntentEntry,\n LifecycleStatusStore,\n NonEmptyReadonlyArray,\n} from './attachment-lifecycle-contract';\nimport { createAggregateError } from './platform-compat';\n\nconst cancelledOutcome = Object.freeze({ kind: 'cancelled' as const });\nconst cleanupCompleted = Object.freeze({ kind: 'completed' as const });\nconst closedOutcome = Object.freeze({ kind: 'committed' as const, state: 'closed' as const });\nconst noop = (): void => undefined;\nconst readyOutcome = Object.freeze({ kind: 'committed' as const, state: 'ready' as const });\nconst supersededOutcome = Object.freeze({ kind: 'superseded' as const });\n\nfunction selectRetirementKeys<Key extends object>(\n targetKey: Key | undefined,\n attemptKeys: WeakSet<Key> | undefined,\n): WeakSet<Key> | undefined {\n if (targetKey === undefined || attemptKeys?.has(targetKey)) return attemptKeys;\n\n return new WeakSet<Key>().add(targetKey);\n}\n\nfunction toAttachmentDrainOutcome(outcome: AttachmentIntentOutcome): AttachmentDrainOutcome {\n switch (outcome.kind) {\n case 'cancelled':\n break;\n case 'committed':\n if (outcome.state === 'closed') return closedOutcome;\n\n break;\n case 'failed':\n break;\n case 'quarantined':\n return outcome;\n case 'superseded':\n break;\n }\n\n throw new TypeError(`Attachment retirement produced invalid ${outcome.kind} outcome.`);\n}\n\nfunction createAttachmentRetirementHandle(state: AttachmentRetirementHandleState): AttachmentRetirement {\n return Object.freeze({\n [attachmentRetirementBrand]: true as const,\n drain(): Promise<AttachmentDrainOutcome> {\n if (state.outcome !== undefined) return state.outcome;\n\n const action = state.action;\n\n if (action === undefined) throw new TypeError('Attachment retirement is not drainable.');\n\n return action();\n },\n });\n}\n\nfunction createStatusStore(): LifecycleStatusStore {\n let closed = false;\n let current: AttachmentLifecycleSnapshot = Object.freeze({\n kind: 'closed' as const,\n lastFailure: null,\n revision: 0,\n });\n const listeners = new Set<{ readonly listener: () => void }>();\n let pendingPublication = false;\n let publishing = false;\n\n const notify = (): void => {\n pendingPublication = true;\n\n if (publishing) return;\n\n publishing = true;\n\n try {\n while (pendingPublication) {\n pendingPublication = false;\n const revision = current.revision;\n\n for (const { listener } of [...listeners]) {\n if (current.revision !== revision) {\n pendingPublication = true;\n\n break;\n }\n\n try {\n listener();\n } catch (error) {\n reportDetachedError(error);\n }\n }\n }\n } finally {\n publishing = false;\n }\n };\n\n return Object.freeze({\n close(): void {\n closed = true;\n listeners.clear();\n },\n getSnapshot(): AttachmentLifecycleSnapshot {\n return current;\n },\n listenerCount(): number {\n return listeners.size;\n },\n notify,\n replace(\n create: (revision: number) => AttachmentLifecycleSnapshot,\n shouldNotify = true,\n ): AttachmentLifecycleSnapshot {\n current = Object.freeze(create(current.revision + 1));\n\n if (shouldNotify) notify();\n\n return current;\n },\n subscribe(listener: () => void): () => void {\n if (closed) return noop;\n\n const registration = { listener };\n listeners.add(registration);\n let subscribed = true;\n\n return (): void => {\n if (!subscribed) return;\n\n subscribed = false;\n listeners.delete(registration);\n };\n },\n });\n}\n\nfunction createIntentEntry<Key extends object, Value>(\n intent: AttachmentLifecycleIntent<Key, Value> | null,\n): IntentEntry<Key, Value> {\n let resolve!: (outcome: AttachmentIntentOutcome) => void;\n const promise = new Promise<AttachmentIntentOutcome>(onResolve => {\n resolve = onResolve;\n });\n\n return { cancelled: false, intent, joinable: true, promise, resolve, settled: false, started: false };\n}\n\nfunction retireEntryIntent<Key extends object, Value>(entry: IntentEntry<Key, Value>): void {\n entry.intent = undefined;\n entry.joinable = false;\n}\n\nfunction settleIntentEntry<Key extends object, Value>(\n entry: IntentEntry<Key, Value>,\n outcome: AttachmentIntentOutcome,\n): void {\n if (entry.settled) return;\n\n retireEntryIntent(entry);\n entry.settled = true;\n entry.resolve(outcome);\n}\n\nfunction sameIntent<Key extends object, Value>(\n left: AttachmentLifecycleIntent<Key, Value> | null,\n right: AttachmentLifecycleIntent<Key, Value> | null,\n): boolean {\n if (left === null || right === null) return left === right;\n\n return Object.is(left.key, right.key);\n}\n\nfunction requestedOpenIntent<Key extends object, Value>(\n entry: IntentEntry<Key, Value>,\n): AttachmentLifecycleIntent<Key, Value> | undefined {\n if (entry.cancelled || entry.intent === null) return undefined;\n\n return entry.intent;\n}\n\nfunction findJoinableEntry<Key extends object, Value>(\n entry: IntentEntry<Key, Value> | undefined,\n intent: AttachmentLifecycleIntent<Key, Value> | null,\n): IntentEntry<Key, Value> | undefined {\n if (entry === undefined || !entry.joinable || entry.cancelled || entry.intent === undefined) return undefined;\n\n return sameIntent(entry.intent, intent) ? entry : undefined;\n}\n\nfunction keepsCurrentAttempt<Key extends object, Value>(\n entry: IntentEntry<Key, Value>,\n attempt: AttachmentAttempt<Key>,\n state: AttachmentLifecycleSnapshot['kind'],\n): boolean {\n const intent = requestedOpenIntent(entry);\n\n return intent !== undefined && state === 'ready' && Object.is(attempt.key, intent.key);\n}\n\nfunction countCleanupHandles<Key extends object>(attempt: AttachmentAttempt<Key> | undefined): number {\n if (attempt === undefined) return 0;\n\n let count = 0;\n\n for (const cleanup of attempt.cleanups) {\n if (cleanup.cleanup !== undefined) count += 1;\n }\n\n return count;\n}\n\nfunction makeCleanupOutcome(ownerId: string, failures: AttachmentCleanupFailure[]): AttachmentCleanupOutcome {\n const [first, ...rest] = failures;\n\n if (first === undefined) return cleanupCompleted;\n\n const nonEmptyFailures: NonEmptyReadonlyArray<AttachmentCleanupFailure> = Object.freeze([first, ...rest]);\n const error = createAggregateError(\n nonEmptyFailures.map(failure => failure.error),\n `Attachment ${ownerId} cleanup failed.`,\n );\n\n return Object.freeze({ error, failures: nonEmptyFailures, kind: 'failed' as const });\n}\n\nfunction openingFailure(id: string, error: unknown): AttachmentOpeningFailure {\n return Object.freeze({ error, failedStep: id });\n}\n\nfunction failureOrigin(failure: AttachmentQuarantineFailureRecord): AttachmentFailureOrigin {\n if (failure.kind === 'close-failed') return failure.origin;\n\n if (failure.kind === 'open-failed') {\n return Object.freeze({\n generation: failure.generation,\n kind: 'open' as const,\n opening: failure.opening,\n rollback: failure.rollback,\n });\n }\n\n return Object.freeze({ cleanup: failure.cleanup, generation: failure.generation, kind: 'rollback' as const });\n}\n\nexport {\n cancelledOutcome,\n cleanupCompleted,\n closedOutcome,\n countCleanupHandles,\n createAttachmentRetirementHandle,\n createIntentEntry,\n createStatusStore,\n failureOrigin,\n findJoinableEntry,\n keepsCurrentAttempt,\n makeCleanupOutcome,\n noop,\n openingFailure,\n readyOutcome,\n requestedOpenIntent,\n retireEntryIntent,\n selectRetirementKeys,\n settleIntentEntry,\n supersededOutcome,\n toAttachmentDrainOutcome,\n};\n"],"names":["cancelledOutcome","cleanupCompleted","closedOutcome","noop","readyOutcome","supersededOutcome","selectRetirementKeys","targetKey","attemptKeys","toAttachmentDrainOutcome","outcome","createAttachmentRetirementHandle","state","attachmentRetirementBrand","action","createStatusStore","closed","current","listeners","pendingPublication","publishing","notify","revision","listener","error","reportDetachedError","create","shouldNotify","registration","subscribed","createIntentEntry","intent","resolve","promise","onResolve","retireEntryIntent","entry","settleIntentEntry","sameIntent","left","right","requestedOpenIntent","findJoinableEntry","keepsCurrentAttempt","attempt","countCleanupHandles","count","cleanup","makeCleanupOutcome","ownerId","failures","first","rest","nonEmptyFailures","createAggregateError","failure","openingFailure","id","failureOrigin"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AttachmentLifecycleMachine, AttachmentLifecycleMachineOptions } from './attachment-lifecycle-contract.js';
|
|
2
|
+
declare function createAttachmentLifecycleMachine<Key extends object, Value>(options: AttachmentLifecycleMachineOptions<Key, Value>): AttachmentLifecycleMachine<Key, Value>;
|
|
3
|
+
export { createAttachmentLifecycleMachine };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{abortWithReason as U,combineAbortSignals as G,throwIfSignalAborted as F}from"./abort-compat.js";import{reportDetachedError as M}from"./attachment.js";import{runAttachmentCleanup as S}from"./attachment-lifecycle-cleanup.js";import{retiredAttachmentKey as B}from"./attachment-lifecycle-contract.js";import{cleanupCompleted as H,openingFailure as k,retireEntryIntent as h,cancelledOutcome as f,closedOutcome as J,keepsCurrentAttempt as N,readyOutcome as R,requestedOpenIntent as Q,failureOrigin as V}from"./attachment-lifecycle-helpers.js";import{createOpenStepCoordinator as X}from"./attachment-lifecycle-open.js";import{settleGuardedResult as Y}from"./call-target-result.js";import{FeatureError as Z}from"./errors.js";function _(g){const{readiness:d,state:r,status:c}=g;let O=g.close,A=g.open;const m=()=>{!r.disposeRequested||r.disposed||c.getSnapshot().kind!=="closed"||(r.disposed=!0,O=void 0,A=void 0,d.dispose(),c.replace(e=>Object.freeze({kind:"closed",lastFailure:null,revision:e}),!1),c.close())},u=e=>{c.replace(n=>Object.freeze({kind:"closed",lastFailure:e,revision:n})),m()},p=e=>{const n=r.currentAttempt,t=c.getSnapshot();if(n===void 0||t.kind==="closing"||t.kind==="failed-close")return;const i=new Z("retired",d.ref.id);n.acceptingSteps=!1,n.key=B,c.replace(a=>Object.freeze({generation:n.generation,kind:"closing",phase:e,revision:a}),!1),d.publishInactive(i);const o=n.openAbort;o!==void 0&&U(o,i),n.openAbort=void 0,c.notify()},w=e=>{const n=r.activeRetirement;if(!(n===void 0||n.targetAttempt!==e))return n.drainPermission},j=(e,n)=>{r.activeEntry!==void 0&&h(r.activeEntry),c.replace(t=>Object.freeze({failure:e,generation:n.generation,kind:"failed-close",revision:t}))},l=async(e,n)=>{p("rollback");const t=w(e);t!==void 0&&await t;const i=await S(d.ref.id,e);if(i.kind==="failed"){const a=Object.freeze(n===void 0?{cleanup:i,generation:e.generation,kind:"rollback-failed"}:{generation:e.generation,kind:"open-failed",opening:n,rollback:i});return j(a,e),Object.freeze({failure:a,kind:"quarantined"})}if(r.currentAttempt=void 0,n===void 0)return u(null),f;const o=Object.freeze({generation:e.generation,kind:"open-failed",opening:n,rollback:i});return r.activeEntry!==void 0&&h(r.activeEntry),u(o),Object.freeze({failure:o,kind:"failed"})},q=(e,n,t,i)=>{const o=n.openAbort;if(o===void 0)throw new TypeError("Cannot open an attachment after logical close.");const a=i===void 0?o.signal:G([i,o.signal]).signal,s=X(n,a,()=>p("rollback"),()=>!e.cancelled),b=Object.freeze({signal:a,step:s.step,value:t}),v=A;if(v===void 0)throw new TypeError("Cannot open a disposed attachment lifecycle.");const K=(async()=>{try{const y=v(b);await Y(y,{assertCurrent:()=>F(a),waitForPhysicalSettlement:!0})}catch(y){let C=y;try{F(a)}catch(L){C=L}s.fail("attachment.open",C)}finally{s.seal()}})();return Object.freeze({completion:K,firstFailure:s.firstFailure})},I=async e=>(await e.completion,e.firstFailure()),z=e=>e.cancelled||c.getSnapshot().kind!=="ready",P=async(e,n,t)=>{c.replace(i=>Object.freeze({generation:r.generation,kind:"ready",revision:i}),!1);try{d.publishReady(t)}catch(i){return l(n,k("attachment.ready",i))}return z(e)||(c.notify(),z(e))?l(n,void 0):R},x=async e=>{let n=Q(e);if(n===void 0)return f;r.generation+=1;const t=d.beginOpen(),i=O;if(i===void 0)throw new TypeError("Cannot open a disposed attachment lifecycle.");const o={acceptingSteps:!0,cleanups:[{cleanup:i,id:"attachment.close"}],generation:r.generation,key:n.key,openAbort:new AbortController,originKeys:new WeakSet().add(n.key)};r.currentAttempt=o,c.replace(b=>Object.freeze({generation:r.generation,kind:"opening",revision:b}));const a=e.cancelled?void 0:q(e,o,n.value,n.signal);n=void 0;const s=a===void 0?void 0:await I(a);return e.cancelled||s!==void 0?l(o,s):P(e,o,t)},E=async(e,n,t)=>{const i=w(e);i!==void 0&&await i;const o=await S(d.ref.id,e);if(o.kind==="failed"){const a=Object.freeze({cleanup:o,generation:e.generation,kind:"close-failed",origin:t===null?Object.freeze({cleanup:o,generation:e.generation,kind:"close"}):V(t),phase:n});return j(a,e),a}r.currentAttempt=void 0,u(t)},D=async()=>{const e=r.currentAttempt,n=c.getSnapshot();if(!(e===void 0||n.kind!=="failed-close"))return c.replace(t=>Object.freeze({generation:e.generation,kind:"closing",phase:"retry",revision:t})),E(e,"retry",n.failure)},T=async e=>{if(c.getSnapshot().kind!=="failed-close")return;const n=await D();return n!==void 0?Object.freeze({failure:n,kind:"quarantined"}):e.cancelled?f:void 0},W=async e=>{const n=r.currentAttempt;if(n===void 0)return;if(N(e,n,c.getSnapshot().kind))return R;p("close");const t=await E(n,"close",null);return t!==void 0?Object.freeze({failure:t,kind:"quarantined"}):e.cancelled?f:void 0};return Object.freeze({beginLogicalClose:p,finishDisposal:m,reconcile:async e=>{const n=await T(e);if(n!==void 0)return n;const t=await W(e);return t!==void 0?t:e.cancelled||e.intent===void 0?f:e.intent===null?(m(),J):x(e)},recoverUnexpected:async e=>{M(e);const n=r.currentAttempt;if(n===void 0){const t=Object.freeze({generation:r.generation,kind:"open-failed",opening:k("attachment.lifecycle",e),rollback:H});return r.activeEntry!==void 0&&h(r.activeEntry),u(t),Object.freeze({failure:t,kind:"failed"})}return l(n,k("attachment.lifecycle",e))}})}export{_ as createAttachmentLifecycleMachine};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle-machine.js","sources":["../src/attachment-lifecycle-machine.ts"],"sourcesContent":["import { abortWithReason, combineAbortSignals, throwIfSignalAborted } from './abort-compat';\nimport { reportDetachedError } from './attachment';\nimport { runAttachmentCleanup } from './attachment-lifecycle-cleanup';\nimport { retiredAttachmentKey } from './attachment-lifecycle-contract';\nimport type {\n AttachmentAttempt,\n AttachmentCloseFailureRecord,\n AttachmentFailureRecord,\n AttachmentIntentOutcome,\n AttachmentLifecycleMachine,\n AttachmentLifecycleMachineOptions,\n AttachmentOpenContext,\n AttachmentOpeningFailure,\n AttachmentOpenRolledBackFailureRecord,\n AttachmentQuarantineFailureRecord,\n IntentEntry,\n StartedAttachmentOpen,\n} from './attachment-lifecycle-contract';\nimport {\n cancelledOutcome,\n cleanupCompleted,\n closedOutcome,\n failureOrigin,\n keepsCurrentAttempt,\n openingFailure,\n readyOutcome,\n requestedOpenIntent,\n retireEntryIntent,\n} from './attachment-lifecycle-helpers';\nimport { createOpenStepCoordinator } from './attachment-lifecycle-open';\nimport { settleGuardedResult } from './call-target';\nimport { FeatureError } from './errors';\n\nfunction createAttachmentLifecycleMachine<Key extends object, Value>(\n options: AttachmentLifecycleMachineOptions<Key, Value>,\n): AttachmentLifecycleMachine<Key, Value> {\n const { readiness, state, status } = options;\n let closeAttachment: AttachmentLifecycleMachineOptions<Key, Value>['close'] | undefined = options.close;\n let openAttachment: AttachmentLifecycleMachineOptions<Key, Value>['open'] | undefined = options.open;\n\n const finishDisposal = (): void => {\n if (!state.disposeRequested || state.disposed || status.getSnapshot().kind !== 'closed') return;\n\n state.disposed = true;\n closeAttachment = undefined;\n openAttachment = undefined;\n readiness.dispose();\n status.replace(revision => Object.freeze({ kind: 'closed' as const, lastFailure: null, revision }), false);\n status.close();\n };\n\n const publishClosed = (lastFailure: AttachmentFailureRecord | null): void => {\n status.replace(revision => Object.freeze({ kind: 'closed' as const, lastFailure, revision }));\n finishDisposal();\n };\n\n const beginLogicalClose = (phase: 'close' | 'retry' | 'rollback'): void => {\n const attempt = state.currentAttempt;\n const snapshot = status.getSnapshot();\n\n if (attempt === undefined || snapshot.kind === 'closing' || snapshot.kind === 'failed-close') return;\n\n const reason = new FeatureError('retired', readiness.ref.id);\n attempt.acceptingSteps = false;\n attempt.key = retiredAttachmentKey;\n status.replace(\n revision => Object.freeze({ generation: attempt.generation, kind: 'closing' as const, phase, revision }),\n false,\n );\n readiness.publishInactive(reason);\n const openAbort = attempt.openAbort;\n\n if (openAbort !== undefined) abortWithReason(openAbort, reason);\n\n attempt.openAbort = undefined;\n status.notify();\n };\n\n const coordinatedDrainPermissionFor = (attempt: AttachmentAttempt<Key>): Promise<void> | undefined => {\n const retirement = state.activeRetirement;\n\n if (retirement === undefined || retirement.targetAttempt !== attempt) return undefined;\n\n return retirement.drainPermission;\n };\n\n const publishFailedClose = (failure: AttachmentQuarantineFailureRecord, attempt: AttachmentAttempt<Key>): void => {\n if (state.activeEntry !== undefined) retireEntryIntent(state.activeEntry);\n\n status.replace(revision =>\n Object.freeze({ failure, generation: attempt.generation, kind: 'failed-close' as const, revision }),\n );\n };\n\n const rollbackAttempt = async (\n attempt: AttachmentAttempt<Key>,\n failure: AttachmentOpeningFailure | undefined,\n ): Promise<AttachmentIntentOutcome> => {\n beginLogicalClose('rollback');\n const drainPermission = coordinatedDrainPermissionFor(attempt);\n\n if (drainPermission !== undefined) await drainPermission;\n\n const rollback = await runAttachmentCleanup(readiness.ref.id, attempt);\n\n if (rollback.kind === 'failed') {\n const record: AttachmentQuarantineFailureRecord =\n failure === undefined\n ? Object.freeze({ cleanup: rollback, generation: attempt.generation, kind: 'rollback-failed' as const })\n : Object.freeze({ generation: attempt.generation, kind: 'open-failed' as const, opening: failure, rollback });\n publishFailedClose(record, attempt);\n\n return Object.freeze({ failure: record, kind: 'quarantined' as const });\n }\n\n state.currentAttempt = undefined;\n\n if (failure === undefined) {\n publishClosed(null);\n\n return cancelledOutcome;\n }\n\n const record: AttachmentOpenRolledBackFailureRecord = Object.freeze({\n generation: attempt.generation,\n kind: 'open-failed' as const,\n opening: failure,\n rollback,\n });\n\n if (state.activeEntry !== undefined) retireEntryIntent(state.activeEntry);\n\n publishClosed(record);\n\n return Object.freeze({ failure: record, kind: 'failed' as const });\n };\n\n const startOpen = (\n entry: IntentEntry<Key, Value>,\n attempt: AttachmentAttempt<Key>,\n value: Value,\n authoritySignal?: AbortSignal,\n ): StartedAttachmentOpen => {\n const openAbort = attempt.openAbort;\n\n if (openAbort === undefined) throw new TypeError('Cannot open an attachment after logical close.');\n\n const signal =\n authoritySignal === undefined\n ? openAbort.signal\n : combineAbortSignals([authoritySignal, openAbort.signal]).signal;\n const steps = createOpenStepCoordinator(\n attempt,\n signal,\n () => beginLogicalClose('rollback'),\n () => !entry.cancelled,\n );\n const context: AttachmentOpenContext<Value> = Object.freeze({ signal, step: steps.step, value });\n const open = openAttachment;\n\n if (open === undefined) throw new TypeError('Cannot open a disposed attachment lifecycle.');\n\n const completion = (async (): Promise<void> => {\n try {\n const result = open(context);\n\n await settleGuardedResult(result, {\n assertCurrent: () => throwIfSignalAborted(signal),\n waitForPhysicalSettlement: true,\n });\n } catch (error) {\n let failure = error;\n\n try {\n throwIfSignalAborted(signal);\n } catch (currentError) {\n failure = currentError;\n }\n\n steps.fail('attachment.open', failure);\n } finally {\n steps.seal();\n }\n })();\n\n return Object.freeze({ completion, firstFailure: steps.firstFailure });\n };\n\n const finishOpen = async (started: StartedAttachmentOpen): Promise<AttachmentOpeningFailure | undefined> => {\n await started.completion;\n\n return started.firstFailure();\n };\n\n const readyWasRetired = (entry: IntentEntry<Key, Value>): boolean =>\n entry.cancelled || status.getSnapshot().kind !== 'ready';\n\n const commitReady = async (\n entry: IntentEntry<Key, Value>,\n attempt: AttachmentAttempt<Key>,\n permit: Parameters<typeof readiness.publishReady>[0],\n ): Promise<AttachmentIntentOutcome> => {\n status.replace(\n revision => Object.freeze({ generation: state.generation, kind: 'ready' as const, revision }),\n false,\n );\n\n try {\n readiness.publishReady(permit);\n } catch (error) {\n return rollbackAttempt(attempt, openingFailure('attachment.ready', error));\n }\n\n if (readyWasRetired(entry)) return rollbackAttempt(attempt, undefined);\n\n status.notify();\n\n if (readyWasRetired(entry)) return rollbackAttempt(attempt, undefined);\n\n return readyOutcome;\n };\n\n const openIntent = async (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome> => {\n let intent = requestedOpenIntent(entry);\n\n if (intent === undefined) return cancelledOutcome;\n\n state.generation += 1;\n const permit = readiness.beginOpen();\n const close = closeAttachment;\n\n if (close === undefined) throw new TypeError('Cannot open a disposed attachment lifecycle.');\n\n const attempt: AttachmentAttempt<Key> = {\n acceptingSteps: true,\n cleanups: [{ cleanup: close, id: 'attachment.close' }],\n generation: state.generation,\n key: intent.key,\n openAbort: new AbortController(),\n originKeys: new WeakSet<Key>().add(intent.key),\n };\n state.currentAttempt = attempt;\n status.replace(revision => Object.freeze({ generation: state.generation, kind: 'opening' as const, revision }));\n\n const started = entry.cancelled ? undefined : startOpen(entry, attempt, intent.value, intent.signal);\n intent = undefined;\n const failure = started === undefined ? undefined : await finishOpen(started);\n\n if (entry.cancelled || failure !== undefined) return rollbackAttempt(attempt, failure);\n\n return commitReady(entry, attempt, permit);\n };\n\n const closeAttempt = async (\n attempt: AttachmentAttempt<Key>,\n phase: AttachmentCloseFailureRecord['phase'],\n retainedFailure: AttachmentQuarantineFailureRecord | null,\n ): Promise<AttachmentCloseFailureRecord | undefined> => {\n const drainPermission = coordinatedDrainPermissionFor(attempt);\n\n if (drainPermission !== undefined) await drainPermission;\n\n const cleanup = await runAttachmentCleanup(readiness.ref.id, attempt);\n\n if (cleanup.kind === 'failed') {\n const failure: AttachmentCloseFailureRecord = Object.freeze({\n cleanup,\n generation: attempt.generation,\n kind: 'close-failed' as const,\n origin:\n retainedFailure === null\n ? Object.freeze({ cleanup, generation: attempt.generation, kind: 'close' as const })\n : failureOrigin(retainedFailure),\n phase,\n });\n publishFailedClose(failure, attempt);\n\n return failure;\n }\n\n state.currentAttempt = undefined;\n publishClosed(retainedFailure);\n\n return undefined;\n };\n\n const recoverFailedClose = async (): Promise<AttachmentCloseFailureRecord | undefined> => {\n const attempt = state.currentAttempt;\n const snapshot = status.getSnapshot();\n\n if (attempt === undefined || snapshot.kind !== 'failed-close') return undefined;\n\n status.replace(revision =>\n Object.freeze({ generation: attempt.generation, kind: 'closing' as const, phase: 'retry' as const, revision }),\n );\n\n return closeAttempt(attempt, 'retry', snapshot.failure);\n };\n\n const recoverForEntry = async (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome | undefined> => {\n if (status.getSnapshot().kind !== 'failed-close') return undefined;\n\n const retryFailure = await recoverFailedClose();\n\n if (retryFailure !== undefined) {\n return Object.freeze({ failure: retryFailure, kind: 'quarantined' as const });\n }\n\n return entry.cancelled ? cancelledOutcome : undefined;\n };\n\n const closeForEntry = async (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome | undefined> => {\n const attempt = state.currentAttempt;\n\n if (attempt === undefined) return undefined;\n\n if (keepsCurrentAttempt(entry, attempt, status.getSnapshot().kind)) return readyOutcome;\n\n beginLogicalClose('close');\n const closeFailure = await closeAttempt(attempt, 'close', null);\n\n if (closeFailure !== undefined) {\n return Object.freeze({ failure: closeFailure, kind: 'quarantined' as const });\n }\n\n return entry.cancelled ? cancelledOutcome : undefined;\n };\n\n const reconcile = async (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome> => {\n const recoveryOutcome = await recoverForEntry(entry);\n\n if (recoveryOutcome !== undefined) return recoveryOutcome;\n\n const closeOutcome = await closeForEntry(entry);\n\n if (closeOutcome !== undefined) return closeOutcome;\n\n if (entry.cancelled || entry.intent === undefined) return cancelledOutcome;\n\n if (entry.intent === null) {\n finishDisposal();\n\n return closedOutcome;\n }\n\n return openIntent(entry);\n };\n\n const recoverUnexpected = async (error: unknown): Promise<AttachmentIntentOutcome> => {\n reportDetachedError(error);\n const attempt = state.currentAttempt;\n\n if (attempt === undefined) {\n const record: AttachmentOpenRolledBackFailureRecord = Object.freeze({\n generation: state.generation,\n kind: 'open-failed' as const,\n opening: openingFailure('attachment.lifecycle', error),\n rollback: cleanupCompleted,\n });\n\n if (state.activeEntry !== undefined) retireEntryIntent(state.activeEntry);\n\n publishClosed(record);\n\n return Object.freeze({ failure: record, kind: 'failed' as const });\n }\n\n return rollbackAttempt(attempt, openingFailure('attachment.lifecycle', error));\n };\n\n return Object.freeze({ beginLogicalClose, finishDisposal, reconcile, recoverUnexpected });\n}\n\nexport { createAttachmentLifecycleMachine };\n"],"names":["createAttachmentLifecycleMachine","options","readiness","state","status","closeAttachment","openAttachment","finishDisposal","revision","publishClosed","lastFailure","beginLogicalClose","phase","attempt","snapshot","reason","FeatureError","retiredAttachmentKey","openAbort","abortWithReason","coordinatedDrainPermissionFor","retirement","publishFailedClose","failure","retireEntryIntent","rollbackAttempt","drainPermission","rollback","runAttachmentCleanup","record","cancelledOutcome","startOpen","entry","value","authoritySignal","signal","combineAbortSignals","steps","createOpenStepCoordinator","context","open","completion","result","settleGuardedResult","throwIfSignalAborted","error","currentError","finishOpen","started","readyWasRetired","commitReady","permit","openingFailure","readyOutcome","openIntent","intent","requestedOpenIntent","close","closeAttempt","retainedFailure","cleanup","failureOrigin","recoverFailedClose","recoverForEntry","retryFailure","closeForEntry","keepsCurrentAttempt","closeFailure","recoveryOutcome","closeOutcome","closedOutcome","reportDetachedError","cleanupCompleted"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AttachmentReadinessController } from './attachment.js';
|
|
2
|
+
import type { AttachmentLifecycleController, AttachmentLifecycleMachine, AttachmentLifecycleState, LifecycleStatusStore } from './attachment-lifecycle-contract.js';
|
|
3
|
+
interface AttachmentLifecycleMailboxOptions<Key extends object, Value> {
|
|
4
|
+
readonly machine: AttachmentLifecycleMachine<Key, Value>;
|
|
5
|
+
readonly readiness: AttachmentReadinessController;
|
|
6
|
+
readonly state: AttachmentLifecycleState<Key, Value>;
|
|
7
|
+
readonly status: LifecycleStatusStore;
|
|
8
|
+
}
|
|
9
|
+
declare function createAttachmentLifecycleMailbox<Key extends object, Value>(options: AttachmentLifecycleMailboxOptions<Key, Value>): AttachmentLifecycleController<Key, Value>;
|
|
10
|
+
export { createAttachmentLifecycleMailbox };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{reportDetachedError as _}from"./attachment.js";import{attachmentLifecycleControllerBrand as ee,retiredAttachmentKey as te}from"./attachment-lifecycle-contract.js";import{closedOutcome as v,countCleanupHandles as ne,noop as a,createAttachmentRetirementHandle as P,selectRetirementKeys as re,toAttachmentDrainOutcome as ie,createIntentEntry as ce,readyOutcome as se,findJoinableEntry as C,settleIntentEntry as O,supersededOutcome as L}from"./attachment-lifecycle-helpers.js";function oe(T){const{machine:d,readiness:u,state:t,status:o}=T;let E=!1,m=!1;const $=async()=>{if(!m){m=!0;try{for(;t.activeEntry!==void 0;){const e=t.activeEntry;e.started=!0;let n;try{n=await d.reconcile(e)}catch(i){n=await d.recoverUnexpected(i)}O(e,n),t.activeEntry===e&&(t.activeEntry=t.queuedEntry,t.queuedEntry=void 0)}}finally{m=!1}}};function R(){E||m||(E=!0,queueMicrotask(()=>{E=!1,$().catch(_)}))}const F=()=>{const e=t.activeEntry;if(e===void 0||e.cancelled)return;e.cancelled=!0,e.intent=void 0,e.joinable=!1;const n=o.getSnapshot().kind;n==="opening"?d.beginLogicalClose("rollback"):n==="ready"&&d.beginLogicalClose("close")},H=e=>(t.activeEntry=e,o.getSnapshot().kind==="ready"&&(e.started=!0,d.beginLogicalClose("close")),R(),e.promise),x=e=>C(t.activeEntry,e)??C(t.queuedEntry,e),B=e=>(t.activeEntry!==void 0&&O(t.activeEntry,L),t.activeEntry=e,R(),e.promise),J=e=>(t.queuedEntry!==void 0&&O(t.queuedEntry,L),t.queuedEntry=e,F(),e.promise),M=e=>{const n=x(e);if(n!==void 0)return n.promise;const i=ce(e);return t.activeEntry===void 0?H(i):t.activeEntry.started?J(i):B(i)},U=e=>{if(!(e===null||t.currentAttempt===void 0)&&Object.is(t.currentAttempt.key,e.key))return se},G=e=>{if(t.activeEntry!==void 0)return;const n=o.getSnapshot();if(n.kind==="closed")return e===null?v:void 0;if(n.kind==="ready")return U(e)},I=e=>{if(e!==null){if(t.activeRetirement!==void 0)throw new TypeError(`Attachment lifecycle ${u.ref.id} is retiring and cannot accept a new generation.`);if(t.disposeRequested)throw new TypeError(`Attachment lifecycle ${u.ref.id} is disposing or disposed.`)}},y=e=>{var l;const n=(l=t.activeRetirement)==null?void 0:l.requestOutcome;if(e===null&&n!==void 0)return n;if(I(e),t.disposed)return Promise.resolve(v);const i=e===null?null:Object.freeze({key:e.key,signal:e.signal,value:e.value}),s=G(i);return s!==void 0?Promise.resolve(s):M(i)},p=e=>{const n=e==null?void 0:e.intent;return n==null?void 0:n.key},N=()=>{var n;const e=(n=t.currentAttempt)==null?void 0:n.key;return e===te?void 0:e},A=()=>p(t.queuedEntry)??p(t.activeEntry)??N(),Q=e=>{const n=p(t.queuedEntry)??p(t.activeEntry);return n!==void 0&&!Object.is(n,e)},V=e=>{var i,s;if(t.activeRetirement!==void 0)return((i=t.activeRetirement.targetKeys)==null?void 0:i.has(e))===!0;const n=A();return Object.is(n,e)||((s=t.currentAttempt)==null?void 0:s.originKeys.has(e))===!0},q=e=>{if(!V(e))throw new TypeError(`Attachment ${u.ref.id} does not own the expected key.`)};function g(){var K;if(t.activeRetirement!==void 0)return t.activeRetirement.handle;if(o.getSnapshot().kind==="closing"){const r=t.activeEntry,f=r===void 0?Promise.resolve():r.promise.then(a,a);return P({action:void 0,outcome:f.then(()=>g().drain())})}let n=a,i,s,l;const X=new Promise(r=>{n=r}),k=new Promise((r,f)=>{i=f,l=r});k.catch(a);const h={action:void 0,outcome:void 0},S=P(h),Y=A(),Z=re(Y,(K=t.currentAttempt)==null?void 0:K.originKeys),c={allowDrain:n,drainAllowed:!1,drainPermission:X,handle:S,requestOutcome:void 0,targetAttempt:t.currentAttempt,targetKeys:Z};let z=!1;const D=()=>{z||(z=!0,c.allowDrain=a,c.drainPermission=void 0,c.requestOutcome=void 0,c.targetAttempt=void 0,c.targetKeys=void 0,h.action=void 0,h.outcome=k,s=void 0,t.activeRetirement===c&&(t.activeRetirement=void 0))},w=()=>{if(!c.drainAllowed||s===void 0)return;const r=s;switch(D(),r.kind){case"failed":i(r.error);break;case"succeeded":l(r.outcome);break}};h.action=()=>{if(!c.drainAllowed){c.drainAllowed=!0;const r=c.allowDrain;c.allowDrain=a,r()}return w(),k},t.activeRetirement=c;let b;try{b=y(null)}catch(r){throw c.allowDrain(),D(),i(r),r}return c.requestOutcome=b,b.then(r=>{try{s=Object.freeze({kind:"succeeded",outcome:ie(r)})}catch(f){s=Object.freeze({error:f,kind:"failed"})}w()},r=>{s=Object.freeze({error:r,kind:"failed"}),w()}),S}const W=e=>{if(q(e),Q(e))throw new TypeError(`Attachment ${u.ref.id} is claimed by another key and cannot join a retirement.`);return g()},j=e=>{switch(e.kind){case"cancelled":case"committed":case"failed":return Object.freeze({kind:"recovered"});case"quarantined":return e;case"superseded":return Object.freeze({kind:"interrupted",outcome:"superseded"})}};return Object.freeze({assertRetirable:q,[ee]:!0,diagnostics(){return Object.freeze({activeIntent:t.activeEntry!==void 0,awaitingDrain:t.activeRetirement!==void 0&&!t.activeRetirement.drainAllowed,cleanupHandles:ne(t.currentAttempt),disposed:t.disposed,disposeRequested:t.disposeRequested,generation:t.generation,listeners:o.listenerCount(),queuedIntent:t.queuedEntry!==void 0,state:o.getSnapshot().kind})},dispose(){return t.disposeRequested=!0,t.disposed?Promise.resolve(v):t.activeEntry===void 0&&o.getSnapshot().kind==="closed"?(d.finishDisposal(),Promise.resolve(v)):y(null)},getSnapshot:o.getSnapshot,ref:u.ref,request:y,retire:g,retireExpected:W,retryClose(){const e=o.getSnapshot();return e.kind==="failed-close"?y(null).then(j):e.kind==="closing"&&e.phase==="retry"&&t.activeEntry!==void 0?t.activeEntry.promise.then(j):Promise.resolve(Object.freeze({kind:"not-needed",state:e.kind}))},subscribe:o.subscribe})}export{oe as createAttachmentLifecycleMailbox};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle-mailbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle-mailbox.js","sources":["../src/attachment-lifecycle-mailbox.ts"],"sourcesContent":["import { reportDetachedError } from './attachment';\nimport type { AttachmentReadinessController } from './attachment';\nimport { attachmentLifecycleControllerBrand, retiredAttachmentKey } from './attachment-lifecycle-contract';\nimport type {\n ActiveAttachmentRetirement,\n AttachmentIntentOutcome,\n AttachmentLifecycleController,\n AttachmentLifecycleIntent,\n AttachmentLifecycleMachine,\n AttachmentLifecycleState,\n AttachmentRetirement,\n AttachmentRetirementHandleState,\n AttachmentRetirementRequestResult,\n AttachmentRetryOutcome,\n IntentEntry,\n LifecycleStatusStore,\n} from './attachment-lifecycle-contract';\nimport {\n closedOutcome,\n countCleanupHandles,\n createAttachmentRetirementHandle,\n createIntentEntry,\n findJoinableEntry,\n noop,\n readyOutcome,\n selectRetirementKeys,\n settleIntentEntry,\n supersededOutcome,\n toAttachmentDrainOutcome,\n} from './attachment-lifecycle-helpers';\n\ninterface AttachmentLifecycleMailboxOptions<Key extends object, Value> {\n readonly machine: AttachmentLifecycleMachine<Key, Value>;\n readonly readiness: AttachmentReadinessController;\n readonly state: AttachmentLifecycleState<Key, Value>;\n readonly status: LifecycleStatusStore;\n}\n\nfunction createAttachmentLifecycleMailbox<Key extends object, Value>(\n options: AttachmentLifecycleMailboxOptions<Key, Value>,\n): AttachmentLifecycleController<Key, Value> {\n const { machine, readiness, state, status } = options;\n let driverScheduled = false;\n let driving = false;\n\n const drive = async (): Promise<void> => {\n if (driving) return;\n\n driving = true;\n\n try {\n while (state.activeEntry !== undefined) {\n const entry = state.activeEntry;\n entry.started = true;\n let outcome: AttachmentIntentOutcome;\n\n try {\n outcome = await machine.reconcile(entry);\n } catch (error) {\n outcome = await machine.recoverUnexpected(error);\n }\n\n settleIntentEntry(entry, outcome);\n\n if (state.activeEntry === entry) {\n state.activeEntry = state.queuedEntry;\n state.queuedEntry = undefined;\n }\n }\n } finally {\n driving = false;\n }\n };\n\n function scheduleDriver(): void {\n if (driverScheduled || driving) return;\n\n driverScheduled = true;\n queueMicrotask(() => {\n driverScheduled = false;\n drive().catch(reportDetachedError);\n });\n }\n\n const cancelActiveEntry = (): void => {\n const entry = state.activeEntry;\n\n if (entry === undefined || entry.cancelled) return;\n\n entry.cancelled = true;\n entry.intent = undefined;\n entry.joinable = false;\n const lifecycleState = status.getSnapshot().kind;\n\n if (lifecycleState === 'opening') machine.beginLogicalClose('rollback');\n else if (lifecycleState === 'ready') machine.beginLogicalClose('close');\n };\n\n const startEntry = (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome> => {\n state.activeEntry = entry;\n\n if (status.getSnapshot().kind === 'ready') {\n entry.started = true;\n machine.beginLogicalClose('close');\n }\n\n scheduleDriver();\n\n return entry.promise;\n };\n\n const findJoinedEntry = (intent: AttachmentLifecycleIntent<Key, Value> | null): IntentEntry<Key, Value> | undefined =>\n findJoinableEntry(state.activeEntry, intent) ?? findJoinableEntry(state.queuedEntry, intent);\n\n const replaceUnstartedEntry = (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome> => {\n if (state.activeEntry !== undefined) settleIntentEntry(state.activeEntry, supersededOutcome);\n\n state.activeEntry = entry;\n scheduleDriver();\n\n return entry.promise;\n };\n\n const queueLatestEntry = (entry: IntentEntry<Key, Value>): Promise<AttachmentIntentOutcome> => {\n if (state.queuedEntry !== undefined) settleIntentEntry(state.queuedEntry, supersededOutcome);\n\n state.queuedEntry = entry;\n cancelActiveEntry();\n\n return entry.promise;\n };\n\n const enqueue = (intent: AttachmentLifecycleIntent<Key, Value> | null): Promise<AttachmentIntentOutcome> => {\n const joinedEntry = findJoinedEntry(intent);\n\n if (joinedEntry !== undefined) return joinedEntry.promise;\n\n const entry = createIntentEntry(intent);\n\n if (state.activeEntry === undefined) return startEntry(entry);\n\n if (!state.activeEntry.started) return replaceUnstartedEntry(entry);\n\n return queueLatestEntry(entry);\n };\n\n const stableReadyOutcomeFor = (\n intent: AttachmentLifecycleIntent<Key, Value> | null,\n ): AttachmentIntentOutcome | undefined => {\n if (intent === null || state.currentAttempt === undefined) return undefined;\n\n if (Object.is(state.currentAttempt.key, intent.key)) return readyOutcome;\n\n return undefined;\n };\n\n const stableOutcomeFor = (\n intent: AttachmentLifecycleIntent<Key, Value> | null,\n ): AttachmentIntentOutcome | undefined => {\n if (state.activeEntry !== undefined) return undefined;\n\n const snapshot = status.getSnapshot();\n\n if (snapshot.kind === 'closed') {\n if (intent === null) return closedOutcome;\n\n return undefined;\n }\n\n if (snapshot.kind !== 'ready') return undefined;\n\n return stableReadyOutcomeFor(intent);\n };\n\n const assertRequestAccepted = (requestedIntent: AttachmentLifecycleIntent<Key, Value> | null): void => {\n if (requestedIntent === null) return;\n\n if (state.activeRetirement !== undefined) {\n throw new TypeError(`Attachment lifecycle ${readiness.ref.id} is retiring and cannot accept a new generation.`);\n }\n\n if (state.disposeRequested) {\n throw new TypeError(`Attachment lifecycle ${readiness.ref.id} is disposing or disposed.`);\n }\n };\n\n const request = (requestedIntent: AttachmentLifecycleIntent<Key, Value> | null): Promise<AttachmentIntentOutcome> => {\n const retirementRequest = state.activeRetirement?.requestOutcome;\n\n if (requestedIntent === null && retirementRequest !== undefined) return retirementRequest;\n\n assertRequestAccepted(requestedIntent);\n\n if (state.disposed) return Promise.resolve(closedOutcome);\n\n const intent =\n requestedIntent === null\n ? null\n : (Object.freeze({\n key: requestedIntent.key,\n signal: requestedIntent.signal,\n value: requestedIntent.value,\n }) as AttachmentLifecycleIntent<Key, Value>);\n const stableOutcome = stableOutcomeFor(intent);\n\n if (stableOutcome !== undefined) return Promise.resolve(stableOutcome);\n\n return enqueue(intent);\n };\n\n const liveIntentKey = (entry: IntentEntry<Key, Value> | undefined): Key | undefined => {\n const intent = entry?.intent;\n\n return intent === undefined || intent === null ? undefined : intent.key;\n };\n\n const currentAttemptKey = (): Key | undefined => {\n const key = state.currentAttempt?.key;\n\n return key === retiredAttachmentKey ? undefined : key;\n };\n\n const currentRetirementKey = (): Key | undefined => {\n return liveIntentKey(state.queuedEntry) ?? liveIntentKey(state.activeEntry) ?? currentAttemptKey();\n };\n\n /**\n * Whether a live intent is taking this lifecycle for someone else. A close driven by our own rollback has no such\n * intent and can be joined; a foreign key switch must still refuse the fence, or the owner would report a\n * retirement of something another generation now owns.\n */\n const claimedByOther = (expectedKey: Key): boolean => {\n const pending = liveIntentKey(state.queuedEntry) ?? liveIntentKey(state.activeEntry);\n\n return pending !== undefined && !Object.is(pending, expectedKey);\n };\n\n const ownsRetirementKey = (expectedKey: Key): boolean => {\n if (state.activeRetirement !== undefined) return state.activeRetirement.targetKeys?.has(expectedKey) === true;\n\n const retirementKey = currentRetirementKey();\n\n return Object.is(retirementKey, expectedKey) || state.currentAttempt?.originKeys.has(expectedKey) === true;\n };\n\n const assertRetirable = (expectedKey: Key): void => {\n if (!ownsRetirementKey(expectedKey)) {\n throw new TypeError(`Attachment ${readiness.ref.id} does not own the expected key.`);\n }\n };\n\n function retire(): AttachmentRetirement {\n if (state.activeRetirement !== undefined) return state.activeRetirement.handle;\n\n const snapshot = status.getSnapshot();\n\n // A close already in flight — the rollback of a failed open, or a retry — is not a reason to refuse a\n // coordinated retirement: the owner joins it. Waiting for that drain puts the lifecycle back into a workspace\n // state, and the ordinary retirement then reports whatever that state is, quarantine included.\n if (snapshot.kind === 'closing') {\n const draining = state.activeEntry;\n const settled = draining === undefined ? Promise.resolve() : draining.promise.then(noop, noop);\n\n return createAttachmentRetirementHandle({ action: undefined, outcome: settled.then(() => retire().drain()) });\n }\n\n let allowDrain = noop;\n let rejectOutcome!: (reason: unknown) => void;\n let requestedResult: AttachmentRetirementRequestResult | undefined;\n let resolveOutcome!: (outcome: Awaited<ReturnType<AttachmentRetirement['drain']>>) => void;\n const drainPermission = new Promise<void>(resolve => {\n allowDrain = resolve;\n });\n const retirementOutcome = new Promise<Awaited<ReturnType<AttachmentRetirement['drain']>>>((resolve, reject) => {\n rejectOutcome = reject;\n resolveOutcome = resolve;\n });\n // Supervise a possibly unobserved host-level failure without changing the Promise returned by drain().\n void retirementOutcome.catch(noop);\n const handleState: AttachmentRetirementHandleState = { action: undefined, outcome: undefined };\n const handle = createAttachmentRetirementHandle(handleState);\n const targetKey = currentRetirementKey();\n const targetKeys = selectRetirementKeys(targetKey, state.currentAttempt?.originKeys);\n const retirement: ActiveAttachmentRetirement<Key> = {\n allowDrain,\n drainAllowed: false,\n drainPermission,\n handle,\n requestOutcome: undefined,\n targetAttempt: state.currentAttempt,\n targetKeys,\n };\n let retirementFinalized = false;\n const finishRetirement = (): void => {\n if (retirementFinalized) return;\n\n retirementFinalized = true;\n retirement.allowDrain = noop;\n retirement.drainPermission = undefined;\n retirement.requestOutcome = undefined;\n retirement.targetAttempt = undefined;\n retirement.targetKeys = undefined;\n handleState.action = undefined;\n handleState.outcome = retirementOutcome;\n requestedResult = undefined;\n\n if (state.activeRetirement === retirement) state.activeRetirement = undefined;\n };\n const settleRetirement = (): void => {\n if (!retirement.drainAllowed || requestedResult === undefined) return;\n\n const result = requestedResult;\n\n finishRetirement();\n\n switch (result.kind) {\n case 'failed':\n rejectOutcome(result.error);\n break;\n case 'succeeded':\n resolveOutcome(result.outcome);\n break;\n }\n };\n handleState.action = () => {\n if (!retirement.drainAllowed) {\n retirement.drainAllowed = true;\n const allow = retirement.allowDrain;\n retirement.allowDrain = noop;\n allow();\n }\n\n settleRetirement();\n\n return retirementOutcome;\n };\n state.activeRetirement = retirement;\n\n let requestedOutcome: Promise<AttachmentIntentOutcome>;\n\n try {\n requestedOutcome = request(null);\n } catch (error) {\n retirement.allowDrain();\n finishRetirement();\n rejectOutcome(error);\n\n throw error;\n }\n retirement.requestOutcome = requestedOutcome;\n\n void requestedOutcome.then(\n outcome => {\n try {\n requestedResult = Object.freeze({ kind: 'succeeded' as const, outcome: toAttachmentDrainOutcome(outcome) });\n } catch (error) {\n requestedResult = Object.freeze({ error, kind: 'failed' as const });\n }\n\n settleRetirement();\n },\n (error: unknown) => {\n requestedResult = Object.freeze({ error, kind: 'failed' as const });\n settleRetirement();\n },\n );\n\n return handle;\n }\n\n const retireExpected = (expectedKey: Key): AttachmentRetirement => {\n assertRetirable(expectedKey);\n\n // Joining a close is only safe while the close is ours: a live intent for another key means this lifecycle is\n // being taken over, and the owner must hear about that instead of reporting a retirement of someone else's\n // generation.\n if (claimedByOther(expectedKey)) {\n throw new TypeError(`Attachment ${readiness.ref.id} is claimed by another key and cannot join a retirement.`);\n }\n\n return retire();\n };\n\n const mapRetryOutcome = (outcome: AttachmentIntentOutcome): AttachmentRetryOutcome => {\n switch (outcome.kind) {\n case 'cancelled':\n case 'committed':\n case 'failed':\n return Object.freeze({ kind: 'recovered' as const });\n case 'quarantined':\n return outcome;\n case 'superseded':\n return Object.freeze({ kind: 'interrupted' as const, outcome: 'superseded' as const });\n }\n };\n\n return Object.freeze({\n assertRetirable,\n [attachmentLifecycleControllerBrand]: true as const,\n diagnostics() {\n return Object.freeze({\n activeIntent: state.activeEntry !== undefined,\n awaitingDrain: state.activeRetirement !== undefined && !state.activeRetirement.drainAllowed,\n cleanupHandles: countCleanupHandles(state.currentAttempt),\n disposed: state.disposed,\n disposeRequested: state.disposeRequested,\n generation: state.generation,\n listeners: status.listenerCount(),\n queuedIntent: state.queuedEntry !== undefined,\n state: status.getSnapshot().kind,\n });\n },\n dispose(): Promise<AttachmentIntentOutcome> {\n state.disposeRequested = true;\n\n if (state.disposed) return Promise.resolve(closedOutcome);\n\n if (state.activeEntry === undefined && status.getSnapshot().kind === 'closed') {\n machine.finishDisposal();\n\n return Promise.resolve(closedOutcome);\n }\n\n return request(null);\n },\n getSnapshot: status.getSnapshot,\n ref: readiness.ref,\n request,\n retire,\n retireExpected,\n retryClose(): Promise<AttachmentRetryOutcome> {\n const snapshot = status.getSnapshot();\n\n if (snapshot.kind === 'failed-close') return request(null).then(mapRetryOutcome);\n\n if (snapshot.kind === 'closing' && snapshot.phase === 'retry' && state.activeEntry !== undefined) {\n return state.activeEntry.promise.then(mapRetryOutcome);\n }\n\n return Promise.resolve(Object.freeze({ kind: 'not-needed' as const, state: snapshot.kind }));\n },\n subscribe: status.subscribe,\n });\n}\n\nexport { createAttachmentLifecycleMailbox };\n"],"names":["createAttachmentLifecycleMailbox","options","machine","readiness","state","status","driverScheduled","driving","drive","entry","outcome","error","settleIntentEntry","scheduleDriver","reportDetachedError","cancelActiveEntry","lifecycleState","startEntry","findJoinedEntry","intent","findJoinableEntry","replaceUnstartedEntry","supersededOutcome","queueLatestEntry","enqueue","joinedEntry","createIntentEntry","stableReadyOutcomeFor","readyOutcome","stableOutcomeFor","snapshot","closedOutcome","assertRequestAccepted","requestedIntent","request","retirementRequest","_a","stableOutcome","liveIntentKey","currentAttemptKey","key","retiredAttachmentKey","currentRetirementKey","claimedByOther","expectedKey","pending","ownsRetirementKey","retirementKey","_b","assertRetirable","retire","draining","settled","noop","createAttachmentRetirementHandle","allowDrain","rejectOutcome","requestedResult","resolveOutcome","drainPermission","resolve","retirementOutcome","reject","handleState","handle","targetKey","targetKeys","selectRetirementKeys","retirement","retirementFinalized","finishRetirement","settleRetirement","result","allow","requestedOutcome","toAttachmentDrainOutcome","retireExpected","mapRetryOutcome","attachmentLifecycleControllerBrand","countCleanupHandles"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AttachmentAttempt, OpenStepCoordinator } from './attachment-lifecycle-contract.js';
|
|
2
|
+
declare function createOpenStepCoordinator<Key extends object>(attempt: AttachmentAttempt<Key>, signal: AbortSignal, onFailure: () => void, shouldRecordFailure: () => boolean): OpenStepCoordinator;
|
|
3
|
+
export { createOpenStepCoordinator };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{throwIfSignalAborted as u}from"./abort-compat.js";import{openingFailure as P,noop as v}from"./attachment-lifecycle-helpers.js";import{settleGuardedResult as E}from"./call-target-result.js";function F(t,e){if(e)throw new TypeError("Cannot register an attachment step after open settled.");u(t)}function b(t,e,r,n){if(typeof e!="string"||e.length===0||n.has(e))throw new TypeError(`Attachment step id ${e} is empty, reserved or duplicated.`);if(typeof t!="function"||typeof r!="function")throw new TypeError(`Attachment step ${e} requires run and cleanup callbacks.`)}function j(t,e){let r;try{u(e),r=t()}catch(n){r=Promise.reject(n)}try{return Promise.resolve(E(r,{assertCurrent:()=>u(e),waitForPhysicalSettlement:!0}))}catch(n){return Promise.reject(n)}}function q(t,e,r,n){const f=new Set(["attachment.close"]);let c,a=0,d=!1,p=v,l=!1;const g=new Promise(o=>{p=o}),h=(o,s)=>{c!==void 0||!n()||(c=P(o,s),r())},m=()=>{!l||a!==0||d||(d=!0,p(),p=v)},y=()=>{a-=1,m()};return Object.freeze({fail:h,async firstFailure(){return await g,c},seal(){l=!0,t.acceptingSteps=!1,m()},step(o){F(e,l||!t.acceptingSteps);const{cleanup:s,id:i,run:w}=o;b(s,i,w,f),f.add(i),t.cleanups.push({cleanup:s,id:i}),a+=1;const S=j(w,e);return S.then(()=>y(),O=>{try{h(i,O)}finally{y()}}),S}})}export{q as createOpenStepCoordinator};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle-open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle-open.js","sources":["../src/attachment-lifecycle-open.ts"],"sourcesContent":["import { throwIfSignalAborted } from './abort-compat';\nimport type {\n AttachmentAttempt,\n AttachmentOpeningFailure,\n AttachmentOpenStep,\n Awaitable,\n OpenStepCoordinator,\n} from './attachment-lifecycle-contract';\nimport { noop, openingFailure } from './attachment-lifecycle-helpers';\nimport { settleGuardedResult } from './call-target';\n\nfunction assertOpenStepEnrollment(signal: AbortSignal, sealed: boolean): void {\n if (sealed) throw new TypeError('Cannot register an attachment step after open settled.');\n\n throwIfSignalAborted(signal);\n}\n\nfunction assertOpenStepDefinition<Result>(\n cleanup: AttachmentOpenStep<Result>['cleanup'],\n id: AttachmentOpenStep<Result>['id'],\n run: AttachmentOpenStep<Result>['run'],\n ids: Set<string>,\n): void {\n if (typeof id !== 'string' || id.length === 0 || ids.has(id)) {\n throw new TypeError(`Attachment step id ${id} is empty, reserved or duplicated.`);\n }\n\n if (typeof cleanup !== 'function' || typeof run !== 'function') {\n throw new TypeError(`Attachment step ${id} requires run and cleanup callbacks.`);\n }\n}\n\nfunction invokeOpenStep<Result>(run: () => Awaitable<Result>, signal: AbortSignal): Promise<Result> {\n let result: Awaitable<Result>;\n\n try {\n throwIfSignalAborted(signal);\n result = run();\n } catch (error) {\n result = Promise.reject(error);\n }\n\n try {\n return Promise.resolve(\n settleGuardedResult(result, {\n assertCurrent: () => throwIfSignalAborted(signal),\n waitForPhysicalSettlement: true,\n }),\n );\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\nfunction createOpenStepCoordinator<Key extends object>(\n attempt: AttachmentAttempt<Key>,\n signal: AbortSignal,\n onFailure: () => void,\n shouldRecordFailure: () => boolean,\n): OpenStepCoordinator {\n const ids = new Set<string>(['attachment.close']);\n let firstFailure: AttachmentOpeningFailure | undefined;\n let pendingSteps = 0;\n let quiescenceResolved = false;\n let resolveQuiescence = noop;\n let sealed = false;\n const quiescence = new Promise<void>(resolve => {\n resolveQuiescence = resolve;\n });\n const fail = (id: string, error: unknown): void => {\n if (firstFailure !== undefined || !shouldRecordFailure()) return;\n\n firstFailure = openingFailure(id, error);\n onFailure();\n };\n const resolveIfQuiescent = (): void => {\n if (!sealed || pendingSteps !== 0 || quiescenceResolved) return;\n\n quiescenceResolved = true;\n resolveQuiescence();\n resolveQuiescence = noop;\n };\n const finishStep = (): void => {\n pendingSteps -= 1;\n\n resolveIfQuiescent();\n };\n\n return Object.freeze({\n fail,\n async firstFailure() {\n await quiescence;\n\n return firstFailure;\n },\n seal(): void {\n sealed = true;\n attempt.acceptingSteps = false;\n resolveIfQuiescent();\n },\n step<Result>(definition: AttachmentOpenStep<Result>): Promise<Result> {\n assertOpenStepEnrollment(signal, sealed || !attempt.acceptingSteps);\n const { cleanup, id, run } = definition;\n assertOpenStepDefinition(cleanup, id, run, ids);\n ids.add(id);\n attempt.cleanups.push({ cleanup, id });\n pendingSteps += 1;\n const promise = invokeOpenStep(run, signal);\n void promise.then(\n () => finishStep(),\n (error: unknown) => {\n try {\n fail(id, error);\n } finally {\n finishStep();\n }\n },\n );\n\n return promise;\n },\n });\n}\n\nexport { createOpenStepCoordinator };\n"],"names":["assertOpenStepEnrollment","signal","sealed","throwIfSignalAborted","assertOpenStepDefinition","cleanup","id","run","ids","invokeOpenStep","result","error","settleGuardedResult","createOpenStepCoordinator","attempt","onFailure","shouldRecordFailure","firstFailure","pendingSteps","quiescenceResolved","resolveQuiescence","noop","quiescence","resolve","fail","openingFailure","resolveIfQuiescent","finishStep","definition","promise"],"mappings":"oMAWA,SAASA,EAAyBC,EAAqBC,EAAe,CACpE,GAAIA,EAAQ,MAAM,IAAI,UAAU,wDAAwD,EAExFC,EAAqBF,CAAM,CAC7B,CAEA,SAASG,EACPC,EACAC,EACAC,EACAC,EAAgB,CAEhB,GAAI,OAAOF,GAAO,UAAYA,EAAG,SAAW,GAAKE,EAAI,IAAIF,CAAE,EACzD,MAAM,IAAI,UAAU,sBAAsBA,CAAE,oCAAoC,EAGlF,GAAI,OAAOD,GAAY,YAAc,OAAOE,GAAQ,WAClD,MAAM,IAAI,UAAU,mBAAmBD,CAAE,sCAAsC,CAEnF,CAEA,SAASG,EAAuBF,EAA8BN,EAAmB,CAC/E,IAAIS,EAEJ,GAAI,CACFP,EAAqBF,CAAM,EAC3BS,EAASH,EAAG,CACd,OAASI,EAAO,CACdD,EAAS,QAAQ,OAAOC,CAAK,CAC/B,CAEA,GAAI,CACF,OAAO,QAAQ,QACbC,EAAoBF,EAAQ,CAC1B,cAAe,IAAMP,EAAqBF,CAAM,EAChD,0BAA2B,EAC5B,CAAA,CAAC,CAEN,OAASU,EAAO,CACd,OAAO,QAAQ,OAAOA,CAAK,CAC7B,CACF,CAEA,SAASE,EACPC,EACAb,EACAc,EACAC,EAAkC,CAElC,MAAMR,EAAM,IAAI,IAAY,CAAC,kBAAkB,CAAC,EAChD,IAAIS,EACAC,EAAe,EACfC,EAAqB,GACrBC,EAAoBC,EACpBnB,EAAS,GACb,MAAMoB,EAAa,IAAI,QAAcC,GAAU,CAC7CH,EAAoBG,CACtB,CAAC,EACKC,EAAO,CAAClB,EAAYK,IAAwB,CAC5CM,IAAiB,QAAa,CAACD,EAAmB,IAEtDC,EAAeQ,EAAenB,EAAIK,CAAK,EACvCI,EAAS,EACX,EACMW,EAAqB,IAAW,CAChC,CAACxB,GAAUgB,IAAiB,GAAKC,IAErCA,EAAqB,GACrBC,EAAiB,EACjBA,EAAoBC,EACtB,EACMM,EAAa,IAAW,CAC5BT,GAAgB,EAEhBQ,EAAkB,CACpB,EAEA,OAAO,OAAO,OAAO,CACnB,KAAAF,EACA,MAAM,cAAY,CAChB,aAAMF,EAECL,CACT,EACA,MAAI,CACFf,EAAS,GACTY,EAAQ,eAAiB,GACzBY,EAAkB,CACpB,EACA,KAAaE,EAAsC,CACjD5B,EAAyBC,EAAQC,GAAU,CAACY,EAAQ,cAAc,EAClE,KAAM,CAAE,QAAAT,EAAS,GAAAC,EAAI,IAAAC,CAAG,EAAKqB,EAC7BxB,EAAyBC,EAASC,EAAIC,EAAKC,CAAG,EAC9CA,EAAI,IAAIF,CAAE,EACVQ,EAAQ,SAAS,KAAK,CAAE,QAAAT,EAAS,GAAAC,CAAE,CAAE,EACrCY,GAAgB,EAChB,MAAMW,EAAUpB,EAAeF,EAAKN,CAAM,EAC1C,OAAK4B,EAAQ,KACX,IAAMF,EAAU,EACfhB,GAAkB,CACjB,GAAI,CACFa,EAAKlB,EAAIK,CAAK,CAChB,SACEgB,EAAU,CACZ,CACF,CAAC,EAGIE,CACT,CACD,CAAA,CACH"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AttachmentCleanupContext, AttachmentCleanupFailure, AttachmentCleanupOutcome, AttachmentDrainOutcome, AttachmentFailureRecord, AttachmentIntentOutcome, AttachmentLifecycleController, AttachmentLifecycleDiagnostics, AttachmentLifecycleIntent, AttachmentLifecycleOptions, AttachmentLifecycleSnapshot, AttachmentOpenContext, AttachmentOpenStep, AttachmentRetirement, AttachmentRetryOutcome } from './attachment-lifecycle-contract.js';
|
|
2
|
+
declare function createAttachmentLifecycleController<Key extends object, Value>(options: AttachmentLifecycleOptions<Value>): AttachmentLifecycleController<Key, Value>;
|
|
3
|
+
export { createAttachmentLifecycleController };
|
|
4
|
+
export type { AttachmentCleanupContext, AttachmentCleanupFailure, AttachmentCleanupOutcome, AttachmentDrainOutcome, AttachmentFailureRecord, AttachmentIntentOutcome, AttachmentLifecycleController, AttachmentLifecycleDiagnostics, AttachmentLifecycleIntent, AttachmentLifecycleOptions, AttachmentLifecycleSnapshot, AttachmentOpenContext, AttachmentOpenStep, AttachmentRetirement, AttachmentRetryOutcome, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createAttachmentReadinessController as s}from"./attachment.js";import{createStatusStore as f}from"./attachment-lifecycle-helpers.js";import{createAttachmentLifecycleMachine as d}from"./attachment-lifecycle-machine.js";import{createAttachmentLifecycleMailbox as l}from"./attachment-lifecycle-mailbox.js";function m(r){const{close:e,id:i,open:t}=r;if(typeof t!="function"||typeof e!="function")throw new TypeError("Attachment lifecycle requires open and close callbacks.");const n=s({id:i}),c={activeEntry:void 0,activeRetirement:void 0,currentAttempt:void 0,disposed:!1,disposeRequested:!1,generation:0,queuedEntry:void 0},o=f(),a=d({close:e,open:t,readiness:n,state:c,status:o});return l({machine:a,readiness:n,state:c,status:o})}export{m as createAttachmentLifecycleController};
|
|
2
|
+
//# sourceMappingURL=attachment-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-lifecycle.js","sources":["../src/attachment-lifecycle.ts"],"sourcesContent":["import { createAttachmentReadinessController } from './attachment';\nimport type {\n AttachmentCleanupContext,\n AttachmentCleanupFailure,\n AttachmentCleanupOutcome,\n AttachmentDrainOutcome,\n AttachmentFailureRecord,\n AttachmentIntentOutcome,\n AttachmentLifecycleController,\n AttachmentLifecycleDiagnostics,\n AttachmentLifecycleIntent,\n AttachmentLifecycleOptions,\n AttachmentLifecycleSnapshot,\n AttachmentLifecycleState,\n AttachmentOpenContext,\n AttachmentOpenStep,\n AttachmentRetirement,\n AttachmentRetryOutcome,\n} from './attachment-lifecycle-contract';\nimport { createStatusStore } from './attachment-lifecycle-helpers';\nimport { createAttachmentLifecycleMachine } from './attachment-lifecycle-machine';\nimport { createAttachmentLifecycleMailbox } from './attachment-lifecycle-mailbox';\n\nfunction createAttachmentLifecycleController<Key extends object, Value>(\n options: AttachmentLifecycleOptions<Value>,\n): AttachmentLifecycleController<Key, Value> {\n const { close, id, open } = options;\n\n if (typeof open !== 'function' || typeof close !== 'function') {\n throw new TypeError('Attachment lifecycle requires open and close callbacks.');\n }\n\n const readiness = createAttachmentReadinessController({ id });\n const state: AttachmentLifecycleState<Key, Value> = {\n activeEntry: undefined,\n activeRetirement: undefined,\n currentAttempt: undefined,\n disposed: false,\n disposeRequested: false,\n generation: 0,\n queuedEntry: undefined,\n };\n const status = createStatusStore();\n const machine = createAttachmentLifecycleMachine({ close, open, readiness, state, status });\n\n return createAttachmentLifecycleMailbox({ machine, readiness, state, status });\n}\n\nexport { createAttachmentLifecycleController };\nexport type {\n AttachmentCleanupContext,\n AttachmentCleanupFailure,\n AttachmentCleanupOutcome,\n AttachmentDrainOutcome,\n AttachmentFailureRecord,\n AttachmentIntentOutcome,\n AttachmentLifecycleController,\n AttachmentLifecycleDiagnostics,\n AttachmentLifecycleIntent,\n AttachmentLifecycleOptions,\n AttachmentLifecycleSnapshot,\n AttachmentOpenContext,\n AttachmentOpenStep,\n AttachmentRetirement,\n AttachmentRetryOutcome,\n};\n"],"names":["createAttachmentLifecycleController","options","close","id","open","readiness","createAttachmentReadinessController","state","status","createStatusStore","machine","createAttachmentLifecycleMachine","createAttachmentLifecycleMailbox"],"mappings":"sTAuBA,SAASA,EACPC,EAA0C,CAE1C,KAAM,CAAE,MAAAC,EAAO,GAAAC,EAAI,KAAAC,CAAI,EAAKH,EAE5B,GAAI,OAAOG,GAAS,YAAc,OAAOF,GAAU,WACjD,MAAM,IAAI,UAAU,yDAAyD,EAG/E,MAAMG,EAAYC,EAAoC,CAAE,GAAAH,EAAI,EACtDI,EAA8C,CAClD,YAAa,OACb,iBAAkB,OAClB,eAAgB,OAChB,SAAU,GACV,iBAAkB,GAClB,WAAY,EACZ,YAAa,QAETC,EAASC,EAAiB,EAC1BC,EAAUC,EAAiC,CAAE,MAAAT,EAAO,KAAAE,EAAM,UAAAC,EAAW,MAAAE,EAAO,OAAAC,EAAQ,EAE1F,OAAOI,EAAiC,CAAE,QAAAF,EAAS,UAAAL,EAAW,MAAAE,EAAO,OAAAC,CAAM,CAAE,CAC/E"}
|