@nimbus-sh/core 0.5.0 → 0.7.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.
Files changed (145) hide show
  1. package/README.md +47 -26
  2. package/dist/_shared/byte-stream.d.ts +5 -4
  3. package/dist/_shared/byte-stream.d.ts.map +1 -1
  4. package/dist/_shared/cache-stats.d.ts +23 -1
  5. package/dist/_shared/cache-stats.d.ts.map +1 -1
  6. package/dist/_shared/cache-stats.js +13 -1
  7. package/dist/_shared/exports-resolver.d.ts +1 -1
  8. package/dist/_shared/exports-resolver.js +1 -1
  9. package/dist/_shared/real-node-imports.d.ts +7 -0
  10. package/dist/_shared/real-node-imports.d.ts.map +1 -1
  11. package/dist/_shared/real-node-imports.js +8 -0
  12. package/dist/_shared/retry.js +1 -1
  13. package/dist/_shared/tarball.d.ts +23 -5
  14. package/dist/_shared/tarball.d.ts.map +1 -1
  15. package/dist/_shared/tarball.js +38 -5
  16. package/dist/_shared/vfs-write-ledger.d.ts.map +1 -1
  17. package/dist/_shared/vfs-write-ledger.js +22 -16
  18. package/dist/constants.d.ts +5 -11
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +16 -56
  21. package/dist/runtime/assets-loader.js +1 -1
  22. package/dist/runtime/comment-strip.d.ts +0 -35
  23. package/dist/runtime/comment-strip.d.ts.map +1 -1
  24. package/dist/runtime/comment-strip.js +48 -20
  25. package/dist/runtime/esbuild-service.d.ts +38 -42
  26. package/dist/runtime/esbuild-service.d.ts.map +1 -1
  27. package/dist/runtime/esbuild-service.js +494 -197
  28. package/dist/runtime/javascript-ast.d.ts.map +1 -1
  29. package/dist/runtime/javascript-ast.js +45 -7
  30. package/dist/runtime/opentui-wasm-backend.d.ts.map +1 -1
  31. package/dist/runtime/opentui-wasm-backend.js +18 -16
  32. package/dist/runtime/port-registry.d.ts +4 -2
  33. package/dist/runtime/port-registry.d.ts.map +1 -1
  34. package/dist/runtime/port-registry.js +60 -8
  35. package/dist/runtime/virtual-socket-kernel.generated.d.ts +1 -1
  36. package/dist/runtime/virtual-socket-kernel.generated.js +1 -1
  37. package/dist/shell/stdin-adapter.d.ts +11 -0
  38. package/dist/shell/stdin-adapter.d.ts.map +1 -0
  39. package/dist/shell/stdin-adapter.js +59 -0
  40. package/dist/shell/unix-commands.d.ts +2 -1
  41. package/dist/shell/unix-commands.d.ts.map +1 -1
  42. package/dist/shell/unix-commands.js +1078 -50
  43. package/dist/substrate/lifo/commands/io/dd.js +1 -1
  44. package/dist/substrate/lifo/commands/net/curl.d.ts.map +1 -1
  45. package/dist/substrate/lifo/commands/net/curl.js +270 -54
  46. package/dist/substrate/lifo/commands/system/npm.d.ts +18 -1
  47. package/dist/substrate/lifo/commands/system/npm.d.ts.map +1 -1
  48. package/dist/substrate/lifo/commands/system/npm.js +26 -43
  49. package/dist/substrate/lifo/commands/text/head.d.ts.map +1 -1
  50. package/dist/substrate/lifo/commands/text/head.js +2 -1
  51. package/dist/substrate/lifo/commands/text/sed.d.ts.map +1 -1
  52. package/dist/substrate/lifo/commands/text/sed.js +499 -117
  53. package/dist/substrate/lifo/commands/types.d.ts +8 -4
  54. package/dist/substrate/lifo/commands/types.d.ts.map +1 -1
  55. package/dist/substrate/lifo/node-compat/zlib.d.ts +37 -18
  56. package/dist/substrate/lifo/node-compat/zlib.d.ts.map +1 -1
  57. package/dist/substrate/lifo/node-compat/zlib.js +122 -23
  58. package/dist/substrate/lifo/shell/interpreter.d.ts +9 -1
  59. package/dist/substrate/lifo/shell/interpreter.d.ts.map +1 -1
  60. package/dist/substrate/lifo/shell/interpreter.js +79 -29
  61. package/dist/substrate/lifo/shell/pipe.d.ts +16 -0
  62. package/dist/substrate/lifo/shell/pipe.d.ts.map +1 -1
  63. package/dist/substrate/lifo/shell/pipe.js +62 -18
  64. package/dist/substrate/lifo/shell/terminal-stdin.d.ts +20 -3
  65. package/dist/substrate/lifo/shell/terminal-stdin.d.ts.map +1 -1
  66. package/dist/substrate/lifo/shell/terminal-stdin.js +60 -24
  67. package/dist/vfs/seed-project.d.ts.map +1 -1
  68. package/dist/vfs/seed-project.js +1 -1
  69. package/dist/vfs/sqlite-vfs.d.ts +21 -30
  70. package/dist/vfs/sqlite-vfs.d.ts.map +1 -1
  71. package/dist/vfs/sqlite-vfs.js +113 -29
  72. package/dist/workspace/nimbus-workspace.d.ts +15 -0
  73. package/dist/workspace/nimbus-workspace.d.ts.map +1 -1
  74. package/dist/workspace/nimbus-workspace.js +20 -3
  75. package/dist/workspace/supervisor-op.d.ts +23 -0
  76. package/dist/workspace/supervisor-op.d.ts.map +1 -0
  77. package/dist/workspace/supervisor-op.js +92 -0
  78. package/package.json +3 -2
  79. package/src/_shared/byte-stream.ts +5 -4
  80. package/src/_shared/cache-stats.ts +27 -1
  81. package/src/_shared/exports-resolver.ts +1 -1
  82. package/src/_shared/real-node-imports.ts +8 -0
  83. package/src/_shared/retry.ts +1 -1
  84. package/src/_shared/tarball.ts +56 -5
  85. package/src/_shared/vfs-write-ledger.ts +22 -16
  86. package/src/constants.ts +30 -60
  87. package/src/runtime/assets-loader.ts +1 -1
  88. package/src/runtime/comment-strip.ts +42 -23
  89. package/src/runtime/esbuild-service.ts +566 -217
  90. package/src/runtime/javascript-ast.ts +40 -9
  91. package/src/runtime/opentui-wasm-backend.ts +19 -17
  92. package/src/runtime/port-registry.ts +66 -8
  93. package/src/runtime/virtual-socket-kernel.generated.ts +1 -1
  94. package/src/shell/stdin-adapter.ts +58 -0
  95. package/src/shell/unix-commands.ts +1054 -50
  96. package/src/substrate/lifo/commands/io/dd.ts +2 -2
  97. package/src/substrate/lifo/commands/net/curl.ts +310 -58
  98. package/src/substrate/lifo/commands/system/npm.ts +58 -38
  99. package/src/substrate/lifo/commands/text/head.ts +2 -1
  100. package/src/substrate/lifo/commands/text/sed.ts +519 -109
  101. package/src/substrate/lifo/commands/types.ts +8 -5
  102. package/src/substrate/lifo/node-compat/zlib.ts +155 -26
  103. package/src/substrate/lifo/shell/interpreter.ts +74 -27
  104. package/src/substrate/lifo/shell/pipe.ts +65 -24
  105. package/src/substrate/lifo/shell/terminal-stdin.ts +66 -30
  106. package/src/vfs/seed-project.ts +3 -3
  107. package/src/vfs/sqlite-vfs.ts +128 -64
  108. package/src/workspace/nimbus-workspace.ts +26 -2
  109. package/src/workspace/supervisor-op.ts +117 -0
  110. package/dist/_shared/install-phase.d.ts +0 -47
  111. package/dist/_shared/install-phase.d.ts.map +0 -1
  112. package/dist/_shared/install-phase.js +0 -1
  113. package/dist/_shared/rpc-dispose.d.ts +0 -4
  114. package/dist/_shared/rpc-dispose.d.ts.map +0 -1
  115. package/dist/_shared/rpc-dispose.js +0 -30
  116. package/dist/_shared/w7-frame.d.ts +0 -79
  117. package/dist/_shared/w7-frame.d.ts.map +0 -1
  118. package/dist/_shared/w7-frame.js +0 -840
  119. package/dist/_shared/weighted-credit-pool.d.ts +0 -61
  120. package/dist/_shared/weighted-credit-pool.d.ts.map +0 -1
  121. package/dist/_shared/weighted-credit-pool.js +0 -196
  122. package/dist/observability/diag-counters.d.ts +0 -236
  123. package/dist/observability/diag-counters.d.ts.map +0 -1
  124. package/dist/observability/diag-counters.js +0 -195
  125. package/dist/observability/heap-estimate.d.ts +0 -225
  126. package/dist/observability/heap-estimate.d.ts.map +0 -1
  127. package/dist/observability/heap-estimate.js +0 -185
  128. package/dist/observability/heavy-alloc-coord.d.ts +0 -93
  129. package/dist/observability/heavy-alloc-coord.d.ts.map +0 -1
  130. package/dist/observability/heavy-alloc-coord.js +0 -181
  131. package/dist/observability/oom-classify.d.ts +0 -138
  132. package/dist/observability/oom-classify.d.ts.map +0 -1
  133. package/dist/observability/oom-classify.js +0 -268
  134. package/dist/observability/oom-discriminator.d.ts +0 -176
  135. package/dist/observability/oom-discriminator.d.ts.map +0 -1
  136. package/dist/observability/oom-discriminator.js +0 -272
  137. package/src/_shared/install-phase.ts +0 -56
  138. package/src/_shared/rpc-dispose.ts +0 -31
  139. package/src/_shared/w7-frame.ts +0 -1013
  140. package/src/_shared/weighted-credit-pool.ts +0 -244
  141. package/src/observability/diag-counters.ts +0 -343
  142. package/src/observability/heap-estimate.ts +0 -331
  143. package/src/observability/heavy-alloc-coord.ts +0 -241
  144. package/src/observability/oom-classify.ts +0 -260
  145. package/src/observability/oom-discriminator.ts +0 -405
@@ -1,272 +0,0 @@
1
- /**
2
- * oom-discriminator.ts — singleton ring buffer for OOM / failure
3
- * forensics + last-known-RPC-frame + last-known-facet-id +
4
- * session-recovery-event ring, plus snapshot/rehydrate hooks for DO
5
- * storage persistence.
6
- *
7
- * W5 (Lever 5 / J.1.1) — original module. Pairs with oom-classify.ts.
8
- * C'.2 — added the recovery_event ring.
9
- *
10
- * Why singleton-per-isolate
11
- * ─────────────────────────
12
- * Same pattern as src/observability/diag-counters.ts. The supervisor bundle
13
- * is the consumer; all writers (sqlite-vfs, facet-pool, facet-manager,
14
- * supervisor-rpc, npm-installer, nimbus-session) live in the same
15
- * isolate. Module scope provides one process-local diagnostic without
16
- * threading a handle through each writer.
17
- *
18
- * Two distinct rings
19
- * ──────────────────
20
- * - failures: things that failed (the original W5 ring).
21
- * - recoveryEvents: lifecycle transitions of the session. Cold isolate
22
- * boot → 'cold' → 'hydrated' → 'active' → 'drained'.
23
- *
24
- * Bounded-size guarantees
25
- * ───────────────────────
26
- * - failures ring: 50 entries (RING_SIZE).
27
- * - recoveryEvents ring: 50 entries (RECOVERY_RING_SIZE).
28
- * - per-message cap: 200 chars (truncated at insert).
29
- * - per-RPC-frame: single slot, one object.
30
- * - per-facet-id: single slot, one object.
31
- *
32
- * Snapshot size stays bounded even with both rings full.
33
- */
34
- import { isOomCause } from './oom-classify.js';
35
- const RING_SIZE = 50;
36
- const RECOVERY_RING_SIZE = 50;
37
- const MESSAGE_CAP = 200;
38
- const state = {
39
- failures: [],
40
- recoveryEvents: [],
41
- lastRpcFrame: null,
42
- lastFacetId: null,
43
- };
44
- function getState() {
45
- return state;
46
- }
47
- /** Append a failure to the ring. Newest first. Capped at RING_SIZE. */
48
- export function recordFailure(f) {
49
- const s = getState();
50
- // Defensive copy + message cap.
51
- const entry = {
52
- at: Number(f.at) || Date.now(),
53
- phase: String(f.phase ?? 'unknown'),
54
- cause: f.cause,
55
- rssEstimateBytes: Number(f.rssEstimateBytes) || 0,
56
- heapUsedBytes: Number(f.heapUsedBytes) || 0,
57
- lruBytes: Number(f.lruBytes) || 0,
58
- inFlightBytes: Number(f.inFlightBytes) || 0,
59
- lastRpcFrame: f.lastRpcFrame ?? s.lastRpcFrame,
60
- lastFacetId: f.lastFacetId ?? s.lastFacetId,
61
- };
62
- if (typeof f.exitCode === 'number')
63
- entry.exitCode = f.exitCode;
64
- if (typeof f.pid === 'number')
65
- entry.pid = f.pid;
66
- if (f.message) {
67
- const m = String(f.message);
68
- entry.message = m.length > MESSAGE_CAP ? m.slice(0, MESSAGE_CAP) : m;
69
- }
70
- s.failures.unshift(entry);
71
- if (s.failures.length > RING_SIZE)
72
- s.failures.length = RING_SIZE;
73
- }
74
- /** Read a snapshot of the ring. Newest first. Caller-side mutations
75
- * do not affect the singleton. */
76
- export function getFailures() {
77
- return getState().failures.slice(0);
78
- }
79
- /** Record the current RPC frame (called at every RPC entry). Bounded
80
- * to a single slot — the LATEST frame wins. */
81
- export function setLastRpcFrame(method, payloadBytes) {
82
- const s = getState();
83
- s.lastRpcFrame = {
84
- method: String(method),
85
- payloadBytes: Number(payloadBytes) || 0,
86
- atMs: Date.now(),
87
- };
88
- }
89
- export function getLastRpcFrame() {
90
- return getState().lastRpcFrame;
91
- }
92
- /** Record the most recent facet dispatch. */
93
- export function setLastFacetId(codeId, slotIndex) {
94
- const s = getState();
95
- s.lastFacetId = {
96
- codeId: String(codeId),
97
- slotIndex: Number(slotIndex) || 0,
98
- atMs: Date.now(),
99
- };
100
- }
101
- export function getLastFacetId() {
102
- return getState().lastFacetId;
103
- }
104
- // ── C'.2 recovery_event ring ────────────────────────────────────────────
105
- //
106
- // The ring is bounded at RECOVERY_RING_SIZE; the diag endpoint reads via
107
- // getRecoveryEvents() (newest first).
108
- /** Append a recovery event to the ring. Newest first. Capped at
109
- * RECOVERY_RING_SIZE. */
110
- export function recordRecoveryEvent(e) {
111
- const s = getState();
112
- // Defensive copy + notes cap. We intentionally do NOT validate the
113
- // state-machine direction here (e.g. that 'drained' only follows
114
- // 'active') — the state machine lives elsewhere; this ring is a
115
- // recorder, not an enforcer. If a probe sees an impossible
116
- // transition, that's a real bug in the state machine and the
117
- // probe must fail.
118
- const entry = {
119
- at: Number(e.at) || Date.now(),
120
- fromState: e.fromState,
121
- toState: e.toState,
122
- trigger: String(e.trigger ?? 'unknown'),
123
- isolateGen: Number(e.isolateGen) || 0,
124
- dataLoss: !!e.dataLoss,
125
- snapshotKeysRehydrated: Number(e.snapshotKeysRehydrated) || 0,
126
- };
127
- if (e.notes) {
128
- const n = String(e.notes);
129
- entry.notes = n.length > MESSAGE_CAP ? n.slice(0, MESSAGE_CAP) : n;
130
- }
131
- s.recoveryEvents.unshift(entry);
132
- if (s.recoveryEvents.length > RECOVERY_RING_SIZE) {
133
- s.recoveryEvents.length = RECOVERY_RING_SIZE;
134
- }
135
- }
136
- /** Read a snapshot of the recovery ring. Newest first. */
137
- export function getRecoveryEvents() {
138
- return getState().recoveryEvents.slice(0);
139
- }
140
- /** Reset the recovery ring. Tests + manual operator use only. */
141
- export function resetRecoveryEvents() {
142
- getState().recoveryEvents.length = 0;
143
- }
144
- export function snapshotForStorage() {
145
- const s = getState();
146
- return {
147
- v: 2,
148
- failures: s.failures.slice(0),
149
- recoveryEvents: s.recoveryEvents.slice(0),
150
- lastRpcFrame: s.lastRpcFrame,
151
- lastFacetId: s.lastFacetId,
152
- };
153
- }
154
- /**
155
- * Restore from a snapshot. Garbage / null / wrong-shape input is
156
- * silently ignored. Does NOT throw — constructor-time rehydration must
157
- * never block DO startup.
158
- *
159
- * Only the current v2 schema is accepted.
160
- */
161
- export function rehydrateFromStorage(blob) {
162
- if (!isRecord(blob) || blob.v !== 2)
163
- return;
164
- const b = blob;
165
- if (!Array.isArray(b.failures))
166
- return;
167
- const s = getState();
168
- s.failures.length = 0;
169
- for (const f of b.failures) {
170
- const entry = parseFailure(f);
171
- if (!entry)
172
- continue;
173
- s.failures.push(entry);
174
- if (s.failures.length >= RING_SIZE)
175
- break;
176
- }
177
- s.recoveryEvents.length = 0;
178
- if (Array.isArray(b.recoveryEvents)) {
179
- for (const e of b.recoveryEvents) {
180
- const entry = parseRecoveryEvent(e);
181
- if (!entry)
182
- continue;
183
- s.recoveryEvents.push(entry);
184
- if (s.recoveryEvents.length >= RECOVERY_RING_SIZE)
185
- break;
186
- }
187
- }
188
- const lastRpcFrame = parseRpcFrame(b.lastRpcFrame);
189
- if (lastRpcFrame)
190
- s.lastRpcFrame = lastRpcFrame;
191
- const lastFacetId = parseFacetId(b.lastFacetId);
192
- if (lastFacetId)
193
- s.lastFacetId = lastFacetId;
194
- }
195
- function isRecord(value) {
196
- return typeof value === 'object' && value !== null;
197
- }
198
- function parseRpcFrame(value) {
199
- if (!isRecord(value)
200
- || typeof value.method !== 'string'
201
- || typeof value.payloadBytes !== 'number'
202
- || typeof value.atMs !== 'number')
203
- return null;
204
- return { method: value.method, payloadBytes: value.payloadBytes, atMs: value.atMs };
205
- }
206
- function parseFacetId(value) {
207
- if (!isRecord(value)
208
- || typeof value.codeId !== 'string'
209
- || typeof value.slotIndex !== 'number'
210
- || typeof value.atMs !== 'number')
211
- return null;
212
- return { codeId: value.codeId, slotIndex: value.slotIndex, atMs: value.atMs };
213
- }
214
- function parseFailure(value) {
215
- if (!isRecord(value)
216
- || typeof value.at !== 'number'
217
- || typeof value.phase !== 'string'
218
- || !isOomCause(value.cause)
219
- || typeof value.rssEstimateBytes !== 'number'
220
- || typeof value.heapUsedBytes !== 'number'
221
- || typeof value.lruBytes !== 'number'
222
- || typeof value.inFlightBytes !== 'number')
223
- return null;
224
- const entry = {
225
- at: value.at,
226
- phase: value.phase,
227
- cause: value.cause,
228
- rssEstimateBytes: value.rssEstimateBytes,
229
- heapUsedBytes: value.heapUsedBytes,
230
- lruBytes: value.lruBytes,
231
- inFlightBytes: value.inFlightBytes,
232
- lastRpcFrame: parseRpcFrame(value.lastRpcFrame),
233
- lastFacetId: parseFacetId(value.lastFacetId),
234
- };
235
- if (typeof value.exitCode === 'number')
236
- entry.exitCode = value.exitCode;
237
- if (typeof value.pid === 'number')
238
- entry.pid = value.pid;
239
- if (typeof value.message === 'string')
240
- entry.message = value.message.slice(0, MESSAGE_CAP);
241
- return entry;
242
- }
243
- const SESSION_STATES = [
244
- 'cold', 'hydrated', 'active', 'drained',
245
- 'rehydrate', 'build', 'wire', 'online',
246
- ];
247
- function isSessionState(value) {
248
- return SESSION_STATES.some((state) => state === value);
249
- }
250
- function parseRecoveryEvent(value) {
251
- if (!isRecord(value)
252
- || typeof value.at !== 'number'
253
- || !isSessionState(value.fromState)
254
- || !isSessionState(value.toState)
255
- || typeof value.trigger !== 'string'
256
- || typeof value.isolateGen !== 'number'
257
- || typeof value.dataLoss !== 'boolean'
258
- || typeof value.snapshotKeysRehydrated !== 'number')
259
- return null;
260
- const entry = {
261
- at: value.at,
262
- fromState: value.fromState,
263
- toState: value.toState,
264
- trigger: value.trigger,
265
- isolateGen: value.isolateGen,
266
- dataLoss: value.dataLoss,
267
- snapshotKeysRehydrated: value.snapshotKeysRehydrated,
268
- };
269
- if (typeof value.notes === 'string')
270
- entry.notes = value.notes.slice(0, MESSAGE_CAP);
271
- return entry;
272
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * _shared/install-phase.ts — single source of truth for the npm-install
3
- * state-machine phase enum.
4
- *
5
- * History: CLN-1 (2026-05-11) — consolidated from two diverged copies.
6
- * - `npm/installer.ts:93-95` was the progress-event variant. Included
7
- * 'lock-check' (a real progress event emitted while parsing
8
- * package-lock.json) but lacked 'idle'.
9
- * - `observability/diag-counters.ts:33-35` was the counter-state variant.
10
- * Included 'idle' (the resting state when no install is in flight)
11
- * but lacked 'lock-check'. The diag-counter's `setInstallPhase()`
12
- * was actually called with 'idle' (installer.ts:184,201) — passing
13
- * a value not declared in installer.ts's local type. The type check
14
- * fell through to diag-counters' type because installer.ts imports
15
- * setInstallPhase from there; the local `InstallPhase` definition
16
- * in installer.ts was only used by `InstallProgress.phase`.
17
- *
18
- * Going forward both consumers import from this module; any new phase
19
- * value added here is automatically available everywhere.
20
- *
21
- * Phase semantics (chronological order for a single install run):
22
- *
23
- * idle resting state, no install in flight
24
- * ↓
25
- * lock-check parsing existing package-lock.json (if present)
26
- * ↓
27
- * resolve walking the dep tree, fetching packuments
28
- * ↓
29
- * hoist hoisting peer-deps + flattening node_modules
30
- * ↓
31
- * diff comparing target tree against current install state
32
- * ↓
33
- * fetch downloading missing tarballs
34
- * ↓
35
- * write extracting tarballs into the VFS
36
- * ↓
37
- * link-bins creating bin/ symlinks
38
- * ↓
39
- * bundle (post-install) pre-bundling for esbuild fast path
40
- * ↓
41
- * done install complete; about to return to 'idle'
42
- *
43
- * The phase strings are surfaced via /api/_diag/install-pipeline and
44
- * displayed in the install-progress UI; treat them as a public API.
45
- */
46
- export type InstallPhase =
47
- | 'idle'
48
- | 'lock-check'
49
- | 'resolve'
50
- | 'hoist'
51
- | 'diff'
52
- | 'fetch'
53
- | 'write'
54
- | 'link-bins'
55
- | 'bundle'
56
- | 'done';
@@ -1,31 +0,0 @@
1
- type DisposableSymbolConstructor = SymbolConstructor & { readonly dispose?: symbol };
2
-
3
- export function disposeRpcResource(value: unknown): boolean {
4
- if ((typeof value !== 'object' && typeof value !== 'function') || value === null) return false;
5
- const disposerKey = (Symbol as DisposableSymbolConstructor).dispose;
6
- if (!disposerKey) return false;
7
- const disposer = Reflect.get(value, disposerKey);
8
- if (typeof disposer !== 'function') return false;
9
- try {
10
- Reflect.apply(disposer, value, []);
11
- return true;
12
- } catch {
13
- return false;
14
- }
15
- }
16
-
17
- export function disposeRpcResources(values: Iterable<unknown>): void {
18
- for (const value of values) disposeRpcResource(value);
19
- }
20
-
21
- export async function useRpcResource<T, R>(
22
- promise: Promise<T>,
23
- use: (value: T) => R | Promise<R>,
24
- ): Promise<R> {
25
- const value = await promise;
26
- try {
27
- return await use(value);
28
- } finally {
29
- disposeRpcResource(value);
30
- }
31
- }