@solidrt/flux-types 0.0.50 → 0.0.52

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.
@@ -5,6 +5,7 @@
5
5
  // module; requestFrame here only schedules a future frame.
6
6
 
7
7
  declare module "flux:rendertree" {
8
+ import type { TextureId } from "flux:gpu"
8
9
  /** Font options for {@link measureText} and {@link prepareText}. */
9
10
  export interface MeasureTextOptions {
10
11
  fontFamily?: "sans" | "serif" | "mono" | (string & {})
@@ -14,6 +15,27 @@ declare module "flux:rendertree" {
14
15
  lineHeight?: number
15
16
  /** measureText only. */
16
17
  maxLines?: number
18
+ /** prepareText only: also report each unit's {@link TextUnit.carets}. */
19
+ carets?: boolean
20
+ /**
21
+ * prepareText only: styled ranges over the text, in JS string offsets,
22
+ * sorted and disjoint (text between them is in the base font). Each
23
+ * overrides the font options it names. A wrap unit crossing a range
24
+ * boundary comes back as one {@link TextUnit} per range, the pieces
25
+ * after the first `glue`d to it. Throws on an invalid range.
26
+ */
27
+ runs?: TextRunRange[]
28
+ }
29
+
30
+ /** One styled range for {@link MeasureTextOptions.runs}. */
31
+ export interface TextRunRange {
32
+ start: number
33
+ end: number
34
+ fontFamily?: "sans" | "serif" | "mono" | (string & {})
35
+ fontSize?: number
36
+ fontStyle?: "normal" | "italic"
37
+ fontWeight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
38
+ lineHeight?: number
17
39
  }
18
40
 
19
41
  /**
@@ -35,6 +57,17 @@ declare module "flux:rendertree" {
35
57
  descent: number
36
58
  /** The unit ends at a hard line break (newline). */
37
59
  hardBreak: boolean
60
+ /** A continuation piece of the previous unit (it crossed a `runs` boundary): a line never breaks before it. */
61
+ glue: boolean
62
+ /** Index into `runs` of the range this piece was shaped in; absent for the base font. */
63
+ run?: number
64
+ /**
65
+ * With `carets`: the caret positions inside the unit, one per grapheme
66
+ * cluster boundary from its start (`offset` = start, x 0) to the end of
67
+ * its shaped text (before any break characters), in order. `offset` is
68
+ * into the prepared text, `x` from the unit's pen position.
69
+ */
70
+ carets?: { offset: number, x: number }[]
38
71
  }
39
72
 
40
73
  /** The wrap units of a text in one font, shaped once. Plain data; layout is arithmetic over `units`. */
@@ -45,24 +78,41 @@ declare module "flux:rendertree" {
45
78
 
46
79
  /** Create the window root node with the given id. */
47
80
  export function createRoot(id: number): void
48
- /** Create a node of `kind` (the primitive element name) with the given id. */
81
+ /**
82
+ * Make `id`, an existing window node, the root again. Creating a window
83
+ * takes the root over, so this is the way back to an earlier window without
84
+ * recreating it (render()'s error boundary swapping the app's window back
85
+ * in on reset). No-op for the current root or an unknown id.
86
+ */
87
+ export function setRoot(id: number): void
88
+ /** 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
89
  export function createNode(id: number, kind: string): void
50
90
  /** Insert `nodeId` under `parentId`, before `anchorId` if given (else appended). */
51
91
  export function insertNode(parentId: number, nodeId: number, anchorId?: number): void
52
92
  /**
53
93
  * Unlink `nodeId` from `parentId` but keep its subtree alive, so it can be
54
94
  * re-inserted elsewhere (a move). Mirrors DOM removeChild. Pair with
55
- * {@link destroyNode} once the node is confirmed dead.
95
+ * {@link destroyNode} once the node is confirmed dead. Divergence: a node
96
+ * whose `transition` declares `exit` values stays linked and animates them
97
+ * first; the unlink happens when the exit settles, and a re-insert before
98
+ * then abandons it (moves never play removal animations).
56
99
  */
57
100
  export function detachNode(parentId: number, nodeId: number): void
58
- /** Free `nodeId` and its whole subtree. Call after {@link detachNode}. */
101
+ /**
102
+ * Free `nodeId` and its whole subtree. Call after {@link detachNode}. A
103
+ * node mid-exit is freed when its exit animation settles instead.
104
+ */
59
105
  export function destroyNode(nodeId: number): void
60
106
  /**
61
107
  * 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.
108
+ * `null`/`undefined` resets the property to its default (its value before
109
+ * anything was set, per element kind; on a span, back to inheriting from
110
+ * the paragraph). Content props (`text`, `d`) still require a value.
111
+ * Throws an `Error` for an unknown
112
+ * property name (message starts with "Unknown property") or a value that
113
+ * does not decode; it never aborts the runtime. Core's renderer
114
+ * warns-and-continues on the name-level rejections and rethrows value
115
+ * errors.
66
116
  */
67
117
  export function setProperty(nodeId: number, name: string, value: unknown): void
68
118
  /**
@@ -87,6 +137,13 @@ declare module "flux:rendertree" {
87
137
  }
88
138
  /** Enable or disable text-input capture / the on-screen keyboard. */
89
139
  export function setTextInputActive(active: boolean, hints?: TextInputHints): void
140
+ /**
141
+ * Enter or leave relative mouse mode (pointer lock): the cursor hides and
142
+ * confines to the window, absolute pointer positions freeze, and mouse
143
+ * motion keeps reporting through movementX/movementY. The applied state
144
+ * comes back on the sticky "pointerLock" bus event.
145
+ */
146
+ export function setPointerLock(locked: boolean): void
90
147
  /** Request that a frame be rendered soon (coalesced by the demand-driven loop). */
91
148
  export function requestFrame(): void
92
149
  /**
@@ -121,4 +178,30 @@ declare module "flux:rendertree" {
121
178
  * semantics), for comparing against pointer event coordinates.
122
179
  */
123
180
  export function getBoundingBoxViewport(id: number): { x: number, y: number, width: number, height: number } | null
181
+ /**
182
+ * The texture id of a snapshot repaint boundary's retained rasterization
183
+ * (its subtree's pixels at display scale, premultiplied, top-left origin,
184
+ * cropped to the layout box). Allocated on the first call and stable for
185
+ * the node's lifetime; it is re-pointed at the current pixels after every
186
+ * rasterization, so consumers never rebind. Before the first paint the id
187
+ * has no pixels yet (a `<texture>` measures 0x0, a shader pass skips the
188
+ * binding). Owned by the boundary: `destroyTexture` on it throws, and an
189
+ * unmounted boundary releases it through the deferred-destroy path. Throws
190
+ * if the node is not a snapshot boundary.
191
+ */
192
+ export function snapshotTexture(id: number): TextureId
193
+ /**
194
+ * Parses a CSS color string (hex, rgb()/rgba(), hsl()/hsla(), hwb(),
195
+ * named colors) into packed 0xRRGGBBAA form (which the color property
196
+ * also accepts alongside plain CSS strings). Throws on an invalid string.
197
+ */
198
+ export function parseColor(color: string): number
199
+ /**
200
+ * Mixes two CSS colors in oklab; `t` is the fraction of `b` (0 = pure
201
+ * `a`, 1 = pure `b`). Returns a hex string, with an alpha byte only when
202
+ * the mix is translucent.
203
+ */
204
+ export function mixColors(a: string, b: string, t: number): string
205
+ /** Perceived brightness of a CSS color, 0 (black) to 1 (white), YIQ-weighted. */
206
+ export function brightness(color: string): number
124
207
  }
@@ -0,0 +1,188 @@
1
+ // The spatial core (gui-enabled runtime only): a native transform hierarchy
2
+ // whose flush recomputes only the subtrees that changed and writes the
3
+ // results to draw sinks - a draw entry's `uModel` (+ `uNormal`) params and
4
+ // its instance count as the visibility switch. Generic on purpose: no camera,
5
+ // mesh or light concept. @solidrt/3d is the first consumer; any draw-list
6
+ // user with a tree of transforms (a 2D sprite scene, a skeleton) is the same
7
+ // shape. Node ids are plain numbers, generation-tagged and never reused, so
8
+ // a destroyed node's id throws everywhere.
9
+ //
10
+ // A transform argument is one Float32Array of 10: position xyz, unit
11
+ // quaternion xyzw, scale xyz. Writes queue the node; nothing reaches the
12
+ // GPU until flush(). worldMatrix() reads through pending writes.
13
+
14
+ declare module "flux:spatial" {
15
+ import type { BufferId, DrawId, TextureId } from "flux:gpu"
16
+
17
+ export type NodeId = number & { readonly __spatialNode: unique symbol }
18
+
19
+ /** A new root node. `visible: false` hides the node's whole subtree. */
20
+ export function createNode(transform: Float32Array, visible: boolean): NodeId
21
+ /** Free a node; its children become roots. A bound sink is dropped
22
+ * without a write (removing the entry is the caller's job). */
23
+ export function destroyNode(node: NodeId): void
24
+ /** Re-parent (null = make a root). Throws on a cycle. */
25
+ export function setParent(node: NodeId, parent: NodeId | null): void
26
+ /** Replace the local transform (compare before calling; an unchanged
27
+ * write still queues the node). Never consults or cancels transition
28
+ * tracks: a running track overwrites a raw write at the next frame
29
+ * (last write wins - the producer rule). */
30
+ export function setTransform(node: NodeId, transform: Float32Array): void
31
+ /**
32
+ * One node-transition spec, the element `transition` vocabulary minus
33
+ * the lifecycle conveniences: `{ duration }` / `{ duration, bounce }`
34
+ * is a spring (the default kind; retargets keep position and velocity,
35
+ * rotation springs keep angular velocity along the geodesic),
36
+ * `{ duration, curve }` a tween (rotation tweens slerp the geodesic;
37
+ * retargets restart from the current value), or the shorthand string
38
+ * `"<duration>ms [curve]"`. Durations in ms; no delay, from or exit.
39
+ */
40
+ export type NodeTransitionSpec =
41
+ | { duration: number; bounce?: number }
42
+ | { duration: number; curve: "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | [number, number, number, number] }
43
+ | string
44
+ /** The declaration setTransition takes: a spec per transform component
45
+ * plus `all` as a catch-all (per-component entries win). */
46
+ export interface NodeTransition {
47
+ position?: NodeTransitionSpec
48
+ rotation?: NodeTransitionSpec
49
+ scale?: NodeTransitionSpec
50
+ all?: NodeTransitionSpec
51
+ }
52
+ /**
53
+ * Declare (or with null clear) the node's transitions: with a config
54
+ * set, writeTransform animates instead of snapping. A bare string is
55
+ * the `all` catch-all. Clearing cancels the node's running tracks in
56
+ * place - it keeps its mid-flight transform, no settled events fire,
57
+ * and later writes snap. Replacing a config affects future writes only.
58
+ */
59
+ export function setTransition(node: NodeId, transition: NodeTransition | string | null): void
60
+ /**
61
+ * Replace the local transform THROUGH the transition declaration: a
62
+ * declared component animates toward the written value (the write is a
63
+ * target), an undeclared one snaps. Without a declaration this is
64
+ * setTransform. A component matching its running track's target is
65
+ * left alone, so rewriting the whole array to move one component never
66
+ * restarts the others. Each settled component fires one
67
+ * "spatialTransitionEnd" engine event (srt:events), payload
68
+ * `{ node, component: "position" | "rotation" | "scale" }`.
69
+ */
70
+ export function writeTransform(node: NodeId, transform: Float32Array): void
71
+ export function setVisible(node: NodeId, visible: boolean): void
72
+ /**
73
+ * Route the node's world matrix to one draw entry's `uModel` (and
74
+ * `uNormal`, the inverse-transpose, when `normal`). Validated like
75
+ * setDrawParams: the entry must exist and declare those uniforms. The
76
+ * entry is assumed switched off (instanceCount 0); the next flush turns it
77
+ * on with `count` when the node is shown, and off again when hidden.
78
+ * One draw sink PER TARGET: binding on a target the node already draws
79
+ * into replaces that sink, binding on another target adds one - a mesh
80
+ * drawn by a scene and by each of its views is one node with one flush.
81
+ */
82
+ export function bindDraw(node: NodeId, target: TextureId, draw: DrawId, normal: boolean, count: number): void
83
+ /** Remove the node's draw sink on `target`, or every draw sink without
84
+ * one. Issues no write: the entries are the caller's to remove. */
85
+ export function unbindDraw(node: NodeId, target?: TextureId): void
86
+ /** Change every bound entry's "on" count (an instanced mesh's record
87
+ * count); written at once to the entries currently on. */
88
+ export function setDrawCount(node: NodeId, count: number): void
89
+ /** Fill `out` (a Float32Array of 16, column-major) with the node's world
90
+ * matrix as the tree stands now, pending writes included. */
91
+ export function worldMatrix(node: NodeId, out: Float32Array): void
92
+ /** Effective visibility (every ancestor visible too) as of the last flush. */
93
+ export function shown(node: NodeId): boolean
94
+ /** Recompute every changed subtree and write the sinks; requests a frame
95
+ * when anything was written. */
96
+ export function flush(): void
97
+
98
+ export type ShapeId = number & { readonly __spatialShape: unique symbol }
99
+
100
+ /** One hit of raycast(), nearest first. `face`/`uv`/`normal` are present
101
+ * for nodes with a shape (uv only when the shape has UVs); a node with
102
+ * bounds but no shape reports its local box, distance and point only. */
103
+ export type Hit = {
104
+ node: NodeId
105
+ /** World units along the normalized ray. */
106
+ distance: number
107
+ point: [number, number, number]
108
+ /** World-space geometric normal, facing the ray. */
109
+ normal?: [number, number, number]
110
+ /** Triangle index into the shape's index list. */
111
+ face?: number
112
+ uv?: [number, number]
113
+ }
114
+
115
+ /** Set (null clears) the node's LOCAL tight box [minX, minY, minZ, maxX,
116
+ * maxY, maxZ]. With one the node is in the picking index: its world box
117
+ * follows the flush; hidden nodes stay in and are skipped at query time. */
118
+ export function setBounds(node: NodeId, bounds: Float32Array | null): void
119
+ /**
120
+ * Triangle data for the picking narrowphase, one copy shared by every
121
+ * node that references it: positions read from an interleaved vertex
122
+ * array (`stride` floats per vertex, xyz at `posOffset`, uv at
123
+ * `uvOffset`, -1 for none) and a Uint16Array/Uint32Array triangle list.
124
+ * Throws on out-of-range indices.
125
+ */
126
+ export function createShape(vertices: Float32Array, stride: number, posOffset: number, uvOffset: number, indices: Uint16Array | Uint32Array): ShapeId
127
+ /** Free a shape; nodes still referencing it fall back to their box. */
128
+ export function destroyShape(shape: ShapeId): void
129
+ export function setShape(node: NodeId, shape: ShapeId | null): void
130
+ /** Every shown node with bounds the ray strikes, nearest first. The
131
+ * direction need not be normalized; distances are world units. Reads
132
+ * the index as of the last flush. */
133
+ export function raycast(origin: Float32Array, direction: Float32Array): Hit[]
134
+ /**
135
+ * Every shown node with bounds whose local box, carried through its
136
+ * world transform, overlaps the world-axis box `bounds` (a Float32Array
137
+ * of 6: [minX, minY, minZ, maxX, maxY, maxZ]; touching counts, a point
138
+ * is min == max). Tested by separating axes, so a rotated flat rect -
139
+ * the 2d marquee case - tests exactly, never by its world AABB.
140
+ * Unordered; reads the index as of the last flush, like raycast.
141
+ */
142
+ export function overlap(bounds: Float32Array): NodeId[]
143
+
144
+ /**
145
+ * Route the world DIRECTION of the node's local `vector` (a
146
+ * Float32Array of 3) into
147
+ * vec3 slot `index` of the `len`-float shared array param `name` on a
148
+ * draw target: the flush writes `normalize(worldRotation * v)` there
149
+ * and re-sends the whole array when any slot changes; unbound slots are
150
+ * zeros. Every sink naming the same param shares one array (`len` must
151
+ * agree); what the slots mean - light directions, an emitter axis - is
152
+ * the caller's business, packed alongside its own non-spatial params.
153
+ * One slot sink per target, like bindDraw: rebinding on the same target
154
+ * replaces that sink (the abandoned slot zeroes), another target adds one.
155
+ */
156
+ export function bindDirectionSlot(node: NodeId, target: TextureId, name: string, len: number, index: number, vector: Float32Array): void
157
+ /** Remove the node's slot sink on `target`, or every slot sink without
158
+ * one (the abandoned slots zero at the next flush). */
159
+ export function unbindSlot(node: NodeId, target?: TextureId): void
160
+
161
+ /**
162
+ * Route the node's world pose to record slot `index` of vertex buffer
163
+ * `buffer` used as an instance buffer: the flush writes the 5 floats
164
+ * [x, y, angle, sx, sy] (world xy translation, rotation of the local x
165
+ * axis in the world xy plane, xy scale with sy negated when the matrix
166
+ * mirrors) at float offset index * 5. Writes batch: however many bound
167
+ * nodes moved, each flush issues at most one coalesced write per
168
+ * buffer, so producer-driven populations cost one buffer write per
169
+ * frame. A hidden node's slot zeroes (zero scale collapses the
170
+ * instance); so does an unbound or destroyed node's. Validated at bind
171
+ * time: the buffer must exist and the slot must fit its byte size.
172
+ * Rebinding replaces the node's record sink; the abandoned slot zeroes.
173
+ */
174
+ export function bindPoseRecord(node: NodeId, buffer: BufferId, index: number): void
175
+ /** Remove the node's record sink (its slot zeroes at the next flush). */
176
+ export function unbindRecord(node: NodeId): void
177
+ /**
178
+ * Move every record sink on buffer `old` to buffer `new`, slot indices
179
+ * untouched: the growth swap. The whole used range republishes into
180
+ * `new` at the next flush, so a population outgrowing its buffer swaps
181
+ * in a larger one with one call and one bulk write instead of a
182
+ * bindPoseRecord per node (pair it with the draw entry's own buffer
183
+ * swap, setDraw's `instanceBuffers`). Throws when nothing is bound to
184
+ * `old`, when `new` does not exist or cannot hold every bound slot, or
185
+ * when `new` already carries record sinks.
186
+ */
187
+ export function retargetRecords(old: BufferId, next: BufferId): void
188
+ }
package/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference path="./modules/process.d.ts" />
2
+ /// <reference path="./modules/tty.d.ts" />
2
3
  /// <reference path="./modules/path.d.ts" />
3
4
  /// <reference path="./modules/http.d.ts" />
4
5
  /// <reference path="./modules/fs.d.ts" />
@@ -15,13 +16,15 @@
15
16
 
16
17
  // Web-standard globals. The runtime is QuickJS, not a browser or Node, so it
17
18
  // ships no lib.dom / @types/bun: these declarations are the sole source for
18
- // console, fetch, the Fetch types, timers, WebSocket, and the encoders.
19
+ // console, fetch, the Fetch types, timers, WebSocket, the encoders, and crypto.
19
20
  /// <reference path="./standards/console.d.ts" />
20
21
  /// <reference path="./standards/time.d.ts" />
21
22
  /// <reference path="./standards/text.d.ts" />
22
23
  /// <reference path="./standards/base64.d.ts" />
23
24
  /// <reference path="./standards/fetch.d.ts" />
24
25
  /// <reference path="./standards/websocket.d.ts" />
26
+ /// <reference path="./standards/abort.d.ts" />
27
+ /// <reference path="./standards/crypto.d.ts" />
25
28
 
26
29
  // GUI capabilities (present only on a gui-enabled runtime). rendertree/camera/
27
30
  // microphone/gpu are flux:* modules like the rest; requestAnimationFrame stays a
@@ -33,6 +36,7 @@
33
36
  /// <reference path="./gui/microphone.d.ts" />
34
37
  /// <reference path="./gui/audio.d.ts" />
35
38
  /// <reference path="./gui/gpu.d.ts" />
39
+ /// <reference path="./gui/spatial.d.ts" />
36
40
  /// <reference path="./gui/video.d.ts" />
37
41
  /// <reference path="./gui/raf.d.ts" />
38
42
 
package/modules/fs.d.ts CHANGED
@@ -34,6 +34,24 @@ declare module "flux:fs" {
34
34
  write(data: string | Uint8Array): Promise<void>
35
35
  /** Append `data` to the end of the file, creating it if missing. */
36
36
  append(data: string | Uint8Array): Promise<void>
37
+ /** Remove the file. A missing file is not an error. */
38
+ remove(): Promise<void>
39
+ }
40
+
41
+ /**
42
+ * One change under a watched directory. `path` is the absolute path of the
43
+ * entry. `rename` names the path a file now has (the target of a rename:
44
+ * an editor's atomic save shows up as one); the old name of a rename
45
+ * arrives as `remove`.
46
+ */
47
+ type WatchEvent = {
48
+ kind: "create" | "modify" | "remove" | "rename"
49
+ path: string
50
+ }
51
+
52
+ type WatchOptions = {
53
+ /** Watch the whole tree below the directory too. Default false. */
54
+ recursive?: boolean
37
55
  }
38
56
 
39
57
  type FluxDir = {
@@ -47,6 +65,13 @@ declare module "flux:fs" {
47
65
  * already exists.
48
66
  */
49
67
  create(): Promise<void>
68
+ /**
69
+ * Watch the directory for changes, calling `callback` for each one.
70
+ * Events are raw and undebounced: one save usually arrives as several,
71
+ * so coalesce them yourself. The watch keeps the process alive until the
72
+ * returned function is called. Throws if the directory does not exist.
73
+ */
74
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): () => void
50
75
  }
51
76
 
52
77
  /**
@@ -66,4 +91,12 @@ declare module "flux:fs" {
66
91
  * @param path Path to the directory.
67
92
  */
68
93
  export function dir(path: string): FluxDir
94
+ /**
95
+ * The canonical absolute path: symlinks resolved, `.`/`..` collapsed, the
96
+ * spelling the OS reports (no `\\?\` prefix on Windows). Rejects if the
97
+ * path does not exist.
98
+ *
99
+ * @param path Path to a file or directory.
100
+ */
101
+ export function realpath(path: string): Promise<string>
69
102
  }
package/modules/http.d.ts CHANGED
@@ -149,7 +149,7 @@ declare module "flux:http" {
149
149
  }
150
150
 
151
151
  type Server = {
152
- /** The bound port. */
152
+ /** The bound port (the OS-assigned one when `port` was 0 or omitted). */
153
153
  readonly port: number
154
154
  /** The bound host/interface. */
155
155
  readonly host: string
@@ -191,8 +191,8 @@ declare module "flux:http" {
191
191
  }
192
192
 
193
193
  type ServeOptions = {
194
- /** Port to listen on. */
195
- port: number
194
+ /** Port to listen on. 0 or omitted picks a free port; read it back from `server.port`. */
195
+ port?: number
196
196
  /** Hostname/interface to bind. Defaults to "0.0.0.0" (all interfaces). */
197
197
  host?: string
198
198
  /**
@@ -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
  }
package/modules/net.d.ts CHANGED
@@ -43,6 +43,8 @@ declare module "flux:net" {
43
43
  mac: string | null
44
44
  /** Whether the interface is up. */
45
45
  up: boolean
46
+ /** Whether it holds the default route (the interface other hosts reach). */
47
+ default: boolean
46
48
  /** Whether it is a loopback interface. */
47
49
  loopback: boolean
48
50
  /** Whether it supports multicast. */
@@ -6,6 +6,8 @@ declare module "flux:process" {
6
6
  * argument.
7
7
  */
8
8
  export let argv: string[]
9
+ /** The OS process id of this process (what a registry record or a `kill` names). */
10
+ export let pid: number
9
11
  /** The host OS: "darwin", "win32", "linux", "android", ... */
10
12
  export let platform: string
11
13
  /** The CPU architecture: "x64", "arm64", ... */
@@ -16,6 +18,40 @@ declare module "flux:process" {
16
18
  * provided for now.)
17
19
  */
18
20
  export function memoryUsage(): { rss: number }
21
+ /**
22
+ * The current user's home directory, or `null` when the environment does
23
+ * not name one (HOME on unix, USERPROFILE on Windows).
24
+ */
25
+ export function homedir(): string | null
26
+ /**
27
+ * The path of the running executable, or `null` when the OS cannot name it
28
+ * (Node's is always a string). What a dev tool spawns through
29
+ * `flux:subprocess` to start another instance of the runtime it runs in.
30
+ * In a packed app this is the app itself: spawning it launches that app,
31
+ * not a bare runtime.
32
+ */
33
+ export let execPath: string | null
34
+ /**
35
+ * Terminate another process. Portable (SIGKILL / TerminateProcess), so
36
+ * there is no signal argument, unlike Node's `process.kill(pid, signal)`.
37
+ *
38
+ * @param pid The OS process id.
39
+ * @returns `true` when the process was terminated; `false` when it does not
40
+ * exist or the OS refused.
41
+ */
42
+ export function kill(pid: number): boolean
43
+ /**
44
+ * Whether a process with `pid` exists. The `process.kill(pid, 0)` idiom
45
+ * under its own name. A zombie (exited, not yet reaped) counts as gone.
46
+ *
47
+ * @param pid The OS process id.
48
+ */
49
+ export function alive(pid: number): boolean
50
+ /**
51
+ * The process environment, snapshotted when the module is evaluated: a
52
+ * plain object, not Node's live and writable `process.env`.
53
+ */
54
+ export let env: Record<string, string | undefined>
19
55
  /**
20
56
  * Listen for an OS signal. The callback receives the signal name. Returns an
21
57
  * unsubscribe function. Unix only; a no-op elsewhere.
@@ -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
  }