-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
333 lines (293 loc) · 20.1 KB
/
Copy pathindex.html
File metadata and controls
333 lines (293 loc) · 20.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>@gottheflag/lifecycle 0.1.0 — API Reference</title>
<meta name="description" content="API reference for @gottheflag/lifecycle 0.1.0.">
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<a class="skip-link" href="#content">Skip to content</a>
<header class="topbar">
<div class="brand">
<div class="brand-mark" aria-hidden="true">L</div>
<div>
<strong>@gottheflag/lifecycle</strong>
<span>API Reference · 0.1.0</span>
</div>
</div>
<label class="search" for="docs-search">
<span aria-hidden="true">⌕</span>
<input id="docs-search" type="search" placeholder="Search API…" autocomplete="off">
<kbd>Ctrl K</kbd>
</label>
</header>
<div class="layout">
<aside class="sidebar" aria-label="Documentation navigation">
<nav id="docs-nav">
<div class="nav-group">
<p>Start</p>
<a href="#overview">Overview</a>
<a href="#installation">Installation</a>
<a href="#requirements">Requirements</a>
<a href="#exports">Exports</a>
</div>
<div class="nav-group">
<p>Lifecycle</p>
<a href="#lifecycle">Lifecycle</a>
<a href="#lifecycle-constructor">constructor</a>
<a href="#lifecycle-destroyed">destroyed</a>
<a href="#lifecycle-defer">defer()</a>
<a href="#lifecycle-own">own()</a>
<a href="#lifecycle-child">child()</a>
<a href="#lifecycle-destroy">destroy()</a>
<a href="#lifecycle-dispose">Symbol.dispose</a>
</div>
<div class="nav-group">
<p>AsyncLifecycle</p>
<a href="#async-lifecycle">AsyncLifecycle</a>
<a href="#async-destroyed">destroyed</a>
<a href="#async-defer">defer()</a>
<a href="#async-own">own()</a>
<a href="#async-child">child()</a>
<a href="#async-destroy">destroy()</a>
<a href="#async-dispose">Symbol.asyncDispose</a>
</div>
<div class="nav-group">
<p>Events</p>
<a href="#events">Event model</a>
<a href="#events-on">on()</a>
<a href="#events-once">once()</a>
<a href="#events-emit">emit()</a>
<a href="#events-clear">clear()</a>
</div>
<div class="nav-group">
<p>Contracts</p>
<a href="#signals">Abort signal</a>
<a href="#children">Child lifecycles</a>
<a href="#ordering">Cleanup order</a>
<a href="#errors">Errors</a>
<a href="#late-registration">Late registration</a>
<a href="#types">Exported types</a>
</div>
</nav>
</aside>
<main id="content" class="content">
<section id="overview" class="hero doc-section" data-search="overview lifecycle resource events cleanup ownership version 0.1.0">
<p class="eyebrow">Reference</p>
<h1>Lifecycle</h1>
<p class="lead">Typed lifetime, event, and resource management for JavaScript and TypeScript.</p>
<div class="facts">
<div><span>Package</span><strong>@gottheflag/lifecycle</strong></div>
<div><span>Version</span><strong>0.1.0</strong></div>
<div><span>Modules</span><strong>ESM + CJS</strong></div>
<div><span>License</span><strong>Apache-2.0</strong></div>
</div>
</section>
<section id="installation" class="doc-section" data-search="installation install pnpm npm yarn bun package">
<div class="section-heading">
<p class="eyebrow">Start</p>
<h2>Installation</h2>
</div>
<div class="install-grid">
<div class="install-row"><span>pnpm</span><code>pnpm add @gottheflag/lifecycle</code><button class="copy" data-copy="pnpm add @gottheflag/lifecycle">Copy</button></div>
<div class="install-row"><span>npm</span><code>npm install @gottheflag/lifecycle</code><button class="copy" data-copy="npm install @gottheflag/lifecycle">Copy</button></div>
<div class="install-row"><span>yarn</span><code>yarn add @gottheflag/lifecycle</code><button class="copy" data-copy="yarn add @gottheflag/lifecycle">Copy</button></div>
<div class="install-row"><span>bun</span><code>bun add @gottheflag/lifecycle</code><button class="copy" data-copy="bun add @gottheflag/lifecycle">Copy</button></div>
</div>
</section>
<section id="requirements" class="doc-section reference-block" data-search="requirements compatibility node nodejs typescript suppressederror explicit resource management using">
<p class="eyebrow">Start</p>
<h2>Requirements</h2>
<div class="type-list">
<div><code>Node.js</code><span>18.18.0 or newer.</span></div>
<div><code>TypeScript</code><span>5.2 or newer for TypeScript consumers.</span></div>
<div><code>SuppressedError</code><span>Runtimes without a native implementation need a polyfill only when both a using block body and its disposal throw.</span></div>
</div>
</section>
<section id="exports" class="doc-section" data-search="exports Lifecycle AsyncLifecycle LifecycleOptions LifecycleSignal NoEvents Cleanup AsyncCleanup Destroyable AsyncDestroyable EventArguments EventListener">
<div class="section-heading">
<p class="eyebrow">Package surface</p>
<h2>Exports</h2>
</div>
<div class="symbol-table">
<div><code>Lifecycle</code><span>Class</span><p>Synchronous lifetime, ownership, cleanup, child, and event management.</p></div>
<div><code>AsyncLifecycle</code><span>Class</span><p>Asynchronous lifetime management with awaited teardown.</p></div>
<div><code>LifecycleOptions</code><span>Type</span><p>Constructor options accepted by <code>Lifecycle</code>.</p></div>
<div><code>LifecycleSignal</code><span>Type</span><p>Environment-agnostic structural contract for an abort-compatible signal.</p></div>
<div><code>NoEvents</code><span>Type</span><p>Empty event map used by lifecycles with no typed events.</p></div>
<div><code>Cleanup</code><span>Type</span><p>Synchronous cleanup callback.</p></div>
<div><code>AsyncCleanup</code><span>Type</span><p>Synchronous or asynchronous cleanup callback.</p></div>
<div><code>Destroyable</code><span>Type</span><p>Resource exposing synchronous <code>destroy()</code>.</p></div>
<div><code>AsyncDestroyable</code><span>Type</span><p>Resource exposing sync or async <code>destroy()</code>.</p></div>
<div><code>EventArguments</code><span>Type</span><p>Conditional argument tuple used by typed event emission.</p></div>
<div><code>EventListener</code><span>Type</span><p>Typed synchronous event listener.</p></div>
</div>
</section>
<section id="lifecycle" class="doc-section api-class" data-search="Lifecycle synchronous class">
<div class="class-heading">
<div><p class="eyebrow">Class</p><h2>Lifecycle<TEvents></h2></div>
<span class="badge">sync</span>
</div>
<p>Owns everything associated with one synchronous lifetime: deferred cleanup, destroyable resources, child lifecycles, and typed event listeners.</p>
<div class="signature">class Lifecycle<TEvents extends object = NoEvents></div>
</section>
<article id="lifecycle-constructor" class="api-card doc-section" data-search="Lifecycle constructor options signal LifecycleSignal">
<div class="api-title"><h3>constructor</h3><span>Lifecycle</span></div>
<div class="signature">new Lifecycle<TEvents>(options?: LifecycleOptions)</div>
<p>Creates a synchronous lifecycle. When an abort-compatible signal is supplied, aborting that signal destroys the lifecycle. An already-aborted signal creates an already-destroyed lifecycle.</p>
</article>
<article id="lifecycle-destroyed" class="api-card doc-section" data-search="Lifecycle destroyed getter boolean">
<div class="api-title"><h3>destroyed</h3><span>getter</span></div>
<div class="signature">get destroyed(): boolean</div>
<p>Indicates whether destruction has started. Once true, it never becomes false.</p>
</article>
<article id="lifecycle-defer" class="api-card doc-section" data-search="Lifecycle defer cleanup early exactly once">
<div class="api-title"><h3>defer()</h3><span>cleanup</span></div>
<div class="signature">defer<TCleanup extends Cleanup>(cleanup: TCleanup): Cleanup</div>
<p>Registers synchronous cleanup work. Returns an exactly-once cleanup function that can execute the registered cleanup early and remove it from lifecycle teardown.</p>
<ul class="contract"><li>Async cleanup callbacks are rejected by the type system.</li><li>Registration after destruction executes immediately.</li><li>Repeated execution is ignored.</li></ul>
</article>
<article id="lifecycle-own" class="api-card doc-section" data-search="Lifecycle own resource Destroyable destroy">
<div class="api-title"><h3>own()</h3><span>resource</span></div>
<div class="signature">own<TResource extends Destroyable>(resource: TResource): TResource</div>
<p>Registers a synchronous destroyable resource with the lifecycle and returns the same resource unchanged.</p>
<ul class="contract"><li>The resource must expose synchronous <code>destroy(): void</code>.</li><li>Owned resources participate in normal reverse-order teardown.</li><li>Ownership after destruction destroys the resource immediately.</li></ul>
</article>
<article id="lifecycle-child" class="api-card doc-section" data-search="Lifecycle child children events ownership">
<div class="api-title"><h3>child()</h3><span>hierarchy</span></div>
<div class="signature">child<TChildEvents extends object = NoEvents>(): Lifecycle<TChildEvents></div>
<p>Creates an independently typed child lifecycle owned by the parent. Destroying the child early detaches it from the parent. Destroying the parent destroys every still-owned child.</p>
</article>
<article id="lifecycle-destroy" class="api-card doc-section" data-search="Lifecycle destroy teardown LIFO errors listeners">
<div class="api-title"><h3>destroy()</h3><span>termination</span></div>
<div class="signature">destroy(): void</div>
<p>Ends the lifecycle exactly once. Event delivery stops first, then active cleanup entries run in reverse registration order. Every cleanup is attempted even when another cleanup throws.</p>
</article>
<article id="lifecycle-dispose" class="api-card doc-section" data-search="Lifecycle Symbol.dispose using explicit resource management">
<div class="api-title"><h3>Symbol.dispose</h3><span>disposal</span></div>
<div class="signature">[Symbol.dispose](): void</div>
<p>Delegates to <code>destroy()</code> and makes the lifecycle compatible with synchronous explicit resource management.</p>
</article>
<section id="async-lifecycle" class="doc-section api-class" data-search="AsyncLifecycle asynchronous class await async cleanup">
<div class="class-heading">
<div><p class="eyebrow">Class</p><h2>AsyncLifecycle<TEvents></h2></div>
<span class="badge">async</span>
</div>
<p>Asynchronous counterpart to <code>Lifecycle</code>. Cleanup entries may return promises and are awaited sequentially in reverse registration order. Event dispatch remains synchronous.</p>
<div class="signature">class AsyncLifecycle<TEvents extends object = NoEvents></div>
</section>
<article id="async-destroyed" class="api-card doc-section" data-search="AsyncLifecycle destroyed getter">
<div class="api-title"><h3>destroyed</h3><span>getter</span></div>
<div class="signature">get destroyed(): boolean</div>
<p>Indicates whether asynchronous destruction has started. It may be true while cleanup work is still being awaited.</p>
</article>
<article id="async-defer" class="api-card doc-section" data-search="AsyncLifecycle defer async cleanup early">
<div class="api-title"><h3>defer()</h3><span>cleanup</span></div>
<div class="signature">defer(cleanup: AsyncCleanup): AsyncCleanup</div>
<p>Registers synchronous or asynchronous cleanup work and returns an exactly-once cleanup function that may be awaited when executed early.</p>
<ul class="contract"><li>Registration after destruction throws.</li><li>Cleanup is awaited during destruction.</li><li>Repeated execution is ignored.</li></ul>
</article>
<article id="async-own" class="api-card doc-section" data-search="AsyncLifecycle own AsyncDestroyable resource">
<div class="api-title"><h3>own()</h3><span>resource</span></div>
<div class="signature">own<TResource extends AsyncDestroyable>(resource: TResource): TResource</div>
<p>Owns a resource whose <code>destroy()</code> method may complete synchronously or return a promise-like value.</p>
</article>
<article id="async-child" class="api-card doc-section" data-search="AsyncLifecycle child hierarchy">
<div class="api-title"><h3>child()</h3><span>hierarchy</span></div>
<div class="signature">child<TChildEvents extends object = NoEvents>(): AsyncLifecycle<TChildEvents></div>
<p>Creates an independently typed asynchronous child owned by the parent. Early child destruction detaches it from parent teardown.</p>
</article>
<article id="async-destroy" class="api-card doc-section" data-search="AsyncLifecycle destroy Promise LIFO concurrent same promise AggregateError">
<div class="api-title"><h3>destroy()</h3><span>termination</span></div>
<div class="signature">destroy(): Promise<void></div>
<p>Starts teardown once and returns the destruction promise. Cleanup entries are awaited sequentially in reverse registration order. Concurrent calls receive the same promise.</p>
</article>
<article id="async-dispose" class="api-card doc-section" data-search="AsyncLifecycle Symbol.asyncDispose await using explicit resource management">
<div class="api-title"><h3>Symbol.asyncDispose</h3><span>disposal</span></div>
<div class="signature">[Symbol.asyncDispose](): Promise<void></div>
<p>Delegates to <code>destroy()</code> and makes the lifecycle compatible with asynchronous explicit resource management.</p>
</article>
<section id="events" class="doc-section api-class" data-search="events Eventful typed event model listeners emit">
<div class="class-heading"><div><p class="eyebrow">Shared API</p><h2>Typed events</h2></div><span class="badge">sync dispatch</span></div>
<p>Both lifecycle classes expose the same typed synchronous event API. Event spaces belong to each lifecycle independently and do not inherit or bubble between parent and child lifecycles.</p>
</section>
<article id="events-on" class="api-card doc-section" data-search="events on listener subscribe cleanup off">
<div class="api-title"><h3>on()</h3><span>event</span></div>
<div class="signature">on<TKey extends keyof TEvents>(type: TKey, listener: EventListener<TEvents[TKey]>): Cleanup</div>
<p>Registers a synchronous listener for an event key. Returns an exactly-once unsubscribe function.</p>
</article>
<article id="events-once" class="api-card doc-section" data-search="events once listener one time">
<div class="api-title"><h3>once()</h3><span>event</span></div>
<div class="signature">once<TKey extends keyof TEvents>(type: TKey, listener: EventListener<TEvents[TKey]>): Cleanup</div>
<p>Registers a synchronous listener that unsubscribes before its first invocation. Returns an unsubscribe function for cancellation before emission.</p>
</article>
<article id="events-emit" class="api-card doc-section" data-search="events emit payload void EventArguments errors">
<div class="api-title"><h3>emit()</h3><span>event</span></div>
<div class="signature">emit<TKey extends keyof TEvents>(type: TKey, ...args: EventArguments<TEvents[TKey]>): void</div>
<p>Synchronously dispatches an event to the listeners registered on that lifecycle. Void events require no payload. Emission after destruction is ignored.</p>
</article>
<article id="events-clear" class="api-card doc-section" data-search="events clear listeners all event type">
<div class="api-title"><h3>clear()</h3><span>event</span></div>
<div class="signature">clear(): void<br>clear<TKey extends keyof TEvents>(type: TKey): void</div>
<p>Removes every event listener or every listener for one event key. It does not run deferred cleanup, destroy resources, or destroy child lifecycles.</p>
</article>
<section id="signals" class="doc-section reference-block" data-search="signal LifecycleSignal AbortSignal LifecycleOptions abort destroy constructor">
<p class="eyebrow">Contract</p>
<h2>Abort signal</h2>
<div class="signature">interface LifecycleOptions { signal?: LifecycleSignal }</div>
<p><code>Lifecycle</code> accepts an abort-compatible signal. Aborting it triggers synchronous destruction. Manual destruction removes the abort listener. <code>AsyncLifecycle</code> currently has no signal constructor option.</p>
</section>
<section id="children" class="doc-section reference-block" data-search="children child parent event isolation detach ownership">
<p class="eyebrow">Contract</p>
<h2>Child lifecycles</h2>
<p>Children are ownership relationships, not event inheritance. A child may have a different event map. Parent destruction destroys live children; early child destruction detaches that child from its parent.</p>
</section>
<section id="ordering" class="doc-section reference-block" data-search="cleanup ordering LIFO reverse registration destroy order">
<p class="eyebrow">Contract</p>
<h2>Cleanup order</h2>
<p>Active cleanup entries are executed in reverse registration order. This applies to deferred callbacks, owned resources, and children because each is represented in the same teardown sequence.</p>
</section>
<section id="errors" class="doc-section reference-block" data-search="errors AggregateError SuppressedError cleanup failures event listener failures">
<p class="eyebrow">Contract</p>
<h2>Errors</h2>
<p>Destruction attempts every active cleanup even when earlier cleanup fails. Multiple failures are reported through <code>AggregateError</code>. Event emission also completes listener delivery before collected listener failures are reported.</p>
</section>
<section id="late-registration" class="doc-section reference-block" data-search="late registration destroyed Lifecycle AsyncLifecycle defer own child on once">
<p class="eyebrow">Contract</p>
<h2>Late registration</h2>
<div class="comparison">
<div><strong>Lifecycle</strong><p><code>defer()</code> after destruction executes immediately. Consequently, late <code>own()</code> destroys immediately and late <code>child()</code> returns an already-destroyed child. New event subscriptions are rejected.</p></div>
<div><strong>AsyncLifecycle</strong><p>New cleanup, ownership, child, and event subscriptions are rejected after destruction starts because asynchronous cleanup cannot be completed synchronously at registration time.</p></div>
</div>
</section>
<section id="types" class="doc-section reference-block" data-search="types Cleanup AsyncCleanup Destroyable AsyncDestroyable EventArguments EventListener LifecycleOptions LifecycleSignal NoEvents">
<p class="eyebrow">Reference</p>
<h2>Exported types</h2>
<div class="type-list">
<div><code>Cleanup</code><span>() => void</span></div>
<div><code>AsyncCleanup</code><span>() => void | PromiseLike<void></span></div>
<div><code>Destroyable</code><span>{ destroy(): void }</span></div>
<div><code>AsyncDestroyable</code><span>{ destroy(): void | PromiseLike<void> }</span></div>
<div><code>LifecycleOptions</code><span>{ signal?: LifecycleSignal }</span></div>
<div><code>LifecycleSignal</code><span>{ readonly aborted: boolean; addEventListener(...); removeEventListener(...) }</span></div>
<div><code>NoEvents</code><span>Record<never, never></span></div>
<div><code>EventArguments<TPayload></code><span>void payload → []; otherwise [payload]</span></div>
<div><code>EventListener<TPayload></code><span>typed synchronous listener</span></div>
</div>
</section>
<footer>
<span>@gottheflag/lifecycle</span>
<span>v0.1.0 · Static API reference · no server required</span>
</footer>
</main>
</div>
<div id="empty-state" class="empty-state" hidden>
<strong>No API entries matched.</strong>
<span>Try another search term.</span>
</div>
<script src="./docs.js"></script>
</body>
</html>