lumiverse-spindle-types 0.6.2 → 0.6.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumiverse-spindle-types",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "types": "./src/index.ts",
5
5
  "keywords": [
6
6
  "lumiverse",
package/src/api.ts CHANGED
@@ -1101,6 +1101,14 @@ export interface PromptBlockCategoryGroupDTO {
1101
1101
  children: PromptBlockDTO[];
1102
1102
  }
1103
1103
 
1104
+ export interface HostResponseErrorDTO {
1105
+ code: string;
1106
+ message: string;
1107
+ presetId?: string;
1108
+ expectedCacheRevision?: number;
1109
+ actualCacheRevision?: number;
1110
+ }
1111
+
1104
1112
  export interface UserPresetDTO {
1105
1113
  id: string;
1106
1114
  name: string;
@@ -1110,6 +1118,7 @@ export interface UserPresetDTO {
1110
1118
  prompt_order: PromptBlockDTO[];
1111
1119
  prompts: Record<string, unknown>;
1112
1120
  metadata: Record<string, unknown>;
1121
+ cache_revision: number;
1113
1122
  created_at: number;
1114
1123
  updated_at: number;
1115
1124
  }
@@ -1124,7 +1133,9 @@ export interface UserPresetCreateDTO {
1124
1133
  metadata?: Record<string, unknown>;
1125
1134
  }
1126
1135
 
1127
- export type UserPresetUpdateDTO = Partial<UserPresetCreateDTO>;
1136
+ export type UserPresetUpdateDTO = Partial<UserPresetCreateDTO> & {
1137
+ expected_cache_revision: number;
1138
+ };
1128
1139
  export type PromptBlockCreateDTO = Partial<PromptBlockDTO>;
1129
1140
  export type PromptBlockUpdateDTO = Partial<Omit<PromptBlockDTO, "id">>;
1130
1141
 
@@ -3234,7 +3245,7 @@ export type HostToWorker =
3234
3245
  type: "response";
3235
3246
  requestId: string;
3236
3247
  result?: unknown;
3237
- error?: string;
3248
+ error?: string | HostResponseErrorDTO;
3238
3249
  }
3239
3250
  | {
3240
3251
  type: "permission_denied";
package/src/components.ts CHANGED
@@ -22,6 +22,33 @@
22
22
  * Components inherit the active Lumiverse theme via CSS variables, so they
23
23
  * visually match the rest of the host UI without any additional wiring.
24
24
  */
25
+ import type { PromptBlockDTO, PromptVariableValuesDTO } from "./api";
26
+
27
+ // ──────────────────────────────────────────────────────────────────────────
28
+ // Loom block editor
29
+ // ──────────────────────────────────────────────────────────────────────────
30
+
31
+ /** Editable public value rendered by the native Loom block editor. */
32
+ export interface SpindleLoomBlockEditorValue {
33
+ blocks: PromptBlockDTO[];
34
+ promptVariableValues: PromptVariableValuesDTO;
35
+ }
36
+
37
+ /** Controlled options for the native Loom block editor. */
38
+ export interface SpindleLoomBlockEditorOptions {
39
+ value: SpindleLoomBlockEditorValue;
40
+ onChange?: (value: SpindleLoomBlockEditorValue) => void;
41
+ readOnly?: boolean;
42
+ compact?: boolean;
43
+ }
44
+
45
+ /** Handle returned by `mountLoomBlockEditor`. */
46
+ export interface SpindleLoomBlockEditorHandle
47
+ extends SpindleMountedComponent<SpindleLoomBlockEditorOptions> {
48
+ getValue(): SpindleLoomBlockEditorValue;
49
+ refreshMacros(): Promise<void>;
50
+ }
51
+
25
52
 
26
53
  // ──────────────────────────────────────────────────────────────────────────
27
54
  // Shared base shapes
@@ -39,10 +66,7 @@ export interface SpindleMountedComponent<TOptions> {
39
66
  readonly componentId: string;
40
67
  /** The container element the component was mounted into. Same node passed as `target`. */
41
68
  readonly element: HTMLElement;
42
- /**
43
- * Merge a partial set of options into the live component. Pass any subset of
44
- * the original mount options — undefined fields are ignored.
45
- */
69
+ /** Merge supplied option fields into the live component. Omitted fields remain unchanged. */
46
70
  update(patch: Partial<TOptions>): void;
47
71
  /** Unmount the React tree and release host resources. The target element is left in place. */
48
72
  destroy(): void;
@@ -655,4 +679,9 @@ export interface SpindleComponentsHelper {
655
679
  mountCollapsibleSection(target: SpindleComponentTarget, options: SpindleCollapsibleSectionOptions): SpindleCollapsibleSectionHandle;
656
680
  mountPagination(target: SpindleComponentTarget, options: SpindlePaginationOptions): SpindlePaginationHandle;
657
681
  mountCloseButton(target: SpindleComponentTarget, options?: SpindleCloseButtonOptions): SpindleCloseButtonHandle;
682
+ // Loom editor
683
+ mountLoomBlockEditor(
684
+ target: SpindleComponentTarget,
685
+ options: SpindleLoomBlockEditorOptions,
686
+ ): SpindleLoomBlockEditorHandle;
658
687
  }
package/src/dom.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PromptBlockDTO, RequestInitDTO } from "./api";
1
+ import type { PromptBlockDTO, PromptVariableValuesDTO, RequestInitDTO } from "./api";
2
2
  import type { SpindleComponentsHelper } from "./components";
3
3
 
4
4
  /** A chat-message DOM element paired with its stable message id. */
@@ -221,6 +221,21 @@ export interface SpindlePresetEditorTabHandle {
221
221
  onActivate(handler: () => void): () => void;
222
222
  }
223
223
 
224
+ /** Extension-owned root placed above Loom's list and editor branches. */
225
+ export interface SpindlePresetEditorToolbarItemOptions {
226
+ /** Unique toolbar item identifier within the current extension. */
227
+ id: string;
228
+ /** Required accessible label for the extension-owned toolbar root. */
229
+ ariaLabel: string;
230
+ }
231
+
232
+ export interface SpindlePresetEditorToolbarItemHandle {
233
+ readonly root: HTMLElement;
234
+ readonly itemId: string;
235
+ setVisible(visible: boolean): void;
236
+ destroy(): void;
237
+ }
238
+
224
239
  /** Mutable, editor-native snapshot of the current Loom preset draft. */
225
240
  export interface SpindlePresetEditorDraft {
226
241
  id: string;
@@ -259,6 +274,38 @@ export interface SpindlePresetEditorHelper {
259
274
  ): void;
260
275
  /** Immediately persist and await any pending draft changes. */
261
276
  flush(): Promise<void>;
277
+ /**
278
+ * Cooperative, extension-identifier-scoped metadata access. This does not
279
+ * sandbox same-origin extension code; it prevents accidental whole-draft
280
+ * writes through the supported helper.
281
+ */
282
+ readonly extension: SpindlePresetEditorScopedHelper;
283
+ }
284
+
285
+ export type SpindlePresetEditorBuiltinTabId = "blocks";
286
+
287
+ export interface SpindlePresetEditorExtensionState {
288
+ readonly open: boolean;
289
+ readonly presetId: string | null;
290
+ readonly activeTabId: string | null;
291
+ /** Detached array cloned from the host draft. */
292
+ readonly blocks: readonly PromptBlockDTO[];
293
+ /** Detached prompt-variable values cloned from the host draft. */
294
+ readonly promptVariableValues: Readonly<PromptVariableValuesDTO>;
295
+ /** The raw metadata value currently owned by the calling extension. */
296
+ readonly metadata: unknown;
297
+ }
298
+
299
+ export interface SpindlePresetEditorScopedHelper {
300
+ getState(): SpindlePresetEditorExtensionState;
301
+ onChange(handler: (state: SpindlePresetEditorExtensionState) => void): () => void;
302
+ setMetadata(value: Record<string, unknown>, options?: SpindlePresetEditorSaveOptions): void;
303
+ updateMetadata(
304
+ mutator: (current: unknown) => Record<string, unknown>,
305
+ options?: SpindlePresetEditorSaveOptions,
306
+ ): void;
307
+ activateBuiltinTab(tab: SpindlePresetEditorBuiltinTabId): void;
308
+ flush(): Promise<void>;
262
309
  }
263
310
 
264
311
  // ── Float Widget ──
@@ -824,6 +871,7 @@ export interface SpindleFrontendContext {
824
871
  registerCharacterEditorTab(options: SpindleCharacterEditorTabOptions): SpindleCharacterEditorTabHandle;
825
872
  characterEditor: SpindleCharacterEditorHelper;
826
873
  registerPresetEditorTab(options: SpindlePresetEditorTabOptions): SpindlePresetEditorTabHandle;
874
+ registerPresetEditorToolbarItem(options: SpindlePresetEditorToolbarItemOptions): SpindlePresetEditorToolbarItemHandle;
827
875
  presetEditor: SpindlePresetEditorHelper;
828
876
  createFloatWidget(options?: SpindleFloatWidgetOptions): SpindleFloatWidgetHandle;
829
877
  requestDockPanel(options: SpindleDockPanelOptions): SpindleDockPanelHandle;
package/src/index.ts CHANGED
@@ -62,6 +62,7 @@ export type {
62
62
  PromptBlockCreateDTO,
63
63
  PromptBlockUpdateDTO,
64
64
  PromptBlockCategoryGroupDTO,
65
+ HostResponseErrorDTO,
65
66
  UserPresetDTO,
66
67
  UserPresetCreateDTO,
67
68
  UserPresetUpdateDTO,
@@ -224,10 +225,15 @@ export type {
224
225
  SpindleCharacterEditorHelper,
225
226
  SpindlePresetEditorTabOptions,
226
227
  SpindlePresetEditorTabHandle,
228
+ SpindlePresetEditorToolbarItemOptions,
229
+ SpindlePresetEditorToolbarItemHandle,
227
230
  SpindlePresetEditorDraft,
228
231
  SpindlePresetEditorState,
229
232
  SpindlePresetEditorSaveOptions,
230
233
  SpindlePresetEditorHelper,
234
+ SpindlePresetEditorBuiltinTabId,
235
+ SpindlePresetEditorExtensionState,
236
+ SpindlePresetEditorScopedHelper,
231
237
  SpindleFloatWidgetOptions,
232
238
  SpindleFloatWidgetHandle,
233
239
  SpindleDockEdge,
@@ -313,6 +319,9 @@ export type {
313
319
  SpindlePaginationHandle,
314
320
  SpindleCloseButtonOptions,
315
321
  SpindleCloseButtonHandle,
322
+ SpindleLoomBlockEditorValue,
323
+ SpindleLoomBlockEditorOptions,
324
+ SpindleLoomBlockEditorHandle,
316
325
  SpindleComponentsHelper,
317
326
  } from "./components";
318
327
 
@@ -0,0 +1,31 @@
1
+ import type { SpindleFrontendContext } from "./dom";
2
+
3
+ /** Compile-time fixture for the additive preset-editor extension API. */
4
+ export function verifyPresetEditorContract(ctx: SpindleFrontendContext): void {
5
+ const toolbar = ctx.ui.registerPresetEditorToolbarItem({
6
+ id: "mode-controls",
7
+ ariaLabel: "Agent mode controls",
8
+ });
9
+ toolbar.setVisible(true);
10
+ // @ts-expect-error Extension-owned handles do not expose mutable host identity.
11
+ toolbar.itemId = "replacement";
12
+ toolbar.destroy();
13
+
14
+ const editor = ctx.ui.presetEditor.extension;
15
+ // @ts-expect-error Scoped helpers are acquired from a read-only getter.
16
+ ctx.ui.presetEditor.extension = editor;
17
+ const state = editor.getState();
18
+ state.blocks.forEach((block) => block.id);
19
+ // @ts-expect-error Snapshot identity is host-owned.
20
+ state.open = true;
21
+ // @ts-expect-error Scoped metadata is a read-only host snapshot.
22
+ state.metadata = { mode: "replacement" };
23
+
24
+ editor.setMetadata({ mode: "parallel" }, { immediate: true });
25
+ editor.updateMetadata((current) => ({
26
+ ...(current && typeof current === "object" && !Array.isArray(current) ? current : {}),
27
+ revision: 1,
28
+ }));
29
+ editor.activateBuiltinTab("blocks");
30
+ void editor.flush();
31
+ }
@@ -0,0 +1,39 @@
1
+ import type {
2
+ SpindleComponentTarget,
3
+ SpindleComponentsHelper,
4
+ SpindleLoomBlockEditorHandle,
5
+ SpindleLoomBlockEditorOptions,
6
+ SpindleLoomBlockEditorValue,
7
+ } from "lumiverse-spindle-types";
8
+
9
+ /**
10
+ * Package-root consumer fixture: this function is never called at runtime.
11
+ * Its body intentionally exercises the complete controlled Loom editor API so
12
+ * a consumer is checked against the package entry point rather than an
13
+ * internal source module.
14
+ */
15
+ export function compileLoomBlockEditorContract(
16
+ helper: SpindleComponentsHelper,
17
+ target: SpindleComponentTarget,
18
+ options: SpindleLoomBlockEditorOptions,
19
+ ): Promise<void> {
20
+ const handle: SpindleLoomBlockEditorHandle = helper.mountLoomBlockEditor(target, options);
21
+ const initial: SpindleLoomBlockEditorValue = handle.getValue();
22
+
23
+ handle.update({
24
+ value: initial,
25
+ onChange: (next: SpindleLoomBlockEditorValue) => {
26
+ const checked: SpindleLoomBlockEditorValue = next;
27
+ void checked;
28
+ },
29
+ readOnly: !options.readOnly,
30
+ compact: !options.compact,
31
+ });
32
+
33
+ const updated: SpindleLoomBlockEditorValue = handle.getValue();
34
+ const refreshed: Promise<void> = handle.refreshMacros();
35
+ handle.destroy();
36
+
37
+ void updated;
38
+ return refreshed;
39
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "outDir": "./.consumer-dist",
6
+ "declaration": false
7
+ },
8
+ "include": ["test/loom-block-editor-consumer.ts"]
9
+ }
package/tsconfig.json CHANGED
@@ -6,7 +6,8 @@
6
6
  "strict": true,
7
7
  "declaration": true,
8
8
  "skipLibCheck": true,
9
- "outDir": "./dist"
9
+ "outDir": "./dist",
10
+ "rootDir": "./src"
10
11
  },
11
12
  "include": ["src"]
12
13
  }