@dxos/context 0.8.4-main.dedc0f3 → 0.8.4-main.e250131250
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +163 -297
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +163 -297
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/context.d.ts +4 -3
- package/dist/types/src/context.d.ts.map +1 -1
- package/dist/types/src/resource.d.ts +17 -3
- package/dist/types/src/resource.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -6
- package/src/context.ts +17 -4
- package/src/resource.ts +33 -9
|
@@ -14,59 +14,6 @@ var ContextDisposedError = class extends Error {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/context.ts
|
|
17
|
-
function _check_private_redeclaration(obj, privateCollection) {
|
|
18
|
-
if (privateCollection.has(obj)) {
|
|
19
|
-
throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
23
|
-
if (descriptor.get) {
|
|
24
|
-
return descriptor.get.call(receiver);
|
|
25
|
-
}
|
|
26
|
-
return descriptor.value;
|
|
27
|
-
}
|
|
28
|
-
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
29
|
-
if (descriptor.set) {
|
|
30
|
-
descriptor.set.call(receiver, value);
|
|
31
|
-
} else {
|
|
32
|
-
if (!descriptor.writable) {
|
|
33
|
-
throw new TypeError("attempted to set read only private field");
|
|
34
|
-
}
|
|
35
|
-
descriptor.value = value;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
39
|
-
if (!privateMap.has(receiver)) {
|
|
40
|
-
throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
41
|
-
}
|
|
42
|
-
return privateMap.get(receiver);
|
|
43
|
-
}
|
|
44
|
-
function _class_private_field_get(receiver, privateMap) {
|
|
45
|
-
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
46
|
-
return _class_apply_descriptor_get(receiver, descriptor);
|
|
47
|
-
}
|
|
48
|
-
function _class_private_field_init(obj, privateMap, value) {
|
|
49
|
-
_check_private_redeclaration(obj, privateMap);
|
|
50
|
-
privateMap.set(obj, value);
|
|
51
|
-
}
|
|
52
|
-
function _class_private_field_set(receiver, privateMap, value) {
|
|
53
|
-
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
54
|
-
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
function _define_property(obj, key, value) {
|
|
58
|
-
if (key in obj) {
|
|
59
|
-
Object.defineProperty(obj, key, {
|
|
60
|
-
value,
|
|
61
|
-
enumerable: true,
|
|
62
|
-
configurable: true,
|
|
63
|
-
writable: true
|
|
64
|
-
});
|
|
65
|
-
} else {
|
|
66
|
-
obj[key] = value;
|
|
67
|
-
}
|
|
68
|
-
return obj;
|
|
69
|
-
}
|
|
70
17
|
function _ts_decorate(decorators, target, key, desc) {
|
|
71
18
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
72
19
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -85,25 +32,51 @@ var DEFAULT_ERROR_HANDLER = (error, ctx) => {
|
|
|
85
32
|
};
|
|
86
33
|
var CONTEXT_FLAG_IS_DISPOSED = 1 << 0;
|
|
87
34
|
var CONTEXT_FLAG_LEAK_DETECTED = 1 << 1;
|
|
88
|
-
var _disposeCallbacks = /* @__PURE__ */ new WeakMap();
|
|
89
|
-
var _name = /* @__PURE__ */ new WeakMap();
|
|
90
|
-
var _parent = /* @__PURE__ */ new WeakMap();
|
|
91
|
-
var _attributes = /* @__PURE__ */ new WeakMap();
|
|
92
|
-
var _onError = /* @__PURE__ */ new WeakMap();
|
|
93
|
-
var _flags = /* @__PURE__ */ new WeakMap();
|
|
94
|
-
var _disposePromise = /* @__PURE__ */ new WeakMap();
|
|
95
|
-
var _isDisposed = /* @__PURE__ */ new WeakMap();
|
|
96
|
-
var _leakDetected = /* @__PURE__ */ new WeakMap();
|
|
97
|
-
var _inspect_custom = inspect.custom;
|
|
98
35
|
var Context = class _Context {
|
|
99
36
|
static default() {
|
|
100
37
|
return new _Context();
|
|
101
38
|
}
|
|
39
|
+
#disposeCallbacks = [];
|
|
40
|
+
#name = void 0;
|
|
41
|
+
#parent = void 0;
|
|
42
|
+
#attributes;
|
|
43
|
+
#onError;
|
|
44
|
+
#flags = 0;
|
|
45
|
+
#disposePromise = void 0;
|
|
46
|
+
#signal = void 0;
|
|
47
|
+
maxSafeDisposeCallbacks = MAX_SAFE_DISPOSE_CALLBACKS;
|
|
48
|
+
constructor(params = {}, callMeta) {
|
|
49
|
+
this.#name = getContextName(params, callMeta);
|
|
50
|
+
this.#parent = params.parent;
|
|
51
|
+
this.#attributes = params.attributes ?? {};
|
|
52
|
+
this.#onError = params.onError ?? DEFAULT_ERROR_HANDLER;
|
|
53
|
+
}
|
|
54
|
+
get #isDisposed() {
|
|
55
|
+
return !!(this.#flags & CONTEXT_FLAG_IS_DISPOSED);
|
|
56
|
+
}
|
|
57
|
+
set #isDisposed(value) {
|
|
58
|
+
this.#flags = value ? this.#flags | CONTEXT_FLAG_IS_DISPOSED : this.#flags & ~CONTEXT_FLAG_IS_DISPOSED;
|
|
59
|
+
}
|
|
60
|
+
get #leakDetected() {
|
|
61
|
+
return !!(this.#flags & CONTEXT_FLAG_LEAK_DETECTED);
|
|
62
|
+
}
|
|
63
|
+
set #leakDetected(value) {
|
|
64
|
+
this.#flags = value ? this.#flags | CONTEXT_FLAG_LEAK_DETECTED : this.#flags & ~CONTEXT_FLAG_LEAK_DETECTED;
|
|
65
|
+
}
|
|
102
66
|
get disposed() {
|
|
103
|
-
return
|
|
67
|
+
return this.#isDisposed;
|
|
104
68
|
}
|
|
105
69
|
get disposeCallbacksLength() {
|
|
106
|
-
return
|
|
70
|
+
return this.#disposeCallbacks.length;
|
|
71
|
+
}
|
|
72
|
+
get signal() {
|
|
73
|
+
if (this.#signal) {
|
|
74
|
+
return this.#signal;
|
|
75
|
+
}
|
|
76
|
+
const controller = new AbortController();
|
|
77
|
+
this.#signal = controller.signal;
|
|
78
|
+
this.onDispose(() => controller.abort());
|
|
79
|
+
return this.#signal;
|
|
107
80
|
}
|
|
108
81
|
/**
|
|
109
82
|
* Schedules a callback to run when the context is disposed.
|
|
@@ -115,41 +88,41 @@ var Context = class _Context {
|
|
|
115
88
|
* @returns A function that can be used to remove the callback from the dispose list.
|
|
116
89
|
*/
|
|
117
90
|
onDispose(callback) {
|
|
118
|
-
if (
|
|
91
|
+
if (this.#isDisposed) {
|
|
119
92
|
void (async () => {
|
|
120
93
|
try {
|
|
121
94
|
await callback();
|
|
122
95
|
} catch (error) {
|
|
123
96
|
log.catch(error, {
|
|
124
|
-
context:
|
|
97
|
+
context: this.#name
|
|
125
98
|
}, {
|
|
126
99
|
F: __dxlog_file,
|
|
127
|
-
L:
|
|
100
|
+
L: 131,
|
|
128
101
|
S: this,
|
|
129
102
|
C: (f, a) => f(...a)
|
|
130
103
|
});
|
|
131
104
|
}
|
|
132
105
|
})();
|
|
133
106
|
}
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
107
|
+
this.#disposeCallbacks.push(callback);
|
|
108
|
+
if (this.#disposeCallbacks.length > this.maxSafeDisposeCallbacks && !this.#leakDetected) {
|
|
109
|
+
this.#leakDetected = true;
|
|
137
110
|
const callSite = new StackTrace().getStackArray(1)[0].trim();
|
|
138
111
|
log.warn("Context has a large number of dispose callbacks (this might be a memory leak).", {
|
|
139
|
-
context:
|
|
112
|
+
context: this.#name,
|
|
140
113
|
callSite,
|
|
141
|
-
count:
|
|
114
|
+
count: this.#disposeCallbacks.length
|
|
142
115
|
}, {
|
|
143
116
|
F: __dxlog_file,
|
|
144
|
-
L:
|
|
117
|
+
L: 140,
|
|
145
118
|
S: this,
|
|
146
119
|
C: (f, a) => f(...a)
|
|
147
120
|
});
|
|
148
121
|
}
|
|
149
122
|
return () => {
|
|
150
|
-
const index =
|
|
123
|
+
const index = this.#disposeCallbacks.indexOf(callback);
|
|
151
124
|
if (index !== -1) {
|
|
152
|
-
|
|
125
|
+
this.#disposeCallbacks.splice(index, 1);
|
|
153
126
|
}
|
|
154
127
|
};
|
|
155
128
|
}
|
|
@@ -162,24 +135,24 @@ var Context = class _Context {
|
|
|
162
135
|
* @returns true if there were no errors during the dispose process.
|
|
163
136
|
*/
|
|
164
137
|
async dispose(throwOnError = false) {
|
|
165
|
-
if (
|
|
166
|
-
return
|
|
138
|
+
if (this.#disposePromise) {
|
|
139
|
+
return this.#disposePromise;
|
|
167
140
|
}
|
|
168
|
-
|
|
141
|
+
this.#isDisposed = true;
|
|
169
142
|
let resolveDispose;
|
|
170
143
|
const promise = new Promise((resolve) => {
|
|
171
144
|
resolveDispose = resolve;
|
|
172
145
|
});
|
|
173
|
-
|
|
174
|
-
const callbacks = Array.from(
|
|
175
|
-
|
|
146
|
+
this.#disposePromise = promise;
|
|
147
|
+
const callbacks = Array.from(this.#disposeCallbacks).reverse();
|
|
148
|
+
this.#disposeCallbacks.length = 0;
|
|
176
149
|
if (DEBUG_LOG_DISPOSE) {
|
|
177
150
|
log("disposing", {
|
|
178
|
-
context:
|
|
151
|
+
context: this.#name,
|
|
179
152
|
count: callbacks.length
|
|
180
153
|
}, {
|
|
181
154
|
F: __dxlog_file,
|
|
182
|
-
L:
|
|
155
|
+
L: 185,
|
|
183
156
|
S: this,
|
|
184
157
|
C: (f, a) => f(...a)
|
|
185
158
|
});
|
|
@@ -197,12 +170,12 @@ var Context = class _Context {
|
|
|
197
170
|
errors.push(err);
|
|
198
171
|
} else {
|
|
199
172
|
log.catch(err, {
|
|
200
|
-
context:
|
|
173
|
+
context: this.#name,
|
|
201
174
|
callback: i,
|
|
202
175
|
count: callbacks.length
|
|
203
176
|
}, {
|
|
204
177
|
F: __dxlog_file,
|
|
205
|
-
L:
|
|
178
|
+
L: 200,
|
|
206
179
|
S: this,
|
|
207
180
|
C: (f, a) => f(...a)
|
|
208
181
|
});
|
|
@@ -215,10 +188,10 @@ var Context = class _Context {
|
|
|
215
188
|
resolveDispose(clean);
|
|
216
189
|
if (DEBUG_LOG_DISPOSE) {
|
|
217
190
|
log("disposed", {
|
|
218
|
-
context:
|
|
191
|
+
context: this.#name
|
|
219
192
|
}, {
|
|
220
193
|
F: __dxlog_file,
|
|
221
|
-
L:
|
|
194
|
+
L: 211,
|
|
222
195
|
S: this,
|
|
223
196
|
C: (f, a) => f(...a)
|
|
224
197
|
});
|
|
@@ -231,17 +204,18 @@ var Context = class _Context {
|
|
|
231
204
|
* IF the error handler is not set, the error will dispose the context and cause an unhandled rejection.
|
|
232
205
|
*/
|
|
233
206
|
raise(error) {
|
|
234
|
-
if (
|
|
207
|
+
if (this.#isDisposed) {
|
|
235
208
|
return;
|
|
236
209
|
}
|
|
237
210
|
try {
|
|
238
|
-
|
|
211
|
+
this.#onError(error, this);
|
|
239
212
|
} catch (err) {
|
|
240
213
|
void Promise.reject(err);
|
|
241
214
|
}
|
|
242
215
|
}
|
|
243
216
|
derive({ onError, attributes } = {}) {
|
|
244
217
|
const newCtx = new _Context({
|
|
218
|
+
parent: this,
|
|
245
219
|
// TODO(dmaretskyi): Optimize to not require allocating a new closure for every context.
|
|
246
220
|
onError: async (error) => {
|
|
247
221
|
if (!onError) {
|
|
@@ -261,78 +235,23 @@ var Context = class _Context {
|
|
|
261
235
|
return newCtx;
|
|
262
236
|
}
|
|
263
237
|
getAttribute(key) {
|
|
264
|
-
if (key in
|
|
265
|
-
return
|
|
238
|
+
if (key in this.#attributes) {
|
|
239
|
+
return this.#attributes[key];
|
|
266
240
|
}
|
|
267
|
-
if (
|
|
268
|
-
return
|
|
241
|
+
if (this.#parent) {
|
|
242
|
+
return this.#parent.getAttribute(key);
|
|
269
243
|
}
|
|
270
244
|
return void 0;
|
|
271
245
|
}
|
|
246
|
+
[Symbol.toStringTag] = "Context";
|
|
247
|
+
[inspect.custom] = () => this.toString();
|
|
272
248
|
toString() {
|
|
273
|
-
return `Context(${
|
|
249
|
+
return `Context(${this.#isDisposed ? "disposed" : "active"})`;
|
|
274
250
|
}
|
|
275
251
|
async [Symbol.asyncDispose]() {
|
|
276
252
|
await this.dispose();
|
|
277
253
|
}
|
|
278
|
-
constructor(params = {}, callMeta) {
|
|
279
|
-
_class_private_field_init(this, _isDisposed, {
|
|
280
|
-
get: get_isDisposed,
|
|
281
|
-
set: set_isDisposed
|
|
282
|
-
});
|
|
283
|
-
_class_private_field_init(this, _leakDetected, {
|
|
284
|
-
get: get_leakDetected,
|
|
285
|
-
set: set_leakDetected
|
|
286
|
-
});
|
|
287
|
-
_class_private_field_init(this, _disposeCallbacks, {
|
|
288
|
-
writable: true,
|
|
289
|
-
value: []
|
|
290
|
-
});
|
|
291
|
-
_class_private_field_init(this, _name, {
|
|
292
|
-
writable: true,
|
|
293
|
-
value: void 0
|
|
294
|
-
});
|
|
295
|
-
_class_private_field_init(this, _parent, {
|
|
296
|
-
writable: true,
|
|
297
|
-
value: void 0
|
|
298
|
-
});
|
|
299
|
-
_class_private_field_init(this, _attributes, {
|
|
300
|
-
writable: true,
|
|
301
|
-
value: void 0
|
|
302
|
-
});
|
|
303
|
-
_class_private_field_init(this, _onError, {
|
|
304
|
-
writable: true,
|
|
305
|
-
value: void 0
|
|
306
|
-
});
|
|
307
|
-
_class_private_field_init(this, _flags, {
|
|
308
|
-
writable: true,
|
|
309
|
-
value: 0
|
|
310
|
-
});
|
|
311
|
-
_class_private_field_init(this, _disposePromise, {
|
|
312
|
-
writable: true,
|
|
313
|
-
value: void 0
|
|
314
|
-
});
|
|
315
|
-
_define_property(this, "maxSafeDisposeCallbacks", MAX_SAFE_DISPOSE_CALLBACKS);
|
|
316
|
-
_define_property(this, Symbol.toStringTag, "Context");
|
|
317
|
-
_define_property(this, _inspect_custom, () => this.toString());
|
|
318
|
-
_class_private_field_set(this, _name, getContextName(params, callMeta));
|
|
319
|
-
_class_private_field_set(this, _parent, params.parent);
|
|
320
|
-
_class_private_field_set(this, _attributes, params.attributes ?? {});
|
|
321
|
-
_class_private_field_set(this, _onError, params.onError ?? DEFAULT_ERROR_HANDLER);
|
|
322
|
-
}
|
|
323
254
|
};
|
|
324
|
-
function get_isDisposed() {
|
|
325
|
-
return !!(_class_private_field_get(this, _flags) & CONTEXT_FLAG_IS_DISPOSED);
|
|
326
|
-
}
|
|
327
|
-
function set_isDisposed(value) {
|
|
328
|
-
_class_private_field_set(this, _flags, value ? _class_private_field_get(this, _flags) | CONTEXT_FLAG_IS_DISPOSED : _class_private_field_get(this, _flags) & ~CONTEXT_FLAG_IS_DISPOSED);
|
|
329
|
-
}
|
|
330
|
-
function get_leakDetected() {
|
|
331
|
-
return !!(_class_private_field_get(this, _flags) & CONTEXT_FLAG_LEAK_DETECTED);
|
|
332
|
-
}
|
|
333
|
-
function set_leakDetected(value) {
|
|
334
|
-
_class_private_field_set(this, _flags, value ? _class_private_field_get(this, _flags) | CONTEXT_FLAG_LEAK_DETECTED : _class_private_field_get(this, _flags) & ~CONTEXT_FLAG_LEAK_DETECTED);
|
|
335
|
-
}
|
|
336
255
|
Context = _ts_decorate([
|
|
337
256
|
safeInstanceof("Context")
|
|
338
257
|
], Context);
|
|
@@ -363,92 +282,60 @@ var cancelWithContext = (ctx, promise) => {
|
|
|
363
282
|
|
|
364
283
|
// src/resource.ts
|
|
365
284
|
import { throwUnhandledError } from "@dxos/util";
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function _class_apply_descriptor_get2(receiver, descriptor) {
|
|
372
|
-
if (descriptor.get) {
|
|
373
|
-
return descriptor.get.call(receiver);
|
|
374
|
-
}
|
|
375
|
-
return descriptor.value;
|
|
376
|
-
}
|
|
377
|
-
function _class_apply_descriptor_set2(receiver, descriptor, value) {
|
|
378
|
-
if (descriptor.set) {
|
|
379
|
-
descriptor.set.call(receiver, value);
|
|
380
|
-
} else {
|
|
381
|
-
if (!descriptor.writable) {
|
|
382
|
-
throw new TypeError("attempted to set read only private field");
|
|
383
|
-
}
|
|
384
|
-
descriptor.value = value;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
function _class_extract_field_descriptor2(receiver, privateMap, action) {
|
|
388
|
-
if (!privateMap.has(receiver)) {
|
|
389
|
-
throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
390
|
-
}
|
|
391
|
-
return privateMap.get(receiver);
|
|
392
|
-
}
|
|
393
|
-
function _class_private_field_get2(receiver, privateMap) {
|
|
394
|
-
var descriptor = _class_extract_field_descriptor2(receiver, privateMap, "get");
|
|
395
|
-
return _class_apply_descriptor_get2(receiver, descriptor);
|
|
396
|
-
}
|
|
397
|
-
function _class_private_field_init2(obj, privateMap, value) {
|
|
398
|
-
_check_private_redeclaration2(obj, privateMap);
|
|
399
|
-
privateMap.set(obj, value);
|
|
400
|
-
}
|
|
401
|
-
function _class_private_field_set2(receiver, privateMap, value) {
|
|
402
|
-
var descriptor = _class_extract_field_descriptor2(receiver, privateMap, "set");
|
|
403
|
-
_class_apply_descriptor_set2(receiver, descriptor, value);
|
|
404
|
-
return value;
|
|
405
|
-
}
|
|
406
|
-
function _class_private_method_get(receiver, privateSet, fn) {
|
|
407
|
-
if (!privateSet.has(receiver)) {
|
|
408
|
-
throw new TypeError("attempted to get private field on non-instance");
|
|
409
|
-
}
|
|
410
|
-
return fn;
|
|
411
|
-
}
|
|
412
|
-
function _class_private_method_init(obj, privateSet) {
|
|
413
|
-
_check_private_redeclaration2(obj, privateSet);
|
|
414
|
-
privateSet.add(obj);
|
|
415
|
-
}
|
|
416
|
-
var LifecycleState = /* @__PURE__ */ function(LifecycleState2) {
|
|
285
|
+
import "@hazae41/symbol-dispose-polyfill";
|
|
286
|
+
var LifecycleState = /* @__PURE__ */ (function(LifecycleState2) {
|
|
417
287
|
LifecycleState2["CLOSED"] = "CLOSED";
|
|
418
288
|
LifecycleState2["OPEN"] = "OPEN";
|
|
419
289
|
LifecycleState2["ERROR"] = "ERROR";
|
|
420
290
|
return LifecycleState2;
|
|
421
|
-
}({});
|
|
291
|
+
})({});
|
|
422
292
|
var CLOSE_RESOURCE_ON_UNHANDLED_ERROR = false;
|
|
423
|
-
var _lifecycleState = /* @__PURE__ */ new WeakMap();
|
|
424
|
-
var _openPromise = /* @__PURE__ */ new WeakMap();
|
|
425
|
-
var _closePromise = /* @__PURE__ */ new WeakMap();
|
|
426
|
-
var _internalCtx = /* @__PURE__ */ new WeakMap();
|
|
427
|
-
var _parentCtx = /* @__PURE__ */ new WeakMap();
|
|
428
|
-
var _name2 = /* @__PURE__ */ new WeakMap();
|
|
429
|
-
var _open = /* @__PURE__ */ new WeakSet();
|
|
430
|
-
var _close = /* @__PURE__ */ new WeakSet();
|
|
431
|
-
var _createContext = /* @__PURE__ */ new WeakSet();
|
|
432
|
-
var _createParentContext = /* @__PURE__ */ new WeakSet();
|
|
433
293
|
var Resource = class {
|
|
294
|
+
#lifecycleState = "CLOSED";
|
|
295
|
+
#openPromise = null;
|
|
296
|
+
#closePromise = null;
|
|
297
|
+
/**
|
|
298
|
+
* Managed internally by the resource.
|
|
299
|
+
* Recreated on close.
|
|
300
|
+
* Errors are propagated to the `_catch` method and the parent context.
|
|
301
|
+
*/
|
|
302
|
+
#internalCtx = this.#createContext();
|
|
303
|
+
/**
|
|
304
|
+
* Context that is used to bubble up errors that are not handled by the resource.
|
|
305
|
+
* Provided in the open method.
|
|
306
|
+
*/
|
|
307
|
+
#parentCtx = this.#createParentContext();
|
|
308
|
+
/**
|
|
309
|
+
* ```ts
|
|
310
|
+
* await using resource = new Resource();
|
|
311
|
+
* await resource.open();
|
|
312
|
+
* ```
|
|
313
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using
|
|
314
|
+
*/
|
|
315
|
+
async [Symbol.asyncDispose]() {
|
|
316
|
+
await this.close();
|
|
317
|
+
}
|
|
318
|
+
get #name() {
|
|
319
|
+
return Object.getPrototypeOf(this).constructor.name;
|
|
320
|
+
}
|
|
434
321
|
get isOpen() {
|
|
435
|
-
return
|
|
322
|
+
return this.#lifecycleState === "OPEN" && this.#closePromise == null;
|
|
436
323
|
}
|
|
437
324
|
get _lifecycleState() {
|
|
438
|
-
return
|
|
325
|
+
return this.#lifecycleState;
|
|
439
326
|
}
|
|
440
327
|
get _ctx() {
|
|
441
|
-
return
|
|
328
|
+
return this.#internalCtx;
|
|
442
329
|
}
|
|
443
330
|
/**
|
|
444
331
|
* To be overridden by subclasses.
|
|
445
332
|
*/
|
|
446
|
-
async _open(
|
|
333
|
+
async _open(_ctx) {
|
|
447
334
|
}
|
|
448
335
|
/**
|
|
449
336
|
* To be overridden by subclasses.
|
|
450
337
|
*/
|
|
451
|
-
async _close(
|
|
338
|
+
async _close(_ctx) {
|
|
452
339
|
}
|
|
453
340
|
/**
|
|
454
341
|
* Error handler for errors that are caught by the context.
|
|
@@ -465,6 +352,19 @@ var Resource = class {
|
|
|
465
352
|
throw err;
|
|
466
353
|
}
|
|
467
354
|
/**
|
|
355
|
+
* Calls the provided function, opening and closing the resource.
|
|
356
|
+
* NOTE: Consider using `using` instead.
|
|
357
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using
|
|
358
|
+
*/
|
|
359
|
+
async use(fn) {
|
|
360
|
+
try {
|
|
361
|
+
await this.open();
|
|
362
|
+
return await fn(this);
|
|
363
|
+
} finally {
|
|
364
|
+
await this.close();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
468
368
|
* Opens the resource.
|
|
469
369
|
* If the resource is already open, it does nothing.
|
|
470
370
|
* If the resource is in an error state, it throws an error.
|
|
@@ -472,15 +372,15 @@ var Resource = class {
|
|
|
472
372
|
* @param ctx - Context to use for opening the resource. This context will receive errors that are not handled in `_catch`.
|
|
473
373
|
*/
|
|
474
374
|
async open(ctx) {
|
|
475
|
-
switch (
|
|
375
|
+
switch (this.#lifecycleState) {
|
|
476
376
|
case "OPEN":
|
|
477
377
|
return this;
|
|
478
378
|
case "ERROR":
|
|
479
|
-
throw new Error(`Invalid state: ${
|
|
379
|
+
throw new Error(`Invalid state: ${this.#lifecycleState}`);
|
|
480
380
|
default:
|
|
481
381
|
}
|
|
482
|
-
await
|
|
483
|
-
await
|
|
382
|
+
await this.#closePromise;
|
|
383
|
+
await (this.#openPromise ??= this.#open(ctx));
|
|
484
384
|
return this;
|
|
485
385
|
}
|
|
486
386
|
/**
|
|
@@ -488,98 +388,64 @@ var Resource = class {
|
|
|
488
388
|
* If the resource is already closed, it does nothing.
|
|
489
389
|
*/
|
|
490
390
|
async close(ctx) {
|
|
491
|
-
if (
|
|
391
|
+
if (this.#lifecycleState === "CLOSED") {
|
|
492
392
|
return this;
|
|
493
393
|
}
|
|
494
|
-
await
|
|
495
|
-
await
|
|
394
|
+
await this.#openPromise;
|
|
395
|
+
await (this.#closePromise ??= this.#close(ctx));
|
|
496
396
|
return this;
|
|
497
397
|
}
|
|
498
398
|
/**
|
|
499
399
|
* Waits until the resource is open.
|
|
500
400
|
*/
|
|
501
401
|
async waitUntilOpen() {
|
|
502
|
-
switch (
|
|
402
|
+
switch (this.#lifecycleState) {
|
|
503
403
|
case "OPEN":
|
|
504
404
|
return;
|
|
505
405
|
case "ERROR":
|
|
506
|
-
throw new Error(`Invalid state: ${
|
|
406
|
+
throw new Error(`Invalid state: ${this.#lifecycleState}`);
|
|
507
407
|
}
|
|
508
|
-
if (!
|
|
408
|
+
if (!this.#openPromise) {
|
|
509
409
|
throw new Error("Resource is not being opened");
|
|
510
410
|
}
|
|
511
|
-
await
|
|
512
|
-
}
|
|
513
|
-
async
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
411
|
+
await this.#openPromise;
|
|
412
|
+
}
|
|
413
|
+
async #open(ctx) {
|
|
414
|
+
this.#closePromise = null;
|
|
415
|
+
this.#parentCtx = ctx?.derive({
|
|
416
|
+
name: this.#name
|
|
417
|
+
}) ?? this.#createParentContext();
|
|
418
|
+
this.#internalCtx = this.#createContext(this.#parentCtx);
|
|
419
|
+
await this._open(this.#parentCtx);
|
|
420
|
+
this.#lifecycleState = "OPEN";
|
|
421
|
+
}
|
|
422
|
+
async #close(ctx = Context.default()) {
|
|
423
|
+
this.#openPromise = null;
|
|
424
|
+
await this.#internalCtx.dispose();
|
|
425
|
+
await this._close(ctx);
|
|
426
|
+
this.#internalCtx = this.#createContext();
|
|
427
|
+
this.#lifecycleState = "CLOSED";
|
|
428
|
+
}
|
|
429
|
+
#createContext(attributeParent) {
|
|
430
|
+
return new Context({
|
|
431
|
+
name: this.#name,
|
|
432
|
+
parent: attributeParent,
|
|
433
|
+
onError: (error) => queueMicrotask(async () => {
|
|
434
|
+
try {
|
|
435
|
+
await this._catch(error);
|
|
436
|
+
} catch (err) {
|
|
437
|
+
this.#lifecycleState = "ERROR";
|
|
438
|
+
this.#parentCtx.raise(err);
|
|
439
|
+
}
|
|
440
|
+
})
|
|
540
441
|
});
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
442
|
+
}
|
|
443
|
+
#createParentContext() {
|
|
444
|
+
return new Context({
|
|
445
|
+
name: this.#name
|
|
544
446
|
});
|
|
545
447
|
}
|
|
546
448
|
};
|
|
547
|
-
function get_name() {
|
|
548
|
-
return Object.getPrototypeOf(this).constructor.name;
|
|
549
|
-
}
|
|
550
|
-
async function open(ctx) {
|
|
551
|
-
_class_private_field_set2(this, _closePromise, null);
|
|
552
|
-
_class_private_field_set2(this, _parentCtx, ctx?.derive({
|
|
553
|
-
name: _class_private_field_get2(this, _name2)
|
|
554
|
-
}) ?? _class_private_method_get(this, _createParentContext, createParentContext).call(this));
|
|
555
|
-
await this._open(_class_private_field_get2(this, _parentCtx));
|
|
556
|
-
_class_private_field_set2(this, _lifecycleState, "OPEN");
|
|
557
|
-
}
|
|
558
|
-
async function close(ctx = Context.default()) {
|
|
559
|
-
_class_private_field_set2(this, _openPromise, null);
|
|
560
|
-
await _class_private_field_get2(this, _internalCtx).dispose();
|
|
561
|
-
await this._close(ctx);
|
|
562
|
-
_class_private_field_set2(this, _internalCtx, _class_private_method_get(this, _createContext, createContext).call(this));
|
|
563
|
-
_class_private_field_set2(this, _lifecycleState, "CLOSED");
|
|
564
|
-
}
|
|
565
|
-
function createContext() {
|
|
566
|
-
return new Context({
|
|
567
|
-
name: _class_private_field_get2(this, _name2),
|
|
568
|
-
onError: (error) => queueMicrotask(async () => {
|
|
569
|
-
try {
|
|
570
|
-
await this._catch(error);
|
|
571
|
-
} catch (err) {
|
|
572
|
-
_class_private_field_set2(this, _lifecycleState, "ERROR");
|
|
573
|
-
_class_private_field_get2(this, _parentCtx).raise(err);
|
|
574
|
-
}
|
|
575
|
-
})
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
function createParentContext() {
|
|
579
|
-
return new Context({
|
|
580
|
-
name: _class_private_field_get2(this, _name2)
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
449
|
var openInContext = async (ctx, resource) => {
|
|
584
450
|
await resource.open?.(ctx);
|
|
585
451
|
ctx.onDispose(() => resource.close?.());
|