lumiverse-spindle-types 0.4.43 → 0.4.45
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/package.json +1 -1
- package/src/api.ts +196 -2
- package/src/dom.ts +49 -0
- package/src/index.ts +29 -7
- package/src/spindle-api.ts +150 -3
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -1008,7 +1008,8 @@ export interface ThemeVariablesConfigDTO {
|
|
|
1008
1008
|
* This is the safe, presentation-owned path for live extension theming.
|
|
1009
1009
|
* Extensions provide palette intent only; Lumiverse preserves the user's
|
|
1010
1010
|
* radius, glass, font, and UI-scale settings and generates the final
|
|
1011
|
-
* mode-aware variable maps itself.
|
|
1011
|
+
* mode-aware variable maps itself. Pass `null` to clear a previously applied
|
|
1012
|
+
* palette override when no valid color data is available.
|
|
1012
1013
|
*/
|
|
1013
1014
|
export interface ThemePaletteConfigDTO {
|
|
1014
1015
|
/** Primary accent color in HSL. */
|
|
@@ -1081,6 +1082,183 @@ export interface SpindleCommandContextDTO {
|
|
|
1081
1082
|
isGroupChat?: boolean;
|
|
1082
1083
|
}
|
|
1083
1084
|
|
|
1085
|
+
// ─── Frontend Process Lifecycle DTOs ────────────────────────────────────
|
|
1086
|
+
|
|
1087
|
+
/** High-level lifecycle state for a frontend process tracked by the backend host. */
|
|
1088
|
+
export type FrontendProcessStateDTO =
|
|
1089
|
+
| "starting"
|
|
1090
|
+
| "running"
|
|
1091
|
+
| "stopping"
|
|
1092
|
+
| "stopped"
|
|
1093
|
+
| "completed"
|
|
1094
|
+
| "failed"
|
|
1095
|
+
| "timed_out";
|
|
1096
|
+
|
|
1097
|
+
/** Terminal reason attached to lifecycle events and snapshots when available. */
|
|
1098
|
+
export type FrontendProcessExitReasonDTO =
|
|
1099
|
+
| "completed"
|
|
1100
|
+
| "failed"
|
|
1101
|
+
| "stopped"
|
|
1102
|
+
| "timed_out"
|
|
1103
|
+
| "frontend_unloaded"
|
|
1104
|
+
| "backend_unloaded"
|
|
1105
|
+
| "replaced";
|
|
1106
|
+
|
|
1107
|
+
/** Options used when spawning a tracked frontend process from the backend worker. */
|
|
1108
|
+
export interface FrontendProcessSpawnOptionsDTO {
|
|
1109
|
+
/** Frontend handler key registered via `ctx.processes.register(kind, ...)`. */
|
|
1110
|
+
kind: string;
|
|
1111
|
+
/** Optional extension-defined stable key used for dedupe / replacement semantics. */
|
|
1112
|
+
key?: string;
|
|
1113
|
+
/** Optional process-scoped startup payload delivered to the frontend handler. */
|
|
1114
|
+
payload?: unknown;
|
|
1115
|
+
/** Arbitrary metadata stored alongside the process snapshot for backend bookkeeping. */
|
|
1116
|
+
metadata?: Record<string, unknown>;
|
|
1117
|
+
/** For operator-scoped extensions only. */
|
|
1118
|
+
userId?: string;
|
|
1119
|
+
/** Reject spawn if the frontend does not call `process.ready()` within this window. */
|
|
1120
|
+
startupTimeoutMs?: number;
|
|
1121
|
+
/** Mark the process timed out if the frontend stops heartbeating for this long after ready. */
|
|
1122
|
+
heartbeatTimeoutMs?: number;
|
|
1123
|
+
/** Replace any existing process with the same `key` for the target user. */
|
|
1124
|
+
replaceExisting?: boolean;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/** Filter used for controller list queries. */
|
|
1128
|
+
export interface FrontendProcessListOptionsDTO {
|
|
1129
|
+
userId?: string;
|
|
1130
|
+
kind?: string;
|
|
1131
|
+
key?: string;
|
|
1132
|
+
state?: FrontendProcessStateDTO;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/** Current host-tracked snapshot of a frontend process. */
|
|
1136
|
+
export interface FrontendProcessInfoDTO {
|
|
1137
|
+
processId: string;
|
|
1138
|
+
kind: string;
|
|
1139
|
+
key?: string;
|
|
1140
|
+
state: FrontendProcessStateDTO;
|
|
1141
|
+
userId?: string;
|
|
1142
|
+
metadata?: Record<string, unknown>;
|
|
1143
|
+
startedAt: string;
|
|
1144
|
+
readyAt?: string;
|
|
1145
|
+
lastHeartbeatAt?: string;
|
|
1146
|
+
endedAt?: string;
|
|
1147
|
+
exitReason?: FrontendProcessExitReasonDTO;
|
|
1148
|
+
error?: string;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/** Lifecycle event emitted to backend workers for tracked frontend processes. */
|
|
1152
|
+
export interface FrontendProcessLifecycleEventDTO {
|
|
1153
|
+
processId: string;
|
|
1154
|
+
kind: string;
|
|
1155
|
+
key?: string;
|
|
1156
|
+
userId?: string;
|
|
1157
|
+
state: FrontendProcessStateDTO;
|
|
1158
|
+
previousState?: FrontendProcessStateDTO;
|
|
1159
|
+
at: string;
|
|
1160
|
+
exitReason?: FrontendProcessExitReasonDTO;
|
|
1161
|
+
error?: string;
|
|
1162
|
+
metadata?: Record<string, unknown>;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/** Options for graceful process termination. */
|
|
1166
|
+
export interface FrontendProcessStopOptionsDTO {
|
|
1167
|
+
userId?: string;
|
|
1168
|
+
/** Optional reason surfaced to the frontend process' stop handler. */
|
|
1169
|
+
reason?: string;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// ─── Backend Process Lifecycle DTOs ─────────────────────────────────────
|
|
1173
|
+
|
|
1174
|
+
/** High-level lifecycle state for an isolated backend subprocess tracked by the host. */
|
|
1175
|
+
export type BackendProcessStateDTO =
|
|
1176
|
+
| "starting"
|
|
1177
|
+
| "running"
|
|
1178
|
+
| "stopping"
|
|
1179
|
+
| "stopped"
|
|
1180
|
+
| "completed"
|
|
1181
|
+
| "failed"
|
|
1182
|
+
| "timed_out";
|
|
1183
|
+
|
|
1184
|
+
/** Terminal reason attached to backend-process lifecycle events and snapshots when available. */
|
|
1185
|
+
export type BackendProcessExitReasonDTO =
|
|
1186
|
+
| "completed"
|
|
1187
|
+
| "failed"
|
|
1188
|
+
| "stopped"
|
|
1189
|
+
| "timed_out"
|
|
1190
|
+
| "backend_unloaded"
|
|
1191
|
+
| "replaced";
|
|
1192
|
+
|
|
1193
|
+
/** Options used when spawning an isolated backend subprocess from the backend worker. */
|
|
1194
|
+
export interface BackendProcessSpawnOptionsDTO {
|
|
1195
|
+
/** Built JS entry file under the extension repo, typically in `dist/`. */
|
|
1196
|
+
entry: string;
|
|
1197
|
+
/** Optional logical label used for lifecycle filtering and dedupe semantics. Defaults to `entry`. */
|
|
1198
|
+
kind?: string;
|
|
1199
|
+
/** Optional extension-defined stable key used for dedupe / replacement semantics. */
|
|
1200
|
+
key?: string;
|
|
1201
|
+
/** Optional process-scoped startup payload delivered to the subprocess entry. */
|
|
1202
|
+
payload?: unknown;
|
|
1203
|
+
/** Arbitrary metadata stored alongside the process snapshot for backend bookkeeping. */
|
|
1204
|
+
metadata?: Record<string, unknown>;
|
|
1205
|
+
/** For operator-scoped extensions only. */
|
|
1206
|
+
userId?: string;
|
|
1207
|
+
/** Reject spawn if the subprocess does not call `process.ready()` within this window. */
|
|
1208
|
+
startupTimeoutMs?: number;
|
|
1209
|
+
/** Mark the subprocess timed out if it stops heartbeating for this long after ready. */
|
|
1210
|
+
heartbeatTimeoutMs?: number;
|
|
1211
|
+
/** Replace any existing process with the same `key` for the target user. */
|
|
1212
|
+
replaceExisting?: boolean;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/** Filter used for backend subprocess list queries. */
|
|
1216
|
+
export interface BackendProcessListOptionsDTO {
|
|
1217
|
+
userId?: string;
|
|
1218
|
+
kind?: string;
|
|
1219
|
+
key?: string;
|
|
1220
|
+
state?: BackendProcessStateDTO;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
/** Current host-tracked snapshot of an isolated backend subprocess. */
|
|
1224
|
+
export interface BackendProcessInfoDTO {
|
|
1225
|
+
processId: string;
|
|
1226
|
+
entry: string;
|
|
1227
|
+
kind: string;
|
|
1228
|
+
key?: string;
|
|
1229
|
+
state: BackendProcessStateDTO;
|
|
1230
|
+
userId?: string;
|
|
1231
|
+
metadata?: Record<string, unknown>;
|
|
1232
|
+
startedAt: string;
|
|
1233
|
+
readyAt?: string;
|
|
1234
|
+
lastHeartbeatAt?: string;
|
|
1235
|
+
endedAt?: string;
|
|
1236
|
+
exitReason?: BackendProcessExitReasonDTO;
|
|
1237
|
+
error?: string;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/** Lifecycle event emitted to backend workers for isolated backend subprocesses. */
|
|
1241
|
+
export interface BackendProcessLifecycleEventDTO {
|
|
1242
|
+
processId: string;
|
|
1243
|
+
entry: string;
|
|
1244
|
+
kind: string;
|
|
1245
|
+
key?: string;
|
|
1246
|
+
userId?: string;
|
|
1247
|
+
state: BackendProcessStateDTO;
|
|
1248
|
+
previousState?: BackendProcessStateDTO;
|
|
1249
|
+
at: string;
|
|
1250
|
+
exitReason?: BackendProcessExitReasonDTO;
|
|
1251
|
+
error?: string;
|
|
1252
|
+
metadata?: Record<string, unknown>;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
/** Options for graceful isolated-backend-process termination. */
|
|
1256
|
+
export interface BackendProcessStopOptionsDTO {
|
|
1257
|
+
userId?: string;
|
|
1258
|
+
/** Optional reason surfaced to the subprocess stop handler. */
|
|
1259
|
+
reason?: string;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1084
1262
|
// ─── Generation Event Payload DTOs ──────────────────────────────────────
|
|
1085
1263
|
|
|
1086
1264
|
/** Payload for `GENERATION_STARTED` events. */
|
|
@@ -1641,6 +1819,18 @@ export type WorkerToHost =
|
|
|
1641
1819
|
| { type: "modal_close"; requestId: string; openRequestId: string; userId?: string }
|
|
1642
1820
|
| { type: "confirm_open"; requestId: string; title: string; message: string; variant?: "info" | "warning" | "danger" | "success"; confirmLabel?: string; cancelLabel?: string; userId?: string }
|
|
1643
1821
|
| { type: "input_prompt_open"; requestId: string; title: string; message?: string; placeholder?: string; defaultValue?: string; submitLabel?: string; cancelLabel?: string; multiline?: boolean; userId?: string }
|
|
1822
|
+
// ─── Frontend Process Lifecycle (free tier) ───────────────────────────
|
|
1823
|
+
| { type: "frontend_process_spawn"; requestId: string; options: FrontendProcessSpawnOptionsDTO }
|
|
1824
|
+
| { type: "frontend_process_list"; requestId: string; filter?: FrontendProcessListOptionsDTO }
|
|
1825
|
+
| { type: "frontend_process_get"; requestId: string; processId: string }
|
|
1826
|
+
| { type: "frontend_process_stop"; requestId: string; processId: string; options?: FrontendProcessStopOptionsDTO }
|
|
1827
|
+
| { type: "frontend_process_send"; processId: string; payload: unknown; userId?: string }
|
|
1828
|
+
// ─── Backend Process Lifecycle (free tier) ────────────────────────────
|
|
1829
|
+
| { type: "backend_process_spawn"; requestId: string; options: BackendProcessSpawnOptionsDTO }
|
|
1830
|
+
| { type: "backend_process_list"; requestId: string; filter?: BackendProcessListOptionsDTO }
|
|
1831
|
+
| { type: "backend_process_get"; requestId: string; processId: string }
|
|
1832
|
+
| { type: "backend_process_stop"; requestId: string; processId: string; options?: BackendProcessStopOptionsDTO }
|
|
1833
|
+
| { type: "backend_process_send"; processId: string; payload: unknown; userId?: string }
|
|
1644
1834
|
// ─── Macro Resolution (free tier) ──────────────────────────────────
|
|
1645
1835
|
| { type: "macros_resolve"; requestId: string; template: string; chatId?: string; characterId?: string; userId?: string; commit?: boolean }
|
|
1646
1836
|
// ─── Image Generation (gated: "image_gen") ──────────────────────────
|
|
@@ -1651,7 +1841,7 @@ export type WorkerToHost =
|
|
|
1651
1841
|
| { type: "image_gen_models"; requestId: string; connectionId: string; userId?: string }
|
|
1652
1842
|
// ─── Theme (gated: "app_manipulation") ──────────────────────────────────
|
|
1653
1843
|
| { type: "theme_apply"; requestId: string; overrides: ThemeOverrideDTO; userId?: string }
|
|
1654
|
-
| { type: "theme_apply_palette"; requestId: string; palette: ThemePaletteConfigDTO; userId?: string }
|
|
1844
|
+
| { type: "theme_apply_palette"; requestId: string; palette: ThemePaletteConfigDTO | null; userId?: string }
|
|
1655
1845
|
| { type: "theme_clear"; requestId: string; userId?: string }
|
|
1656
1846
|
| { type: "theme_get_current"; requestId: string; userId?: string }
|
|
1657
1847
|
// ─── Color Extraction (gated: "app_manipulation") ─────────────────────
|
|
@@ -1757,6 +1947,10 @@ export type HostToWorker =
|
|
|
1757
1947
|
}
|
|
1758
1948
|
| { type: "shutdown" }
|
|
1759
1949
|
| { type: "frontend_message"; payload: unknown; userId: string }
|
|
1950
|
+
| { type: "frontend_process_lifecycle"; event: FrontendProcessLifecycleEventDTO }
|
|
1951
|
+
| { type: "frontend_process_message"; processId: string; payload: unknown; userId: string }
|
|
1952
|
+
| { type: "backend_process_lifecycle"; event: BackendProcessLifecycleEventDTO }
|
|
1953
|
+
| { type: "backend_process_message"; processId: string; payload: unknown; userId: string }
|
|
1760
1954
|
| {
|
|
1761
1955
|
type: "oauth_callback";
|
|
1762
1956
|
requestId: string;
|
package/src/dom.ts
CHANGED
|
@@ -326,6 +326,53 @@ export interface SpindleConfirmResult {
|
|
|
326
326
|
confirmed: boolean;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
// ── Frontend Process Lifecycle ──
|
|
330
|
+
|
|
331
|
+
/** Controller passed to a frontend process instance spawned by the backend runtime. */
|
|
332
|
+
export interface SpindleFrontendProcessContext {
|
|
333
|
+
/** Host-assigned ID unique within the extension runtime. */
|
|
334
|
+
processId: string;
|
|
335
|
+
/** Frontend handler key used when the backend called `spindle.frontendProcesses.spawn()`. */
|
|
336
|
+
kind: string;
|
|
337
|
+
/** Optional extension-defined stable key passed at spawn time. */
|
|
338
|
+
key?: string;
|
|
339
|
+
/** Arbitrary spawn payload provided by the backend. */
|
|
340
|
+
payload: unknown;
|
|
341
|
+
/** Optional backend-side bookkeeping metadata snapshot. */
|
|
342
|
+
metadata?: Record<string, unknown>;
|
|
343
|
+
/** Signal that startup completed successfully. Required for startup watchdogs. */
|
|
344
|
+
ready(): void;
|
|
345
|
+
/** Refresh the host-side heartbeat timer for long-lived loops. */
|
|
346
|
+
heartbeat(): void;
|
|
347
|
+
/** Send a process-scoped message back to the backend runtime. */
|
|
348
|
+
send(payload: unknown): void;
|
|
349
|
+
/** Subscribe to process-scoped messages from the backend runtime. */
|
|
350
|
+
onMessage(handler: (payload: unknown) => void): () => void;
|
|
351
|
+
/** Mark the process as completed and release host tracking. */
|
|
352
|
+
complete(result?: unknown): void;
|
|
353
|
+
/** Mark the process as failed. */
|
|
354
|
+
fail(error: string): void;
|
|
355
|
+
/** Called when the backend requests graceful termination. */
|
|
356
|
+
onStop(handler: (detail: { reason?: string }) => void): () => void;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Registry exposed to frontend modules for backend-spawned frontend processes. */
|
|
360
|
+
export interface SpindleFrontendProcessRegistry {
|
|
361
|
+
/**
|
|
362
|
+
* Register a process handler for the given `kind`.
|
|
363
|
+
*
|
|
364
|
+
* The returned cleanup function unregisters the handler. If the handler
|
|
365
|
+
* itself returns a cleanup function, the host should call it when the
|
|
366
|
+
* process is stopped, replaced, or the extension is unloaded.
|
|
367
|
+
*/
|
|
368
|
+
register(
|
|
369
|
+
kind: string,
|
|
370
|
+
handler: (
|
|
371
|
+
process: SpindleFrontendProcessContext,
|
|
372
|
+
) => void | (() => void) | Promise<void | (() => void)>,
|
|
373
|
+
): () => void;
|
|
374
|
+
}
|
|
375
|
+
|
|
329
376
|
/** Context object provided to frontend extension modules */
|
|
330
377
|
export interface SpindleFrontendContext {
|
|
331
378
|
dom: SpindleDOMHelper;
|
|
@@ -416,6 +463,8 @@ export interface SpindleFrontendContext {
|
|
|
416
463
|
getActiveChat(): { chatId: string | null; characterId: string | null };
|
|
417
464
|
sendToBackend(payload: unknown): void;
|
|
418
465
|
onBackendMessage(handler: (payload: unknown) => void): () => void;
|
|
466
|
+
/** Structured lifecycle hooks for backend-spawned frontend processes. */
|
|
467
|
+
processes: SpindleFrontendProcessRegistry;
|
|
419
468
|
messages: {
|
|
420
469
|
registerTagInterceptor(
|
|
421
470
|
options: SpindleMessageTagInterceptorOptions,
|
package/src/index.ts
CHANGED
|
@@ -75,9 +75,23 @@ export type {
|
|
|
75
75
|
ColorRGB,
|
|
76
76
|
ColorHSL,
|
|
77
77
|
SpindleModalItemDTO,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
SpindleCommandDTO,
|
|
79
|
+
SpindleCommandContextDTO,
|
|
80
|
+
FrontendProcessStateDTO,
|
|
81
|
+
FrontendProcessExitReasonDTO,
|
|
82
|
+
FrontendProcessSpawnOptionsDTO,
|
|
83
|
+
FrontendProcessListOptionsDTO,
|
|
84
|
+
FrontendProcessInfoDTO,
|
|
85
|
+
FrontendProcessLifecycleEventDTO,
|
|
86
|
+
FrontendProcessStopOptionsDTO,
|
|
87
|
+
BackendProcessStateDTO,
|
|
88
|
+
BackendProcessExitReasonDTO,
|
|
89
|
+
BackendProcessSpawnOptionsDTO,
|
|
90
|
+
BackendProcessListOptionsDTO,
|
|
91
|
+
BackendProcessInfoDTO,
|
|
92
|
+
BackendProcessLifecycleEventDTO,
|
|
93
|
+
BackendProcessStopOptionsDTO,
|
|
94
|
+
GenerationStartedPayloadDTO,
|
|
81
95
|
StreamTokenPayloadDTO,
|
|
82
96
|
GenerationEndedPayloadDTO,
|
|
83
97
|
GenerationStoppedPayloadDTO,
|
|
@@ -129,14 +143,22 @@ export type {
|
|
|
129
143
|
SpindleContextMenuResult,
|
|
130
144
|
SpindleModalOptions,
|
|
131
145
|
SpindleModalHandle,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
SpindleConfirmVariant,
|
|
147
|
+
SpindleConfirmOptions,
|
|
148
|
+
SpindleConfirmResult,
|
|
149
|
+
SpindleFrontendProcessContext,
|
|
150
|
+
SpindleFrontendProcessRegistry,
|
|
135
151
|
} from "./dom";
|
|
136
152
|
|
|
137
153
|
export type { ExtensionInfo } from "./extension-info";
|
|
138
154
|
|
|
139
|
-
export type {
|
|
155
|
+
export type {
|
|
156
|
+
SpindleAPI,
|
|
157
|
+
FrontendProcessHandle,
|
|
158
|
+
BackendProcessHandle,
|
|
159
|
+
SpindleBackendProcessContext,
|
|
160
|
+
SpindleBackendProcessModule,
|
|
161
|
+
} from "./spindle-api";
|
|
140
162
|
|
|
141
163
|
export type {
|
|
142
164
|
CouncilMember,
|
package/src/spindle-api.ts
CHANGED
|
@@ -53,6 +53,16 @@ import type {
|
|
|
53
53
|
SpindleModalItemDTO,
|
|
54
54
|
SpindleCommandDTO,
|
|
55
55
|
SpindleCommandContextDTO,
|
|
56
|
+
FrontendProcessSpawnOptionsDTO,
|
|
57
|
+
FrontendProcessListOptionsDTO,
|
|
58
|
+
FrontendProcessInfoDTO,
|
|
59
|
+
FrontendProcessLifecycleEventDTO,
|
|
60
|
+
FrontendProcessStopOptionsDTO,
|
|
61
|
+
BackendProcessSpawnOptionsDTO,
|
|
62
|
+
BackendProcessListOptionsDTO,
|
|
63
|
+
BackendProcessInfoDTO,
|
|
64
|
+
BackendProcessLifecycleEventDTO,
|
|
65
|
+
BackendProcessStopOptionsDTO,
|
|
56
66
|
GenerationStartedPayloadDTO,
|
|
57
67
|
StreamTokenPayloadDTO,
|
|
58
68
|
GenerationEndedPayloadDTO,
|
|
@@ -70,6 +80,79 @@ import type {
|
|
|
70
80
|
MessageContentProcessorResultDTO,
|
|
71
81
|
} from "./api";
|
|
72
82
|
|
|
83
|
+
export interface FrontendProcessHandle {
|
|
84
|
+
/** Host-assigned process ID unique within the extension runtime. */
|
|
85
|
+
readonly processId: string;
|
|
86
|
+
/** Frontend handler key the process was spawned against. */
|
|
87
|
+
readonly kind: string;
|
|
88
|
+
/** Optional extension-defined stable key. */
|
|
89
|
+
readonly key?: string;
|
|
90
|
+
/** Current known snapshot at the time the handle was created or last refreshed. */
|
|
91
|
+
readonly info: FrontendProcessInfoDTO;
|
|
92
|
+
/** Send a process-scoped message to the frontend instance. */
|
|
93
|
+
send(payload: unknown): void;
|
|
94
|
+
/** Request graceful termination. */
|
|
95
|
+
stop(options?: FrontendProcessStopOptionsDTO): Promise<void>;
|
|
96
|
+
/** Fetch the latest authoritative snapshot from the host. */
|
|
97
|
+
refresh(): Promise<FrontendProcessInfoDTO | null>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface BackendProcessHandle {
|
|
101
|
+
/** Host-assigned process ID unique within the extension runtime. */
|
|
102
|
+
readonly processId: string;
|
|
103
|
+
/** Built subprocess entry file spawned by the host. */
|
|
104
|
+
readonly entry: string;
|
|
105
|
+
/** Logical process kind used for filtering and dedupe semantics. */
|
|
106
|
+
readonly kind: string;
|
|
107
|
+
/** Optional extension-defined stable key. */
|
|
108
|
+
readonly key?: string;
|
|
109
|
+
/** Current known snapshot at the time the handle was created or last refreshed. */
|
|
110
|
+
readonly info: BackendProcessInfoDTO;
|
|
111
|
+
/** Send a process-scoped message to the isolated subprocess. */
|
|
112
|
+
send(payload: unknown): void;
|
|
113
|
+
/** Request graceful termination. */
|
|
114
|
+
stop(options?: BackendProcessStopOptionsDTO): Promise<void>;
|
|
115
|
+
/** Fetch the latest authoritative snapshot from the host. */
|
|
116
|
+
refresh(): Promise<BackendProcessInfoDTO | null>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Controller passed to a backend subprocess entry exported by the extension. */
|
|
120
|
+
export interface SpindleBackendProcessContext {
|
|
121
|
+
/** Host-assigned ID unique within the extension runtime. */
|
|
122
|
+
processId: string;
|
|
123
|
+
/** Built entry file the host spawned. */
|
|
124
|
+
entry: string;
|
|
125
|
+
/** Logical process kind supplied during spawn. */
|
|
126
|
+
kind: string;
|
|
127
|
+
/** Optional extension-defined stable key passed at spawn time. */
|
|
128
|
+
key?: string;
|
|
129
|
+
/** Arbitrary spawn payload provided by the parent backend runtime. */
|
|
130
|
+
payload: unknown;
|
|
131
|
+
/** Optional backend-side bookkeeping metadata snapshot. */
|
|
132
|
+
metadata?: Record<string, unknown>;
|
|
133
|
+
/** Target user for operator-scoped spawns. */
|
|
134
|
+
userId?: string;
|
|
135
|
+
/** Signal that startup completed successfully. Required for startup watchdogs. */
|
|
136
|
+
ready(): void;
|
|
137
|
+
/** Refresh the host-side heartbeat timer for long-lived loops. */
|
|
138
|
+
heartbeat(): void;
|
|
139
|
+
/** Send a process-scoped message back to the parent backend runtime. */
|
|
140
|
+
send(payload: unknown): void;
|
|
141
|
+
/** Subscribe to process-scoped messages from the parent backend runtime. */
|
|
142
|
+
onMessage(handler: (payload: unknown) => void): () => void;
|
|
143
|
+
/** Mark the subprocess as completed and release host tracking. */
|
|
144
|
+
complete(result?: unknown): void;
|
|
145
|
+
/** Mark the subprocess as failed. */
|
|
146
|
+
fail(error: string): void;
|
|
147
|
+
/** Called when the parent backend runtime requests graceful termination. */
|
|
148
|
+
onStop(handler: (detail: { reason?: string }) => void): () => void;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type SpindleBackendProcessModule = {
|
|
152
|
+
default?: (process: SpindleBackendProcessContext) => void | (() => void) | Promise<void | (() => void)>;
|
|
153
|
+
run?: (process: SpindleBackendProcessContext) => void | (() => void) | Promise<void | (() => void)>;
|
|
154
|
+
};
|
|
155
|
+
|
|
73
156
|
/** The global `spindle` object available in backend extension workers */
|
|
74
157
|
export interface SpindleAPI {
|
|
75
158
|
/** Subscribe to generation-started events (requires `generation` permission). The optional `userId` identifies which user triggered the event. */
|
|
@@ -815,6 +898,69 @@ export interface SpindleAPI {
|
|
|
815
898
|
/** Receive messages from the frontend module (userId is the sender) */
|
|
816
899
|
onFrontendMessage(handler: (payload: unknown, userId: string) => void): () => void;
|
|
817
900
|
|
|
901
|
+
/**
|
|
902
|
+
* Backend-owned lifecycle controller for tracked frontend processes.
|
|
903
|
+
*
|
|
904
|
+
* Use this when the frontend needs to run one or more long-lived loops,
|
|
905
|
+
* workers, or UI-adjacent controllers whose liveness must be observable from
|
|
906
|
+
* the backend runtime. The frontend side registers handlers by `kind` via
|
|
907
|
+
* `ctx.processes.register(kind, handler)`.
|
|
908
|
+
*
|
|
909
|
+
* This is layered on top of the existing backend/frontend messaging model,
|
|
910
|
+
* but adds startup acknowledgement, heartbeat timeouts, process-scoped
|
|
911
|
+
* messaging, and structured lifecycle events.
|
|
912
|
+
*/
|
|
913
|
+
frontendProcesses: {
|
|
914
|
+
/**
|
|
915
|
+
* Spawn a frontend process and wait for the frontend handler to call
|
|
916
|
+
* `process.ready()`. If `startupTimeoutMs` elapses first, the promise
|
|
917
|
+
* rejects and the process transitions to `timed_out`.
|
|
918
|
+
*/
|
|
919
|
+
spawn(options: FrontendProcessSpawnOptionsDTO): Promise<FrontendProcessHandle>;
|
|
920
|
+
/** List tracked frontend processes visible to this extension runtime. */
|
|
921
|
+
list(filter?: FrontendProcessListOptionsDTO): Promise<FrontendProcessInfoDTO[]>;
|
|
922
|
+
/** Get a single tracked process by ID. Returns `null` if it no longer exists. */
|
|
923
|
+
get(processId: string): Promise<FrontendProcessInfoDTO | null>;
|
|
924
|
+
/** Request graceful termination of a tracked process. */
|
|
925
|
+
stop(processId: string, options?: FrontendProcessStopOptionsDTO): Promise<void>;
|
|
926
|
+
/** Subscribe to lifecycle transitions (`starting`, `running`, `timed_out`, etc.). */
|
|
927
|
+
onLifecycle(handler: (event: FrontendProcessLifecycleEventDTO) => void): () => void;
|
|
928
|
+
/** Receive process-scoped messages sent from the frontend side. */
|
|
929
|
+
onMessage(
|
|
930
|
+
handler: (event: { processId: string; payload: unknown; userId: string }) => void,
|
|
931
|
+
): () => void;
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Host-owned lifecycle controller for isolated backend subprocesses.
|
|
936
|
+
*
|
|
937
|
+
* Use this when one slice of backend extension logic may block or hang and
|
|
938
|
+
* you need the host to retain kill authority via startup and heartbeat
|
|
939
|
+
* watchdogs. The spawned entry receives a
|
|
940
|
+
* {@link SpindleBackendProcessContext} and communicates only with its parent
|
|
941
|
+
* backend runtime through process-scoped messages.
|
|
942
|
+
*/
|
|
943
|
+
backendProcesses: {
|
|
944
|
+
/**
|
|
945
|
+
* Spawn an isolated backend subprocess and wait for the entry to call
|
|
946
|
+
* `process.ready()`. If `startupTimeoutMs` elapses first, the promise
|
|
947
|
+
* rejects and the process transitions to `timed_out`.
|
|
948
|
+
*/
|
|
949
|
+
spawn(options: BackendProcessSpawnOptionsDTO): Promise<BackendProcessHandle>;
|
|
950
|
+
/** List tracked backend subprocesses visible to this extension runtime. */
|
|
951
|
+
list(filter?: BackendProcessListOptionsDTO): Promise<BackendProcessInfoDTO[]>;
|
|
952
|
+
/** Get a single tracked subprocess by ID. Returns `null` if it no longer exists. */
|
|
953
|
+
get(processId: string): Promise<BackendProcessInfoDTO | null>;
|
|
954
|
+
/** Request graceful termination of a tracked subprocess. */
|
|
955
|
+
stop(processId: string, options?: BackendProcessStopOptionsDTO): Promise<void>;
|
|
956
|
+
/** Subscribe to lifecycle transitions (`starting`, `running`, `timed_out`, etc.). */
|
|
957
|
+
onLifecycle(handler: (event: BackendProcessLifecycleEventDTO) => void): () => void;
|
|
958
|
+
/** Receive process-scoped messages sent from the subprocess entry. */
|
|
959
|
+
onMessage(
|
|
960
|
+
handler: (event: { processId: string; payload: unknown; userId: string }) => void,
|
|
961
|
+
): () => void;
|
|
962
|
+
};
|
|
963
|
+
|
|
818
964
|
/** Logging */
|
|
819
965
|
log: {
|
|
820
966
|
info(msg: string): void;
|
|
@@ -1005,14 +1151,15 @@ export interface SpindleAPI {
|
|
|
1005
1151
|
* Unlike `apply()`, this method does not let extensions push raw CSS
|
|
1006
1152
|
* variables. Lumiverse derives the full light/dark variable maps from the
|
|
1007
1153
|
* provided accent and preserves the user's glass, radius, font, and UI
|
|
1008
|
-
* scale settings.
|
|
1154
|
+
* scale settings. Pass `null` to clear the extension's active palette
|
|
1155
|
+
* override when no valid color data is available.
|
|
1009
1156
|
*/
|
|
1010
|
-
applyPalette(palette: ThemePaletteConfigDTO, userId?: string): Promise<void>;
|
|
1157
|
+
applyPalette(palette: ThemePaletteConfigDTO | null, userId?: string): Promise<void>;
|
|
1011
1158
|
/**
|
|
1012
1159
|
* Remove all CSS variable overrides previously applied by this extension.
|
|
1013
1160
|
* The UI reverts to the user's base theme.
|
|
1014
1161
|
*/
|
|
1015
|
-
clear(): Promise<void>;
|
|
1162
|
+
clear(userId?: string): Promise<void>;
|
|
1016
1163
|
/**
|
|
1017
1164
|
* Get a read-only snapshot of the user's current theme configuration.
|
|
1018
1165
|
* Returns the base theme info (not including any extension overrides).
|