@solidrt/flux-types 0.0.50 → 0.0.51

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/gui/audio.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- // Sound playback (gui-enabled runtime only). The imperative primitive; `play`
2
- // decodes and starts a clip in one call, while `load`/`loadPcm`/`stream` yield
3
- // a Clip that starts cheap overlapping Playbacks. Handles carry controls bound
4
- // to just that clip or playback, so raw ids never leave the runtime.
1
+ // Sound playback (gui-enabled runtime only: feature-detect with
2
+ // `Flux.capabilities.includes("audio")` before importing on a runtime that may
3
+ // lack it - a static import fails at module load there). The imperative
4
+ // primitive; `play` decodes and starts a clip in one call, while
5
+ // `load`/`loadPcm`/`stream` yield a Clip that starts cheap overlapping
6
+ // Playbacks. Handles carry controls bound to just that clip or playback, so
7
+ // raw ids never leave the runtime.
5
8
 
6
9
  declare module "flux:audio" {
7
10
  /** Options for {@link play} and {@link Clip.play}. */
@@ -16,31 +19,97 @@ declare module "flux:audio" {
16
19
  * all, which for a mono clip is about 3 dB louder than `pan: 0`.
17
20
  */
18
21
  pan?: number
22
+ /**
23
+ * Playback rate: 1.0 plays as loaded, higher is faster and higher-pitched,
24
+ * lower slower and deeper (a plain resample, no formant correction).
25
+ * Clamped to [0.01, 100]. Defaults to 1.0.
26
+ */
27
+ rate?: number
28
+ /**
29
+ * Fade in from silence over this many milliseconds (sample-accurate).
30
+ * Defaults to 0 (start at full level).
31
+ */
32
+ fadeInMs?: number
33
+ /**
34
+ * Name of the bus this playback belongs to, so `stop({ bus })` can stop
35
+ * the whole group at once. Buses are plain names created by use - no
36
+ * setup call, and (for now) no per-bus gain.
37
+ */
38
+ bus?: string
39
+ }
40
+
41
+ /** Options for the live setters ({@link Playback.setGain} and friends). */
42
+ type RampOptions = {
43
+ /**
44
+ * Reach the new value by ramping over this many milliseconds instead of
45
+ * jumping. Linear, stepped by the engine at control rate (about every
46
+ * 10 ms), so a fade stays smooth regardless of the app's frame rate. A
47
+ * later set on the same parameter takes over from the ramp's current
48
+ * value; omitted (or 0) sets immediately and cancels any ramp in flight.
49
+ */
50
+ rampMs?: number
51
+ }
52
+
53
+ /** Options for {@link Playback.stop} and the module-level {@link stop}. */
54
+ type StopOptions = {
55
+ /**
56
+ * Fade to silence over this many milliseconds before stopping
57
+ * (sample-accurate) instead of cutting immediately. The playback keeps
58
+ * playing while it fades; ended() turns true once the fade completes.
59
+ */
60
+ fadeOutMs?: number
61
+ }
62
+
63
+ /** Options for the module-level {@link stop}. */
64
+ type StopAllOptions = StopOptions & {
65
+ /**
66
+ * Stop only the playbacks on this bus (see {@link PlayOptions.bus})
67
+ * instead of everything.
68
+ */
69
+ bus?: string
19
70
  }
20
71
 
21
72
  /** One playing instance of a clip, with live controls bound to it. */
22
73
  type Playback = {
23
- /** Stop this playback. A no-op if it already finished. */
24
- stop(): void
74
+ /**
75
+ * Stop this playback. A no-op if it already finished. Stopping is not
76
+ * pausing: a stopped playback is gone for good, including a looping one -
77
+ * to silence it temporarily, ramp its gain to 0 instead.
78
+ */
79
+ stop(options?: StopOptions): void
25
80
  /**
26
81
  * Change the volume while playing. A finite number >= 0; 1.0 is the clip's
27
82
  * own level. A no-op after the playback finished.
28
83
  */
29
- setGain(gain: number): void
84
+ setGain(gain: number, options?: RampOptions): void
30
85
  /**
31
86
  * Move the stereo position while playing (see {@link PlayOptions.pan}).
87
+ * A ramped set on a never-panned playback sweeps from center. A no-op
88
+ * after the playback finished.
89
+ */
90
+ setPan(pan: number, options?: RampOptions): void
91
+ /**
92
+ * Change the playback rate while playing (see {@link PlayOptions.rate}) -
93
+ * a live rate sweep is how an engine revs or a doppler pass falls.
32
94
  * A no-op after the playback finished.
33
95
  */
34
- setPan(pan: number): void
96
+ setRate(rate: number, options?: RampOptions): void
35
97
  /** Whether playback finished, naturally or via {@link stop}. */
36
98
  ended(): boolean
37
99
  }
38
100
 
39
101
  /** A loaded clip that can be played without re-decoding. */
40
102
  type Clip = {
41
- /** Start a fresh overlapping playback of this clip. */
103
+ /**
104
+ * Start a fresh overlapping playback of this clip. Throws once 256
105
+ * playbacks are live at once - a guard that turns a runaway play() loop
106
+ * into an error instead of a saturated mixer.
107
+ */
42
108
  play(options?: PlayOptions): Playback
43
- /** Release the clip. Playbacks already running keep going. */
109
+ /**
110
+ * Release the clip. Playbacks already running keep going; `play()` after
111
+ * unloading throws.
112
+ */
44
113
  unload(): void
45
114
  }
46
115
 
@@ -80,6 +149,41 @@ declare module "flux:audio" {
80
149
  * playback; do not overlap a stream with itself. Call `unload()` when done.
81
150
  */
82
151
  export function stream(source: ReturnType<typeof import("flux:fs").file>): Clip
83
- /** Stop every playing sound. */
84
- export function stop(): void
152
+ /**
153
+ * Stop every playing sound - or just one bus with `{ bus }` - fading it
154
+ * out first if asked. Stopping is not pausing: stopped playbacks (looping
155
+ * ones included) cannot be restarted - to silence a group temporarily,
156
+ * ramp gains to 0 instead.
157
+ */
158
+ export function stop(options?: StopAllOptions): void
159
+ /**
160
+ * Scale the whole mix: every playing and future flux:audio playback, on top
161
+ * of per-playback gains (1.0 = unchanged, 0 = silence). A finite number
162
+ * >= 0; ramps like the per-playback setters. Resets to 1.0 when the app
163
+ * reloads.
164
+ */
165
+ export function setMasterGain(gain: number, options?: RampOptions): void
166
+ /**
167
+ * Scale one bus (see {@link PlayOptions.bus}): a playback's audible level
168
+ * is its own gain x its bus's gain x the master gain, each layer set
169
+ * independently - none overwrites another. Applies to live and future
170
+ * playbacks on the bus, defaults to 1.0, resets to 1.0 when the app
171
+ * reloads, and ramps like the other gain setters.
172
+ *
173
+ * NOT IMPLEMENTED YET: calling this throws. Until it lands, keep the bus
174
+ * gain in the app and fold it into each voice's setGain - one ramped
175
+ * write per change:
176
+ *
177
+ * ```ts
178
+ * let musicGain = 0.3
179
+ * for (let v of musicVoices) v.setGain(voiceGain * musicGain, { rampMs: 200 })
180
+ * ```
181
+ */
182
+ export function setBusGain(bus: string, gain: number, options?: RampOptions): void
183
+ /**
184
+ * The mixer's output sample rate in Hz. Synthesize PCM at this rate and
185
+ * {@link loadPcm} feeds it to the mixer without a resample. Opens the audio
186
+ * device on first use, like the load and play calls.
187
+ */
188
+ export function outputSampleRate(): number
85
189
  }
package/gui/gpu.d.ts CHANGED
@@ -310,7 +310,11 @@ declare module "flux:gpu" {
310
310
  * arithmetic. Declaring any makes `instanceBuffer` required on every
311
311
  * entry drawn with this pipeline. A mat4 per instance is its four
312
312
  * vec4 columns, reassembled in the shader (attributes have no matrix
313
- * formats, as in WebGPU).
313
+ * formats, as in WebGPU). Instance N always reads record N of the
314
+ * entry's buffer, from record 0 (ES 3.0 has no base instance), so
315
+ * several independently culled groups cannot share one buffer as
316
+ * sub-ranges: give each group its own `instanceBuffer` and entry, and
317
+ * cull it by `instanceCount`.
314
318
  */
315
319
  instanceAttributes?: VertexAttribute[]
316
320
  topology?: Topology
@@ -453,7 +457,9 @@ declare module "flux:gpu" {
453
457
  * buffer bound, `instanceCount` is bounds-checked against it like every
454
458
  * fetch (instances 0..N-1 each read one record). Two GL facts worth
455
459
  * knowing: `gl_VertexID` includes `firstVertex` (as in WebGPU), and
456
- * `gl_InstanceID` always counts from 0 - ES 3.0 has no base instance.
460
+ * `gl_InstanceID` always counts from 0 - ES 3.0 has no base instance, so
461
+ * instance N reads record N of the entry's `instanceBuffer` and a group
462
+ * that is culled independently needs its own buffer and entry.
457
463
  */
458
464
  export type DrawRange = { firstVertex?: number; vertexCount?: number; instanceCount?: number }
459
465
  /**
@@ -546,10 +552,34 @@ declare module "flux:gpu" {
546
552
 
547
553
  /**
548
554
  * Create a vertex buffer from raw bytes (interleave attribute data to match
549
- * the pipeline's attribute list). Buffer ids are their own space, separate
550
- * from texture ids.
555
+ * the pipeline's attribute list), or from a byte length alone - a zeroed
556
+ * buffer, the natural create when the contents arrive through the write
557
+ * lease ({@link beginBufferWrite}). Buffer ids are their own space,
558
+ * separate from texture ids. Size is fixed for the id's lifetime: reserve
559
+ * the maximum up front and publish a prefix.
560
+ */
561
+ export function createBuffer(data: Uint8Array | number, opts?: LabelOption): BufferId
562
+ /**
563
+ * Open a zero-copy write into a vertex buffer: returns an ArrayBuffer over
564
+ * runtime-owned memory exactly the buffer's size. Write into it in place
565
+ * (wrap it in a Float32Array or any view), then publish with
566
+ * {@link endBufferWrite} - no copy happens anywhere on the CPU path.
567
+ *
568
+ * Contents are UNSPECIFIED at begin: a recycled block holds what was
569
+ * published the time before last, so fill everything you publish. One open
570
+ * write per buffer id at a time (a second begin throws). The view is
571
+ * detached at end/destroy - a retained reference becomes zero-length, and
572
+ * writes through it are inert, never a race.
573
+ */
574
+ export function beginBufferWrite(id: BufferId): ArrayBuffer
575
+ /**
576
+ * Publish the open write's first `byteLength` bytes at offset 0 (default:
577
+ * the whole buffer) and close the lease. `byteLength` 0 cancels: the lease
578
+ * closes and nothing is published. Always closes the lease, error or not;
579
+ * throws when no write is open or `byteLength` exceeds the buffer size.
580
+ * Pipelines drawing from the buffer re-render, like {@link writeBuffer}.
551
581
  */
552
- export function createBuffer(data: Uint8Array, opts?: LabelOption): BufferId
582
+ export function endBufferWrite(id: BufferId, byteLength?: number): void
553
583
  /**
554
584
  * Overwrite part of a vertex buffer at `byteOffset` (default 0), within the
555
585
  * size it was created with. Pipelines drawing from the buffer re-render
@@ -14,6 +14,27 @@ declare module "flux:rendertree" {
14
14
  lineHeight?: number
15
15
  /** measureText only. */
16
16
  maxLines?: number
17
+ /** prepareText only: also report each unit's {@link TextUnit.carets}. */
18
+ carets?: boolean
19
+ /**
20
+ * prepareText only: styled ranges over the text, in JS string offsets,
21
+ * sorted and disjoint (text between them is in the base font). Each
22
+ * overrides the font options it names. A wrap unit crossing a range
23
+ * boundary comes back as one {@link TextUnit} per range, the pieces
24
+ * after the first `glue`d to it. Throws on an invalid range.
25
+ */
26
+ runs?: TextRunRange[]
27
+ }
28
+
29
+ /** One styled range for {@link MeasureTextOptions.runs}. */
30
+ export interface TextRunRange {
31
+ start: number
32
+ end: number
33
+ fontFamily?: "sans" | "serif" | "mono" | (string & {})
34
+ fontSize?: number
35
+ fontStyle?: "normal" | "italic"
36
+ fontWeight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
37
+ lineHeight?: number
17
38
  }
18
39
 
19
40
  /**
@@ -35,6 +56,17 @@ declare module "flux:rendertree" {
35
56
  descent: number
36
57
  /** The unit ends at a hard line break (newline). */
37
58
  hardBreak: boolean
59
+ /** A continuation piece of the previous unit (it crossed a `runs` boundary): a line never breaks before it. */
60
+ glue: boolean
61
+ /** Index into `runs` of the range this piece was shaped in; absent for the base font. */
62
+ run?: number
63
+ /**
64
+ * With `carets`: the caret positions inside the unit, one per grapheme
65
+ * cluster boundary from its start (`offset` = start, x 0) to the end of
66
+ * its shaped text (before any break characters), in order. `offset` is
67
+ * into the prepared text, `x` from the unit's pen position.
68
+ */
69
+ carets?: { offset: number, x: number }[]
38
70
  }
39
71
 
40
72
  /** The wrap units of a text in one font, shaped once. Plain data; layout is arithmetic over `units`. */
@@ -45,24 +77,34 @@ declare module "flux:rendertree" {
45
77
 
46
78
  /** Create the window root node with the given id. */
47
79
  export function createRoot(id: number): void
48
- /** Create a node of `kind` (the primitive element name) with the given id. */
80
+ /** Create a node of `kind` (the primitive element name) with the given id. Throws an `Error` for a name that is not an element. */
49
81
  export function createNode(id: number, kind: string): void
50
82
  /** Insert `nodeId` under `parentId`, before `anchorId` if given (else appended). */
51
83
  export function insertNode(parentId: number, nodeId: number, anchorId?: number): void
52
84
  /**
53
85
  * Unlink `nodeId` from `parentId` but keep its subtree alive, so it can be
54
86
  * re-inserted elsewhere (a move). Mirrors DOM removeChild. Pair with
55
- * {@link destroyNode} once the node is confirmed dead.
87
+ * {@link destroyNode} once the node is confirmed dead. Divergence: a node
88
+ * whose `transition` declares `exit` values stays linked and animates them
89
+ * first; the unlink happens when the exit settles, and a re-insert before
90
+ * then abandons it (moves never play removal animations).
56
91
  */
57
92
  export function detachNode(parentId: number, nodeId: number): void
58
- /** Free `nodeId` and its whole subtree. Call after {@link detachNode}. */
93
+ /**
94
+ * Free `nodeId` and its whole subtree. Call after {@link detachNode}. A
95
+ * node mid-exit is freed when its exit animation settles instead.
96
+ */
59
97
  export function destroyNode(nodeId: number): void
60
98
  /**
61
99
  * Write a single property on a node; `value` is marshalled per property.
62
- * Throws an `Error` for an unknown property name (message starts with
63
- * "Unknown property") or a value that does not decode; it never aborts the
64
- * runtime. Core's renderer warns-and-continues on the name-level rejections
65
- * and rethrows value errors.
100
+ * `null`/`undefined` resets the property to its default (its value before
101
+ * anything was set, per element kind; on a span, back to inheriting from
102
+ * the paragraph). Content props (`text`, `d`) still require a value.
103
+ * Throws an `Error` for an unknown
104
+ * property name (message starts with "Unknown property") or a value that
105
+ * does not decode; it never aborts the runtime. Core's renderer
106
+ * warns-and-continues on the name-level rejections and rethrows value
107
+ * errors.
66
108
  */
67
109
  export function setProperty(nodeId: number, name: string, value: unknown): void
68
110
  /**
@@ -87,6 +129,13 @@ declare module "flux:rendertree" {
87
129
  }
88
130
  /** Enable or disable text-input capture / the on-screen keyboard. */
89
131
  export function setTextInputActive(active: boolean, hints?: TextInputHints): void
132
+ /**
133
+ * Enter or leave relative mouse mode (pointer lock): the cursor hides and
134
+ * confines to the window, absolute pointer positions freeze, and mouse
135
+ * motion keeps reporting through movementX/movementY. The applied state
136
+ * comes back on the sticky "pointerLock" bus event.
137
+ */
138
+ export function setPointerLock(locked: boolean): void
90
139
  /** Request that a frame be rendered soon (coalesced by the demand-driven loop). */
91
140
  export function requestFrame(): void
92
141
  /**
@@ -121,4 +170,18 @@ declare module "flux:rendertree" {
121
170
  * semantics), for comparing against pointer event coordinates.
122
171
  */
123
172
  export function getBoundingBoxViewport(id: number): { x: number, y: number, width: number, height: number } | null
173
+ /**
174
+ * Parses a CSS color string (hex, rgb()/rgba(), hsl()/hsla(), hwb(),
175
+ * named colors) into packed 0xRRGGBBAA form (which the color property
176
+ * also accepts alongside plain CSS strings). Throws on an invalid string.
177
+ */
178
+ export function parseColor(color: string): number
179
+ /**
180
+ * Mixes two CSS colors in oklab; `t` is the fraction of `b` (0 = pure
181
+ * `a`, 1 = pure `b`). Returns a hex string, with an alpha byte only when
182
+ * the mix is translucent.
183
+ */
184
+ export function mixColors(a: string, b: string, t: number): string
185
+ /** Perceived brightness of a CSS color, 0 (black) to 1 (white), YIQ-weighted. */
186
+ export function brightness(color: string): number
124
187
  }
package/index.d.ts CHANGED
@@ -22,6 +22,7 @@
22
22
  /// <reference path="./standards/base64.d.ts" />
23
23
  /// <reference path="./standards/fetch.d.ts" />
24
24
  /// <reference path="./standards/websocket.d.ts" />
25
+ /// <reference path="./standards/abort.d.ts" />
25
26
 
26
27
  // GUI capabilities (present only on a gui-enabled runtime). rendertree/camera/
27
28
  // microphone/gpu are flux:* modules like the rest; requestAnimationFrame stays a
@@ -22,6 +22,14 @@ declare module "flux:isolate" {
22
22
  type IsolateOptions = {
23
23
  /** The child's `flux:process` `argv`. Default `[]`. */
24
24
  args?: string[]
25
+ /**
26
+ * Heap limit in bytes for the child runtime. Once reached, allocations in
27
+ * the child fail with an out-of-memory error where they happen instead of
28
+ * growing the process; an exit this causes is observable via `exited`.
29
+ * Applies to this child only (not to isolates it spawns itself). Default:
30
+ * unlimited.
31
+ */
32
+ memoryLimit?: number
25
33
  }
26
34
 
27
35
  /**
@@ -36,8 +44,10 @@ declare module "flux:isolate" {
36
44
  ? 0 extends 1 & R // an `any` result (untyped module) is a plain call, not a stream
37
45
  ? (...args: A) => Promise<any>
38
46
  : R extends AsyncIterable<infer Y>
39
- ? (...args: A) => AsyncIterableIterator<Y>
40
- : (...args: A) => Promise<Awaited<R>>
47
+ ? (...args: A | [...A, AbortSignal]) => AsyncIterableIterator<Y>
48
+ : R extends Generator<any, any, any> // sync generators do not stream: the call rejects
49
+ ? never
50
+ : (...args: A | [...A, AbortSignal]) => Promise<Awaited<R>>
41
51
  : never
42
52
  } & {
43
53
  /**
@@ -46,28 +56,58 @@ declare module "flux:isolate" {
46
56
  * anything never spawned.
47
57
  */
48
58
  terminate(): void
59
+ /**
60
+ * Settles once the child is gone: with the uncaught error that ended it,
61
+ * or `null` after `terminate()` or a clean end. Reading `exited` is a
62
+ * first use (it starts the child like a call does) and keeps the runtime
63
+ * watching the child - the loop stays open until the child exits, so an
64
+ * exit is noticed with no call in flight. Each read returns an
65
+ * equivalent promise.
66
+ */
67
+ readonly exited: Promise<string | null>
49
68
  }
50
69
 
51
70
  /**
52
71
  * A handle on an isolate module: a `"use isolate"` module in a SolidRT
53
72
  * project (id = its path relative to the source root, without extension),
54
- * or `<id>.js` next to the entry under standalone flux. Each property is
73
+ * or `isolates/<id>.bin`/`.js` next to the entry under standalone flux. Each property is
55
74
  * an async function that runs the export of that name in a second runtime
56
75
  * on its own thread (own heap, own event loop, the non-gui `flux:*`
57
76
  * modules). Arguments and results are copied ({@link Sendable}).
58
77
  *
59
- * The child starts on the first call and lives until `terminate()` or the
60
- * parent's end; module state persists between calls; each `isolate()` call
61
- * is its own instance. Calls start in call order and run concurrently, as
78
+ * The child starts on first use (a call, or reading `exited`) and lives
79
+ * until `terminate()` or the parent's end; module state persists between
80
+ * calls; each `isolate()` call is its own instance. Calls start in call order and run concurrently, as
62
81
  * the same functions would in-process: a sync export runs to completion
63
82
  * before anything else (one thread), an async export lets other calls and
64
83
  * stream steps run at each `await`; an export that must not interleave with
65
84
  * itself serialises inside the module. A throw in the export rejects that
66
- * call (a throw in a generator rejects the pending step); an uncaught error
67
- * that ends the child rejects pending and later calls with a message naming
68
- * it. Awaiting a stream call rejects; iterating a plain call rejects. An
85
+ * call (a throw in a generator rejects the pending step) with the error
86
+ * rebuilt from its data: `name`, `message` and `stack` carry over, `e
87
+ * instanceof RangeError` holds for the standard error types (a custom error
88
+ * class arrives as an `Error` with its `name`), and the `cause` chain
89
+ * carries over - each cause another rebuilt error or a {@link Sendable}
90
+ * value (an unsendable cause is dropped; the chain is capped). A thrown
91
+ * non-Error rejects with the thrown value itself when it is sendable, else
92
+ * with an `Error` describing it. An uncaught
93
+ * error that ends the child rejects pending and later calls with a message
94
+ * naming it. Awaiting a stream call rejects; iterating a plain call rejects. An
69
95
  * open stream keeps both runtimes alive until it ends, `break`s, or the
70
- * child is terminated. Reserved names: `terminate`, `then`.
96
+ * child is terminated. A sync generator export rejects when called: only
97
+ * async generators stream.
98
+ *
99
+ * An `AbortSignal` among a call's arguments (anywhere in the list; at most
100
+ * one, more throw) is consumed as the call's signal rather than sent: the
101
+ * export sees only the other arguments. On a plain call, aborting stops
102
+ * the waiting - the call rejects with `signal.reason` and the eventual
103
+ * result is dropped - but does not interrupt the export; interrupting is
104
+ * `terminate()`'s job. On a stream, aborting acts as `return()`: the
105
+ * generator ends in the isolate (its `finally` runs) and the `for await`
106
+ * loop finishes cleanly, like a `break` from outside it. A call on an
107
+ * already-aborted signal rejects without sending anything (or starting the
108
+ * child).
109
+ *
110
+ * Reserved names: `terminate`, `exited`, `then`.
71
111
  */
72
112
  export function isolate<T = Record<string, (...args: any[]) => any>>(id: string, opts?: IsolateOptions): Isolated<T>
73
113
  }
@@ -1,12 +1,12 @@
1
1
  declare module "flux:sqlite" {
2
2
  /** Values accepted as bound parameters. booleans bind as 0/1. */
3
- type SqlParam = null | boolean | number | string | Uint8Array
3
+ export type SqlParam = null | boolean | number | string | Uint8Array
4
4
  /** Values returned in result rows. BLOB comes back as Uint8Array. */
5
- type SqlValue = null | number | string | Uint8Array
6
- type Row = Record<string, SqlValue>
5
+ export type SqlValue = null | number | string | Uint8Array
6
+ export type Row = Record<string, SqlValue>
7
7
 
8
8
  /** The outcome of a write. */
9
- type RunResult = { changes: number; lastInsertRowid: number }
9
+ export type RunResult = { changes: number; lastInsertRowid: number }
10
10
 
11
11
  /**
12
12
  * A reusable prepared statement. Created with {@link Database.query}; its
@@ -19,13 +19,20 @@ declare module "flux:sqlite" {
19
19
  get(params?: SqlParam[]): Promise<Row | undefined>
20
20
  /** Run the statement as a write and resolve to its {@link RunResult}. */
21
21
  run(params?: SqlParam[]): Promise<RunResult>
22
+ /**
23
+ * The tables this statement reads, sorted (SQLite's authorizer, captured
24
+ * during a compile; the statement is never run). Includes tables reached
25
+ * through views and subqueries. Pair with {@link Database.onWrite} to know
26
+ * when a re-read could return different rows.
27
+ */
28
+ tables(): Promise<string[]>
22
29
  }
23
30
 
24
31
  /**
25
32
  * Open mode: "ro" (default, read-only, must exist), "rw" (read-write, must
26
33
  * exist), "rw+" (read-write, create if missing).
27
34
  */
28
- type OpenMode = "ro" | "rw" | "rw+"
35
+ export type OpenMode = "ro" | "rw" | "rw+"
29
36
 
30
37
  export class Database {
31
38
  /**
@@ -47,6 +54,21 @@ declare module "flux:sqlite" {
47
54
  * must be writes/DDL. Cannot branch on intermediate results.
48
55
  */
49
56
  transaction(statements: [string, SqlParam[]?][]): Promise<RunResult[]>
57
+ /**
58
+ * Subscribe to writes on this connection. After each command that changed
59
+ * rows, `callback` gets one call with the sorted names of the tables
60
+ * touched (SQLite's update hook, so trigger and cascade writes are
61
+ * included). Returns an unsubscribe function.
62
+ *
63
+ * Contract: only THIS connection's writes are seen (another connection or
64
+ * process writing the same file does not report); SQLite does not fire
65
+ * the hook for WITHOUT ROWID tables; a rolled-back transaction may still
66
+ * report its tables (a spurious re-read, never a stale one). A full-table
67
+ * `DELETE FROM t` reports correctly: the connection disables SQLite's
68
+ * truncate optimization, trading row-by-row deletion for a hook that
69
+ * cannot be silently skipped.
70
+ */
71
+ onWrite(callback: (tables: string[]) => void): () => void
50
72
  /** Close the connection. */
51
73
  close(): Promise<void>
52
74
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@solidrt/flux-types",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "license": "MIT",
5
+ "funding": "https://github.com/sponsors/wellawaretech",
5
6
  "author": "Antoine van Wel",
6
7
  "types": "index.d.ts",
7
8
  "files": [
@@ -0,0 +1,36 @@
1
+ // The web-standard abort primitives. A deliberate subset: an `onabort`
2
+ // handler property only (no addEventListener), a plain-object event (not an
3
+ // Event instance), and no `AbortSignal.timeout`/`any`. Without `DOMException`
4
+ // the default abort reason is an `Error` whose `name` is "AbortError".
5
+
6
+ /** The event passed to {@link AbortSignal.onabort}. */
7
+ interface AbortEvent {
8
+ type: "abort"
9
+ }
10
+
11
+ interface AbortSignal {
12
+ /** True once the signal has been aborted. */
13
+ readonly aborted: boolean
14
+ /** The abort reason; `undefined` until aborted. */
15
+ readonly reason: any
16
+ /** Called once when the signal aborts. */
17
+ onabort: ((event: AbortEvent) => void) | null
18
+ /** Throws `reason` if the signal is aborted; no-op otherwise. */
19
+ throwIfAborted(): void
20
+ }
21
+
22
+ declare let AbortSignal: {
23
+ prototype: AbortSignal
24
+ /** An already-aborted signal. */
25
+ abort(reason?: any): AbortSignal
26
+ }
27
+
28
+ declare class AbortController {
29
+ /** The controller's signal; the same object on every read. */
30
+ readonly signal: AbortSignal
31
+ /**
32
+ * Abort the signal with `reason` (default: an `Error` named "AbortError")
33
+ * and fire its `onabort`. Aborting an already-aborted signal is a no-op.
34
+ */
35
+ abort(reason?: any): void
36
+ }
@@ -1,6 +1,6 @@
1
1
  // The Fetch API cluster (Headers, Request, Response, fetch). A deliberate subset
2
2
  // of the WHATWG Fetch standard: flux provides exactly these members and no more
3
- // (no Blob, FormData, ReadableStream, clone(), AbortSignal, ...).
3
+ // (no Blob, FormData, ReadableStream, clone(), ...).
4
4
  // Grouped in one file because the four share BodyInit/HeadersInit and reference
5
5
  // each other.
6
6
 
@@ -70,6 +70,13 @@ interface RequestInit {
70
70
  * throttled.
71
71
  */
72
72
  cache?: "force-cache" | "reload" | "default" | "no-store" | "no-cache"
73
+ /**
74
+ * Abort signal for `fetch`: aborting rejects the fetch promise with the
75
+ * signal's `reason` and drops the request mid-flight; a fetch on an
76
+ * already-aborted signal rejects without sending anything. Ignored by the
77
+ * `Request` constructor.
78
+ */
79
+ signal?: AbortSignal
73
80
  }
74
81
 
75
82
  /**
@@ -2,14 +2,20 @@
2
2
  // from the browser in two ways: the delay is required, and no extra callback
3
3
  // arguments are forwarded.
4
4
  //
5
- // In a GUI runtime the whole time surface here is FRAME-STEPPED: timers and
6
- // performance.now() march on the same paced timeline as onFrame and
7
- // requestAnimationFrame, quantized to frames. So timer resolution is one
8
- // frame (~16 ms at 60 Hz; a setTimeout of 0 runs on the next frame), an
9
- // interval fires at most once per frame, and pausing the runtime clock (the
10
- // dev tools' set_time_scale 0) freezes all of it together deterministically.
11
- // Date.now() is the wall-clock escape hatch: it always reports real calendar
12
- // time. Headless flux (scripts, servers) keeps ordinary wall-clock timers.
5
+ // In a GUI runtime the timers are FRAME-QUANTIZED but WALL-ACCURATE: a
6
+ // deadline is measured against the real clock from the moment of
7
+ // registration, and firing happens on frame boundaries. So a timer fires at
8
+ // the first frame at or after its deadline - at least `ms` after
9
+ // registration, at most one frame late (~16 ms at 60 Hz; a setTimeout of 0
10
+ // runs on the next frame) - and deadlines do not drift when frames run
11
+ // slow. An interval fires at most once per frame (missed periods collapse
12
+ // instead of storming). Pausing the runtime clock (the dev tools'
13
+ // set_time_scale 0) freezes timers and frame callbacks together; a timer
14
+ // that came due while the app was suspended (backgrounded) fires on the
15
+ // resume frame. performance.now() is real elapsed time, for measuring
16
+ // work; the onFrame / requestAnimationFrame timestamp is a separate paced
17
+ // animation timeline. Date.now() is calendar time. Headless flux (scripts,
18
+ // servers) keeps ordinary wall-clock timers.
13
19
 
14
20
  /**
15
21
  * Run `callback` after at least `ms` milliseconds. Returns a timer id for
@@ -33,17 +39,16 @@ declare function queueMicrotask(callback: () => void): void
33
39
 
34
40
  declare let performance: {
35
41
  /**
36
- * Milliseconds since a monotonic origin (high-resolution, not wall-clock). Use
37
- * for measuring durations, not for calendar time. In a GUI runtime this is
38
- * the paced frame timeline (same clock as the onFrame/requestAnimationFrame
39
- * timestamps, frozen while the runtime clock is paused); for real elapsed
40
- * wall time use Date.now().
42
+ * Milliseconds elapsed since the runtime started (high-resolution,
43
+ * monotonic, sub-millisecond). Real time: it keeps advancing across
44
+ * synchronous work and while the runtime clock is paused, so it is the
45
+ * clock for measuring durations. For frame time use the onFrame /
46
+ * requestAnimationFrame timestamp; for calendar time use Date.now().
41
47
  */
42
48
  now(): number
43
49
  /**
44
- * Wall-clock time (ms since the Unix epoch) when the runtime started. Unlike
45
- * the browser, timeOrigin + now() is not the current wall-clock time: now()
46
- * runs on the paced runtime timeline, which can be frozen or scaled.
50
+ * Wall-clock time (ms since the Unix epoch) when the runtime started, so
51
+ * timeOrigin + now() tracks Date.now().
47
52
  */
48
53
  readonly timeOrigin: number
49
54
  }