meocord 4.1.2 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +362 -0
- package/THIRD_PARTY_NOTICES.md +14 -13
- package/dist/cjs/_shared/{controller.decorator-BywwkU9O.cjs → controller.decorator-XKMlcUZz.cjs} +669 -185
- package/dist/cjs/_shared/{providers-BMMLp2SN.cjs → providers-BZgJyfZS.cjs} +218 -75
- package/dist/cjs/_shared/{sharded-cooldown-store-B65iaiAy.cjs → sharded-cooldown-store-CsJJyCZd.cjs} +10 -7
- package/dist/cjs/_shared/{startup-roots-lFc69AxC.cjs → startup-roots-CgfPQrNl.cjs} +374 -132
- package/dist/cjs/_shared/{translate-error-BnM8FbSH.cjs → translate-error-BUAR1WYG.cjs} +21 -7
- package/dist/cjs/common/index.cjs +4 -4
- package/dist/cjs/core/index.cjs +365 -310
- package/dist/cjs/decorator/index.cjs +85 -61
- package/dist/cjs/testing/index.cjs +2236 -496
- package/dist/cli.json +1 -1
- package/dist/esm/bin/app-template/README.md.template +3 -1
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.spec.ts.template +8 -4
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.ts.template +2 -2
- package/dist/esm/bin/app-template/src/guards/owner.guard.spec.ts.template +8 -4
- package/dist/esm/bin/app-template/src/guards/owner.guard.ts.template +1 -1
- package/dist/esm/bin/app-template/vitest.config.ts.template +1 -1
- package/dist/esm/bin/app-template/vitest.setup.ts.template +7 -3
- package/dist/esm/bin/generator.js +4 -5
- package/dist/esm/bin/helper/filter-generator.helper.js +4 -5
- package/dist/esm/bin/helper/guard-generator.helper.js +4 -5
- package/dist/esm/bin/helper/interceptor-generator.helper.js +4 -5
- package/dist/esm/bin/helper/observer-generator.helper.js +4 -5
- package/dist/esm/bin/helper/pipe-generator.helper.js +4 -5
- package/dist/esm/bin/helper/service-generator.helper.js +4 -5
- package/dist/esm/bin/meocord.js +84 -25
- package/dist/esm/build/load-config.pre-entry.js +17 -4
- package/dist/esm/build/rsbuild-config.js +16 -12
- package/dist/esm/build/typed-externals.js +36 -0
- package/dist/esm/common/cooldown-store.js +10 -2
- package/dist/esm/common/decorator.js +6 -6
- package/dist/esm/common/deprecation.js +2 -2
- package/dist/esm/common/errors.js +27 -2
- package/dist/esm/common/execution-context.js +1 -1
- package/dist/esm/common/meocord-text.js +11 -8
- package/dist/esm/common/metadata.js +1 -1
- package/dist/esm/common/response/call-order.js +9 -4
- package/dist/esm/common/response/presenter.js +33 -6
- package/dist/esm/common/response/response-state.js +84 -10
- package/dist/esm/common/route.js +21 -5
- package/dist/esm/common/sharded-cooldown-store.js +1 -1
- package/dist/esm/common/translate-error.js +1 -1
- package/dist/esm/common/translator.js +37 -6
- package/dist/esm/core/command-conflicts.js +34 -34
- package/dist/esm/core/command-registration.js +93 -24
- package/dist/esm/core/command-routes.js +2 -2
- package/dist/esm/core/component-routes.js +74 -31
- package/dist/esm/core/cooldown-runner.js +29 -8
- package/dist/esm/core/dispatcher.js +51 -7
- package/dist/esm/core/fallback.js +20 -11
- package/dist/esm/core/filter-runner.js +2 -2
- package/dist/esm/core/guard-runner.js +16 -3
- package/dist/esm/core/handler-input.js +4 -3
- package/dist/esm/core/handler-pipeline.js +27 -14
- package/dist/esm/core/handler-registry.js +1 -1
- package/dist/esm/core/interceptor-runner.js +2 -2
- package/dist/esm/core/lifecycle-hooks.js +134 -47
- package/dist/esm/core/meocord-factory.js +241 -179
- package/dist/esm/core/meocord.app.js +116 -75
- package/dist/esm/core/message-routes.js +4 -3
- package/dist/esm/core/observer-runner.js +4 -3
- package/dist/esm/core/providers.js +45 -23
- package/dist/esm/core/route-specificity.js +4 -4
- package/dist/esm/core/running-calls.js +43 -0
- package/dist/esm/core/scalar-types.js +15 -3
- package/dist/esm/core/shard-context.js +6 -7
- package/dist/esm/core/shard-manager.js +16 -10
- package/dist/esm/core/startup-roots.js +23 -4
- package/dist/esm/core/theme-resolvers.js +4 -1
- package/dist/esm/core/theme-runtime.js +2 -2
- package/dist/esm/core/theme-scope.js +3 -1
- package/dist/esm/core/theme-validation.js +17 -10
- package/dist/esm/decorator/app.decorator.js +12 -7
- package/dist/esm/decorator/command-builder.decorator.js +4 -4
- package/dist/esm/decorator/controller-class.decorator.js +9 -4
- package/dist/esm/decorator/controller.decorator.js +162 -83
- package/dist/esm/decorator/cooldown.decorator.js +20 -3
- package/dist/esm/decorator/defer.decorator.js +4 -4
- package/dist/esm/decorator/event.decorator.js +5 -5
- package/dist/esm/decorator/filter.decorator.js +7 -7
- package/dist/esm/decorator/guard.decorator.js +11 -10
- package/dist/esm/decorator/inject.decorator.js +4 -4
- package/dist/esm/decorator/interceptor.decorator.js +7 -7
- package/dist/esm/decorator/observer.decorator.js +4 -4
- package/dist/esm/decorator/service.decorator.js +4 -4
- package/dist/esm/decorator/theme.decorator.js +3 -3
- package/dist/esm/decorator/validation.decorator.js +10 -10
- package/dist/esm/package.json.js +1 -1
- package/dist/esm/testing/catalog.js +27 -11
- package/dist/esm/testing/cooldown-store-suite.js +85 -15
- package/dist/esm/testing/discord-defaults.js +249 -21
- package/dist/esm/testing/index.js +4 -2
- package/dist/esm/testing/inspect-handler.js +20 -3
- package/dist/esm/testing/meocord-testing-module.js +352 -205
- package/dist/esm/testing/mock-fn.js +173 -22
- package/dist/esm/testing/mock-interaction.js +1214 -209
- package/dist/esm/testing/response.js +1 -1
- package/dist/esm/testing/routing.js +39 -14
- package/dist/esm/testing/snowflake.js +9 -2
- package/dist/esm/testing/startup-errors.js +26 -0
- package/dist/esm/testing/strict-mocks.js +65 -0
- package/dist/esm/testing/theme.js +1 -1
- package/dist/esm/util/bundle-entry.util.js +2 -1
- package/dist/esm/util/common.util.js +47 -19
- package/dist/esm/util/dev-runner.util.js +8 -8
- package/dist/esm/util/generator-cli.util.js +4 -5
- package/dist/esm/util/interaction.util.js +3 -3
- package/dist/esm/util/meocord-config-loader.util.js +10 -2
- package/dist/esm/util/meocord-config-validation.util.js +4 -5
- package/dist/esm/util/meocord-source-config.util.js +65 -20
- package/dist/esm/util/metadata-keys.js +1 -0
- package/dist/esm/util/method-wrapper.util.js +16 -0
- package/dist/esm/util/platform.util.js +10 -10
- package/dist/esm/util/refusal.util.js +148 -8
- package/dist/esm/util/shard-process.util.js +4 -1
- package/dist/esm/util/sharding-mode.util.js +5 -7
- package/dist/esm/util/shared-state.util.js +21 -0
- package/dist/esm/util/tsconfig-paths.util.js +29 -0
- package/dist/esm/util/tsconfig.util.js +10 -10
- package/dist/esm/util/value.util.js +12 -1
- package/dist/types/common/index.d.cts +8 -8
- package/dist/types/common/index.d.ts +8 -8
- package/dist/types/core/index.d.cts +10 -7
- package/dist/types/core/index.d.ts +10 -7
- package/dist/types/decorator/index.d.cts +31 -29
- package/dist/types/decorator/index.d.ts +31 -29
- package/dist/types/{index-D7n0FBMm.d.ts → index-DKJclIi-.d.ts} +107 -36
- package/dist/types/{index-DEP0NYrU.d.cts → index-Dlf0ZZtS.d.cts} +107 -36
- package/dist/types/interface/index.d.cts +1 -1
- package/dist/types/interface/index.d.ts +1 -1
- package/dist/types/{route-C-aMI7Sl.d.cts → route-Bh1U13yy.d.cts} +8 -4
- package/dist/types/{route-C-aMI7Sl.d.ts → route-Bh1U13yy.d.ts} +8 -4
- package/dist/types/testing/index.d.cts +406 -70
- package/dist/types/testing/index.d.ts +406 -70
- package/dist/types/{theme-resolvers-COHdX5g6.d.cts → theme-resolvers-CyEz9pnv.d.cts} +1 -1
- package/dist/types/{theme-resolvers-DedxyscT.d.ts → theme-resolvers-DA204O-q.d.ts} +1 -1
- package/dist/types/{translator-J6tIUfdp.d.ts → translator-Bg7hwxDF.d.cts} +21 -8
- package/dist/types/{translator-B4mc1lzJ.d.cts → translator-CeP4bCzp.d.ts} +21 -8
- package/package.json +4 -3
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
1
2
|
import { storeOperationsSettled } from './cooldown-runner.js';
|
|
3
|
+
import { RunningCalls } from './running-calls.js';
|
|
2
4
|
|
|
3
5
|
/** The entry of a unit whose instance is `instance`. */ function lifecycleEntry(unit, instance) {
|
|
4
6
|
return {
|
|
@@ -11,11 +13,45 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
11
13
|
}
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The ready hooks' pass, which shutdown waits for before it reads which units to shut down, so a unit whose `onReady`
|
|
18
|
+
* finishes meanwhile is shut down too. An `onReady` still running that asks the app to stop is not waited for; a timer
|
|
19
|
+
* or callback an `onReady` that has settled left behind excuses nothing.
|
|
20
|
+
*/ class ReadyPass {
|
|
21
|
+
/** Runs `pass`, the ready hooks, as the pass shutdown waits for. */ run(pass) {
|
|
22
|
+
return this.passes.run('onReady', pass);
|
|
23
|
+
}
|
|
24
|
+
/** Excuses the pass when this runs within the `onReady` in progress, as one that stops the app does. */ excuseCurrent() {
|
|
25
|
+
if (this.current && this.hooks.getStore() === this.current) this.passes.excuseCurrent();
|
|
26
|
+
}
|
|
27
|
+
/** Settles once the pass has, unless excused. */ settled() {
|
|
28
|
+
return this.passes.settled();
|
|
29
|
+
}
|
|
30
|
+
/** The unit whose `onReady` a wait would still wait for, if any. */ running() {
|
|
31
|
+
return this.passes.running().length > 0 ? [
|
|
32
|
+
this.unit ?? 'a unit'
|
|
33
|
+
] : [];
|
|
34
|
+
}
|
|
35
|
+
constructor(){
|
|
36
|
+
this.passes = new RunningCalls();
|
|
37
|
+
/** The `onReady` each async context belongs to. */ this.hooks = new AsyncLocalStorage();
|
|
38
|
+
/** Runs a unit's `onReady` as the one in progress. */ this.runOnReady = async (unit, run)=>{
|
|
39
|
+
const hook = {};
|
|
40
|
+
this.current = hook;
|
|
41
|
+
this.unit = unit.name;
|
|
42
|
+
try {
|
|
43
|
+
await this.hooks.run(hook, run);
|
|
44
|
+
} finally{
|
|
45
|
+
if (this.current === hook) this.current = undefined;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
14
50
|
/**
|
|
15
51
|
* Resolves each unit and runs its `onReady` one at a time, in the units' dependency order. A failure is
|
|
16
52
|
* reported and the next unit still runs. Each unit whose `onReady` settled, or that has none, is pushed
|
|
17
53
|
* to `entries` as it finishes, so a shutdown that starts meanwhile closes exactly those.
|
|
18
|
-
*/ async function runReadyHooks(container, units, client, info, entries, report, { stopped = ()=>false, slowAfterMs, settled } = {}) {
|
|
54
|
+
*/ async function runReadyHooks(container, units, client, info, entries, report, { stopped = ()=>false, slowAfterMs, settled, runOnReady } = {}) {
|
|
19
55
|
const failed = new Set();
|
|
20
56
|
// For each unit, the failed units it depends on, directly or through another dependency
|
|
21
57
|
const failedUpstream = new Map();
|
|
@@ -23,6 +59,9 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
23
59
|
unit.token,
|
|
24
60
|
unit
|
|
25
61
|
]));
|
|
62
|
+
// The token each instance was first reached by: one instance two tokens reach, an alias or one value provided twice,
|
|
63
|
+
// runs its hooks once
|
|
64
|
+
const firstToken = new Map();
|
|
26
65
|
for (const unit of units){
|
|
27
66
|
if (stopped()) break;
|
|
28
67
|
const upstream = new Set();
|
|
@@ -41,9 +80,17 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
41
80
|
settled?.(unit);
|
|
42
81
|
continue;
|
|
43
82
|
}
|
|
83
|
+
const first = firstToken.get(instance);
|
|
84
|
+
if (first !== undefined) {
|
|
85
|
+
// Failed or not as the token that ran its hooks did, for what depends on this one
|
|
86
|
+
if (failed.has(first)) failed.add(unit.token);
|
|
87
|
+
settled?.(unit);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
firstToken.set(instance, unit.token);
|
|
44
91
|
const entry = lifecycleEntry(unit, instance);
|
|
45
|
-
// Only a unit whose onReady has settled, or that has none, is shut down: a stop mid-ready
|
|
46
|
-
//
|
|
92
|
+
// Only a unit whose onReady has settled, or that has none, is shut down: a stop mid-ready waits for the one still
|
|
93
|
+
// starting, within its time, and skips those not reached yet
|
|
47
94
|
if (typeof instance.onReady !== 'function') {
|
|
48
95
|
entries.push(entry);
|
|
49
96
|
settled?.(unit);
|
|
@@ -54,7 +101,8 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
54
101
|
]);
|
|
55
102
|
const slow = slowAfterMs !== undefined && report.slow ? setTimeout(()=>report.slow(unit), slowAfterMs) : undefined;
|
|
56
103
|
try {
|
|
57
|
-
|
|
104
|
+
const onReady = ()=>instance.onReady(client, info);
|
|
105
|
+
await (runOnReady ? runOnReady(unit, onReady) : onReady());
|
|
58
106
|
} catch (error) {
|
|
59
107
|
failed.add(unit.token);
|
|
60
108
|
report.hookFailed(unit, error);
|
|
@@ -67,12 +115,14 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
67
115
|
}
|
|
68
116
|
/**
|
|
69
117
|
* Runs the entries' `onShutdown` hooks one at a time, in reverse, so a unit stops before those it
|
|
70
|
-
* depends on. A failure is reported and the next hook still runs.
|
|
71
|
-
|
|
118
|
+
* depends on. A failure is reported and the next hook still runs. An instance already in `ran` is not shut down again,
|
|
119
|
+
* so one that two entries reach stops once.
|
|
120
|
+
*/ async function runShutdownHooks(entries, hookFailed, ran = new Set()) {
|
|
72
121
|
for (const { name, instance } of [
|
|
73
122
|
...entries
|
|
74
123
|
].reverse()){
|
|
75
|
-
if (typeof instance.onShutdown !== 'function') continue;
|
|
124
|
+
if (typeof instance.onShutdown !== 'function' || ran.has(instance)) continue;
|
|
125
|
+
ran.add(instance);
|
|
76
126
|
try {
|
|
77
127
|
await instance.onShutdown();
|
|
78
128
|
} catch (error) {
|
|
@@ -80,54 +130,91 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
80
130
|
}
|
|
81
131
|
}
|
|
82
132
|
}
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* reverse dependency order, and the store and what it injects last. The whole sequence is waited for at most
|
|
88
|
-
* `timeoutMs`.
|
|
89
|
-
*/ async function runShutdownSequence(container, entries, { drainCalls, timeoutMs, hookFailed, warn }) {
|
|
90
|
-
// A unit whose onReady settles while the calls drain was still starting when shutdown began, so it is not shut down
|
|
91
|
-
entries = [
|
|
92
|
-
...entries
|
|
93
|
-
];
|
|
94
|
-
const byToken = new Map(entries.map((entry)=>[
|
|
95
|
-
entry.token,
|
|
96
|
-
entry
|
|
97
|
-
]));
|
|
98
|
-
// The store and everything it reaches through what it injects
|
|
99
|
-
const storeSide = new Set();
|
|
100
|
-
const reach = (entry)=>{
|
|
101
|
-
if (!entry || storeSide.has(entry)) return;
|
|
102
|
-
storeSide.add(entry);
|
|
103
|
-
for (const dependency of entry.dependencies)reach(byToken.get(dependency));
|
|
104
|
-
};
|
|
105
|
-
for (const entry of entries)if (entry.cooldownStore) reach(entry);
|
|
106
|
-
const needsStore = [
|
|
107
|
-
...storeSide
|
|
108
|
-
].some((entry)=>typeof entry.instance.onShutdown === 'function');
|
|
109
|
-
const sequence = (async ()=>{
|
|
110
|
-
if (needsStore) {
|
|
111
|
-
await drainCalls();
|
|
112
|
-
await storeOperationsSettled(container);
|
|
113
|
-
}
|
|
114
|
-
// Nothing on the store's side injects anything outside it, so running it last keeps the reverse dependency order
|
|
115
|
-
await runShutdownHooks(entries.filter((entry)=>!storeSide.has(entry)), hookFailed);
|
|
116
|
-
await runShutdownHooks(entries.filter((entry)=>storeSide.has(entry)), hookFailed);
|
|
117
|
-
})();
|
|
133
|
+
/** The part of `timeoutMs` the drain leaves for the hooks: a quarter, at least 1 s, and never more than half. */ function hooksReserveMs(timeoutMs) {
|
|
134
|
+
return Math.min(Math.max(timeoutMs / 4, 1000), timeoutMs / 2);
|
|
135
|
+
}
|
|
136
|
+
/** A timer whose promise resolves with `value` after `ms`, and `cancel` to clear it. */ function after(ms, value) {
|
|
118
137
|
let timer;
|
|
119
|
-
const
|
|
120
|
-
timer = setTimeout(()=>resolve(
|
|
138
|
+
const promise = new Promise((resolve)=>{
|
|
139
|
+
timer = setTimeout(()=>resolve(value), ms);
|
|
121
140
|
});
|
|
141
|
+
return {
|
|
142
|
+
promise,
|
|
143
|
+
cancel: ()=>clearTimeout(timer)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Shuts down the entries there are once an `onReady` in progress has settled, as a bot and a testing module both do.
|
|
148
|
+
* The calls under way finish first, on every shutdown with `drainAlways`, and otherwise when the cooldown store, or
|
|
149
|
+
* anything it injects directly or through another, has an `onShutdown`; then the store operations they started, so the
|
|
150
|
+
* store's last writes and releases still reach it. The other hooks then run in reverse dependency order, and the store
|
|
151
|
+
* and what it injects last.
|
|
152
|
+
*
|
|
153
|
+
* The whole sequence is waited for at most `timeoutMs`. The wait for the `onReady` and the drain stop early enough to
|
|
154
|
+
* leave the hooks {@link hooksReserveMs}, with a warning naming what still runs, and the hooks run in the time left.
|
|
155
|
+
*/ async function runShutdownSequence(container, readEntries, { drainCalls, drainAlways = false, runningCalls, readyPass, timeoutMs, hookFailed, warn }) {
|
|
156
|
+
const whole = after(timeoutMs, 'timeout');
|
|
157
|
+
const reserve = hooksReserveMs(timeoutMs);
|
|
158
|
+
const drainEnds = after(timeoutMs - reserve, false);
|
|
159
|
+
// At once on a shutdown that always drains, so no call starts while an onReady finishes
|
|
160
|
+
let draining = drainAlways ? drainCalls().then(()=>true) : undefined;
|
|
122
161
|
try {
|
|
162
|
+
const readying = readyPass?.running() ?? [];
|
|
163
|
+
if (readying.length > 0 && !await Promise.race([
|
|
164
|
+
readyPass.settled().then(()=>true),
|
|
165
|
+
drainEnds.promise
|
|
166
|
+
])) {
|
|
167
|
+
warn(`onReady in ${readying.join(', ')} is still running after ${timeoutMs - reserve} ms; shutting down without waiting for it.`);
|
|
168
|
+
}
|
|
169
|
+
// Read once the onReady in progress has settled, so its unit is among them
|
|
170
|
+
const entries = [
|
|
171
|
+
...readEntries()
|
|
172
|
+
];
|
|
173
|
+
const byToken = new Map(entries.map((entry)=>[
|
|
174
|
+
entry.token,
|
|
175
|
+
entry
|
|
176
|
+
]));
|
|
177
|
+
// The store and everything it reaches through what it injects
|
|
178
|
+
const storeSide = new Set();
|
|
179
|
+
const reach = (entry)=>{
|
|
180
|
+
if (!entry || storeSide.has(entry)) return;
|
|
181
|
+
storeSide.add(entry);
|
|
182
|
+
for (const dependency of entry.dependencies)reach(byToken.get(dependency));
|
|
183
|
+
};
|
|
184
|
+
for (const entry of entries)if (entry.cooldownStore) reach(entry);
|
|
185
|
+
const needsStore = [
|
|
186
|
+
...storeSide
|
|
187
|
+
].some((entry)=>typeof entry.instance.onShutdown === 'function');
|
|
188
|
+
let drained = true;
|
|
189
|
+
if (needsStore) draining ?? (draining = drainCalls().then(()=>true));
|
|
190
|
+
if (draining) {
|
|
191
|
+
drained = await Promise.race([
|
|
192
|
+
draining,
|
|
193
|
+
drainEnds.promise
|
|
194
|
+
]);
|
|
195
|
+
if (!drained) {
|
|
196
|
+
const running = runningCalls?.() ?? [];
|
|
197
|
+
warn(`Calls still running after ${timeoutMs - reserve} ms${running.length > 0 ? `: ${running.join(', ')}` : ''}; ` + `running the onShutdown hooks in the ${reserve} ms left.`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
drainEnds.cancel();
|
|
201
|
+
const sequence = (async ()=>{
|
|
202
|
+
// Only after the calls settled: a call still running may never let its store operations settle
|
|
203
|
+
if (needsStore && drained) await storeOperationsSettled(container);
|
|
204
|
+
// Nothing on the store's side injects anything outside it, so running it last keeps the reverse dependency order
|
|
205
|
+
const ran = new Set();
|
|
206
|
+
await runShutdownHooks(entries.filter((entry)=>!storeSide.has(entry)), hookFailed, ran);
|
|
207
|
+
await runShutdownHooks(entries.filter((entry)=>storeSide.has(entry)), hookFailed, ran);
|
|
208
|
+
})();
|
|
123
209
|
if (await Promise.race([
|
|
124
210
|
sequence,
|
|
125
|
-
|
|
211
|
+
whole.promise
|
|
126
212
|
]) === 'timeout') {
|
|
127
213
|
warn(`onShutdown hooks did not finish within ${timeoutMs} ms; shutting down anyway.`);
|
|
128
214
|
}
|
|
129
215
|
} finally{
|
|
130
|
-
|
|
216
|
+
drainEnds.cancel();
|
|
217
|
+
whole.cancel();
|
|
131
218
|
}
|
|
132
219
|
}
|
|
133
220
|
/** Settles once every promise in `calls` has, those added while waiting included. */ async function callsSettled(calls) {
|
|
@@ -136,4 +223,4 @@ import { storeOperationsSettled } from './cooldown-runner.js';
|
|
|
136
223
|
]);
|
|
137
224
|
}
|
|
138
225
|
|
|
139
|
-
export { callsSettled, lifecycleEntry, runReadyHooks, runShutdownHooks, runShutdownSequence };
|
|
226
|
+
export { ReadyPass, callsSettled, hooksReserveMs, lifecycleEntry, runReadyHooks, runShutdownHooks, runShutdownSequence };
|