@dougongjs/core 0.3.0 → 0.5.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/README.md +2 -2
- package/dist/change-set.d.ts +15 -6
- package/dist/change-set.d.ts.map +1 -1
- package/dist/configuration.d.ts +12 -1
- package/dist/configuration.d.ts.map +1 -1
- package/dist/contract-registry.d.ts +2 -2
- package/dist/contract-registry.d.ts.map +1 -1
- package/dist/contracts.d.ts +27 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contribution-store.d.ts +21 -2
- package/dist/contribution-store.d.ts.map +1 -1
- package/dist/diagnostics.d.ts +21 -3
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/engine.d.ts +30 -9
- package/dist/engine.d.ts.map +1 -1
- package/dist/errors.d.ts +49 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/event-hub.d.ts +12 -1
- package/dist/event-hub.d.ts.map +1 -1
- package/dist/group-configuration.d.ts +20 -0
- package/dist/group-configuration.d.ts.map +1 -0
- package/dist/group-coordinator.d.ts +34 -15
- package/dist/group-coordinator.d.ts.map +1 -1
- package/dist/group-lifecycle.d.ts +13 -0
- package/dist/group-lifecycle.d.ts.map +1 -1
- package/dist/group.d.ts +5 -11
- package/dist/group.d.ts.map +1 -1
- package/dist/host-api.d.ts +35 -1
- package/dist/host-api.d.ts.map +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1053 -647
- package/dist/installation-graph.d.ts +8 -1
- package/dist/installation-graph.d.ts.map +1 -1
- package/dist/installation-registry.d.ts +7 -2
- package/dist/installation-registry.d.ts.map +1 -1
- package/dist/installation.d.ts +19 -1
- package/dist/installation.d.ts.map +1 -1
- package/dist/instance-coordinator.d.ts +64 -0
- package/dist/instance-coordinator.d.ts.map +1 -0
- package/dist/lifecycle-status.d.ts.map +1 -1
- package/dist/lifetime-diagnostics.d.ts +7 -1
- package/dist/lifetime-diagnostics.d.ts.map +1 -1
- package/dist/lifetime.d.ts +44 -8
- package/dist/lifetime.d.ts.map +1 -1
- package/dist/plugin.d.ts +28 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/readonly-map.d.ts +8 -1
- package/dist/readonly-map.d.ts.map +1 -1
- package/dist/record.d.ts +16 -1
- package/dist/record.d.ts.map +1 -1
- package/dist/resource.d.ts +6 -0
- package/dist/resource.d.ts.map +1 -1
- package/dist/serial-queue.d.ts +7 -1
- package/dist/serial-queue.d.ts.map +1 -1
- package/dist/snapshot-view.d.ts +2 -0
- package/dist/snapshot-view.d.ts.map +1 -1
- package/dist/sync-result.d.ts +3 -0
- package/dist/sync-result.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/runtime.d.ts +0 -36
- package/dist/runtime.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,65 +1,136 @@
|
|
|
1
|
-
function
|
|
1
|
+
function Ot(r, t) {
|
|
2
2
|
if (typeof t != "string" || !t.trim())
|
|
3
3
|
throw new TypeError(`${r} id must be a non-empty string`);
|
|
4
4
|
if (t !== t.trim())
|
|
5
5
|
throw new TypeError(`${r} id cannot start or end with whitespace`);
|
|
6
6
|
}
|
|
7
|
-
function
|
|
8
|
-
return
|
|
7
|
+
function Q(r, t) {
|
|
8
|
+
return Ot("Contract", t), Object.freeze({ id: t, kind: r });
|
|
9
9
|
}
|
|
10
|
-
function
|
|
10
|
+
function E(r, t) {
|
|
11
11
|
if (!r || typeof r != "object") return !1;
|
|
12
12
|
const e = r;
|
|
13
13
|
return typeof e.id == "string" && e.id.length > 0 && e.id === e.id.trim() && (e.kind === "service" || e.kind === "extensionPoint" || e.kind === "event") && (t === void 0 || e.kind === t);
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
if (!
|
|
17
|
-
throw new TypeError(t ? `Expected ${
|
|
15
|
+
function A(r, t) {
|
|
16
|
+
if (!E(r, t))
|
|
17
|
+
throw new TypeError(t ? `Expected ${At(t)}` : "Invalid contract");
|
|
18
18
|
}
|
|
19
|
-
function
|
|
19
|
+
function At(r) {
|
|
20
20
|
return r === "extensionPoint" ? "an ExtensionPoint" : r === "event" ? "an Event" : "a Service";
|
|
21
21
|
}
|
|
22
|
-
function
|
|
23
|
-
return
|
|
22
|
+
function It(r) {
|
|
23
|
+
return Q("service", r);
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
return
|
|
25
|
+
function Le(r) {
|
|
26
|
+
return Q("event", r);
|
|
27
27
|
}
|
|
28
|
-
function
|
|
29
|
-
return
|
|
28
|
+
function ze(r) {
|
|
29
|
+
return Q("extensionPoint", r);
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
if (!
|
|
31
|
+
function Re(r) {
|
|
32
|
+
if (!E(r, "service"))
|
|
33
33
|
throw new TypeError("optional() expects a Service");
|
|
34
|
-
return Object.freeze({ kind: "optional", service: r });
|
|
34
|
+
return Object.freeze({ kind: "optional", service: It(r.id) });
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function jt(r) {
|
|
37
37
|
if (!r || typeof r != "object") return !1;
|
|
38
38
|
const t = r;
|
|
39
|
-
return t.kind === "optional" &&
|
|
39
|
+
return t.kind === "optional" && E(t.service, "service");
|
|
40
40
|
}
|
|
41
41
|
class u extends Error {
|
|
42
|
+
name = "DougongError";
|
|
43
|
+
code;
|
|
42
44
|
constructor(t, e, i) {
|
|
45
|
+
if (typeof t != "string" || t.trim() !== t || t.length === 0)
|
|
46
|
+
throw new TypeError("DougongError code must be a non-empty trimmed string");
|
|
47
|
+
if (typeof e != "string") throw new TypeError("DougongError message must be a string");
|
|
43
48
|
super(e, i), this.code = t;
|
|
44
49
|
}
|
|
50
|
+
}
|
|
51
|
+
class J extends Error {
|
|
52
|
+
name = "RecordedFailure";
|
|
45
53
|
code;
|
|
46
|
-
|
|
54
|
+
snapshot;
|
|
55
|
+
constructor(t) {
|
|
56
|
+
if (!(t instanceof Error)) throw new TypeError("RecordedFailure expects an Error");
|
|
57
|
+
const e = t instanceof J ? t.snapshot : kt(t);
|
|
58
|
+
super(e.message), this.code = e.code, this.snapshot = e, e.stack !== void 0 && (this.stack = e.stack), Object.freeze(this);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function kt(r) {
|
|
62
|
+
const t = /* @__PURE__ */ new Set();
|
|
63
|
+
let e = 32;
|
|
64
|
+
const i = (s, n) => {
|
|
65
|
+
if (n > 4 || e-- <= 0 || t.has(s))
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
name: "TruncatedError",
|
|
68
|
+
message: "Error chain truncated",
|
|
69
|
+
truncated: !0
|
|
70
|
+
});
|
|
71
|
+
if (!(s instanceof Error)) {
|
|
72
|
+
const p = s === null || ["string", "number", "boolean", "undefined", "bigint", "symbol"].includes(typeof s) ? String(s).slice(0, 4096) : "Non-Error object omitted";
|
|
73
|
+
return Object.freeze({ name: "NonError", message: p });
|
|
74
|
+
}
|
|
75
|
+
t.add(s);
|
|
76
|
+
let o = !1;
|
|
77
|
+
const a = (p, w) => (p.length > w && (o = !0), p.slice(0, w)), h = (p, w) => {
|
|
78
|
+
const b = m(s, p);
|
|
79
|
+
return typeof b == "string" ? a(b, w) : void 0;
|
|
80
|
+
}, c = (p) => {
|
|
81
|
+
const w = m(s, p);
|
|
82
|
+
if (Array.isArray(w))
|
|
83
|
+
return w.length > 8 && (o = !0), Array.from(
|
|
84
|
+
{ length: Math.min(w.length, 8) },
|
|
85
|
+
(b, j) => m(w, j)
|
|
86
|
+
);
|
|
87
|
+
}, d = h("name", 256) ?? "Error", l = h("message", 4096) ?? "", f = h("stack", 16384), g = h("code", 256), I = m(s, "cause"), et = c("errors"), it = h("manifestName", 256), st = c("denied")?.filter((p) => typeof p == "string").map((p) => a(p, 256)), rt = c("issues")?.map((p) => {
|
|
88
|
+
const w = m(p, "message"), b = m(p, "path"), j = Array.isArray(b) ? Array.from({ length: Math.min(b.length, 16) }, (Pe, St) => {
|
|
89
|
+
const k = m(b, St), S = k && typeof k == "object" ? m(k, "key") : k;
|
|
90
|
+
return typeof S == "number" ? S : typeof S == "string" || typeof S == "symbol" ? a(String(S), 256) : "[omitted]";
|
|
91
|
+
}) : void 0;
|
|
92
|
+
return Array.isArray(b) && b.length > 16 && (o = !0), Object.freeze({
|
|
93
|
+
message: typeof w == "string" ? a(w, 4096) : "",
|
|
94
|
+
...j ? { path: Object.freeze(j) } : {}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return Object.freeze({
|
|
98
|
+
name: d,
|
|
99
|
+
message: l,
|
|
100
|
+
...g === void 0 ? {} : { code: g },
|
|
101
|
+
...f === void 0 ? {} : { stack: f },
|
|
102
|
+
...I === void 0 ? {} : { cause: i(I, n + 1) },
|
|
103
|
+
...et === void 0 ? {} : { errors: Object.freeze(et.map((p) => i(p, n + 1))) },
|
|
104
|
+
...it === void 0 ? {} : { manifestName: it },
|
|
105
|
+
...st === void 0 ? {} : { denied: Object.freeze(st) },
|
|
106
|
+
...rt === void 0 ? {} : { issues: Object.freeze(rt) },
|
|
107
|
+
...o ? { truncated: !0 } : {}
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
return i(r, 0);
|
|
47
111
|
}
|
|
48
|
-
|
|
112
|
+
function m(r, t) {
|
|
113
|
+
try {
|
|
114
|
+
return r && typeof r == "object" ? r[t] : void 0;
|
|
115
|
+
} catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
49
118
|
}
|
|
50
|
-
|
|
51
|
-
return r instanceof P ? r.code === t ? r : new P(t, e, { cause: r.cause }) : r instanceof Error ? r : new P(t, e, { cause: r });
|
|
119
|
+
class G extends u {
|
|
52
120
|
}
|
|
53
|
-
function
|
|
121
|
+
function V(r, t, e) {
|
|
122
|
+
return r instanceof G ? r.code === t ? r : new G(t, e, { cause: r.cause }) : r instanceof Error ? r : new G(t, e, { cause: r });
|
|
123
|
+
}
|
|
124
|
+
function wt(r, t) {
|
|
54
125
|
if (!r || typeof r != "object" || typeof r.aborted != "boolean" || typeof r.addEventListener != "function" || typeof r.removeEventListener != "function" || typeof r.throwIfAborted != "function")
|
|
55
126
|
throw new TypeError("Cancellation classifier expects an AbortSignal");
|
|
56
127
|
return r.aborted ? Object.is(t, r.reason) ? !0 : t instanceof Error && t.name === "AbortError" : !1;
|
|
57
128
|
}
|
|
58
|
-
class
|
|
129
|
+
class $t extends u {
|
|
59
130
|
name = "ConfigValidationError";
|
|
60
131
|
issues;
|
|
61
132
|
constructor(t) {
|
|
62
|
-
const e =
|
|
133
|
+
const e = Tt(t);
|
|
63
134
|
super(
|
|
64
135
|
"CONFIG_INVALID",
|
|
65
136
|
`Invalid Plugin config:
|
|
@@ -68,7 +139,7 @@ ${e.map((i) => ` - ${i.message}`).join(`
|
|
|
68
139
|
), this.issues = e;
|
|
69
140
|
}
|
|
70
141
|
}
|
|
71
|
-
function
|
|
142
|
+
function Tt(r) {
|
|
72
143
|
if (!Array.isArray(r))
|
|
73
144
|
throw new TypeError("Config validation issues must be an array");
|
|
74
145
|
return Object.freeze(
|
|
@@ -80,23 +151,23 @@ function ct(r) {
|
|
|
80
151
|
throw new TypeError(`Config validation issue at index ${e} message must be a string`);
|
|
81
152
|
return Object.freeze({
|
|
82
153
|
message: i.message,
|
|
83
|
-
...i.path === void 0 ? {} : { path:
|
|
154
|
+
...i.path === void 0 ? {} : { path: Pt(i.path, e) }
|
|
84
155
|
});
|
|
85
156
|
})
|
|
86
157
|
);
|
|
87
158
|
}
|
|
88
|
-
function
|
|
159
|
+
function Pt(r, t) {
|
|
89
160
|
if (!Array.isArray(r))
|
|
90
161
|
throw new TypeError(`Config validation issue at index ${t} path must be an array`);
|
|
91
162
|
return Object.freeze(
|
|
92
163
|
Array.from(r, (e, i) => {
|
|
93
|
-
if (
|
|
164
|
+
if (nt(e)) return e;
|
|
94
165
|
if (!e || typeof e != "object")
|
|
95
166
|
throw new TypeError(
|
|
96
167
|
`Config validation issue at index ${t} path segment ${i} must be a property key`
|
|
97
168
|
);
|
|
98
169
|
const s = e.key;
|
|
99
|
-
if (!
|
|
170
|
+
if (!nt(s))
|
|
100
171
|
throw new TypeError(
|
|
101
172
|
`Config validation issue at index ${t} path segment ${i} must contain a property key`
|
|
102
173
|
);
|
|
@@ -104,10 +175,10 @@ function ht(r, t) {
|
|
|
104
175
|
})
|
|
105
176
|
);
|
|
106
177
|
}
|
|
107
|
-
function
|
|
178
|
+
function nt(r) {
|
|
108
179
|
return typeof r == "string" || typeof r == "number" || typeof r == "symbol";
|
|
109
180
|
}
|
|
110
|
-
async function
|
|
181
|
+
async function Lt(r, t, e) {
|
|
111
182
|
if (!r) return t;
|
|
112
183
|
const i = await r["~standard"].validate(t);
|
|
113
184
|
if (!i || typeof i != "object")
|
|
@@ -116,7 +187,7 @@ async function X(r, t, e) {
|
|
|
116
187
|
);
|
|
117
188
|
const s = Object.hasOwn(i, "issues") ? i.issues : void 0;
|
|
118
189
|
if (s !== void 0)
|
|
119
|
-
throw Array.isArray(s) ? new
|
|
190
|
+
throw Array.isArray(s) ? new $t(s) : new TypeError(
|
|
120
191
|
`Installation '${e}' config validator returned non-array issues`
|
|
121
192
|
);
|
|
122
193
|
if (!Object.hasOwn(i, "value"))
|
|
@@ -125,29 +196,29 @@ async function X(r, t, e) {
|
|
|
125
196
|
);
|
|
126
197
|
return i.value;
|
|
127
198
|
}
|
|
128
|
-
class
|
|
199
|
+
class zt {
|
|
129
200
|
#t = /* @__PURE__ */ new Map();
|
|
130
201
|
get kinds() {
|
|
131
202
|
return this.#t;
|
|
132
203
|
}
|
|
133
204
|
assertCompatible(t) {
|
|
134
|
-
|
|
205
|
+
bt(this.#t, t);
|
|
135
206
|
}
|
|
136
207
|
remember(t) {
|
|
137
|
-
|
|
208
|
+
q(this.#t, t);
|
|
138
209
|
}
|
|
139
|
-
|
|
140
|
-
return new
|
|
210
|
+
writer(t) {
|
|
211
|
+
return new Rt(this, t);
|
|
141
212
|
}
|
|
142
213
|
commit(t) {
|
|
143
214
|
for (const [e, i] of t) this.assertCompatible({ id: e, kind: i });
|
|
144
215
|
for (const [e, i] of t) this.#t.set(e, i);
|
|
145
216
|
}
|
|
146
217
|
}
|
|
147
|
-
class
|
|
218
|
+
class Rt {
|
|
148
219
|
#t;
|
|
149
220
|
constructor(t, e) {
|
|
150
|
-
this.#t = { phase: "
|
|
221
|
+
this.#t = { phase: "staged", registry: t, pending: /* @__PURE__ */ new Map() };
|
|
151
222
|
for (const [i, s] of e) this.remember({ id: i, kind: s });
|
|
152
223
|
}
|
|
153
224
|
remember(t) {
|
|
@@ -157,21 +228,21 @@ class lt {
|
|
|
157
228
|
return;
|
|
158
229
|
}
|
|
159
230
|
if (e.phase === "discarded")
|
|
160
|
-
throw new Error("Contract registry
|
|
161
|
-
e.registry.assertCompatible(t), !e.registry.kinds.has(t.id) &&
|
|
231
|
+
throw new Error("Contract registry writer has been discarded");
|
|
232
|
+
e.registry.assertCompatible(t), !e.registry.kinds.has(t.id) && q(e.pending, t);
|
|
162
233
|
}
|
|
163
234
|
commit() {
|
|
164
235
|
const t = this.#t;
|
|
165
|
-
t.phase === "
|
|
236
|
+
t.phase === "staged" && (t.registry.commit(t.pending), this.#t = { phase: "committed", registry: t.registry });
|
|
166
237
|
}
|
|
167
238
|
discard() {
|
|
168
|
-
this.#t.phase === "
|
|
239
|
+
this.#t.phase === "staged" && (this.#t = { phase: "discarded" });
|
|
169
240
|
}
|
|
170
241
|
}
|
|
171
|
-
function
|
|
172
|
-
|
|
242
|
+
function q(r, t) {
|
|
243
|
+
bt(r, t), r.set(t.id, t.kind);
|
|
173
244
|
}
|
|
174
|
-
function
|
|
245
|
+
function bt(r, t) {
|
|
175
246
|
const e = r.get(t.id);
|
|
176
247
|
if (e && e !== t.kind)
|
|
177
248
|
throw new u(
|
|
@@ -179,9 +250,9 @@ function Z(r, t) {
|
|
|
179
250
|
`Contract '${t.id}' is used as both '${e}' and '${t.kind}'`
|
|
180
251
|
);
|
|
181
252
|
}
|
|
182
|
-
class
|
|
183
|
-
constructor(t, e, i, s, n, o) {
|
|
184
|
-
this.order =
|
|
253
|
+
class X {
|
|
254
|
+
constructor(t, e, i, s, n, o, a) {
|
|
255
|
+
this.order = e, this.layers = i, this.providers = s, this.dependents = n, this.contractKinds = o, this.#t = t, this.#e = a;
|
|
185
256
|
}
|
|
186
257
|
order;
|
|
187
258
|
layers;
|
|
@@ -189,13 +260,15 @@ class M {
|
|
|
189
260
|
dependents;
|
|
190
261
|
contractKinds;
|
|
191
262
|
#t;
|
|
263
|
+
#e;
|
|
192
264
|
static build(t, e) {
|
|
193
|
-
const i = [...t].sort((c, d) => c.index - d.index), s = new Map(e), n =
|
|
265
|
+
const i = [...t].sort((c, d) => c.index - d.index), s = new Map(e), n = Nt(i, s), o = xt(i, n, s), { order: a, layers: h } = Mt(
|
|
194
266
|
i,
|
|
195
267
|
o.dependents,
|
|
196
268
|
o.indegree
|
|
197
269
|
);
|
|
198
|
-
return new
|
|
270
|
+
return new X(
|
|
271
|
+
new Map(i.map((c) => [c, c.declaration])),
|
|
199
272
|
Object.freeze(a),
|
|
200
273
|
Object.freeze(h.map((c) => Object.freeze(c))),
|
|
201
274
|
n,
|
|
@@ -204,17 +277,28 @@ class M {
|
|
|
204
277
|
o.resolvedProviders
|
|
205
278
|
);
|
|
206
279
|
}
|
|
280
|
+
declarationFor(t) {
|
|
281
|
+
const e = this.#t.get(t);
|
|
282
|
+
if (!e) throw new Error(`Installation '${t.id}' is not in this plan`);
|
|
283
|
+
return e;
|
|
284
|
+
}
|
|
207
285
|
providerFor(t, e) {
|
|
208
|
-
return this.#
|
|
286
|
+
return this.#e.get(t)?.get(e);
|
|
209
287
|
}
|
|
210
288
|
provider(t) {
|
|
211
289
|
return this.providers.get(t);
|
|
212
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Transitive dependents in *both* plans. A Service being replaced has old
|
|
293
|
+
* consumers that must stop and new ones that must start, and only the union
|
|
294
|
+
* covers both — expanding in the current plan alone would leave an Instance
|
|
295
|
+
* running against a dependency that no longer exists.
|
|
296
|
+
*/
|
|
213
297
|
affectedByTransitionTo(t, e) {
|
|
214
298
|
const i = /* @__PURE__ */ new Set();
|
|
215
|
-
return this.#
|
|
299
|
+
return this.#i(e, i), t.#i(e, i), i;
|
|
216
300
|
}
|
|
217
|
-
#
|
|
301
|
+
#i(t, e) {
|
|
218
302
|
const i = [...t], s = /* @__PURE__ */ new Set();
|
|
219
303
|
for (let n = 0; n < i.length; n++) {
|
|
220
304
|
const o = i[n];
|
|
@@ -225,11 +309,11 @@ class M {
|
|
|
225
309
|
}
|
|
226
310
|
}
|
|
227
311
|
}
|
|
228
|
-
function
|
|
312
|
+
function Nt(r, t) {
|
|
229
313
|
const e = /* @__PURE__ */ new Map();
|
|
230
314
|
for (const i of r)
|
|
231
|
-
for (const s of Object.values(i.declaration.plugin.provides
|
|
232
|
-
|
|
315
|
+
for (const s of Object.values(i.declaration.plugin.provides)) {
|
|
316
|
+
q(t, s);
|
|
233
317
|
const n = e.get(s.id);
|
|
234
318
|
if (n)
|
|
235
319
|
throw new u(
|
|
@@ -240,12 +324,12 @@ function ut(r, t) {
|
|
|
240
324
|
}
|
|
241
325
|
return e;
|
|
242
326
|
}
|
|
243
|
-
function
|
|
327
|
+
function xt(r, t, e) {
|
|
244
328
|
const i = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), n = new Map(r.map((o) => [o, 0]));
|
|
245
329
|
for (const o of r)
|
|
246
|
-
for (const a of Object.values(o.declaration.plugin.requires
|
|
330
|
+
for (const a of Object.values(o.declaration.plugin.requires)) {
|
|
247
331
|
const h = a.kind === "optional" ? a.service : a;
|
|
248
|
-
if (
|
|
332
|
+
if (q(e, h), h.kind === "extensionPoint") continue;
|
|
249
333
|
const c = t.get(h.id);
|
|
250
334
|
if (!c) {
|
|
251
335
|
if (a.kind === "optional") continue;
|
|
@@ -266,7 +350,7 @@ function ft(r, t, e) {
|
|
|
266
350
|
}
|
|
267
351
|
return { resolvedProviders: i, dependents: s, indegree: n };
|
|
268
352
|
}
|
|
269
|
-
function
|
|
353
|
+
function Mt(r, t, e) {
|
|
270
354
|
let i = r.filter((o) => e.get(o) === 0);
|
|
271
355
|
const s = [], n = [];
|
|
272
356
|
for (; i.length; ) {
|
|
@@ -280,7 +364,7 @@ function pt(r, t, e) {
|
|
|
280
364
|
}
|
|
281
365
|
}
|
|
282
366
|
if (s.length !== r.length) {
|
|
283
|
-
const o =
|
|
367
|
+
const o = Dt(r, t);
|
|
284
368
|
throw new u(
|
|
285
369
|
"SERVICE_CYCLE",
|
|
286
370
|
`Installation dependency cycle: ${o.map((a) => a.id).join(" -> ")}`
|
|
@@ -288,7 +372,7 @@ function pt(r, t, e) {
|
|
|
288
372
|
}
|
|
289
373
|
return { order: s, layers: n };
|
|
290
374
|
}
|
|
291
|
-
function
|
|
375
|
+
function Dt(r, t) {
|
|
292
376
|
const e = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), s = [], n = (o) => {
|
|
293
377
|
i.add(o), s.push(o);
|
|
294
378
|
for (const a of t.get(o) ?? []) {
|
|
@@ -309,7 +393,7 @@ function gt(r, t) {
|
|
|
309
393
|
}
|
|
310
394
|
throw new Error("Dependency graph is cyclic but no cycle path was found");
|
|
311
395
|
}
|
|
312
|
-
class
|
|
396
|
+
class z {
|
|
313
397
|
#t;
|
|
314
398
|
constructor(t = []) {
|
|
315
399
|
if (!t || typeof t != "object" && typeof t != "function" || typeof t[Symbol.iterator] != "function")
|
|
@@ -341,22 +425,65 @@ class S {
|
|
|
341
425
|
return this.entries();
|
|
342
426
|
}
|
|
343
427
|
}
|
|
344
|
-
function
|
|
428
|
+
function Vt(r) {
|
|
345
429
|
if (typeof r != "function")
|
|
346
430
|
throw new Error("Unsupported JavaScript runtime: Promise.withResolvers is required");
|
|
347
431
|
}
|
|
348
|
-
function
|
|
432
|
+
function mt(r, t) {
|
|
349
433
|
return r ?? Symbol.for(t);
|
|
350
434
|
}
|
|
351
|
-
|
|
352
|
-
const
|
|
435
|
+
Vt(Promise.withResolvers);
|
|
436
|
+
const v = mt(
|
|
353
437
|
Symbol.dispose,
|
|
354
438
|
"Symbol.dispose"
|
|
355
|
-
),
|
|
439
|
+
), F = mt(
|
|
356
440
|
Symbol.asyncDispose,
|
|
357
441
|
"Symbol.asyncDispose"
|
|
358
|
-
)
|
|
359
|
-
|
|
442
|
+
);
|
|
443
|
+
function R(r, t) {
|
|
444
|
+
if (qt(r))
|
|
445
|
+
throw Promise.resolve(r).catch(() => {
|
|
446
|
+
}), new TypeError(t);
|
|
447
|
+
}
|
|
448
|
+
function qt(r) {
|
|
449
|
+
return r === null || typeof r != "object" && typeof r != "function" ? !1 : typeof r.then == "function";
|
|
450
|
+
}
|
|
451
|
+
const N = /* @__PURE__ */ new WeakMap(), C = /* @__PURE__ */ new Set();
|
|
452
|
+
let T = 0, U = !1;
|
|
453
|
+
function Ft(r) {
|
|
454
|
+
T++;
|
|
455
|
+
const t = [];
|
|
456
|
+
try {
|
|
457
|
+
r();
|
|
458
|
+
} catch (e) {
|
|
459
|
+
t.push(e);
|
|
460
|
+
} finally {
|
|
461
|
+
if (T--, !T)
|
|
462
|
+
try {
|
|
463
|
+
vt();
|
|
464
|
+
} catch (e) {
|
|
465
|
+
t.push(e);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (t.length === 1) throw t[0];
|
|
469
|
+
if (t.length > 1) throw new AggregateError(t, "Snapshot batch failed");
|
|
470
|
+
}
|
|
471
|
+
function vt() {
|
|
472
|
+
if (U) return;
|
|
473
|
+
U = !0;
|
|
474
|
+
const r = [];
|
|
475
|
+
try {
|
|
476
|
+
for (; C.size; ) {
|
|
477
|
+
const t = C.values().next().value;
|
|
478
|
+
C.delete(t), Gt(t, r);
|
|
479
|
+
}
|
|
480
|
+
} finally {
|
|
481
|
+
U = !1, C.clear();
|
|
482
|
+
}
|
|
483
|
+
if (r.length)
|
|
484
|
+
throw new AggregateError(r, "Snapshot error reporting failed");
|
|
485
|
+
}
|
|
486
|
+
class Z {
|
|
360
487
|
#t = /* @__PURE__ */ new Set();
|
|
361
488
|
#e;
|
|
362
489
|
#i;
|
|
@@ -369,24 +496,12 @@ class q {
|
|
|
369
496
|
}
|
|
370
497
|
view = Object.freeze({
|
|
371
498
|
get: () => this.#n(),
|
|
372
|
-
subscribe: (t) => this.#
|
|
499
|
+
subscribe: (t) => this.#a(t)
|
|
373
500
|
});
|
|
374
501
|
invalidate() {
|
|
375
|
-
|
|
376
|
-
this.#
|
|
377
|
-
|
|
378
|
-
for (const i of [...this.#t])
|
|
379
|
-
try {
|
|
380
|
-
bt(i);
|
|
381
|
-
} catch (s) {
|
|
382
|
-
try {
|
|
383
|
-
t(s);
|
|
384
|
-
} catch (n) {
|
|
385
|
-
e.push(s, n);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
if (e.length)
|
|
389
|
-
throw new AggregateError(e, "Snapshot error reporting failed");
|
|
502
|
+
this.#o(), this.#s = !0;
|
|
503
|
+
for (const t of this.#t) C.add(t);
|
|
504
|
+
T || vt();
|
|
390
505
|
}
|
|
391
506
|
dispose() {
|
|
392
507
|
const t = this.#e;
|
|
@@ -398,53 +513,65 @@ class q {
|
|
|
398
513
|
this.#s = !1;
|
|
399
514
|
const e = [...this.#t];
|
|
400
515
|
this.#t.clear();
|
|
401
|
-
for (const i of e)
|
|
516
|
+
for (const i of e) yt(i);
|
|
402
517
|
}
|
|
403
518
|
}
|
|
404
519
|
}
|
|
405
|
-
[
|
|
520
|
+
[v]() {
|
|
406
521
|
this.dispose();
|
|
407
522
|
}
|
|
408
523
|
#n() {
|
|
409
524
|
const t = this.#e;
|
|
410
525
|
return t.phase === "active" && this.#r(t.read), this.#i;
|
|
411
526
|
}
|
|
412
|
-
#
|
|
527
|
+
#a(t) {
|
|
413
528
|
if (typeof t != "function") throw new TypeError("Subscriber must be a function");
|
|
414
|
-
this.#
|
|
415
|
-
|
|
416
|
-
this.#t.delete(i);
|
|
529
|
+
const { report: e } = this.#o(), i = new Bt(t, e, (s) => {
|
|
530
|
+
this.#t.delete(s);
|
|
417
531
|
});
|
|
418
|
-
return this.#t.add(
|
|
532
|
+
return this.#t.add(i), i;
|
|
419
533
|
}
|
|
420
534
|
#r(t) {
|
|
421
535
|
this.#s && (this.#i = t(), this.#s = !1);
|
|
422
536
|
}
|
|
423
|
-
#
|
|
537
|
+
#o() {
|
|
424
538
|
const t = this.#e;
|
|
425
539
|
if (t.phase === "disposed") throw new TypeError("Snapshot publisher is disposed");
|
|
426
540
|
return t;
|
|
427
541
|
}
|
|
428
542
|
}
|
|
429
|
-
class
|
|
430
|
-
constructor(t, e) {
|
|
431
|
-
|
|
543
|
+
class Bt {
|
|
544
|
+
constructor(t, e, i) {
|
|
545
|
+
N.set(this, { listener: t, report: e, detach: i }), Object.freeze(this);
|
|
432
546
|
}
|
|
433
547
|
dispose() {
|
|
434
|
-
const t =
|
|
435
|
-
t && (
|
|
548
|
+
const t = N.get(this);
|
|
549
|
+
t && (yt(this), t.detach(this));
|
|
436
550
|
}
|
|
437
|
-
[
|
|
551
|
+
[v]() {
|
|
438
552
|
this.dispose();
|
|
439
553
|
}
|
|
440
554
|
}
|
|
441
|
-
function
|
|
442
|
-
|
|
555
|
+
function Gt(r, t) {
|
|
556
|
+
const e = N.get(r);
|
|
557
|
+
if (e)
|
|
558
|
+
try {
|
|
559
|
+
R(e.listener(), "Snapshot subscribers must be synchronous");
|
|
560
|
+
} catch (i) {
|
|
561
|
+
try {
|
|
562
|
+
R(
|
|
563
|
+
e.report(i),
|
|
564
|
+
"Snapshot error reporters must be synchronous"
|
|
565
|
+
);
|
|
566
|
+
} catch (s) {
|
|
567
|
+
t.push(i, s);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
443
570
|
}
|
|
444
|
-
function
|
|
445
|
-
|
|
571
|
+
function yt(r) {
|
|
572
|
+
C.delete(r), N.delete(r);
|
|
446
573
|
}
|
|
447
|
-
class
|
|
574
|
+
class Ut {
|
|
448
575
|
#t;
|
|
449
576
|
get;
|
|
450
577
|
subscribe;
|
|
@@ -466,7 +593,7 @@ class yt {
|
|
|
466
593
|
return t;
|
|
467
594
|
}
|
|
468
595
|
}
|
|
469
|
-
class
|
|
596
|
+
class _t {
|
|
470
597
|
#t;
|
|
471
598
|
constructor(t) {
|
|
472
599
|
this.#t = t, Object.freeze(this);
|
|
@@ -477,16 +604,16 @@ class Et {
|
|
|
477
604
|
dispose() {
|
|
478
605
|
this.#t.dispose();
|
|
479
606
|
}
|
|
480
|
-
[
|
|
607
|
+
[v]() {
|
|
481
608
|
this.dispose();
|
|
482
609
|
}
|
|
483
610
|
}
|
|
484
|
-
class
|
|
611
|
+
class Ht {
|
|
485
612
|
#t;
|
|
486
613
|
#e;
|
|
487
614
|
handle;
|
|
488
615
|
constructor(t, e, i, s) {
|
|
489
|
-
this.#e = e, this.#t = { phase: "staged", store: t, value: i, detachFromOwner: s }, this.handle = new
|
|
616
|
+
this.#e = e, this.#t = { phase: "staged", store: t, value: i, detachFromOwner: s }, this.handle = new _t(this);
|
|
490
617
|
}
|
|
491
618
|
publish() {
|
|
492
619
|
const t = this.#t;
|
|
@@ -515,55 +642,62 @@ class Ct {
|
|
|
515
642
|
}
|
|
516
643
|
}
|
|
517
644
|
}
|
|
518
|
-
[
|
|
645
|
+
[v]() {
|
|
519
646
|
this.dispose();
|
|
520
647
|
}
|
|
521
648
|
}
|
|
522
|
-
class
|
|
649
|
+
class Kt {
|
|
523
650
|
#t;
|
|
524
651
|
#e;
|
|
525
652
|
#i = /* @__PURE__ */ new Map();
|
|
526
653
|
#s = /* @__PURE__ */ new Map();
|
|
527
654
|
#n;
|
|
528
|
-
#
|
|
655
|
+
#a = new z();
|
|
529
656
|
#r = 0;
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
#
|
|
657
|
+
#o = 0;
|
|
658
|
+
#h = !1;
|
|
659
|
+
#p = !1;
|
|
533
660
|
constructor(t, e, i) {
|
|
534
|
-
this.#t = t, this.#e = i, this.#n = new
|
|
661
|
+
this.#t = t, this.#e = i, this.#n = new Z(() => this.#a, e);
|
|
535
662
|
}
|
|
536
663
|
stage(t, e, i, s) {
|
|
537
|
-
|
|
538
|
-
const n =
|
|
664
|
+
Jt(e);
|
|
665
|
+
const n = Xt(t, e);
|
|
539
666
|
if (this.#i.has(n))
|
|
540
667
|
throw new TypeError(`Duplicate contribution '${n}'`);
|
|
541
|
-
const o = new
|
|
668
|
+
const o = new Ht(this, n, i, s);
|
|
542
669
|
return this.#i.set(n, o), o;
|
|
543
670
|
}
|
|
544
671
|
view(t) {
|
|
545
672
|
this.#r++;
|
|
546
673
|
const e = { binding: { store: this, own: t } };
|
|
547
674
|
let i;
|
|
548
|
-
const s = new
|
|
675
|
+
const s = new Wt(e, () => {
|
|
549
676
|
const n = i;
|
|
550
677
|
i = void 0;
|
|
551
678
|
try {
|
|
552
679
|
n?.();
|
|
553
680
|
} finally {
|
|
554
|
-
this.#r--, this.#
|
|
681
|
+
this.#r--, this.#c();
|
|
555
682
|
}
|
|
556
683
|
});
|
|
557
684
|
try {
|
|
558
685
|
i = t(s, "view");
|
|
559
686
|
} catch (n) {
|
|
560
|
-
throw e.binding = void 0, this.#r--, this.#
|
|
687
|
+
throw e.binding = void 0, this.#r--, this.#c(), n;
|
|
561
688
|
}
|
|
562
|
-
return new
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
689
|
+
return new Ut(e);
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* A stable view explicitly owned by the Host for graph-external consumers.
|
|
693
|
+
*
|
|
694
|
+
* Application code has no Lifetime to lease a view from, so this one is
|
|
695
|
+
* retained by the Host instead — which also pins the store open for as long as
|
|
696
|
+
* the Host lives. That is the trade: `host.contributions()` gives a handle that
|
|
697
|
+
* never goes stale, at the cost of a store that is no longer self-releasing.
|
|
698
|
+
*/
|
|
565
699
|
hostView() {
|
|
566
|
-
return this.#
|
|
700
|
+
return this.#h = !0, this.#n.view;
|
|
567
701
|
}
|
|
568
702
|
snapshot() {
|
|
569
703
|
return this.#n.view.get();
|
|
@@ -572,15 +706,15 @@ class Ot {
|
|
|
572
706
|
if (typeof t != "function")
|
|
573
707
|
throw new TypeError("Contribution subscriber must be a function");
|
|
574
708
|
const i = this.#n.view.subscribe(t);
|
|
575
|
-
this.#
|
|
709
|
+
this.#o++;
|
|
576
710
|
let s;
|
|
577
|
-
const n = new
|
|
711
|
+
const n = new Yt(i, () => {
|
|
578
712
|
const o = s;
|
|
579
713
|
s = void 0;
|
|
580
714
|
try {
|
|
581
715
|
o?.();
|
|
582
716
|
} finally {
|
|
583
|
-
this.#
|
|
717
|
+
this.#o--, this.#c();
|
|
584
718
|
}
|
|
585
719
|
});
|
|
586
720
|
try {
|
|
@@ -591,39 +725,50 @@ class Ot {
|
|
|
591
725
|
return n;
|
|
592
726
|
}
|
|
593
727
|
insert(t, e, i) {
|
|
594
|
-
if (this.#
|
|
728
|
+
if (this.#u(t, e), this.#s.has(t))
|
|
595
729
|
throw new Error(`Contribution '${t}' is already published`);
|
|
596
730
|
e.commitPublication(), this.#s.set(t, { contribution: e, value: i }), this.#t(this);
|
|
597
731
|
}
|
|
598
732
|
update(t, e, i) {
|
|
599
|
-
const s = this.#
|
|
733
|
+
const s = this.#f(t, e);
|
|
600
734
|
s.value = i, this.#t(this);
|
|
601
735
|
}
|
|
602
736
|
removeContribution(t, e, i) {
|
|
603
|
-
this.#
|
|
737
|
+
this.#u(t, e), i === "published" && this.#f(t, e);
|
|
604
738
|
try {
|
|
605
739
|
this.#i.delete(t), i === "published" && (this.#s.delete(t), this.#t(this));
|
|
606
740
|
} finally {
|
|
607
|
-
this.#
|
|
741
|
+
this.#c();
|
|
608
742
|
}
|
|
609
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Rebuilds the published snapshot, and does nothing when the result would be
|
|
746
|
+
* equal by identity per key. A change that adds and removes the same entry —
|
|
747
|
+
* an Instance restarting with an identical contribution — therefore notifies
|
|
748
|
+
* nobody, instead of waking every observer to hand them what they already had.
|
|
749
|
+
*/
|
|
610
750
|
publishSnapshot() {
|
|
611
751
|
const t = [...this.#s].map(([i, s]) => [i, s.value]);
|
|
612
|
-
t.length === this.#
|
|
752
|
+
t.length === this.#a.size && t.every(
|
|
753
|
+
([i, s]) => this.#a.has(i) && Object.is(this.#a.get(i), s)
|
|
754
|
+
) || (this.#a = new z(t), this.#n.invalidate());
|
|
613
755
|
}
|
|
614
|
-
#
|
|
756
|
+
#u(t, e) {
|
|
615
757
|
if (this.#i.get(t) !== e)
|
|
616
758
|
throw new Error(`Contribution '${t}' is not the current claim`);
|
|
617
759
|
}
|
|
618
|
-
#
|
|
760
|
+
#f(t, e) {
|
|
619
761
|
const i = this.#s.get(t);
|
|
620
762
|
if (i?.contribution !== e)
|
|
621
763
|
throw new Error(`Contribution '${t}' is not the published entry`);
|
|
622
764
|
return i;
|
|
623
765
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
766
|
+
// The self-release check. Every counter has to be at zero and the Host must
|
|
767
|
+
// not be holding a view; `#released` makes it run once, since disposing the
|
|
768
|
+
// publisher can re-enter through a subscription's own teardown.
|
|
769
|
+
#c() {
|
|
770
|
+
if (!(this.#p || this.#h || this.#i.size || this.#s.size || this.#o || this.#r)) {
|
|
771
|
+
this.#p = !0;
|
|
627
772
|
try {
|
|
628
773
|
this.#n.dispose();
|
|
629
774
|
} finally {
|
|
@@ -632,7 +777,7 @@ class Ot {
|
|
|
632
777
|
}
|
|
633
778
|
}
|
|
634
779
|
}
|
|
635
|
-
class
|
|
780
|
+
class Wt {
|
|
636
781
|
#t;
|
|
637
782
|
constructor(t, e) {
|
|
638
783
|
this.#t = { state: t, release: e }, Object.freeze(this);
|
|
@@ -641,11 +786,11 @@ class St {
|
|
|
641
786
|
const t = this.#t;
|
|
642
787
|
t && (this.#t = void 0, t.state.binding = void 0, t.release());
|
|
643
788
|
}
|
|
644
|
-
[
|
|
789
|
+
[v]() {
|
|
645
790
|
this.dispose();
|
|
646
791
|
}
|
|
647
792
|
}
|
|
648
|
-
class
|
|
793
|
+
class Yt {
|
|
649
794
|
#t;
|
|
650
795
|
constructor(t, e) {
|
|
651
796
|
this.#t = { subscription: t, release: e }, Object.freeze(this);
|
|
@@ -661,11 +806,11 @@ class It {
|
|
|
661
806
|
}
|
|
662
807
|
}
|
|
663
808
|
}
|
|
664
|
-
[
|
|
809
|
+
[v]() {
|
|
665
810
|
this.dispose();
|
|
666
811
|
}
|
|
667
812
|
}
|
|
668
|
-
class
|
|
813
|
+
class Qt {
|
|
669
814
|
#t = /* @__PURE__ */ new Map();
|
|
670
815
|
#e = /* @__PURE__ */ new Set();
|
|
671
816
|
#i;
|
|
@@ -676,7 +821,7 @@ class At {
|
|
|
676
821
|
get(t) {
|
|
677
822
|
const e = this.#t.get(t.id);
|
|
678
823
|
if (e) return e;
|
|
679
|
-
const i = new
|
|
824
|
+
const i = new Kt(
|
|
680
825
|
(s) => this.#n(s),
|
|
681
826
|
this.#i,
|
|
682
827
|
(s) => {
|
|
@@ -691,39 +836,44 @@ class At {
|
|
|
691
836
|
beginBatch() {
|
|
692
837
|
this.#s++;
|
|
693
838
|
}
|
|
839
|
+
// Depth-counted, so nested Host operations collapse into the outermost batch
|
|
840
|
+
// and publication happens exactly once. Every store's snapshot is attempted
|
|
841
|
+
// even if one of them throws, then the failures are aggregated — a single bad
|
|
842
|
+
// subscriber must not leave the remaining stores unpublished.
|
|
694
843
|
endBatch() {
|
|
695
844
|
if (!this.#s) throw new Error("Contribution batch is not active");
|
|
696
845
|
if (this.#s--, this.#s) return;
|
|
697
846
|
const t = [...this.#e];
|
|
698
|
-
this.#e.clear()
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
847
|
+
this.#e.clear(), Ft(() => {
|
|
848
|
+
const e = [];
|
|
849
|
+
for (const i of t)
|
|
850
|
+
try {
|
|
851
|
+
i.publishSnapshot();
|
|
852
|
+
} catch (s) {
|
|
853
|
+
e.push(s);
|
|
854
|
+
}
|
|
855
|
+
if (e.length === 1) throw e[0];
|
|
856
|
+
if (e.length > 1)
|
|
857
|
+
throw new AggregateError(e, "Contribution batch publication failed");
|
|
858
|
+
});
|
|
709
859
|
}
|
|
710
860
|
#n(t) {
|
|
711
861
|
this.#e.add(t), !this.#s && (this.#e.delete(t), t.publishSnapshot());
|
|
712
862
|
}
|
|
713
863
|
}
|
|
714
|
-
function
|
|
864
|
+
function Jt(r) {
|
|
715
865
|
if (typeof r != "string" || !r.trim())
|
|
716
866
|
throw new TypeError("Contribution key must be a non-empty string");
|
|
717
867
|
if (r !== r.trim())
|
|
718
868
|
throw new TypeError("Contribution key cannot start or end with whitespace");
|
|
719
869
|
}
|
|
720
|
-
function
|
|
721
|
-
return `${
|
|
870
|
+
function Xt(r, t) {
|
|
871
|
+
return `${ot(r)}/${ot(t)}`;
|
|
722
872
|
}
|
|
723
|
-
function
|
|
873
|
+
function ot(r) {
|
|
724
874
|
return r.replaceAll("%", "%25").replaceAll("/", "%2F");
|
|
725
875
|
}
|
|
726
|
-
class
|
|
876
|
+
class Zt {
|
|
727
877
|
#t;
|
|
728
878
|
constructor(t) {
|
|
729
879
|
this.#t = t, Object.freeze(this);
|
|
@@ -732,16 +882,16 @@ class jt {
|
|
|
732
882
|
const t = this.#t;
|
|
733
883
|
this.#t = void 0, t?.dispose();
|
|
734
884
|
}
|
|
735
|
-
[
|
|
885
|
+
[v]() {
|
|
736
886
|
this.dispose();
|
|
737
887
|
}
|
|
738
888
|
}
|
|
739
|
-
class
|
|
889
|
+
class te {
|
|
740
890
|
#t;
|
|
741
891
|
#e;
|
|
742
892
|
handle;
|
|
743
893
|
constructor(t, e, i, s) {
|
|
744
|
-
this.#e = e, this.#t = { phase: "staged", hub: t, slot: { listener: i }, release: s }, this.handle = new
|
|
894
|
+
this.#e = e, this.#t = { phase: "staged", hub: t, slot: { listener: i }, release: s }, this.handle = new Zt(this);
|
|
745
895
|
}
|
|
746
896
|
publish() {
|
|
747
897
|
const t = this.#t;
|
|
@@ -750,7 +900,7 @@ class kt {
|
|
|
750
900
|
dispose() {
|
|
751
901
|
const t = this.#t;
|
|
752
902
|
if (t.phase !== "removed") {
|
|
753
|
-
this.#t = { phase: "removed" };
|
|
903
|
+
this.#t = { phase: "removed" }, t.slot.listener = void 0;
|
|
754
904
|
try {
|
|
755
905
|
t.phase === "published" && t.hub.delete(this.#e, t.slot);
|
|
756
906
|
} finally {
|
|
@@ -758,15 +908,15 @@ class kt {
|
|
|
758
908
|
}
|
|
759
909
|
}
|
|
760
910
|
}
|
|
761
|
-
[
|
|
911
|
+
[v]() {
|
|
762
912
|
this.dispose();
|
|
763
913
|
}
|
|
764
914
|
}
|
|
765
|
-
class
|
|
915
|
+
class ee {
|
|
766
916
|
#t = /* @__PURE__ */ new Map();
|
|
767
917
|
stage(t, e, i) {
|
|
768
918
|
if (typeof e != "function") throw new TypeError("Event listener must be a function");
|
|
769
|
-
return new
|
|
919
|
+
return new te(this, t, e, i);
|
|
770
920
|
}
|
|
771
921
|
add(t, e) {
|
|
772
922
|
const i = this.#t.get(t) ?? /* @__PURE__ */ new Set();
|
|
@@ -776,25 +926,34 @@ class Pt {
|
|
|
776
926
|
const i = this.#t.get(t);
|
|
777
927
|
i && (i.delete(e), i.size || this.#t.delete(t));
|
|
778
928
|
}
|
|
929
|
+
/**
|
|
930
|
+
* Every still-subscribed listener runs, then failures are aggregated. Three details, all
|
|
931
|
+
* deliberate:
|
|
932
|
+
*
|
|
933
|
+
* - the listener set is copied first; a new subscription does not join this
|
|
934
|
+
* emission. A disposed slot is skipped if its callback has not started;
|
|
935
|
+
* - each call is wrapped in a resolved promise, so a listener that throws
|
|
936
|
+
* synchronously is collected like one that rejects;
|
|
937
|
+
* - `allSettled`, so one broken listener cannot stop the others from being
|
|
938
|
+
* told. The emitter still learns about it — every error comes back.
|
|
939
|
+
*/
|
|
779
940
|
async emit(t, e) {
|
|
780
|
-
const i = [...this.#t.get(t) ?? []].
|
|
781
|
-
(o) => o.listener
|
|
782
|
-
), n = (await Promise.allSettled(
|
|
783
|
-
i.map((o) => Promise.resolve().then(() => o(e)))
|
|
941
|
+
const i = [...this.#t.get(t) ?? []], n = (await Promise.allSettled(
|
|
942
|
+
i.map((o) => Promise.resolve().then(() => o.listener?.(e)))
|
|
784
943
|
)).filter((o) => o.status === "rejected").map((o) => o.reason);
|
|
785
944
|
if (n.length)
|
|
786
945
|
throw new AggregateError(n, `Event '${t}' listeners failed`);
|
|
787
946
|
}
|
|
788
947
|
}
|
|
789
|
-
class
|
|
948
|
+
class ie {
|
|
790
949
|
#t;
|
|
791
950
|
root;
|
|
792
951
|
view;
|
|
793
952
|
constructor(t, e) {
|
|
794
|
-
this.root =
|
|
953
|
+
this.root = at(t), this.#t = new Z(() => Et(this.root), e), this.view = this.#t.view;
|
|
795
954
|
}
|
|
796
955
|
createNode(t) {
|
|
797
|
-
return
|
|
956
|
+
return at(t);
|
|
798
957
|
}
|
|
799
958
|
attach(t, e) {
|
|
800
959
|
if (t.children.has(e)) throw new Error("Lifetime diagnostic node is attached");
|
|
@@ -815,7 +974,7 @@ class Lt {
|
|
|
815
974
|
this.root.phase !== "disposed" && (this.root.phase = "disposed", this.#t.invalidate(), this.#t.dispose());
|
|
816
975
|
}
|
|
817
976
|
}
|
|
818
|
-
function
|
|
977
|
+
function at(r) {
|
|
819
978
|
return {
|
|
820
979
|
label: r,
|
|
821
980
|
phase: "active",
|
|
@@ -830,8 +989,8 @@ function F(r) {
|
|
|
830
989
|
children: /* @__PURE__ */ new Set()
|
|
831
990
|
};
|
|
832
991
|
}
|
|
833
|
-
function
|
|
834
|
-
const t = Object.freeze([...r.children].map(
|
|
992
|
+
function Et(r) {
|
|
993
|
+
const t = Object.freeze([...r.children].map(Et));
|
|
835
994
|
return Object.freeze({
|
|
836
995
|
label: r.label,
|
|
837
996
|
phase: r.phase,
|
|
@@ -839,15 +998,19 @@ function et(r) {
|
|
|
839
998
|
children: t
|
|
840
999
|
});
|
|
841
1000
|
}
|
|
842
|
-
function
|
|
843
|
-
if (!r || typeof r != "object") return !1;
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1001
|
+
function se(r) {
|
|
1002
|
+
if (!r || typeof r != "object" && typeof r != "function") return !1;
|
|
1003
|
+
try {
|
|
1004
|
+
const t = r;
|
|
1005
|
+
return [t.debug, t.info, t.warn, t.error].every(
|
|
1006
|
+
(e) => typeof e == "function"
|
|
1007
|
+
);
|
|
1008
|
+
} catch {
|
|
1009
|
+
return !1;
|
|
1010
|
+
}
|
|
848
1011
|
}
|
|
849
|
-
const
|
|
850
|
-
class
|
|
1012
|
+
const W = Object.freeze(new DOMException("Resource disposed", "AbortError"));
|
|
1013
|
+
class y {
|
|
851
1014
|
#t = /* @__PURE__ */ new Set();
|
|
852
1015
|
#e;
|
|
853
1016
|
constructor(t) {
|
|
@@ -867,6 +1030,12 @@ class w {
|
|
|
867
1030
|
const e = this.#e;
|
|
868
1031
|
return e && e.diagnostics.change(e.node, e.kind, -1), !0;
|
|
869
1032
|
};
|
|
1033
|
+
/**
|
|
1034
|
+
* Disposes in reverse creation order, collecting failures rather than
|
|
1035
|
+
* throwing. Later resources may depend on earlier ones, and a resource that
|
|
1036
|
+
* refuses to shut down cleanly must not strand its siblings. The caller
|
|
1037
|
+
* aggregates the collected errors.
|
|
1038
|
+
*/
|
|
870
1039
|
async dispose(t) {
|
|
871
1040
|
try {
|
|
872
1041
|
for (const e of [...this.#t].reverse())
|
|
@@ -881,11 +1050,26 @@ class w {
|
|
|
881
1050
|
this.#e = void 0;
|
|
882
1051
|
}
|
|
883
1052
|
}
|
|
1053
|
+
/** Capability withdrawal must finish without yielding to callbacks or tasks. */
|
|
1054
|
+
disposeSynchronously(t) {
|
|
1055
|
+
try {
|
|
1056
|
+
for (const e of [...this.#t].reverse())
|
|
1057
|
+
try {
|
|
1058
|
+
e.dispose();
|
|
1059
|
+
} catch (i) {
|
|
1060
|
+
t.push(i);
|
|
1061
|
+
} finally {
|
|
1062
|
+
this.release(e);
|
|
1063
|
+
}
|
|
1064
|
+
} finally {
|
|
1065
|
+
this.#e = void 0;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
884
1068
|
[Symbol.iterator]() {
|
|
885
1069
|
return this.#t[Symbol.iterator]();
|
|
886
1070
|
}
|
|
887
1071
|
}
|
|
888
|
-
class
|
|
1072
|
+
class re {
|
|
889
1073
|
#t;
|
|
890
1074
|
constructor(t, e) {
|
|
891
1075
|
this.#t = { phase: "active", cleanup: t, detachFromParent: e }, Object.freeze(this);
|
|
@@ -905,11 +1089,11 @@ class Rt {
|
|
|
905
1089
|
});
|
|
906
1090
|
return this.#t = { phase: "disposing", completion: e }, e;
|
|
907
1091
|
}
|
|
908
|
-
[
|
|
1092
|
+
[F]() {
|
|
909
1093
|
return this.dispose();
|
|
910
1094
|
}
|
|
911
1095
|
}
|
|
912
|
-
class
|
|
1096
|
+
class ne {
|
|
913
1097
|
#t;
|
|
914
1098
|
#e;
|
|
915
1099
|
#i;
|
|
@@ -922,7 +1106,7 @@ class Nt {
|
|
|
922
1106
|
() => this.#s(),
|
|
923
1107
|
(a) => {
|
|
924
1108
|
try {
|
|
925
|
-
|
|
1109
|
+
wt(n.signal, a) || i(a);
|
|
926
1110
|
} finally {
|
|
927
1111
|
this.#s();
|
|
928
1112
|
}
|
|
@@ -940,9 +1124,9 @@ class Nt {
|
|
|
940
1124
|
() => {
|
|
941
1125
|
}
|
|
942
1126
|
);
|
|
943
|
-
return this.#i = { phase: "disposing", completion: e }, t.controller.abort(
|
|
1127
|
+
return this.#i = { phase: "disposing", completion: e }, t.controller.abort(W), this.#n(), e;
|
|
944
1128
|
}
|
|
945
|
-
[
|
|
1129
|
+
[F]() {
|
|
946
1130
|
return this.dispose();
|
|
947
1131
|
}
|
|
948
1132
|
#s() {
|
|
@@ -956,54 +1140,54 @@ class Nt {
|
|
|
956
1140
|
this.#t = void 0, t?.();
|
|
957
1141
|
}
|
|
958
1142
|
}
|
|
959
|
-
class
|
|
1143
|
+
class tt {
|
|
960
1144
|
#t;
|
|
961
1145
|
#e;
|
|
962
1146
|
#i;
|
|
963
1147
|
#s;
|
|
964
1148
|
#n;
|
|
965
|
-
#o;
|
|
966
|
-
#r;
|
|
967
1149
|
#a;
|
|
968
|
-
#
|
|
969
|
-
#
|
|
970
|
-
#
|
|
1150
|
+
#r;
|
|
1151
|
+
#o;
|
|
1152
|
+
#h;
|
|
1153
|
+
#p;
|
|
971
1154
|
#u;
|
|
1155
|
+
#f;
|
|
972
1156
|
handle;
|
|
973
|
-
#
|
|
1157
|
+
#c;
|
|
974
1158
|
constructor(t, e, i = {}) {
|
|
975
|
-
this.#e = e, this.handle = new
|
|
1159
|
+
this.#e = e, this.handle = new oe(this);
|
|
976
1160
|
const s = new AbortController();
|
|
977
|
-
this.#
|
|
1161
|
+
this.#c = {
|
|
978
1162
|
phase: "active",
|
|
979
1163
|
controller: s,
|
|
980
1164
|
declarations: i.declarations ?? "staged"
|
|
981
1165
|
};
|
|
982
1166
|
const n = i.parent;
|
|
983
|
-
this.#
|
|
984
|
-
const o = n?.diagnostics ?? new
|
|
1167
|
+
this.#f = n?.detach, this.#p = n ? "child" : "root";
|
|
1168
|
+
const o = n?.diagnostics ?? new ie(e, (l) => t.report(l)), a = n?.diagnosticNode ?? o.root;
|
|
985
1169
|
this.#t = { port: t, diagnostics: o, diagnosticNode: a };
|
|
986
1170
|
const h = (l) => ({
|
|
987
1171
|
diagnostics: o,
|
|
988
1172
|
node: a,
|
|
989
1173
|
kind: l
|
|
990
1174
|
});
|
|
991
|
-
this.#i = new
|
|
1175
|
+
this.#i = new y(h("listeners")), this.#s = new y(h("contributions")), this.#n = new y(h("contributionViews")), this.#a = new y(h("subscriptions")), this.#r = new y(h("tasks")), this.#o = new y(), this.#h = new y(h("cleanups"));
|
|
992
1176
|
const c = i.parentSignal;
|
|
993
1177
|
if (!c) return;
|
|
994
1178
|
const d = () => s.abort(c.reason);
|
|
995
|
-
c.addEventListener("abort", d, { once: !0 }), this.#
|
|
1179
|
+
c.addEventListener("abort", d, { once: !0 }), this.#u = () => c.removeEventListener("abort", d), c.aborted && d();
|
|
996
1180
|
}
|
|
997
1181
|
get signal() {
|
|
998
|
-
const t = this.#
|
|
1182
|
+
const t = this.#c;
|
|
999
1183
|
return t.phase === "disposed" ? t.signal : t.controller.signal;
|
|
1000
1184
|
}
|
|
1001
1185
|
get diagnostics() {
|
|
1002
|
-
return this.#
|
|
1186
|
+
return this.#g().diagnostics.view;
|
|
1003
1187
|
}
|
|
1004
|
-
/** A facade whose only
|
|
1188
|
+
/** A facade whose only InstanceCoordinator edge disappears when this Lifetime terminates. */
|
|
1005
1189
|
contextLogger(t) {
|
|
1006
|
-
const e = (i) => (s, ...n) => this.#
|
|
1190
|
+
const e = (i) => (s, ...n) => this.#g().port.writeLog(i, s, t, n);
|
|
1007
1191
|
return Object.freeze({
|
|
1008
1192
|
debug: e("debug"),
|
|
1009
1193
|
info: e("info"),
|
|
@@ -1012,30 +1196,39 @@ class D {
|
|
|
1012
1196
|
});
|
|
1013
1197
|
}
|
|
1014
1198
|
cleanup(t) {
|
|
1015
|
-
if (this.#
|
|
1016
|
-
const e = new
|
|
1017
|
-
return this.#
|
|
1018
|
-
}
|
|
1199
|
+
if (this.#d(), typeof t != "function") throw new TypeError("Cleanup must be a function");
|
|
1200
|
+
const e = new re(t, this.#h.release);
|
|
1201
|
+
return this.#h.add(e), e;
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* A child scope. It inherits this Lifetime's signal, so cancellation flows
|
|
1205
|
+
* down, and its declaration phase, so a child created during `setup()` also
|
|
1206
|
+
* stages rather than publishing immediately.
|
|
1207
|
+
*
|
|
1208
|
+
* Disposing a child detaches it from both the resource set and the diagnostics
|
|
1209
|
+
* tree. A Plugin can therefore use child lifetimes as a unit of work — one per
|
|
1210
|
+
* open document, per connection — without the parent growing.
|
|
1211
|
+
*/
|
|
1019
1212
|
lifetime(t) {
|
|
1020
|
-
const { port: e, diagnostics: i, diagnosticNode: s } = this.#
|
|
1021
|
-
|
|
1022
|
-
const n = i.createNode(t), o = new
|
|
1213
|
+
const { port: e, diagnostics: i, diagnosticNode: s } = this.#d();
|
|
1214
|
+
ae(t);
|
|
1215
|
+
const n = i.createNode(t), o = new tt(e, this.#e, {
|
|
1023
1216
|
parentSignal: this.signal,
|
|
1024
|
-
declarations: this.#
|
|
1217
|
+
declarations: this.#w(),
|
|
1025
1218
|
parent: {
|
|
1026
1219
|
diagnostics: i,
|
|
1027
1220
|
diagnosticNode: n,
|
|
1028
1221
|
detach: (a) => {
|
|
1029
|
-
this.#
|
|
1222
|
+
this.#o.release(a) && i.detach(s, n);
|
|
1030
1223
|
}
|
|
1031
1224
|
}
|
|
1032
1225
|
});
|
|
1033
|
-
return this.#
|
|
1226
|
+
return this.#o.add(o), i.attach(s, n), o.handle;
|
|
1034
1227
|
}
|
|
1035
1228
|
spawn(t) {
|
|
1036
|
-
const { port: e } = this.#
|
|
1229
|
+
const { port: e } = this.#d();
|
|
1037
1230
|
if (typeof t != "function") throw new TypeError("Background task must be a function");
|
|
1038
|
-
const i = new
|
|
1231
|
+
const i = new ne(
|
|
1039
1232
|
this.signal,
|
|
1040
1233
|
t,
|
|
1041
1234
|
(s) => e.report(s),
|
|
@@ -1044,84 +1237,137 @@ class D {
|
|
|
1044
1237
|
return this.#r.add(i), i;
|
|
1045
1238
|
}
|
|
1046
1239
|
on(t, e) {
|
|
1047
|
-
const { port: i } = this.#
|
|
1048
|
-
|
|
1240
|
+
const { port: i } = this.#d(), s = i.stageOn(
|
|
1241
|
+
this.#e,
|
|
1242
|
+
t,
|
|
1243
|
+
e,
|
|
1244
|
+
this.#i.release
|
|
1245
|
+
);
|
|
1246
|
+
return this.#i.add(s), this.#w() === "published" && s.publish(), s.handle;
|
|
1049
1247
|
}
|
|
1050
1248
|
async emit(t, ...e) {
|
|
1051
|
-
const { port: i } = this.#
|
|
1249
|
+
const { port: i } = this.#d();
|
|
1052
1250
|
await i.emit(this.#e, t, e[0]);
|
|
1053
1251
|
}
|
|
1054
1252
|
contribute(t, e, i) {
|
|
1055
|
-
const { port: s } = this.#
|
|
1253
|
+
const { port: s } = this.#d(), n = s.stageContribution(
|
|
1056
1254
|
this.#e,
|
|
1057
1255
|
t,
|
|
1058
1256
|
e,
|
|
1059
1257
|
i,
|
|
1060
1258
|
this.#s.release
|
|
1061
1259
|
);
|
|
1062
|
-
return this.#s.add(n), this.#
|
|
1260
|
+
return this.#s.add(n), this.#w() === "published" && n.publish(), n.handle;
|
|
1063
1261
|
}
|
|
1064
1262
|
/** Owns an internal live capability without exposing a second Context API. */
|
|
1065
1263
|
ownLease(t, e) {
|
|
1066
|
-
return this.#
|
|
1264
|
+
return this.#d(), (e === "view" ? this.#n : this.#a).own(t);
|
|
1067
1265
|
}
|
|
1068
1266
|
/** Releases a temporary startup cancellation edge after its layer commits. */
|
|
1069
1267
|
detachStartupSignal() {
|
|
1070
|
-
const t = this.#
|
|
1071
|
-
this.#
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1268
|
+
const t = this.#u;
|
|
1269
|
+
this.#u = void 0, t?.();
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Atomically makes all declarations staged during setup visible.
|
|
1273
|
+
*
|
|
1274
|
+
* Children publish too, recursively, so a Lifetime created inside `setup()`
|
|
1275
|
+
* becomes visible with its parent rather than being stranded staged. Called by
|
|
1276
|
+
* the InstanceCoordinator once the whole activation layer has succeeded —
|
|
1277
|
+
* which is what makes "no half-built Instance is observable" true.
|
|
1278
|
+
*/
|
|
1074
1279
|
publish() {
|
|
1075
|
-
const t = this.#
|
|
1076
|
-
if (t.phase !== "active") throw
|
|
1077
|
-
if (this.#
|
|
1280
|
+
const t = this.#c;
|
|
1281
|
+
if (t.phase !== "active") throw $();
|
|
1282
|
+
if (this.#d(), t.declarations !== "published") {
|
|
1078
1283
|
for (const e of this.#i) e.publish();
|
|
1079
1284
|
for (const e of this.#s) e.publish();
|
|
1080
|
-
for (const e of this.#
|
|
1081
|
-
this.#
|
|
1285
|
+
for (const e of this.#o) e.publish();
|
|
1286
|
+
this.#c = { ...t, declarations: "published" };
|
|
1082
1287
|
}
|
|
1083
1288
|
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Disposal is idempotent and joinable: concurrent callers share one completion
|
|
1291
|
+
* promise, so a Lifetime disposed by both its owner and a `using` block runs
|
|
1292
|
+
* its teardown once.
|
|
1293
|
+
*
|
|
1294
|
+
* The three-stage order is the module header's; see it for why. Errors from
|
|
1295
|
+
* every stage accumulate and are aggregated at the end, so one failing cleanup
|
|
1296
|
+
* neither hides the others nor prevents them from running.
|
|
1297
|
+
*/
|
|
1084
1298
|
dispose() {
|
|
1085
|
-
const t = this.#
|
|
1299
|
+
const t = this.#c;
|
|
1086
1300
|
if (t.phase === "disposing") return t.completion;
|
|
1087
1301
|
if (t.phase === "disposed") return Promise.resolve();
|
|
1088
|
-
const e =
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
s?.(this), this.#f === "root" && e.diagnostics.finishRoot();
|
|
1098
|
-
} finally {
|
|
1099
|
-
this.#t = void 0;
|
|
1100
|
-
}
|
|
1101
|
-
});
|
|
1102
|
-
return this.#h = { phase: "disposing", controller: t.controller, completion: i }, e.diagnostics.beginDisposing(e.diagnosticNode), i;
|
|
1302
|
+
const e = [], i = this.#l(e);
|
|
1303
|
+
for (const { lifetime: s, errors: n } of e)
|
|
1304
|
+
s.#i.disposeSynchronously(n), s.#a.disposeSynchronously(n), s.#n.disposeSynchronously(n);
|
|
1305
|
+
for (const { lifetime: s, errors: n } of e)
|
|
1306
|
+
s.#s.disposeSynchronously(n);
|
|
1307
|
+
for (const { lifetime: s, binding: n, controller: o } of e)
|
|
1308
|
+
n.diagnostics.beginDisposing(n.diagnosticNode), o.abort(W), s.detachStartupSignal();
|
|
1309
|
+
for (const s of e) s.finish();
|
|
1310
|
+
return i;
|
|
1103
1311
|
}
|
|
1104
|
-
|
|
1312
|
+
/** Stages joinable completions without running any externally observable work. */
|
|
1313
|
+
#l(t) {
|
|
1314
|
+
const e = this.#c;
|
|
1315
|
+
if (e.phase === "disposing") return e.completion;
|
|
1316
|
+
if (e.phase === "disposed") return Promise.resolve();
|
|
1317
|
+
const i = this.#g(), s = Promise.withResolvers(), n = [];
|
|
1318
|
+
this.#c = {
|
|
1319
|
+
phase: "disposing",
|
|
1320
|
+
controller: e.controller,
|
|
1321
|
+
completion: s.promise
|
|
1322
|
+
};
|
|
1323
|
+
const o = Promise.allSettled(
|
|
1324
|
+
[...this.#o].reverse().map((h) => h.#l(t))
|
|
1325
|
+
), a = () => {
|
|
1326
|
+
(async () => {
|
|
1327
|
+
try {
|
|
1328
|
+
await this.#r.dispose(n);
|
|
1329
|
+
for (const h of await o)
|
|
1330
|
+
h.status === "rejected" && n.push(h.reason);
|
|
1331
|
+
if (await this.#h.dispose(n), n.length === 1) throw n[0];
|
|
1332
|
+
if (n.length > 1) throw new AggregateError(n, "Lifetime cleanup failed");
|
|
1333
|
+
} finally {
|
|
1334
|
+
this.#c = { phase: "disposed", signal: AbortSignal.abort(W) };
|
|
1335
|
+
const h = this.#f;
|
|
1336
|
+
this.#f = void 0;
|
|
1337
|
+
try {
|
|
1338
|
+
h?.(this), this.#p === "root" && i.diagnostics.finishRoot();
|
|
1339
|
+
} finally {
|
|
1340
|
+
this.#t = void 0;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
})().then(s.resolve, s.reject);
|
|
1344
|
+
};
|
|
1345
|
+
return t.push({ lifetime: this, errors: n, binding: i, controller: e.controller, finish: a }), s.promise;
|
|
1346
|
+
}
|
|
1347
|
+
[F]() {
|
|
1105
1348
|
return this.dispose();
|
|
1106
1349
|
}
|
|
1107
|
-
|
|
1350
|
+
// The gate on every operation that creates a resource. `signal.aborted` is
|
|
1351
|
+
// checked as well as the phase, because a parent's disposal aborts this signal
|
|
1352
|
+
// during startup cancellation as well as disposal. Both boundaries close work.
|
|
1353
|
+
#d() {
|
|
1108
1354
|
const t = this.#t;
|
|
1109
|
-
if (this.#
|
|
1110
|
-
throw
|
|
1355
|
+
if (this.#c.phase !== "active" || this.signal.aborted || !t)
|
|
1356
|
+
throw $();
|
|
1111
1357
|
return t;
|
|
1112
1358
|
}
|
|
1113
|
-
#
|
|
1359
|
+
#g() {
|
|
1114
1360
|
const t = this.#t;
|
|
1115
|
-
if (!t) throw
|
|
1361
|
+
if (!t) throw $();
|
|
1116
1362
|
return t;
|
|
1117
1363
|
}
|
|
1118
|
-
#
|
|
1119
|
-
const t = this.#
|
|
1120
|
-
if (t.phase !== "active") throw
|
|
1364
|
+
#w() {
|
|
1365
|
+
const t = this.#c;
|
|
1366
|
+
if (t.phase !== "active") throw $();
|
|
1121
1367
|
return t.declarations;
|
|
1122
1368
|
}
|
|
1123
1369
|
}
|
|
1124
|
-
class
|
|
1370
|
+
class oe {
|
|
1125
1371
|
#t;
|
|
1126
1372
|
constructor(t) {
|
|
1127
1373
|
this.#t = t, Object.freeze(this);
|
|
@@ -1150,32 +1396,32 @@ class xt {
|
|
|
1150
1396
|
dispose() {
|
|
1151
1397
|
return this.#t.dispose();
|
|
1152
1398
|
}
|
|
1153
|
-
[
|
|
1399
|
+
[F]() {
|
|
1154
1400
|
return this.dispose();
|
|
1155
1401
|
}
|
|
1156
1402
|
}
|
|
1157
|
-
function
|
|
1403
|
+
function ae(r) {
|
|
1158
1404
|
if (typeof r != "string" || !r.trim())
|
|
1159
1405
|
throw new TypeError("Lifetime label must be a non-empty string");
|
|
1160
1406
|
if (r !== r.trim())
|
|
1161
1407
|
throw new TypeError("Lifetime label cannot start or end with whitespace");
|
|
1162
1408
|
}
|
|
1163
|
-
function
|
|
1409
|
+
function $() {
|
|
1164
1410
|
return new u("LIFETIME_DISPOSED", "Lifetime is disposing or has been disposed");
|
|
1165
1411
|
}
|
|
1166
|
-
class
|
|
1412
|
+
class Y extends AggregateError {
|
|
1167
1413
|
}
|
|
1168
|
-
class
|
|
1414
|
+
class ce {
|
|
1169
1415
|
#t;
|
|
1170
1416
|
#e;
|
|
1171
1417
|
#i;
|
|
1172
1418
|
#s;
|
|
1173
1419
|
#n = /* @__PURE__ */ new Map();
|
|
1174
|
-
#
|
|
1420
|
+
#a = new ee();
|
|
1175
1421
|
#r;
|
|
1176
|
-
#
|
|
1422
|
+
#o = [];
|
|
1177
1423
|
constructor(t) {
|
|
1178
|
-
this.#t = t.hostName, this.#e = t.logger, this.#i = t.isInstalled, this.#s = t.report, this.#r = new
|
|
1424
|
+
this.#t = t.hostName, this.#e = t.logger, this.#i = t.isInstalled, this.#s = t.report, this.#r = new Qt(t.report);
|
|
1179
1425
|
}
|
|
1180
1426
|
readService(t, e) {
|
|
1181
1427
|
const i = this.#n.get(t);
|
|
@@ -1193,16 +1439,16 @@ class Mt {
|
|
|
1193
1439
|
return e;
|
|
1194
1440
|
}
|
|
1195
1441
|
resetActivationState() {
|
|
1196
|
-
this.#n.clear(), this.#
|
|
1442
|
+
this.#n.clear(), this.#o = [];
|
|
1197
1443
|
}
|
|
1198
1444
|
commitActivationOrder(t) {
|
|
1199
|
-
this.#
|
|
1445
|
+
this.#o = t.slice();
|
|
1200
1446
|
}
|
|
1201
1447
|
deactivateAll() {
|
|
1202
|
-
return this.deactivate(new Set(this.#
|
|
1448
|
+
return this.deactivate(new Set(this.#o));
|
|
1203
1449
|
}
|
|
1204
1450
|
async activate(t, e, i, s) {
|
|
1205
|
-
const n = this.#
|
|
1451
|
+
const n = this.#l(s);
|
|
1206
1452
|
for (const o of t.layers) {
|
|
1207
1453
|
const a = o.filter(
|
|
1208
1454
|
(f) => e.has(f) && !f.instance
|
|
@@ -1211,38 +1457,42 @@ class Mt {
|
|
|
1211
1457
|
const h = new AbortController(), c = await Promise.allSettled(
|
|
1212
1458
|
a.map(async (f) => {
|
|
1213
1459
|
try {
|
|
1214
|
-
|
|
1215
|
-
f.
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
);
|
|
1219
|
-
return await this.#d(
|
|
1460
|
+
if (!i.has(f))
|
|
1461
|
+
throw new Error(`Installation '${f.id}' has no prepared config`);
|
|
1462
|
+
const g = i.get(f);
|
|
1463
|
+
return await this.#h(
|
|
1220
1464
|
t,
|
|
1221
1465
|
f,
|
|
1222
|
-
|
|
1466
|
+
g,
|
|
1223
1467
|
h.signal,
|
|
1224
1468
|
n
|
|
1225
1469
|
);
|
|
1226
|
-
} catch (
|
|
1227
|
-
throw h.abort(
|
|
1470
|
+
} catch (g) {
|
|
1471
|
+
throw h.abort(g), g;
|
|
1228
1472
|
}
|
|
1229
1473
|
})
|
|
1230
|
-
), d =
|
|
1474
|
+
), d = he(c, h.signal), l = c.filter(
|
|
1231
1475
|
(f) => f.status === "fulfilled"
|
|
1232
1476
|
).map((f) => f.value);
|
|
1233
1477
|
if (d.length) {
|
|
1234
|
-
const f = await this.#
|
|
1235
|
-
throw f.length ? new
|
|
1236
|
-
[
|
|
1478
|
+
const f = await this.#u(l), g = d.length === 1 ? d[0] : new AggregateError(d, "Installation startup layer failed");
|
|
1479
|
+
throw f.length ? new Y(
|
|
1480
|
+
[g, ...f],
|
|
1237
1481
|
"Installation startup layer failed and could not be cleanly disposed"
|
|
1238
|
-
) :
|
|
1482
|
+
) : g;
|
|
1239
1483
|
}
|
|
1240
|
-
this.#
|
|
1484
|
+
this.#p(l);
|
|
1241
1485
|
}
|
|
1242
1486
|
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Stops in reverse activation order, sequentially, and collects every failure
|
|
1489
|
+
* instead of stopping at the first. A dependent must be gone before the
|
|
1490
|
+
* Service it consumed, and one Instance that refuses to shut down cleanly must
|
|
1491
|
+
* not leave the rest running — its error is returned, not thrown.
|
|
1492
|
+
*/
|
|
1243
1493
|
async deactivate(t) {
|
|
1244
|
-
const e = [], i = this.#
|
|
1245
|
-
this.#
|
|
1494
|
+
const e = [], i = this.#o.filter((s) => t.has(s)).reverse();
|
|
1495
|
+
this.#o = this.#o.filter(
|
|
1246
1496
|
(s) => !t.has(s)
|
|
1247
1497
|
);
|
|
1248
1498
|
for (const s of i) {
|
|
@@ -1260,6 +1510,17 @@ class Mt {
|
|
|
1260
1510
|
}
|
|
1261
1511
|
return e;
|
|
1262
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Runs one operation with contribution publication deferred to its end, so a
|
|
1515
|
+
* change that withdraws and adds contributions is observed once rather than as
|
|
1516
|
+
* an intermediate state.
|
|
1517
|
+
*
|
|
1518
|
+
* Publication happens even when the operation failed, because contributions
|
|
1519
|
+
* withdrawn by Instances that did stop must not stay visible. If both the
|
|
1520
|
+
* operation and the publication fail, both errors are reported — the
|
|
1521
|
+
* publication failure must not hide the reason the change failed, and the
|
|
1522
|
+
* operation failure must not hide a store left inconsistent.
|
|
1523
|
+
*/
|
|
1263
1524
|
async withContributionBatch(t) {
|
|
1264
1525
|
this.#r.beginBatch();
|
|
1265
1526
|
let e;
|
|
@@ -1283,23 +1544,23 @@ class Mt {
|
|
|
1283
1544
|
if (!i.ok) throw i.error;
|
|
1284
1545
|
return e.value;
|
|
1285
1546
|
}
|
|
1286
|
-
async #
|
|
1547
|
+
async #h(t, e, i, s, n) {
|
|
1287
1548
|
e.deactivate();
|
|
1288
|
-
const o = e.
|
|
1549
|
+
const o = t.declarationFor(e).plugin, a = new tt(n, e.id, { parentSignal: s });
|
|
1289
1550
|
try {
|
|
1290
|
-
const h = this.#
|
|
1551
|
+
const h = this.#f(t, e, o, a), c = Object.freeze({
|
|
1291
1552
|
hostName: this.#t,
|
|
1292
1553
|
pluginName: o.name,
|
|
1293
1554
|
installationId: e.id,
|
|
1294
1555
|
groupId: e.groupId
|
|
1295
|
-
}), d = this.#
|
|
1296
|
-
for (const [
|
|
1297
|
-
if (typeof l != "object" || l === null || !Object.hasOwn(l,
|
|
1556
|
+
}), d = this.#c(a, c, h), l = await o.setup(d, i), f = /* @__PURE__ */ new Map();
|
|
1557
|
+
for (const [g, I] of Object.entries(o.provides)) {
|
|
1558
|
+
if (typeof l != "object" || l === null || !Object.hasOwn(l, g))
|
|
1298
1559
|
throw new u(
|
|
1299
1560
|
"SERVICE_NOT_RETURNED",
|
|
1300
|
-
`Installation '${e.id}' did not return provided Service '${
|
|
1561
|
+
`Installation '${e.id}' did not return provided Service '${g}'`
|
|
1301
1562
|
);
|
|
1302
|
-
f.set(
|
|
1563
|
+
f.set(I.id, l[g]);
|
|
1303
1564
|
}
|
|
1304
1565
|
return Object.freeze({
|
|
1305
1566
|
installation: e,
|
|
@@ -1311,7 +1572,7 @@ class Mt {
|
|
|
1311
1572
|
try {
|
|
1312
1573
|
await a.dispose();
|
|
1313
1574
|
} catch (d) {
|
|
1314
|
-
throw new
|
|
1575
|
+
throw new Y(
|
|
1315
1576
|
[c, d],
|
|
1316
1577
|
`Installation '${e.id}' failed to start and could not be cleanly disposed`
|
|
1317
1578
|
);
|
|
@@ -1319,13 +1580,13 @@ class Mt {
|
|
|
1319
1580
|
throw c;
|
|
1320
1581
|
}
|
|
1321
1582
|
}
|
|
1322
|
-
#
|
|
1583
|
+
#p(t) {
|
|
1323
1584
|
for (const { installation: e, instance: i, services: s } of t)
|
|
1324
|
-
this.#n.set(e, s), e.activate(i), this.#
|
|
1585
|
+
this.#n.set(e, s), e.activate(i), this.#o.push(e);
|
|
1325
1586
|
for (const { instance: e } of t)
|
|
1326
1587
|
e.lifetime.publish(), e.lifetime.detachStartupSignal();
|
|
1327
1588
|
}
|
|
1328
|
-
async #
|
|
1589
|
+
async #u(t) {
|
|
1329
1590
|
const e = [];
|
|
1330
1591
|
for (const i of [...t].reverse())
|
|
1331
1592
|
try {
|
|
@@ -1335,9 +1596,9 @@ class Mt {
|
|
|
1335
1596
|
}
|
|
1336
1597
|
return e;
|
|
1337
1598
|
}
|
|
1338
|
-
#
|
|
1599
|
+
#f(t, e, i, s) {
|
|
1339
1600
|
const n = /* @__PURE__ */ Object.create(null);
|
|
1340
|
-
for (const [o, a] of Object.entries(i.requires
|
|
1601
|
+
for (const [o, a] of Object.entries(i.requires))
|
|
1341
1602
|
if (a.kind === "optional") {
|
|
1342
1603
|
const h = t.providerFor(e, a.service.id);
|
|
1343
1604
|
if (!h) {
|
|
@@ -1360,10 +1621,10 @@ class Mt {
|
|
|
1360
1621
|
);
|
|
1361
1622
|
n[o] = c.get(a.id);
|
|
1362
1623
|
} else
|
|
1363
|
-
n[o] = this.#
|
|
1624
|
+
n[o] = this.#m(a, s);
|
|
1364
1625
|
return n;
|
|
1365
1626
|
}
|
|
1366
|
-
#
|
|
1627
|
+
#c(t, e, i) {
|
|
1367
1628
|
return Object.freeze({
|
|
1368
1629
|
...i,
|
|
1369
1630
|
get signal() {
|
|
@@ -1379,53 +1640,58 @@ class Mt {
|
|
|
1379
1640
|
contribute: t.contribute.bind(t)
|
|
1380
1641
|
});
|
|
1381
1642
|
}
|
|
1382
|
-
#
|
|
1643
|
+
#l(t) {
|
|
1383
1644
|
return {
|
|
1384
|
-
stageOn: (e, i, s, n) => this.#
|
|
1645
|
+
stageOn: (e, i, s, n) => this.#d(e, i, s, n, t),
|
|
1385
1646
|
emit: (e, i, s) => this.#g(e, i, s, t),
|
|
1386
|
-
stageContribution: (e, i, s, n, o) => this.#
|
|
1387
|
-
writeLog: (e, i, s, n) =>
|
|
1647
|
+
stageContribution: (e, i, s, n, o) => this.#w(e, i, s, n, o, t),
|
|
1648
|
+
writeLog: (e, i, s, n) => {
|
|
1649
|
+
R(
|
|
1650
|
+
this.#e[e](i, s, ...n),
|
|
1651
|
+
"Logger methods must be synchronous"
|
|
1652
|
+
);
|
|
1653
|
+
},
|
|
1388
1654
|
report: this.#s
|
|
1389
1655
|
};
|
|
1390
1656
|
}
|
|
1391
|
-
#
|
|
1392
|
-
return this.#
|
|
1657
|
+
#d(t, e, i, s, n) {
|
|
1658
|
+
return this.#b(t), A(e, "event"), n.remember(e), this.#a.stage(e.id, i, s);
|
|
1393
1659
|
}
|
|
1394
1660
|
#g(t, e, i, s) {
|
|
1395
|
-
return this.#
|
|
1661
|
+
return this.#b(t), A(e, "event"), s.remember(e), this.#a.emit(e.id, i);
|
|
1396
1662
|
}
|
|
1397
|
-
#
|
|
1398
|
-
return this.#
|
|
1663
|
+
#w(t, e, i, s, n, o) {
|
|
1664
|
+
return this.#b(t), A(e, "extensionPoint"), o.remember(e), this.#r.get(e).stage(t, i, s, n);
|
|
1399
1665
|
}
|
|
1400
|
-
#
|
|
1666
|
+
#m(t, e) {
|
|
1401
1667
|
return this.#r.get(t).view((i, s) => e.ownLease(i, s));
|
|
1402
1668
|
}
|
|
1403
|
-
#
|
|
1669
|
+
#b(t) {
|
|
1404
1670
|
if (!this.#i(t))
|
|
1405
1671
|
throw new Error(`Installation '${t}' is not installed`);
|
|
1406
1672
|
}
|
|
1407
1673
|
}
|
|
1408
|
-
function
|
|
1674
|
+
function he(r, t) {
|
|
1409
1675
|
const e = [];
|
|
1410
1676
|
let i = !1;
|
|
1411
1677
|
for (const s of r)
|
|
1412
|
-
s.status !== "fulfilled" && (Object.is(s.reason, t.reason) ? (i || e.push(s.reason), i = !0) :
|
|
1678
|
+
s.status !== "fulfilled" && (Object.is(s.reason, t.reason) ? (i || e.push(s.reason), i = !0) : wt(t, s.reason) || e.push(s.reason));
|
|
1413
1679
|
return e;
|
|
1414
1680
|
}
|
|
1415
|
-
class
|
|
1416
|
-
#t = new
|
|
1681
|
+
class de {
|
|
1682
|
+
#t = new zt();
|
|
1417
1683
|
#e;
|
|
1418
1684
|
#i;
|
|
1419
1685
|
constructor(t) {
|
|
1420
|
-
this.#e = new
|
|
1686
|
+
this.#e = new ce(t);
|
|
1421
1687
|
}
|
|
1422
1688
|
get hasCommittedPlan() {
|
|
1423
1689
|
return this.#i !== void 0;
|
|
1424
1690
|
}
|
|
1425
1691
|
get(t, e) {
|
|
1426
|
-
const i =
|
|
1427
|
-
if (
|
|
1428
|
-
const n = this.#
|
|
1692
|
+
const i = jt(t), s = i ? t.service : t;
|
|
1693
|
+
if (A(s, "service"), this.#t.assertCompatible(s), e === "unavailable") throw ct();
|
|
1694
|
+
const n = this.#o().provider(s.id);
|
|
1429
1695
|
if (!n) {
|
|
1430
1696
|
if (i) return;
|
|
1431
1697
|
throw new u("SERVICE_UNAVAILABLE", `Service '${s.id}' is not active`);
|
|
@@ -1438,13 +1704,13 @@ class Dt {
|
|
|
1438
1704
|
return o.value;
|
|
1439
1705
|
}
|
|
1440
1706
|
contributions(t) {
|
|
1441
|
-
return
|
|
1707
|
+
return A(t, "extensionPoint"), this.#t.remember(t), this.#e.contributions(t);
|
|
1442
1708
|
}
|
|
1443
1709
|
buildPlan(t) {
|
|
1444
|
-
return
|
|
1710
|
+
return X.build(t, this.#t.kinds);
|
|
1445
1711
|
}
|
|
1446
1712
|
async start(t) {
|
|
1447
|
-
const e = this.#t.
|
|
1713
|
+
const e = this.#t.writer(t.contractKinds);
|
|
1448
1714
|
try {
|
|
1449
1715
|
await this.#e.withContributionBatch(() => this.#s(t, e)), this.#i = t;
|
|
1450
1716
|
} catch (i) {
|
|
@@ -1452,17 +1718,34 @@ class Dt {
|
|
|
1452
1718
|
}
|
|
1453
1719
|
}
|
|
1454
1720
|
async stop() {
|
|
1455
|
-
const t = await this.#e.withContributionBatch(
|
|
1721
|
+
const t = await this.#e.withContributionBatch(
|
|
1722
|
+
() => this.#e.deactivateAll()
|
|
1723
|
+
);
|
|
1456
1724
|
return this.#i = void 0, t;
|
|
1457
1725
|
}
|
|
1726
|
+
/**
|
|
1727
|
+
* The whole transaction, in the order the steps have to happen.
|
|
1728
|
+
*
|
|
1729
|
+
* Configs resolve and Contract identities draft *before* anything stops,
|
|
1730
|
+
* because those are the failures that can still be taken back for free — a
|
|
1731
|
+
* schema rejection at this point costs nothing. Once the affected Instances
|
|
1732
|
+
* are down, every remaining failure has a price, and the only question left is
|
|
1733
|
+
* whether the previous state can be restored.
|
|
1734
|
+
*
|
|
1735
|
+
* The whole body runs inside one contribution batch, so contributions
|
|
1736
|
+
* withdrawn by stopping Instances and added by starting ones become visible in
|
|
1737
|
+
* a single step. Without it, an ExtensionPoint observer would see the set
|
|
1738
|
+
* briefly empty in the middle of a successful change.
|
|
1739
|
+
*/
|
|
1458
1740
|
async transition(t, e, i) {
|
|
1459
1741
|
return this.#e.withContributionBatch(async () => {
|
|
1460
|
-
const s = this.#
|
|
1742
|
+
const s = this.#o(), n = s.affectedByTransitionTo(t, e);
|
|
1461
1743
|
let o, a;
|
|
1462
1744
|
try {
|
|
1463
1745
|
o = await this.#r(
|
|
1746
|
+
t,
|
|
1464
1747
|
t.order.filter((d) => n.has(d))
|
|
1465
|
-
), a = this.#t.
|
|
1748
|
+
), a = this.#t.writer(t.contractKinds);
|
|
1466
1749
|
} catch (d) {
|
|
1467
1750
|
throw i(), d;
|
|
1468
1751
|
}
|
|
@@ -1477,11 +1760,11 @@ class Dt {
|
|
|
1477
1760
|
return await this.#e.activate(t, n, o, a), a.commit(), this.#e.commitActivationOrder(t.order), this.#i = t, Object.freeze({ kind: "committed", affected: n });
|
|
1478
1761
|
} catch (d) {
|
|
1479
1762
|
const l = await this.#e.deactivate(n);
|
|
1480
|
-
return a.discard(), d instanceof
|
|
1763
|
+
return a.discard(), d instanceof Y || l.length ? this.#n(
|
|
1481
1764
|
i,
|
|
1482
1765
|
[d, ...l],
|
|
1483
1766
|
"Installation change failed and its partial activation could not be cleanly disposed"
|
|
1484
|
-
) : this.#
|
|
1767
|
+
) : this.#a(i, s, n, h, [
|
|
1485
1768
|
d,
|
|
1486
1769
|
...l
|
|
1487
1770
|
]);
|
|
@@ -1489,7 +1772,7 @@ class Dt {
|
|
|
1489
1772
|
});
|
|
1490
1773
|
}
|
|
1491
1774
|
async #s(t, e) {
|
|
1492
|
-
const i = new Set(t.order), s = await this.#r(t.order);
|
|
1775
|
+
const i = new Set(t.order), s = await this.#r(t, t.order);
|
|
1493
1776
|
this.#e.resetActivationState();
|
|
1494
1777
|
try {
|
|
1495
1778
|
await this.#e.activate(t, i, s, e), e.commit(), this.#e.commitActivationOrder(t.order);
|
|
@@ -1498,14 +1781,30 @@ class Dt {
|
|
|
1498
1781
|
throw o.length ? new AggregateError([n, ...o], "Host startup failed") : n;
|
|
1499
1782
|
}
|
|
1500
1783
|
}
|
|
1784
|
+
/**
|
|
1785
|
+
* The last level: no consistent graph could be reached, so none is presented.
|
|
1786
|
+
*
|
|
1787
|
+
* Everything stops and `#plan` is cleared, which drops the Host to `idle` and
|
|
1788
|
+
* closes reads. The AggregateError carries every cause — the original failure
|
|
1789
|
+
* first, then whatever shutdown itself hit. Nothing is swallowed here; the
|
|
1790
|
+
* point of failing closed is that the report is complete.
|
|
1791
|
+
*/
|
|
1501
1792
|
async #n(t, e, i) {
|
|
1502
1793
|
t();
|
|
1503
1794
|
const s = await this.#e.deactivateAll();
|
|
1504
1795
|
throw this.#i = void 0, new AggregateError([...e, ...s], i);
|
|
1505
1796
|
}
|
|
1506
|
-
|
|
1797
|
+
/**
|
|
1798
|
+
* Restores the previous plan using the configs captured before the change, not
|
|
1799
|
+
* mutable records. Declaration versions belong to the plan; re-validating
|
|
1800
|
+
* configs could fail for a second,
|
|
1801
|
+
* unrelated reason while trying to recover from the first.
|
|
1802
|
+
*
|
|
1803
|
+
* A rollback that itself fails escalates to fail-closed by throwing.
|
|
1804
|
+
*/
|
|
1805
|
+
async #a(t, e, i, s, n) {
|
|
1507
1806
|
t();
|
|
1508
|
-
const o = this.#t.
|
|
1807
|
+
const o = this.#t.writer(e.contractKinds);
|
|
1509
1808
|
try {
|
|
1510
1809
|
await this.#e.activate(e, i, s, o), o.commit(), this.#e.commitActivationOrder(e.order), this.#i = e;
|
|
1511
1810
|
} catch (h) {
|
|
@@ -1518,48 +1817,47 @@ class Dt {
|
|
|
1518
1817
|
const a = n.length === 1 ? n[0] : new AggregateError(n, "Installation change failed");
|
|
1519
1818
|
return Object.freeze({ kind: "rolled-back", affected: i, error: a });
|
|
1520
1819
|
}
|
|
1521
|
-
async #r(t) {
|
|
1522
|
-
const
|
|
1523
|
-
for (const
|
|
1820
|
+
async #r(t, e) {
|
|
1821
|
+
const i = /* @__PURE__ */ new Map();
|
|
1822
|
+
for (const s of e)
|
|
1524
1823
|
try {
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
await X(
|
|
1528
|
-
i.declaration.plugin.config,
|
|
1529
|
-
i.declaration.config,
|
|
1530
|
-
i.id
|
|
1531
|
-
)
|
|
1532
|
-
);
|
|
1533
|
-
} catch (s) {
|
|
1534
|
-
throw $(
|
|
1824
|
+
const n = t.declarationFor(s);
|
|
1825
|
+
i.set(
|
|
1535
1826
|
s,
|
|
1827
|
+
await Lt(n.plugin.config, n.config, s.id)
|
|
1828
|
+
);
|
|
1829
|
+
} catch (n) {
|
|
1830
|
+
throw V(
|
|
1831
|
+
n,
|
|
1536
1832
|
"INSTALLATION_UNAVAILABLE",
|
|
1537
|
-
`Installation '${
|
|
1833
|
+
`Installation '${s.id}' failed with a non-Error value`
|
|
1538
1834
|
);
|
|
1539
1835
|
}
|
|
1540
|
-
return
|
|
1836
|
+
return i;
|
|
1541
1837
|
}
|
|
1542
|
-
#
|
|
1543
|
-
if (!this.#i) throw
|
|
1838
|
+
#o() {
|
|
1839
|
+
if (!this.#i) throw ct();
|
|
1544
1840
|
return this.#i;
|
|
1545
1841
|
}
|
|
1546
1842
|
}
|
|
1547
|
-
function
|
|
1843
|
+
function ct() {
|
|
1548
1844
|
return new u("SERVICE_UNAVAILABLE", "Host services are not active");
|
|
1549
1845
|
}
|
|
1550
|
-
class
|
|
1846
|
+
class le {
|
|
1551
1847
|
#t;
|
|
1552
1848
|
#e;
|
|
1553
|
-
#i;
|
|
1554
|
-
#s = 0;
|
|
1849
|
+
#i = 0;
|
|
1555
1850
|
view;
|
|
1556
1851
|
constructor(t, e, i) {
|
|
1557
|
-
this.#t = t, this.#
|
|
1852
|
+
this.#t = t, this.#e = new Z(() => {
|
|
1853
|
+
const { status: s, installations: n, groups: o } = e();
|
|
1854
|
+
return this.#s(s, n, o);
|
|
1855
|
+
}, i), this.view = this.#e.view;
|
|
1558
1856
|
}
|
|
1559
|
-
publish(
|
|
1560
|
-
this.#
|
|
1857
|
+
publish() {
|
|
1858
|
+
this.#i++, this.#e.invalidate();
|
|
1561
1859
|
}
|
|
1562
|
-
#
|
|
1860
|
+
#s(t, e, i) {
|
|
1563
1861
|
const s = /* @__PURE__ */ new Map();
|
|
1564
1862
|
for (const o of e) {
|
|
1565
1863
|
const a = {
|
|
@@ -1568,10 +1866,10 @@ class Gt {
|
|
|
1568
1866
|
groupId: o.groupId,
|
|
1569
1867
|
status: o.status,
|
|
1570
1868
|
requires: Object.freeze(
|
|
1571
|
-
Object.values(o.declaration.plugin.requires
|
|
1869
|
+
Object.values(o.declaration.plugin.requires).map((c) => c.kind === "optional" ? c.service.id : c.id)
|
|
1572
1870
|
),
|
|
1573
1871
|
provides: Object.freeze(
|
|
1574
|
-
Object.values(o.declaration.plugin.provides
|
|
1872
|
+
Object.values(o.declaration.plugin.provides).map((c) => c.id)
|
|
1575
1873
|
),
|
|
1576
1874
|
...o.instance ? { lifetime: o.instance.lifetime.diagnostics } : {}
|
|
1577
1875
|
}, h = o.error;
|
|
@@ -1591,29 +1889,32 @@ class Gt {
|
|
|
1591
1889
|
return Object.freeze({
|
|
1592
1890
|
name: this.#t,
|
|
1593
1891
|
status: t,
|
|
1594
|
-
revision: this.#
|
|
1595
|
-
installations: new
|
|
1596
|
-
groups: new
|
|
1892
|
+
revision: this.#i,
|
|
1893
|
+
installations: new z(s),
|
|
1894
|
+
groups: new z(n)
|
|
1597
1895
|
});
|
|
1598
1896
|
}
|
|
1599
1897
|
}
|
|
1600
|
-
function
|
|
1898
|
+
function B(r, t, e = {}) {
|
|
1601
1899
|
if (!r || typeof r != "object" || Array.isArray(r))
|
|
1602
|
-
throw
|
|
1900
|
+
throw O(e, `${t} must be a plain record`);
|
|
1603
1901
|
const i = Object.getPrototypeOf(r);
|
|
1604
1902
|
if (i !== Object.prototype && i !== null)
|
|
1605
|
-
throw
|
|
1903
|
+
throw O(e, `${t} must be a plain record`);
|
|
1606
1904
|
for (const s of Reflect.ownKeys(r)) {
|
|
1607
|
-
|
|
1608
|
-
|
|
1905
|
+
const n = Reflect.getOwnPropertyDescriptor(r, s);
|
|
1906
|
+
if (typeof s != "string" || !n?.enumerable)
|
|
1907
|
+
throw O(e, `${t} keys must be enumerable strings`);
|
|
1908
|
+
if (!("value" in n))
|
|
1909
|
+
throw O(e, `${t} field '${s}' must be a data property`);
|
|
1609
1910
|
if (e.fields && !e.fields.has(s))
|
|
1610
|
-
throw
|
|
1911
|
+
throw O(e, `${t}: unknown field '${s}'`);
|
|
1611
1912
|
}
|
|
1612
1913
|
}
|
|
1613
|
-
function
|
|
1914
|
+
function O(r, t) {
|
|
1614
1915
|
return r.createError?.(t) ?? new TypeError(t);
|
|
1615
1916
|
}
|
|
1616
|
-
const
|
|
1917
|
+
const ue = /* @__PURE__ */ new Set([
|
|
1617
1918
|
"signal",
|
|
1618
1919
|
"meta",
|
|
1619
1920
|
"log",
|
|
@@ -1623,12 +1924,12 @@ const Bt = /* @__PURE__ */ new Set([
|
|
|
1623
1924
|
"on",
|
|
1624
1925
|
"emit",
|
|
1625
1926
|
"contribute"
|
|
1626
|
-
]),
|
|
1627
|
-
function
|
|
1628
|
-
return
|
|
1927
|
+
]), fe = /* @__PURE__ */ new Set(["name", "config", "requires", "provides", "setup"]);
|
|
1928
|
+
function Ne(r) {
|
|
1929
|
+
return Ct(r);
|
|
1629
1930
|
}
|
|
1630
|
-
function
|
|
1631
|
-
|
|
1931
|
+
function Ct(r) {
|
|
1932
|
+
pe(r);
|
|
1632
1933
|
const t = Object.hasOwn(r, "name") ? r.name : void 0, e = Object.hasOwn(r, "config") ? r.config : void 0, i = Object.hasOwn(r, "requires") ? r.requires : void 0, s = Object.hasOwn(r, "provides") ? r.provides : void 0, n = Object.hasOwn(r, "setup") ? r.setup : void 0;
|
|
1633
1934
|
if (typeof t != "string" || !t.trim())
|
|
1634
1935
|
throw new TypeError("Plugin name must be a non-empty string");
|
|
@@ -1636,24 +1937,27 @@ function it(r) {
|
|
|
1636
1937
|
throw new TypeError("Plugin name cannot start or end with whitespace");
|
|
1637
1938
|
if (typeof n != "function")
|
|
1638
1939
|
throw new TypeError(`Plugin '${t}' must define setup()`);
|
|
1639
|
-
if (e !== void 0 && !
|
|
1940
|
+
if (e !== void 0 && !ge(e))
|
|
1640
1941
|
throw new TypeError(`Plugin '${t}' config must implement Standard Schema V1`);
|
|
1641
|
-
|
|
1642
|
-
const o =
|
|
1643
|
-
for (const [c, d] of Object.entries(
|
|
1942
|
+
ht(i, t, "requires"), ht(s, t, "provides");
|
|
1943
|
+
const o = /* @__PURE__ */ Object.create(null), a = /* @__PURE__ */ Object.create(null), h = /* @__PURE__ */ new Map();
|
|
1944
|
+
for (const [c, d] of Object.entries(i ?? {})) {
|
|
1644
1945
|
if (!c.trim()) throw new TypeError("Plugin requirement alias cannot be empty");
|
|
1645
1946
|
if (c !== c.trim())
|
|
1646
1947
|
throw new TypeError("Plugin requirement alias cannot start or end with whitespace");
|
|
1647
|
-
if (
|
|
1948
|
+
if (ue.has(c))
|
|
1648
1949
|
throw new TypeError(`Plugin requirement '${c}' conflicts with the context API`);
|
|
1649
1950
|
if (!d || typeof d != "object")
|
|
1650
1951
|
throw new TypeError(`Plugin requirement '${c}' is not a contract`);
|
|
1651
1952
|
if (d.kind === "optional") {
|
|
1652
|
-
if (!
|
|
1953
|
+
if (!E(d.service, "service"))
|
|
1653
1954
|
throw new TypeError(`Optional requirement '${c}' must wrap a Service`);
|
|
1654
|
-
} else if (!
|
|
1955
|
+
} else if (!E(d, "service") && !E(d, "extensionPoint"))
|
|
1655
1956
|
throw new TypeError(`Plugin requirement '${c}' must be a Service or ExtensionPoint`);
|
|
1656
|
-
|
|
1957
|
+
o[c] = d.kind === "optional" ? Object.freeze({
|
|
1958
|
+
kind: "optional",
|
|
1959
|
+
service: _(d.service)
|
|
1960
|
+
}) : _(d), dt(
|
|
1657
1961
|
t,
|
|
1658
1962
|
h,
|
|
1659
1963
|
"requirement",
|
|
@@ -1661,36 +1965,41 @@ function it(r) {
|
|
|
1661
1965
|
d.kind === "optional" ? d.service : d
|
|
1662
1966
|
);
|
|
1663
1967
|
}
|
|
1664
|
-
for (const [c, d] of Object.entries(
|
|
1968
|
+
for (const [c, d] of Object.entries(s ?? {})) {
|
|
1665
1969
|
if (!c.trim()) throw new TypeError("Plugin provision alias cannot be empty");
|
|
1666
1970
|
if (c !== c.trim())
|
|
1667
1971
|
throw new TypeError("Plugin provision alias cannot start or end with whitespace");
|
|
1668
|
-
if (
|
|
1972
|
+
if (c === "then")
|
|
1973
|
+
throw new TypeError("Plugin provision alias 'then' conflicts with the Promise protocol");
|
|
1974
|
+
if (!E(d, "service"))
|
|
1669
1975
|
throw new TypeError(`Plugin provision '${c}' must be a Service`);
|
|
1670
|
-
|
|
1976
|
+
a[c] = _(d), dt(t, h, "provision", c, a[c]);
|
|
1671
1977
|
}
|
|
1672
1978
|
return Object.freeze({
|
|
1673
1979
|
name: t,
|
|
1674
1980
|
...e === void 0 ? {} : { config: e },
|
|
1675
|
-
|
|
1676
|
-
|
|
1981
|
+
requires: Object.freeze(o),
|
|
1982
|
+
provides: Object.freeze(a),
|
|
1677
1983
|
setup: n
|
|
1678
1984
|
});
|
|
1679
1985
|
}
|
|
1680
|
-
function
|
|
1681
|
-
|
|
1986
|
+
function _(r) {
|
|
1987
|
+
return Object.freeze({ id: r.id, kind: r.kind });
|
|
1988
|
+
}
|
|
1989
|
+
function pe(r) {
|
|
1990
|
+
B(r, "Plugin declaration", { fields: fe });
|
|
1682
1991
|
}
|
|
1683
|
-
function
|
|
1992
|
+
function ge(r) {
|
|
1684
1993
|
if (!r || typeof r != "object" && typeof r != "function") return !1;
|
|
1685
1994
|
const t = r["~standard"];
|
|
1686
1995
|
if (!t || typeof t != "object") return !1;
|
|
1687
1996
|
const e = t;
|
|
1688
1997
|
return e.version === 1 && typeof e.vendor == "string" && typeof e.validate == "function";
|
|
1689
1998
|
}
|
|
1690
|
-
function
|
|
1691
|
-
r !== void 0 &&
|
|
1999
|
+
function ht(r, t, e) {
|
|
2000
|
+
r !== void 0 && B(r, `Plugin '${t}' ${e}`);
|
|
1692
2001
|
}
|
|
1693
|
-
function
|
|
2002
|
+
function dt(r, t, e, i, s) {
|
|
1694
2003
|
const n = t.get(s.id);
|
|
1695
2004
|
if (!n) {
|
|
1696
2005
|
t.set(s.id, { alias: i, kind: s.kind, role: e });
|
|
@@ -1698,38 +2007,49 @@ function H(r, t, e, i, s) {
|
|
|
1698
2007
|
}
|
|
1699
2008
|
if (n.kind !== s.kind)
|
|
1700
2009
|
throw new TypeError(
|
|
1701
|
-
`Plugin '${r}' uses Contract '${s.id}' as both ${
|
|
2010
|
+
`Plugin '${r}' uses Contract '${s.id}' as both ${H(n.kind)} and ${H(s.kind)}`
|
|
1702
2011
|
);
|
|
1703
|
-
const o =
|
|
2012
|
+
const o = H(s.kind);
|
|
1704
2013
|
throw n.role !== e ? new TypeError(
|
|
1705
2014
|
`Plugin '${r}' cannot both require and provide ${o} '${s.id}'`
|
|
1706
2015
|
) : new TypeError(
|
|
1707
2016
|
`Plugin '${r}' ${e} aliases '${n.alias}' and '${i}' reference the same ${o} '${s.id}'`
|
|
1708
2017
|
);
|
|
1709
2018
|
}
|
|
1710
|
-
function
|
|
2019
|
+
function H(r) {
|
|
1711
2020
|
return r === "extensionPoint" ? "ExtensionPoint" : r === "event" ? "Event" : "Service";
|
|
1712
2021
|
}
|
|
1713
|
-
function
|
|
1714
|
-
return
|
|
2022
|
+
function lt(r) {
|
|
2023
|
+
return Ct(r);
|
|
1715
2024
|
}
|
|
1716
|
-
const
|
|
1717
|
-
function
|
|
1718
|
-
x.get(r)?.(t);
|
|
2025
|
+
const we = /* @__PURE__ */ new Set(["plugin", "config"]), x = /* @__PURE__ */ new WeakMap();
|
|
2026
|
+
function be(r, t) {
|
|
2027
|
+
x.get(r)?.discard(t);
|
|
1719
2028
|
}
|
|
1720
|
-
|
|
2029
|
+
function me(r, t, e, i) {
|
|
2030
|
+
const s = x.get(r);
|
|
2031
|
+
if (!s) throw new Error("ChangeSet draft control has been released");
|
|
2032
|
+
return s.install(t, e, i);
|
|
2033
|
+
}
|
|
2034
|
+
class ve {
|
|
1721
2035
|
#t = /* @__PURE__ */ new Map();
|
|
1722
2036
|
#e;
|
|
1723
2037
|
constructor(t) {
|
|
1724
|
-
this.#e = { phase: "open", port: t }, x.set(this,
|
|
2038
|
+
this.#e = { phase: "open", port: t }, x.set(this, {
|
|
2039
|
+
discard: (e) => this.#s(e),
|
|
2040
|
+
install: (e, i, s) => this.#i(e, i, s)
|
|
2041
|
+
}), Object.freeze(this);
|
|
1725
2042
|
}
|
|
1726
2043
|
install(t, ...e) {
|
|
1727
|
-
|
|
1728
|
-
|
|
2044
|
+
return this.#i(t, e[0]);
|
|
2045
|
+
}
|
|
2046
|
+
#i(t, e, i) {
|
|
2047
|
+
const s = this.#a(), n = lt(t), o = (i ?? s.create)(n, e);
|
|
2048
|
+
return this.#n({ kind: "install", installation: o.record }), o.facade;
|
|
1729
2049
|
}
|
|
1730
2050
|
update(t, e) {
|
|
1731
|
-
const i = this.#
|
|
1732
|
-
|
|
2051
|
+
const i = this.#a();
|
|
2052
|
+
B(e, "Installation update", { fields: we });
|
|
1733
2053
|
const s = Object.hasOwn(e, "plugin"), n = Object.hasOwn(e, "config");
|
|
1734
2054
|
if (!s && !n)
|
|
1735
2055
|
throw new TypeError("Installation update must include 'plugin' or 'config'");
|
|
@@ -1738,17 +2058,23 @@ class Wt {
|
|
|
1738
2058
|
if (s) {
|
|
1739
2059
|
const d = e.plugin;
|
|
1740
2060
|
if (!d) throw new TypeError("Installation update 'plugin' must be a Plugin");
|
|
1741
|
-
a =
|
|
2061
|
+
a = lt(d);
|
|
1742
2062
|
}
|
|
1743
2063
|
let h;
|
|
1744
2064
|
a && n ? h = { kind: "plugin-and-config", plugin: a, config: e.config } : a ? h = { kind: "plugin", plugin: a } : h = { kind: "config", config: e.config };
|
|
1745
2065
|
const c = { kind: "update", installation: o, declaration: h };
|
|
1746
|
-
this.#
|
|
2066
|
+
this.#n(c);
|
|
1747
2067
|
}
|
|
1748
2068
|
remove(t) {
|
|
1749
|
-
const e = this.#
|
|
1750
|
-
this.#
|
|
1751
|
-
}
|
|
2069
|
+
const e = this.#a();
|
|
2070
|
+
this.#n({ kind: "remove", installation: e.resolve(t) });
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* Commit is idempotent by returning the same promise, so two callers awaiting
|
|
2074
|
+
* one draft get one transaction rather than two. `committing` exists to catch
|
|
2075
|
+
* the reentrant case — an `attach` hook that calls `commit()` again — which
|
|
2076
|
+
* would otherwise submit the operation list twice.
|
|
2077
|
+
*/
|
|
1752
2078
|
commit() {
|
|
1753
2079
|
const t = this.#e;
|
|
1754
2080
|
if (t.phase === "submitted") return t.promise;
|
|
@@ -1764,7 +2090,7 @@ class Wt {
|
|
|
1764
2090
|
} catch (n) {
|
|
1765
2091
|
for (const o of e)
|
|
1766
2092
|
o.kind === "install" && i.discard(o.installation, n);
|
|
1767
|
-
return this.#
|
|
2093
|
+
return this.#r(Promise.reject(n));
|
|
1768
2094
|
}
|
|
1769
2095
|
let s;
|
|
1770
2096
|
try {
|
|
@@ -1772,83 +2098,42 @@ class Wt {
|
|
|
1772
2098
|
} catch (n) {
|
|
1773
2099
|
s = Promise.reject(n);
|
|
1774
2100
|
}
|
|
1775
|
-
return this.#
|
|
2101
|
+
return this.#r(s);
|
|
1776
2102
|
}
|
|
1777
|
-
#
|
|
2103
|
+
#s(t) {
|
|
1778
2104
|
const e = this.#e;
|
|
1779
2105
|
if (e.phase !== "open") return;
|
|
1780
2106
|
this.#e = { phase: "discarded" };
|
|
1781
2107
|
const i = [...this.#t.values()];
|
|
1782
|
-
this.#
|
|
2108
|
+
this.#o();
|
|
1783
2109
|
for (const s of i)
|
|
1784
2110
|
s.kind === "install" && e.port.discard(s.installation, t);
|
|
1785
2111
|
}
|
|
1786
|
-
|
|
2112
|
+
// One operation per Installation per ChangeSet. Allowing two would make the
|
|
2113
|
+
// outcome depend on staging order — `update` then `remove` versus the reverse —
|
|
2114
|
+
// and there is no reading of "both" that is obviously right. The caller has to
|
|
2115
|
+
// say which one it meant.
|
|
2116
|
+
#n(t) {
|
|
1787
2117
|
if (this.#t.has(t.installation))
|
|
1788
2118
|
throw new TypeError(
|
|
1789
2119
|
`Installation '${t.installation.id}' can only appear once in the same ChangeSet`
|
|
1790
2120
|
);
|
|
1791
2121
|
this.#t.set(t.installation, Object.freeze(t));
|
|
1792
2122
|
}
|
|
1793
|
-
#
|
|
2123
|
+
#a() {
|
|
1794
2124
|
const t = this.#e;
|
|
1795
2125
|
if (t.phase !== "open")
|
|
1796
2126
|
throw new TypeError(`Cannot modify a ${t.phase} ChangeSet`);
|
|
1797
2127
|
return t.port;
|
|
1798
2128
|
}
|
|
1799
|
-
#
|
|
1800
|
-
return this.#e = { phase: "submitted", promise: t }, this.#
|
|
2129
|
+
#r(t) {
|
|
2130
|
+
return this.#e = { phase: "submitted", promise: t }, this.#o(), t;
|
|
1801
2131
|
}
|
|
1802
|
-
#
|
|
2132
|
+
#o() {
|
|
1803
2133
|
this.#t.clear(), x.delete(this);
|
|
1804
2134
|
}
|
|
1805
2135
|
}
|
|
1806
|
-
class
|
|
1807
|
-
#t;
|
|
1808
|
-
constructor(t, e, i) {
|
|
1809
|
-
this.#t = { phase: "open", draft: t, discard: e, normalize: i };
|
|
1810
|
-
}
|
|
1811
|
-
get failure() {
|
|
1812
|
-
return this.#t.phase === "failed" ? this.#t.error : void 0;
|
|
1813
|
-
}
|
|
1814
|
-
requireDraft() {
|
|
1815
|
-
const t = this.#t;
|
|
1816
|
-
if (t.phase === "failed") throw t.error;
|
|
1817
|
-
if (t.phase === "sealed") throw z();
|
|
1818
|
-
return t.draft;
|
|
1819
|
-
}
|
|
1820
|
-
assertOpen() {
|
|
1821
|
-
this.requireDraft();
|
|
1822
|
-
}
|
|
1823
|
-
fail(t) {
|
|
1824
|
-
const e = this.#t;
|
|
1825
|
-
if (e.phase === "failed") return e.error;
|
|
1826
|
-
if (e.phase === "sealed") throw z();
|
|
1827
|
-
const i = e.normalize(t);
|
|
1828
|
-
return this.#t = {
|
|
1829
|
-
phase: "failed",
|
|
1830
|
-
draft: e.draft,
|
|
1831
|
-
discard: e.discard,
|
|
1832
|
-
error: i
|
|
1833
|
-
}, i;
|
|
1834
|
-
}
|
|
1835
|
-
seal() {
|
|
1836
|
-
const t = this.#t;
|
|
1837
|
-
if (t.phase === "failed") throw t.error;
|
|
1838
|
-
if (t.phase === "sealed") throw z();
|
|
1839
|
-
return this.#t = { phase: "sealed" }, t.draft;
|
|
1840
|
-
}
|
|
1841
|
-
discard(t) {
|
|
1842
|
-
const e = this.#t;
|
|
1843
|
-
if (e.phase === "sealed") return;
|
|
1844
|
-
const i = e.phase === "failed" ? e.error : e.normalize(t);
|
|
1845
|
-
this.#t = { phase: "sealed" }, e.discard(e.draft, i);
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
function z() {
|
|
1849
|
-
return new Error("Group configuration has been sealed");
|
|
1850
|
-
}
|
|
1851
|
-
class I {
|
|
2136
|
+
class M {
|
|
1852
2137
|
constructor(t, e, i) {
|
|
1853
2138
|
this.id = t, this.name = e, this.#e = { phase: "attached", parent: i };
|
|
1854
2139
|
}
|
|
@@ -1857,7 +2142,7 @@ class I {
|
|
|
1857
2142
|
#t = /* @__PURE__ */ new Map();
|
|
1858
2143
|
#e;
|
|
1859
2144
|
static root(t) {
|
|
1860
|
-
return new
|
|
2145
|
+
return new M("/", t, void 0);
|
|
1861
2146
|
}
|
|
1862
2147
|
get attached() {
|
|
1863
2148
|
return this.#e.phase !== "detached";
|
|
@@ -1870,21 +2155,24 @@ class I {
|
|
|
1870
2155
|
return t.phase === "detached" ? void 0 : t.parent;
|
|
1871
2156
|
}
|
|
1872
2157
|
create(t) {
|
|
1873
|
-
if (this.assertAttached(),
|
|
2158
|
+
if (this.assertAttached(), ye(t), this.#t.has(t))
|
|
1874
2159
|
throw new TypeError(`Group '${this.#i(t)}' already exists`);
|
|
1875
|
-
const e = new
|
|
2160
|
+
const e = new M(this.#i(t), t, this);
|
|
1876
2161
|
return this.#t.set(t, e), e;
|
|
1877
2162
|
}
|
|
1878
2163
|
contains(t) {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
if (e.contains(t)) return !0;
|
|
2164
|
+
for (let e = t; e; e = e.parent)
|
|
2165
|
+
if (e === this) return !0;
|
|
1882
2166
|
return !1;
|
|
1883
2167
|
}
|
|
1884
2168
|
assertAttached() {
|
|
1885
2169
|
if (this.#e.phase === "detached")
|
|
1886
2170
|
throw new TypeError(`Group '${this.id}' has been removed`);
|
|
1887
2171
|
}
|
|
2172
|
+
// Depth-first, and children are detached before this node unlinks itself from
|
|
2173
|
+
// its parent. A node that unlinked first would leave its subtree unreachable
|
|
2174
|
+
// but still attached, so those groups would report themselves as live with no
|
|
2175
|
+
// path back to the root.
|
|
1888
2176
|
detach() {
|
|
1889
2177
|
const t = this.#e;
|
|
1890
2178
|
if (t.phase !== "detached") {
|
|
@@ -1904,14 +2192,59 @@ class I {
|
|
|
1904
2192
|
return this.id === "/" ? `/${t}` : `${this.id}/${t}`;
|
|
1905
2193
|
}
|
|
1906
2194
|
}
|
|
1907
|
-
function
|
|
2195
|
+
function ye(r) {
|
|
1908
2196
|
if (typeof r != "string" || !r.trim())
|
|
1909
2197
|
throw new TypeError("Group name must be a non-empty string");
|
|
1910
2198
|
if (r !== r.trim())
|
|
1911
2199
|
throw new TypeError("Group name cannot start or end with whitespace");
|
|
1912
2200
|
if (r.includes("/")) throw new TypeError("Group name cannot contain '/'");
|
|
1913
2201
|
}
|
|
1914
|
-
class
|
|
2202
|
+
class Ee {
|
|
2203
|
+
#t;
|
|
2204
|
+
constructor(t, e, i) {
|
|
2205
|
+
this.#t = { phase: "open", draft: t, discard: e, normalize: i };
|
|
2206
|
+
}
|
|
2207
|
+
get failure() {
|
|
2208
|
+
return this.#t.phase === "failed" ? this.#t.error : void 0;
|
|
2209
|
+
}
|
|
2210
|
+
requireDraft() {
|
|
2211
|
+
const t = this.#t;
|
|
2212
|
+
if (t.phase === "failed") throw t.error;
|
|
2213
|
+
if (t.phase === "sealed") throw K();
|
|
2214
|
+
return t.draft;
|
|
2215
|
+
}
|
|
2216
|
+
assertOpen() {
|
|
2217
|
+
this.requireDraft();
|
|
2218
|
+
}
|
|
2219
|
+
fail(t) {
|
|
2220
|
+
const e = this.#t;
|
|
2221
|
+
if (e.phase === "failed") return e.error;
|
|
2222
|
+
if (e.phase === "sealed") throw K();
|
|
2223
|
+
const i = e.normalize(t);
|
|
2224
|
+
return this.#t = {
|
|
2225
|
+
phase: "failed",
|
|
2226
|
+
draft: e.draft,
|
|
2227
|
+
discard: e.discard,
|
|
2228
|
+
error: i
|
|
2229
|
+
}, i;
|
|
2230
|
+
}
|
|
2231
|
+
seal() {
|
|
2232
|
+
const t = this.#t;
|
|
2233
|
+
if (t.phase === "failed") throw t.error;
|
|
2234
|
+
if (t.phase === "sealed") throw K();
|
|
2235
|
+
return this.#t = { phase: "sealed" }, t.draft;
|
|
2236
|
+
}
|
|
2237
|
+
discard(t) {
|
|
2238
|
+
const e = this.#t;
|
|
2239
|
+
if (e.phase === "sealed") return;
|
|
2240
|
+
const i = e.phase === "failed" ? e.error : e.normalize(t);
|
|
2241
|
+
this.#t = { phase: "sealed" }, e.discard(e.draft, i);
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
function K() {
|
|
2245
|
+
return new Error("Group configuration has been sealed");
|
|
2246
|
+
}
|
|
2247
|
+
class ut {
|
|
1915
2248
|
constructor(t, e, i) {
|
|
1916
2249
|
this.node = t, this.#t = { phase: e }, this.#e = i;
|
|
1917
2250
|
}
|
|
@@ -1931,6 +2264,19 @@ class W {
|
|
|
1931
2264
|
if (i.phase === "failed") throw i.error;
|
|
1932
2265
|
await t();
|
|
1933
2266
|
}
|
|
2267
|
+
/**
|
|
2268
|
+
* `preserveCommittedState` is the whole point of this class.
|
|
2269
|
+
*
|
|
2270
|
+
* A Group that has already committed something is established, and a later
|
|
2271
|
+
* failed change does not un-establish it — the transaction rolled back, so the
|
|
2272
|
+
* state the Group describes is still the one that was committed. Such a
|
|
2273
|
+
* failure leaves the phase at `established` and does not rethrow, because the
|
|
2274
|
+
* caller of the failed change already has the error.
|
|
2275
|
+
*
|
|
2276
|
+
* A Group whose *first* change fails never had a committed state, so it does
|
|
2277
|
+
* become `failed` and the failure propagates: there is nothing to report but
|
|
2278
|
+
* the failure.
|
|
2279
|
+
*/
|
|
1934
2280
|
track(t) {
|
|
1935
2281
|
this.node.assertAttached();
|
|
1936
2282
|
const e = this.#t, i = e.phase === "established" || e.phase === "pending" && e.baseline === "established", s = {}, n = t.then(
|
|
@@ -1938,7 +2284,7 @@ class W {
|
|
|
1938
2284
|
this.#i(s) && (this.#t = { phase: "established" }, this.#e?.());
|
|
1939
2285
|
},
|
|
1940
2286
|
(o) => {
|
|
1941
|
-
const a =
|
|
2287
|
+
const a = V(
|
|
1942
2288
|
o,
|
|
1943
2289
|
"GROUP_UNAVAILABLE",
|
|
1944
2290
|
`Group '${this.node.id}' operation failed with a non-Error value`
|
|
@@ -1962,15 +2308,15 @@ class W {
|
|
|
1962
2308
|
return e.phase === "pending" && e.attempt === t;
|
|
1963
2309
|
}
|
|
1964
2310
|
}
|
|
1965
|
-
function
|
|
2311
|
+
function D(r) {
|
|
1966
2312
|
return new u("GROUP_REMOVED", `Group '${r.id}' has been removed`);
|
|
1967
2313
|
}
|
|
1968
|
-
const
|
|
1969
|
-
class
|
|
2314
|
+
const P = /* @__PURE__ */ new WeakMap();
|
|
2315
|
+
class Ce {
|
|
1970
2316
|
#t;
|
|
1971
2317
|
#e;
|
|
1972
2318
|
constructor(t, e, i) {
|
|
1973
|
-
this.#t = e, this.#e = i ? { phase: "configuring", coordinator: t, configuration: i } : { phase: "attached", coordinator: t },
|
|
2319
|
+
this.#t = e, this.#e = i ? { phase: "configuring", coordinator: t, configuration: i } : { phase: "attached", coordinator: t }, P.set(this, {
|
|
1974
2320
|
finishConfiguration: () => {
|
|
1975
2321
|
const s = this.#e;
|
|
1976
2322
|
s.phase === "configuring" && (this.#e = { phase: "attached", coordinator: s.coordinator });
|
|
@@ -1992,11 +2338,16 @@ class Jt {
|
|
|
1992
2338
|
}
|
|
1993
2339
|
ready() {
|
|
1994
2340
|
const t = this.#e;
|
|
1995
|
-
return t.phase === "revoked" ? Promise.reject(
|
|
2341
|
+
return t.phase === "revoked" ? Promise.reject(D(this.#t)) : t.coordinator.ready(this.#t);
|
|
1996
2342
|
}
|
|
1997
2343
|
install(t, ...e) {
|
|
1998
2344
|
const i = this.#e;
|
|
1999
|
-
return i.phase === "configuring" ? i.
|
|
2345
|
+
return i.phase === "configuring" ? i.coordinator.stageConfigurationInstall(
|
|
2346
|
+
this.#t,
|
|
2347
|
+
i.configuration,
|
|
2348
|
+
t,
|
|
2349
|
+
...e
|
|
2350
|
+
) : this.#i().install(this.#t, t, ...e);
|
|
2000
2351
|
}
|
|
2001
2352
|
change() {
|
|
2002
2353
|
if (this.#e.phase === "configuring")
|
|
@@ -2020,19 +2371,19 @@ class Jt {
|
|
|
2020
2371
|
}
|
|
2021
2372
|
#i() {
|
|
2022
2373
|
const t = this.#e;
|
|
2023
|
-
if (t.phase === "revoked") throw
|
|
2374
|
+
if (t.phase === "revoked") throw D(this.#t);
|
|
2024
2375
|
return t.coordinator;
|
|
2025
2376
|
}
|
|
2026
2377
|
}
|
|
2027
|
-
class
|
|
2378
|
+
class Se {
|
|
2028
2379
|
root;
|
|
2029
2380
|
#t;
|
|
2030
2381
|
#e = /* @__PURE__ */ new WeakMap();
|
|
2031
2382
|
#i = /* @__PURE__ */ new WeakMap();
|
|
2032
2383
|
constructor(t, e) {
|
|
2033
|
-
this.root =
|
|
2384
|
+
this.root = M.root(t), this.#t = e, this.#i.set(
|
|
2034
2385
|
this.root,
|
|
2035
|
-
new
|
|
2386
|
+
new ut(this.root, "established", () => e.notifyChanged())
|
|
2036
2387
|
);
|
|
2037
2388
|
}
|
|
2038
2389
|
nodes() {
|
|
@@ -2040,15 +2391,29 @@ class Xt {
|
|
|
2040
2391
|
}
|
|
2041
2392
|
install(t, e, ...i) {
|
|
2042
2393
|
const s = this.change(t), n = s.install(e, ...i);
|
|
2043
|
-
return
|
|
2394
|
+
return ft(s.commit()), n;
|
|
2044
2395
|
}
|
|
2396
|
+
stageConfigurationInstall(t, e, i, ...s) {
|
|
2397
|
+
return this.#r(t), me(
|
|
2398
|
+
e.requireDraft(),
|
|
2399
|
+
i,
|
|
2400
|
+
s[0],
|
|
2401
|
+
(n, o) => (this.#r(t), this.#t.createDraft(t, n, o))
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
/**
|
|
2405
|
+
* `deferred` tracking exists for `create()`. A Group being configured must not
|
|
2406
|
+
* mark itself pending on each nested install, because the whole configuration
|
|
2407
|
+
* commits once; the coordinator attaches that single operation to every node in
|
|
2408
|
+
* the finished subtree instead.
|
|
2409
|
+
*/
|
|
2045
2410
|
change(t, e = "immediate") {
|
|
2046
|
-
return this.#r(t), new
|
|
2411
|
+
return this.#r(t), new ve({
|
|
2047
2412
|
create: (i, s) => (this.#r(t), this.#t.createDraft(t, i, s)),
|
|
2048
2413
|
resolve: (i) => {
|
|
2049
2414
|
this.#r(t);
|
|
2050
2415
|
const s = this.#t.resolveInstallation(i);
|
|
2051
|
-
if (!s.
|
|
2416
|
+
if (!s.hasAuthority) throw s.unavailableError();
|
|
2052
2417
|
if (!t.contains(s.group))
|
|
2053
2418
|
throw new TypeError(`Installation '${s.id}' is outside Group '${t.id}'`);
|
|
2054
2419
|
return s;
|
|
@@ -2057,7 +2422,7 @@ class Xt {
|
|
|
2057
2422
|
this.#r(t);
|
|
2058
2423
|
const s = this.#t.executeChanges(t, i);
|
|
2059
2424
|
for (const n of i) n.installation.trackReadiness(s);
|
|
2060
|
-
return i.length && e === "immediate" && this.#
|
|
2425
|
+
return i.length && e === "immediate" && this.#a(t, s), s;
|
|
2061
2426
|
},
|
|
2062
2427
|
attach: (i) => {
|
|
2063
2428
|
this.#r(t), this.#t.attachInstallation(i);
|
|
@@ -2068,33 +2433,33 @@ class Xt {
|
|
|
2068
2433
|
create(t, e, i, s) {
|
|
2069
2434
|
if (typeof i != "function") throw new TypeError("Group configure must be a function");
|
|
2070
2435
|
const n = t.create(e);
|
|
2071
|
-
this.#i.set(n, new
|
|
2072
|
-
const o = s === void 0, a = s ?? new
|
|
2436
|
+
this.#i.set(n, new ut(n, "new", () => this.#t.notifyChanged()));
|
|
2437
|
+
const o = s === void 0, a = s ?? new Ee(
|
|
2073
2438
|
this.change(n, "deferred"),
|
|
2074
|
-
|
|
2075
|
-
(c) =>
|
|
2439
|
+
be,
|
|
2440
|
+
(c) => V(
|
|
2076
2441
|
c,
|
|
2077
2442
|
"GROUP_UNAVAILABLE",
|
|
2078
2443
|
`Group '${n.id}' configuration failed with a non-Error value`
|
|
2079
2444
|
)
|
|
2080
|
-
), h = new
|
|
2445
|
+
), h = new Ce(this, n, a);
|
|
2081
2446
|
this.#e.set(n, h);
|
|
2082
2447
|
try {
|
|
2083
2448
|
const c = i(h);
|
|
2084
|
-
|
|
2449
|
+
R(c, "Group configure must be synchronous");
|
|
2085
2450
|
const d = a.failure;
|
|
2086
2451
|
if (d) throw d;
|
|
2087
2452
|
} catch (c) {
|
|
2088
2453
|
const d = a.fail(c), l = n.walk();
|
|
2089
|
-
throw n.detach(), this.#
|
|
2454
|
+
throw n.detach(), this.#o(l), o && a.discard(d), this.#t.notifyChanged(), d;
|
|
2090
2455
|
}
|
|
2091
2456
|
if (o) {
|
|
2092
2457
|
const c = a.seal().commit();
|
|
2093
2458
|
for (const d of n.walk()) {
|
|
2094
2459
|
const l = this.#e.get(d);
|
|
2095
|
-
l &&
|
|
2460
|
+
l && P.get(l)?.finishConfiguration(), this.#a(d, c);
|
|
2096
2461
|
}
|
|
2097
|
-
|
|
2462
|
+
ft(c);
|
|
2098
2463
|
}
|
|
2099
2464
|
return this.#t.notifyChanged(), h;
|
|
2100
2465
|
}
|
|
@@ -2110,56 +2475,53 @@ class Xt {
|
|
|
2110
2475
|
if (t === this.root) throw new TypeError("The root Group cannot be removed");
|
|
2111
2476
|
return t.attached ? this.#t.runExclusive(async () => {
|
|
2112
2477
|
if (!t.attached) {
|
|
2113
|
-
this.#
|
|
2478
|
+
this.#o([t]);
|
|
2114
2479
|
return;
|
|
2115
2480
|
}
|
|
2116
2481
|
const e = t.walk(), i = this.#s(t).map((s) => ({
|
|
2117
2482
|
kind: "remove",
|
|
2118
2483
|
installation: s
|
|
2119
2484
|
}));
|
|
2120
|
-
await this.#t.removeInstallations(i), t.detach(), this.#
|
|
2121
|
-
}) : (this.#
|
|
2485
|
+
await this.#t.removeInstallations(i), t.detach(), this.#o(e), this.#t.notifyChanged();
|
|
2486
|
+
}) : (this.#o([t]), Promise.resolve());
|
|
2122
2487
|
}
|
|
2123
2488
|
#s(t) {
|
|
2124
2489
|
return [...this.#t.installations()].filter(
|
|
2125
2490
|
(e) => t.contains(e.group)
|
|
2126
2491
|
);
|
|
2127
2492
|
}
|
|
2493
|
+
// A Group has no status of its own — it reports what its contents say, with
|
|
2494
|
+
// the worst news winning. The last line is the one that needs stating: an
|
|
2495
|
+
// empty Group is `active`, because a subtree that owns nothing has nothing
|
|
2496
|
+
// left to wait for.
|
|
2128
2497
|
#n(t) {
|
|
2129
2498
|
const e = this.#s(t);
|
|
2130
2499
|
return e.some((i) => i.status === "failed") ? "failed" : e.some((i) => i.status === "stopping") ? "stopping" : e.length && e.every((i) => i.status === "active") ? "active" : e.length ? "pending" : "active";
|
|
2131
2500
|
}
|
|
2132
|
-
#
|
|
2501
|
+
#a(t, e) {
|
|
2133
2502
|
this.#r(t).track(e);
|
|
2134
2503
|
}
|
|
2135
2504
|
#r(t) {
|
|
2136
2505
|
const e = this.#i.get(t);
|
|
2137
|
-
if (!t.attached || !e) throw
|
|
2506
|
+
if (!t.attached || !e) throw D(t);
|
|
2138
2507
|
return e;
|
|
2139
2508
|
}
|
|
2140
|
-
#
|
|
2509
|
+
#o(t) {
|
|
2141
2510
|
for (const e of t) {
|
|
2142
2511
|
this.#i.get(e)?.release(), this.#i.delete(e);
|
|
2143
2512
|
const i = this.#e.get(e);
|
|
2144
|
-
i && (
|
|
2513
|
+
i && (P.get(i)?.revoke(), P.delete(i)), this.#e.delete(e);
|
|
2145
2514
|
}
|
|
2146
2515
|
}
|
|
2147
2516
|
}
|
|
2148
|
-
function
|
|
2517
|
+
function ft(r) {
|
|
2149
2518
|
Promise.resolve(r).catch(() => {
|
|
2150
2519
|
});
|
|
2151
2520
|
}
|
|
2152
|
-
function
|
|
2153
|
-
throw Promise.resolve(r).catch(() => {
|
|
2154
|
-
}), new TypeError("Group configure must be synchronous");
|
|
2155
|
-
}
|
|
2156
|
-
function te(r) {
|
|
2157
|
-
return r === null || typeof r != "object" && typeof r != "function" ? !1 : typeof r.then == "function";
|
|
2158
|
-
}
|
|
2159
|
-
function Q(r, t) {
|
|
2521
|
+
function pt(r, t) {
|
|
2160
2522
|
return Object.freeze({ plugin: r, config: t });
|
|
2161
2523
|
}
|
|
2162
|
-
class
|
|
2524
|
+
class Oe {
|
|
2163
2525
|
constructor(t, e, i, s) {
|
|
2164
2526
|
this.id = t, this.index = e, this.groupId = i.id, this.#i = { declaration: s, group: i, notifyChanged: void 0 };
|
|
2165
2527
|
}
|
|
@@ -2171,7 +2533,7 @@ class ee {
|
|
|
2171
2533
|
groupId;
|
|
2172
2534
|
#s = /* @__PURE__ */ new Set();
|
|
2173
2535
|
attach(t) {
|
|
2174
|
-
const e = this.#
|
|
2536
|
+
const e = this.#h();
|
|
2175
2537
|
if (e.notifyChanged) throw new Error(`Installation '${this.id}' is already attached`);
|
|
2176
2538
|
e.notifyChanged = t;
|
|
2177
2539
|
}
|
|
@@ -2179,7 +2541,7 @@ class ee {
|
|
|
2179
2541
|
return this.#t.phase;
|
|
2180
2542
|
}
|
|
2181
2543
|
/** Whether the owning ChangeSet has granted this Installation Host authority. */
|
|
2182
|
-
get
|
|
2544
|
+
get hasAuthority() {
|
|
2183
2545
|
return this.#i?.notifyChanged !== void 0;
|
|
2184
2546
|
}
|
|
2185
2547
|
get instance() {
|
|
@@ -2189,18 +2551,18 @@ class ee {
|
|
|
2189
2551
|
get error() {
|
|
2190
2552
|
const t = this.#t;
|
|
2191
2553
|
if (t.phase === "failed")
|
|
2192
|
-
return t.
|
|
2554
|
+
return t.error;
|
|
2193
2555
|
if (t.phase === "removed")
|
|
2194
2556
|
return new u("INSTALLATION_REMOVED", `Installation '${this.id}' has been removed`);
|
|
2195
2557
|
}
|
|
2196
2558
|
get group() {
|
|
2197
|
-
return this.#
|
|
2559
|
+
return this.#h().group;
|
|
2198
2560
|
}
|
|
2199
2561
|
get declaration() {
|
|
2200
|
-
return this.#
|
|
2562
|
+
return this.#h().declaration;
|
|
2201
2563
|
}
|
|
2202
2564
|
replaceDeclaration(t) {
|
|
2203
|
-
this.#
|
|
2565
|
+
this.#h().declaration = t;
|
|
2204
2566
|
}
|
|
2205
2567
|
ready() {
|
|
2206
2568
|
const t = this.#e;
|
|
@@ -2212,18 +2574,34 @@ class ee {
|
|
|
2212
2574
|
`Installation '${this.id}' has not been committed`
|
|
2213
2575
|
);
|
|
2214
2576
|
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Binds `ready()` to the change currently in flight.
|
|
2579
|
+
*
|
|
2580
|
+
* The `attempt` token is the point: a second change can start before the
|
|
2581
|
+
* first one's promise settles, and only the latest attempt is allowed to clear
|
|
2582
|
+
* the barrier. Without it, a stale resolution would report readiness for an
|
|
2583
|
+
* attempt that has already been superseded.
|
|
2584
|
+
*
|
|
2585
|
+
* A rejection is rethrown only when this Installation did not end up active.
|
|
2586
|
+
* A change that failed elsewhere in the batch but left this one running is not
|
|
2587
|
+
* this Installation's failure to report.
|
|
2588
|
+
*/
|
|
2215
2589
|
trackReadiness(t) {
|
|
2216
2590
|
const e = {}, i = t.then(
|
|
2217
2591
|
() => {
|
|
2218
2592
|
this.#e?.attempt === e && (this.#e = void 0);
|
|
2219
2593
|
},
|
|
2220
2594
|
(s) => {
|
|
2221
|
-
if (this.#e?.attempt === e && (this.#e = void 0), this.#t.phase !== "active") throw s;
|
|
2595
|
+
if (this.#e?.attempt === e && (this.#e = void 0), this.#t.phase !== "active") throw this.error ?? s;
|
|
2222
2596
|
}
|
|
2223
2597
|
);
|
|
2224
2598
|
this.#e = { attempt: e, barrier: i }, i.catch(() => {
|
|
2225
2599
|
});
|
|
2226
2600
|
}
|
|
2601
|
+
// A terminal state only answers `ready()` once its readiness has been settled.
|
|
2602
|
+
// Before that the outcome is still being decided by the change in flight, so
|
|
2603
|
+
// the caller joins the waiter set instead of being told a result that the
|
|
2604
|
+
// transaction might still roll back.
|
|
2227
2605
|
#n() {
|
|
2228
2606
|
const t = this.#t;
|
|
2229
2607
|
if ((t.phase === "active" || t.phase === "failed" || t.phase === "removed") && t.readiness === "settled") {
|
|
@@ -2262,23 +2640,29 @@ class ee {
|
|
|
2262
2640
|
this.#r({ phase: "pending" });
|
|
2263
2641
|
}
|
|
2264
2642
|
fail(t) {
|
|
2265
|
-
return this.#
|
|
2266
|
-
}
|
|
2643
|
+
return this.#a(t);
|
|
2644
|
+
}
|
|
2645
|
+
/**
|
|
2646
|
+
* For an Installation that never made it into the graph. Unlike `fail()`, this
|
|
2647
|
+
* is terminal: readiness settles immediately, the attachment is dropped, and
|
|
2648
|
+
* the reason is kept as a RecordedFailure rather than the live Error. The handle the
|
|
2649
|
+
* caller already holds stays usable and reports why it is dead.
|
|
2650
|
+
*/
|
|
2267
2651
|
discard(t) {
|
|
2268
|
-
const e = this.#
|
|
2652
|
+
const e = new J(this.#o(t));
|
|
2269
2653
|
this.#r({
|
|
2270
2654
|
phase: "failed",
|
|
2271
|
-
|
|
2655
|
+
error: e,
|
|
2272
2656
|
readiness: "settled"
|
|
2273
2657
|
});
|
|
2274
2658
|
for (const i of this.#s) i.reject(e);
|
|
2275
2659
|
this.#s.clear(), this.#e = void 0, this.#i = void 0;
|
|
2276
2660
|
}
|
|
2277
|
-
#
|
|
2278
|
-
const e = this.#
|
|
2661
|
+
#a(t) {
|
|
2662
|
+
const e = this.#o(t);
|
|
2279
2663
|
return this.#r({
|
|
2280
2664
|
phase: "failed",
|
|
2281
|
-
|
|
2665
|
+
error: e,
|
|
2282
2666
|
readiness: "unsettled"
|
|
2283
2667
|
}), e;
|
|
2284
2668
|
}
|
|
@@ -2288,36 +2672,25 @@ class ee {
|
|
|
2288
2672
|
#r(t) {
|
|
2289
2673
|
this.#t = t, this.#i?.notifyChanged?.();
|
|
2290
2674
|
}
|
|
2291
|
-
#
|
|
2292
|
-
return
|
|
2675
|
+
#o(t) {
|
|
2676
|
+
return V(
|
|
2293
2677
|
t,
|
|
2294
2678
|
"INSTALLATION_UNAVAILABLE",
|
|
2295
2679
|
`Installation '${this.id}' failed with a non-Error value`
|
|
2296
2680
|
);
|
|
2297
2681
|
}
|
|
2298
|
-
#
|
|
2682
|
+
#h() {
|
|
2299
2683
|
const t = this.#i;
|
|
2300
2684
|
if (!t) throw new Error(`Installation '${this.id}' is no longer installed`);
|
|
2301
2685
|
return t;
|
|
2302
2686
|
}
|
|
2303
2687
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
category: r instanceof TypeError ? "typeError" : "error",
|
|
2307
|
-
name: r.name,
|
|
2308
|
-
message: r.message
|
|
2309
|
-
};
|
|
2310
|
-
}
|
|
2311
|
-
function se(r) {
|
|
2312
|
-
const t = r.category === "dougong" ? new u(r.code, r.message) : r.category === "typeError" ? new TypeError(r.message) : new Error(r.message);
|
|
2313
|
-
return t.name = r.name, t;
|
|
2314
|
-
}
|
|
2315
|
-
const O = /* @__PURE__ */ new WeakMap();
|
|
2316
|
-
class re {
|
|
2688
|
+
const L = /* @__PURE__ */ new WeakMap();
|
|
2689
|
+
class Ae {
|
|
2317
2690
|
#t;
|
|
2318
2691
|
#e = { phase: "draft" };
|
|
2319
2692
|
constructor(t) {
|
|
2320
|
-
this.#t = t,
|
|
2693
|
+
this.#t = t, L.set(this, {
|
|
2321
2694
|
attach: (e, i) => {
|
|
2322
2695
|
if (this.#e.phase !== "draft")
|
|
2323
2696
|
throw new Error(`Installation '${this.#t.id}' control is already sealed`);
|
|
@@ -2362,7 +2735,7 @@ class re {
|
|
|
2362
2735
|
);
|
|
2363
2736
|
}
|
|
2364
2737
|
}
|
|
2365
|
-
class
|
|
2738
|
+
class Ie {
|
|
2366
2739
|
#t = /* @__PURE__ */ new Map();
|
|
2367
2740
|
#e = /* @__PURE__ */ new WeakMap();
|
|
2368
2741
|
#i = /* @__PURE__ */ new WeakMap();
|
|
@@ -2382,13 +2755,13 @@ class ne {
|
|
|
2382
2755
|
}
|
|
2383
2756
|
create(t, e, i) {
|
|
2384
2757
|
t.assertAttached();
|
|
2385
|
-
const s = ++this.#n, n = new
|
|
2758
|
+
const s = ++this.#n, n = new Oe(
|
|
2386
2759
|
`${e.name}:${s}`,
|
|
2387
2760
|
s,
|
|
2388
2761
|
t,
|
|
2389
|
-
|
|
2390
|
-
), o = new
|
|
2391
|
-
return this.#e.set(o, n), this.#i.set(n, o), { record: n,
|
|
2762
|
+
pt(e, i)
|
|
2763
|
+
), o = new Ae(n);
|
|
2764
|
+
return this.#e.set(o, n), this.#i.set(n, o), { record: n, facade: o };
|
|
2392
2765
|
}
|
|
2393
2766
|
resolve(t) {
|
|
2394
2767
|
const e = this.#e.get(t);
|
|
@@ -2398,13 +2771,19 @@ class ne {
|
|
|
2398
2771
|
attach(t) {
|
|
2399
2772
|
const e = this.#i.get(t);
|
|
2400
2773
|
if (!e) throw new Error(`Installation '${t.id}' has no public facade`);
|
|
2401
|
-
const i =
|
|
2774
|
+
const i = L.get(e);
|
|
2402
2775
|
if (!i) throw new Error(`Installation '${t.id}' has no draft control`);
|
|
2403
2776
|
t.attach(this.#s.notifyChanged), i.attach(
|
|
2404
2777
|
(s) => this.#s.update(t, e, s),
|
|
2405
2778
|
() => this.#s.remove(t, e)
|
|
2406
2779
|
);
|
|
2407
2780
|
}
|
|
2781
|
+
/**
|
|
2782
|
+
* Validates the whole batch, then applies the whole batch. The two loops are
|
|
2783
|
+
* not a style choice: a rejected operation halfway through a single loop would
|
|
2784
|
+
* leave the earlier ones already written, and this method has no way to undo
|
|
2785
|
+
* them. Checking first means `apply` either changes everything or nothing.
|
|
2786
|
+
*/
|
|
2408
2787
|
apply(t) {
|
|
2409
2788
|
for (const e of t) {
|
|
2410
2789
|
if (e.kind === "install") {
|
|
@@ -2425,37 +2804,39 @@ class ne {
|
|
|
2425
2804
|
this.#t.set(e.installation.id, e.installation);
|
|
2426
2805
|
else if (e.kind === "update") {
|
|
2427
2806
|
const i = e.installation.declaration, s = e.declaration.kind === "config" ? i.plugin : e.declaration.plugin, n = e.declaration.kind === "plugin" ? i.config : e.declaration.config;
|
|
2428
|
-
e.installation.replaceDeclaration(
|
|
2807
|
+
e.installation.replaceDeclaration(pt(s, n));
|
|
2429
2808
|
} else this.contains(e.installation) && this.#t.delete(e.installation.id);
|
|
2430
2809
|
}
|
|
2431
2810
|
settleChanges(t, e) {
|
|
2432
2811
|
for (const i of t)
|
|
2433
|
-
i.kind === "remove" ? (i.installation.remove(), i.installation.settleReady(), this.#
|
|
2812
|
+
i.kind === "remove" ? (i.installation.remove(), i.installation.settleReady(), this.#a(i.installation)) : e || i.installation.deactivate();
|
|
2434
2813
|
}
|
|
2435
2814
|
settleReadiness(t) {
|
|
2436
2815
|
for (const e of t) e.settleReady();
|
|
2437
2816
|
}
|
|
2438
2817
|
discard(t, e) {
|
|
2439
|
-
t.discard(e), this.#
|
|
2818
|
+
t.discard(e), this.#a(t);
|
|
2440
2819
|
}
|
|
2820
|
+
// Captures declarations only, since that is all a rollback restores. Instances
|
|
2821
|
+
// belong to the InstanceCoordinator and are rebuilt from the previous plan
|
|
2822
|
+
// rather than snapshotted — a live Instance is not a value that can be copied.
|
|
2441
2823
|
capture() {
|
|
2442
|
-
return [...this.#t].map((
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
declaration: e.declaration
|
|
2824
|
+
return [...this.#t.values()].map((t) => ({
|
|
2825
|
+
installation: t,
|
|
2826
|
+
declaration: t.declaration
|
|
2446
2827
|
}));
|
|
2447
2828
|
}
|
|
2448
2829
|
restore(t) {
|
|
2449
2830
|
this.#t.clear();
|
|
2450
2831
|
for (const e of t)
|
|
2451
|
-
e.installation.replaceDeclaration(e.declaration), this.#t.set(e.id, e.installation);
|
|
2832
|
+
e.installation.replaceDeclaration(e.declaration), this.#t.set(e.installation.id, e.installation);
|
|
2452
2833
|
}
|
|
2453
|
-
#
|
|
2834
|
+
#a(t) {
|
|
2454
2835
|
const e = this.#i.get(t);
|
|
2455
|
-
e && (
|
|
2836
|
+
e && (L.get(e)?.revoke(), L.delete(e)), this.#i.delete(t);
|
|
2456
2837
|
}
|
|
2457
2838
|
}
|
|
2458
|
-
class
|
|
2839
|
+
class je {
|
|
2459
2840
|
#t = Promise.resolve();
|
|
2460
2841
|
get settled() {
|
|
2461
2842
|
return this.#t;
|
|
@@ -2472,8 +2853,8 @@ class oe {
|
|
|
2472
2853
|
), e;
|
|
2473
2854
|
}
|
|
2474
2855
|
}
|
|
2475
|
-
const
|
|
2476
|
-
class
|
|
2856
|
+
const ke = console, $e = /* @__PURE__ */ new Set(["name", "logger", "onError"]);
|
|
2857
|
+
class Te {
|
|
2477
2858
|
name;
|
|
2478
2859
|
diagnostics;
|
|
2479
2860
|
#t;
|
|
@@ -2481,11 +2862,11 @@ class he {
|
|
|
2481
2862
|
#i;
|
|
2482
2863
|
#s;
|
|
2483
2864
|
#n;
|
|
2484
|
-
#
|
|
2865
|
+
#a;
|
|
2485
2866
|
#r = "idle";
|
|
2486
|
-
#
|
|
2867
|
+
#o = new je();
|
|
2487
2868
|
constructor(t = {}) {
|
|
2488
|
-
|
|
2869
|
+
B(t, "Host options", { fields: $e });
|
|
2489
2870
|
const e = Object.hasOwn(t, "name") ? t.name : void 0, i = Object.hasOwn(t, "logger") ? t.logger : void 0, s = Object.hasOwn(t, "onError") ? t.onError : void 0, n = e ?? "host";
|
|
2490
2871
|
if (typeof n != "string" || !n.trim())
|
|
2491
2872
|
throw new TypeError("Host name must be a non-empty string");
|
|
@@ -2493,10 +2874,10 @@ class he {
|
|
|
2493
2874
|
throw new TypeError("Host name cannot start or end with whitespace");
|
|
2494
2875
|
if (s !== void 0 && typeof s != "function")
|
|
2495
2876
|
throw new TypeError("Host onError must be a function");
|
|
2496
|
-
if (i !== void 0 && !
|
|
2877
|
+
if (i !== void 0 && !se(i))
|
|
2497
2878
|
throw new TypeError("Host logger must implement debug/info/warn/error");
|
|
2498
|
-
this.name = n, this.#i = i ??
|
|
2499
|
-
notifyChanged: () => this.#
|
|
2879
|
+
this.name = n, this.#i = i ?? ke, this.#n = s ?? ((o) => this.#i.error(o)), this.#t = new Ie({
|
|
2880
|
+
notifyChanged: () => this.#d(),
|
|
2500
2881
|
update: (o, a, h) => {
|
|
2501
2882
|
const c = this.#s.change(o.group);
|
|
2502
2883
|
return c.update(a, h), c.commit();
|
|
@@ -2505,25 +2886,29 @@ class he {
|
|
|
2505
2886
|
const h = this.#s.change(o.group);
|
|
2506
2887
|
return h.remove(a), h.commit();
|
|
2507
2888
|
}
|
|
2508
|
-
}), this.#
|
|
2889
|
+
}), this.#a = new de({
|
|
2509
2890
|
hostName: n,
|
|
2510
2891
|
logger: this.#i,
|
|
2511
2892
|
isInstalled: (o) => this.#t.has(o),
|
|
2512
|
-
report: (o) => this.#
|
|
2513
|
-
}), this.#s = new
|
|
2893
|
+
report: (o) => this.#c(o)
|
|
2894
|
+
}), this.#s = new Se(n, {
|
|
2514
2895
|
installations: () => this.#t.values(),
|
|
2515
2896
|
createDraft: (o, a, h) => this.#t.create(o, a, h),
|
|
2516
2897
|
resolveInstallation: (o) => this.#t.resolve(o),
|
|
2517
|
-
executeChanges: (o, a) => this.#
|
|
2898
|
+
executeChanges: (o, a) => this.#h(o, a),
|
|
2518
2899
|
attachInstallation: (o) => this.#t.attach(o),
|
|
2519
2900
|
discardInstallation: (o, a) => this.#t.discard(o, a),
|
|
2520
|
-
runExclusive: (o) => this.#
|
|
2521
|
-
removeInstallations: (o) => this.#
|
|
2522
|
-
notifyChanged: () => this.#
|
|
2523
|
-
}), this.#e = new
|
|
2901
|
+
runExclusive: (o) => this.#o.run(o),
|
|
2902
|
+
removeInstallations: (o) => this.#p(o),
|
|
2903
|
+
notifyChanged: () => this.#d()
|
|
2904
|
+
}), this.#e = new le(
|
|
2524
2905
|
n,
|
|
2525
|
-
|
|
2526
|
-
|
|
2906
|
+
() => ({
|
|
2907
|
+
status: this.#r,
|
|
2908
|
+
installations: this.#t.values(),
|
|
2909
|
+
groups: this.#s.nodes()
|
|
2910
|
+
}),
|
|
2911
|
+
(o) => this.#c(o)
|
|
2527
2912
|
), this.diagnostics = this.#e.view, Object.freeze(this);
|
|
2528
2913
|
}
|
|
2529
2914
|
get status() {
|
|
@@ -2531,10 +2916,10 @@ class he {
|
|
|
2531
2916
|
}
|
|
2532
2917
|
get(t) {
|
|
2533
2918
|
const e = this.#r === "active" ? "available" : "unavailable";
|
|
2534
|
-
return this.#
|
|
2919
|
+
return this.#a.get(t, e);
|
|
2535
2920
|
}
|
|
2536
2921
|
contributions(t) {
|
|
2537
|
-
return this.#
|
|
2922
|
+
return this.#a.contributions(t);
|
|
2538
2923
|
}
|
|
2539
2924
|
install(t, ...e) {
|
|
2540
2925
|
return this.#s.install(this.#s.root, t, ...e);
|
|
@@ -2546,14 +2931,14 @@ class he {
|
|
|
2546
2931
|
return this.#s.create(this.#s.root, t, e);
|
|
2547
2932
|
}
|
|
2548
2933
|
start() {
|
|
2549
|
-
return this.#
|
|
2934
|
+
return this.#o.run(async () => {
|
|
2550
2935
|
if (this.#r !== "active") {
|
|
2551
|
-
this.#
|
|
2936
|
+
this.#l("starting");
|
|
2552
2937
|
try {
|
|
2553
|
-
const t = this.#
|
|
2554
|
-
await this.#
|
|
2938
|
+
const t = this.#a.buildPlan(this.#t.values());
|
|
2939
|
+
await this.#a.start(t), this.#l("active"), this.#t.settleReadiness(t.order);
|
|
2555
2940
|
} catch (t) {
|
|
2556
|
-
this.#
|
|
2941
|
+
this.#l("idle");
|
|
2557
2942
|
for (const e of this.#t.values())
|
|
2558
2943
|
e.status !== "active" && e.fail(t);
|
|
2559
2944
|
throw this.#t.settleReadiness(this.#t.values()), t;
|
|
@@ -2562,21 +2947,21 @@ class he {
|
|
|
2562
2947
|
});
|
|
2563
2948
|
}
|
|
2564
2949
|
stop() {
|
|
2565
|
-
return this.#
|
|
2950
|
+
return this.#o.run(async () => {
|
|
2566
2951
|
if (this.#r === "idle") return;
|
|
2567
|
-
this.#
|
|
2568
|
-
const t = await this.#
|
|
2569
|
-
if (this.#
|
|
2952
|
+
this.#l("stopping");
|
|
2953
|
+
const t = await this.#a.stop();
|
|
2954
|
+
if (this.#l("idle"), t.length === 1) throw t[0];
|
|
2570
2955
|
if (t.length > 1) throw new AggregateError(t, "Host shutdown failed");
|
|
2571
2956
|
});
|
|
2572
2957
|
}
|
|
2573
|
-
#
|
|
2958
|
+
#h(t, e) {
|
|
2574
2959
|
const i = e.filter((s) => s.kind === "install").map((s) => s.installation);
|
|
2575
|
-
return this.#
|
|
2960
|
+
return this.#o.run(async () => {
|
|
2576
2961
|
try {
|
|
2577
|
-
if (!t.attached) throw
|
|
2962
|
+
if (!t.attached) throw D(t);
|
|
2578
2963
|
if (!e.length) return;
|
|
2579
|
-
this.#r === "active" ? await this.#
|
|
2964
|
+
this.#r === "active" ? await this.#u(e) : (this.#t.apply(e), this.#t.settleChanges(e, !1)), this.#d();
|
|
2580
2965
|
} catch (s) {
|
|
2581
2966
|
for (const n of i)
|
|
2582
2967
|
this.#t.contains(n) || this.#t.discard(n, s);
|
|
@@ -2584,71 +2969,92 @@ class he {
|
|
|
2584
2969
|
}
|
|
2585
2970
|
});
|
|
2586
2971
|
}
|
|
2587
|
-
async #
|
|
2588
|
-
t.length && this.#r === "active" ? await this.#
|
|
2972
|
+
async #p(t) {
|
|
2973
|
+
t.length && this.#r === "active" ? await this.#u(t) : (this.#t.apply(t), this.#t.settleChanges(t, !1));
|
|
2589
2974
|
}
|
|
2590
|
-
async #
|
|
2591
|
-
const e = await this.#
|
|
2975
|
+
async #u(t) {
|
|
2976
|
+
const e = await this.#f(t);
|
|
2592
2977
|
if (this.#t.settleReadiness(e.affected), e.kind === "rolled-back") throw e.error;
|
|
2593
2978
|
this.#t.settleChanges(t, !0);
|
|
2594
2979
|
}
|
|
2595
|
-
|
|
2980
|
+
// Three failure levels, in the order they are attempted:
|
|
2981
|
+
//
|
|
2982
|
+
// 1. the new plan does not even build restore declarations, stay active
|
|
2983
|
+
// 2. the plan builds but activation fails Engine rolls back to the previous
|
|
2984
|
+
// Instances and reports the cause
|
|
2985
|
+
// 3. rollback itself cannot complete fail closed: everything stops and
|
|
2986
|
+
// the Host reports `idle`
|
|
2987
|
+
//
|
|
2988
|
+
// Level 3 is the one worth stating out loud. A Host that cannot restore its
|
|
2989
|
+
// previous state is not healthy, so it refuses to present itself as active —
|
|
2990
|
+
// `hasCommittedPlan` is what distinguishes the two outcomes here.
|
|
2991
|
+
async #f(t) {
|
|
2596
2992
|
const e = this.#t.capture(), i = new Set(t.map((n) => n.installation));
|
|
2597
|
-
this.#
|
|
2993
|
+
this.#l("changing");
|
|
2598
2994
|
let s;
|
|
2599
2995
|
try {
|
|
2600
|
-
this.#t.apply(t), s = this.#
|
|
2996
|
+
this.#t.apply(t), s = this.#a.buildPlan(this.#t.values());
|
|
2601
2997
|
} catch (n) {
|
|
2602
|
-
throw this.#t.restore(e), this.#
|
|
2998
|
+
throw this.#t.restore(e), this.#l("active"), n;
|
|
2603
2999
|
}
|
|
2604
3000
|
try {
|
|
2605
|
-
const n = await this.#
|
|
3001
|
+
const n = await this.#a.transition(
|
|
2606
3002
|
s,
|
|
2607
3003
|
i,
|
|
2608
3004
|
() => this.#t.restore(e)
|
|
2609
3005
|
);
|
|
2610
|
-
return this.#
|
|
3006
|
+
return this.#l("active"), n;
|
|
2611
3007
|
} catch (n) {
|
|
2612
|
-
throw this.#
|
|
3008
|
+
throw this.#l(this.#a.hasCommittedPlan ? "active" : "idle"), n;
|
|
2613
3009
|
}
|
|
2614
3010
|
}
|
|
2615
|
-
#
|
|
3011
|
+
#c(t) {
|
|
3012
|
+
const e = this.#i;
|
|
2616
3013
|
try {
|
|
2617
|
-
this.#n(t);
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
} catch {
|
|
2624
|
-
}
|
|
3014
|
+
const i = this.#n(t);
|
|
3015
|
+
Promise.resolve(i).catch((s) => {
|
|
3016
|
+
gt(e, t, s);
|
|
3017
|
+
});
|
|
3018
|
+
} catch (i) {
|
|
3019
|
+
gt(e, t, i);
|
|
2625
3020
|
}
|
|
2626
3021
|
}
|
|
2627
|
-
#
|
|
2628
|
-
this.#r = t, this.#
|
|
3022
|
+
#l(t) {
|
|
3023
|
+
this.#r = t, this.#d();
|
|
2629
3024
|
}
|
|
2630
|
-
#
|
|
2631
|
-
this.#e.publish(
|
|
3025
|
+
#d() {
|
|
3026
|
+
this.#e.publish();
|
|
2632
3027
|
}
|
|
2633
3028
|
}
|
|
2634
|
-
function
|
|
2635
|
-
return new
|
|
3029
|
+
function xe(r) {
|
|
3030
|
+
return new Te(r);
|
|
3031
|
+
}
|
|
3032
|
+
function gt(r, t, e) {
|
|
3033
|
+
try {
|
|
3034
|
+
const i = r.error(
|
|
3035
|
+
new AggregateError([t, e], "Host error reporter failed")
|
|
3036
|
+
);
|
|
3037
|
+
Promise.resolve(i).catch(() => {
|
|
3038
|
+
});
|
|
3039
|
+
} catch {
|
|
3040
|
+
}
|
|
2636
3041
|
}
|
|
2637
3042
|
export {
|
|
2638
|
-
|
|
3043
|
+
$t as ConfigValidationError,
|
|
2639
3044
|
u as DougongError,
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
3045
|
+
z as ReadonlyMapSnapshot,
|
|
3046
|
+
J as RecordedFailure,
|
|
3047
|
+
je as SerialQueue,
|
|
3048
|
+
Z as SnapshotPublisher,
|
|
3049
|
+
B as assertPlainRecord,
|
|
3050
|
+
F as asyncDisposeSymbol,
|
|
3051
|
+
xe as createHost,
|
|
3052
|
+
Ne as definePlugin,
|
|
3053
|
+
v as disposeSymbol,
|
|
3054
|
+
Le as event,
|
|
3055
|
+
ze as extensionPoint,
|
|
3056
|
+
wt as isCancellationReason,
|
|
3057
|
+
se as isLogger,
|
|
3058
|
+
Re as optional,
|
|
3059
|
+
It as service
|
|
2654
3060
|
};
|