@kittl/sdk 0.0.2 → 0.0.3

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.
@@ -12,6 +12,12 @@ var isStatelessPushMessage = (data) => {
12
12
  var isAIGenerationUpdatePushMessage = (data) => {
13
13
  return typeof data === "object" && data !== null && "command" in data && data.command === "ai-generation-update" && "subscriptionId" in data && typeof data.subscriptionId === "string" && "update" in data && typeof data.update === "object" && data.update !== null;
14
14
  };
15
+ var isDesignStateUpdatePushMessage = (data) => {
16
+ return typeof data === "object" && data !== null && "command" in data && data.command === "design-state-update" && "updates" in data && Array.isArray(data.updates);
17
+ };
18
+ var isAppStateUpdatePushMessage = (data) => {
19
+ return typeof data === "object" && data !== null && "command" in data && data.command === "app-state-update" && "updates" in data && Array.isArray(data.updates);
20
+ };
15
21
 
16
22
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/shared/createApiProxyCore.js
17
23
  var buildMethodPath = (rootPrefix, pathSegments) => {
@@ -278,6 +284,71 @@ function createAIApiProxy() {
278
284
  };
279
285
  }
280
286
 
287
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/appState/index.js
288
+ var sendUnsubscribe = (selectorIds) => {
289
+ const message = {
290
+ command: "app-state-unsubscribe",
291
+ selectorIds
292
+ };
293
+ postMessageToParent(message);
294
+ };
295
+ var createAppStateBridgeApi = () => {
296
+ const localSubscriptions = /* @__PURE__ */ new Map();
297
+ async function subscribe(paths, callback) {
298
+ if (paths.length === 0) {
299
+ return () => {
300
+ };
301
+ }
302
+ const values = new Array(paths.length).fill(void 0);
303
+ const selectorIds = [];
304
+ const pathArrays = [];
305
+ for (const dotPath of paths) {
306
+ const segments = dotPath.split(".");
307
+ if (segments.some((s) => s === "")) {
308
+ throw new Error(
309
+ `Invalid app state path: '${dotPath}'. Path must be a non-empty dot-separated string.`
310
+ );
311
+ }
312
+ selectorIds.push(generateMessageId());
313
+ pathArrays.push(segments);
314
+ }
315
+ const messageId = generateMessageId();
316
+ const subscribeMessage = {
317
+ command: "app-state-subscribe",
318
+ messageId,
319
+ selectorIds,
320
+ paths: pathArrays
321
+ };
322
+ const response = await sendMessage(subscribeMessage);
323
+ if (!response.isOk) {
324
+ throw new Error(`app-state-subscribe failed: ${response.error.message}`);
325
+ }
326
+ for (let i = 0; i < selectorIds.length; i++) {
327
+ localSubscriptions.set(selectorIds[i], {
328
+ callback: (value) => {
329
+ values[i] = value;
330
+ callback(...values);
331
+ }
332
+ });
333
+ }
334
+ return () => {
335
+ for (const selectorId of selectorIds) {
336
+ localSubscriptions.delete(selectorId);
337
+ }
338
+ sendUnsubscribe(selectorIds);
339
+ };
340
+ }
341
+ const dispatch = (updates) => {
342
+ for (const { selectorId, value } of updates) {
343
+ const entry = localSubscriptions.get(selectorId);
344
+ if (entry) {
345
+ entry.callback(value);
346
+ }
347
+ }
348
+ };
349
+ return { subscribe, dispatch };
350
+ };
351
+
281
352
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/authBridge/index.js
282
353
  var hashPKCECode = async (input) => {
283
354
  const textAsBuffer = new TextEncoder().encode(input);
@@ -370,6 +441,118 @@ var createAuthBridgeApi = () => {
370
441
  };
371
442
  };
372
443
 
444
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/batch/index.js
445
+ var createBatch = async () => {
446
+ const response = await sendMessage({
447
+ command: "batch-create",
448
+ messageId: generateMessageId()
449
+ });
450
+ if (!response.isOk) {
451
+ throw response.error;
452
+ }
453
+ const { batchKey } = response.result;
454
+ const sendDesignCall = (dots, args) => sendMessage({
455
+ command: "sdk-call",
456
+ dots,
457
+ args,
458
+ messageId: generateMessageId(),
459
+ apiType: "design",
460
+ batchKey
461
+ });
462
+ const commit = async () => {
463
+ const res = await sendMessage({
464
+ command: "batch-commit",
465
+ messageId: generateMessageId(),
466
+ batchKey
467
+ });
468
+ if (!res.isOk) {
469
+ throw res.error;
470
+ }
471
+ };
472
+ const buildNode = (pathSegments) => {
473
+ const target = () => {
474
+ };
475
+ return new Proxy(target, {
476
+ get: (_t, prop) => {
477
+ if (typeof prop === "symbol" || prop === "then") return void 0;
478
+ if (prop === "commit") return commit;
479
+ return buildNode([...pathSegments, prop]);
480
+ },
481
+ apply: (_t, _this, args) => {
482
+ return sendDesignCall(pathSegments, args);
483
+ }
484
+ });
485
+ };
486
+ return buildNode([]);
487
+ };
488
+
489
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/designState/index.js
490
+ var sendUnsubscribe2 = (selectorIds) => {
491
+ const message = {
492
+ command: "design-state-unsubscribe",
493
+ selectorIds
494
+ };
495
+ postMessageToParent(message);
496
+ };
497
+ var createDesignStateBridgeApi = () => {
498
+ const localSubscriptions = /* @__PURE__ */ new Map();
499
+ async function subscribe(paths, callback) {
500
+ if (paths.length === 0) {
501
+ return () => {
502
+ };
503
+ }
504
+ const values = new Array(paths.length).fill(void 0);
505
+ const selectorIds = [];
506
+ const pathArrays = [];
507
+ for (const dotPath of paths) {
508
+ const segments = dotPath.split(".");
509
+ if (segments.some((s) => s === "")) {
510
+ throw new Error(
511
+ `Invalid design state path: '${dotPath}'. Path must be a non-empty dot-separated string.`
512
+ );
513
+ }
514
+ selectorIds.push(generateMessageId());
515
+ pathArrays.push(segments);
516
+ }
517
+ const messageId = generateMessageId();
518
+ const subscribeMessage = {
519
+ command: "design-state-subscribe",
520
+ messageId,
521
+ selectorIds,
522
+ paths: pathArrays
523
+ };
524
+ const response = await sendMessage(subscribeMessage);
525
+ if (!response.isOk) {
526
+ throw new Error(
527
+ `design-state-subscribe failed: ${response.error.message}`
528
+ );
529
+ }
530
+ for (let i = 0; i < selectorIds.length; i++) {
531
+ localSubscriptions.set(selectorIds[i], {
532
+ callback: (value) => {
533
+ values[i] = value;
534
+ callback(...values);
535
+ }
536
+ });
537
+ }
538
+ return () => {
539
+ for (const selectorId of selectorIds) {
540
+ localSubscriptions.delete(selectorId);
541
+ }
542
+ sendUnsubscribe2(selectorIds);
543
+ };
544
+ }
545
+ const dispatch = (updates) => {
546
+ for (const { selectorId, value } of updates) {
547
+ const entry = localSubscriptions.get(selectorId);
548
+ if (entry) {
549
+ entry.callback(value);
550
+ }
551
+ }
552
+ };
553
+ return { subscribe, dispatch };
554
+ };
555
+
373
556
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/stateless/index.js
374
557
  var createStatelessBridgeApi = () => {
375
558
  const subscribers = /* @__PURE__ */ new Map();
@@ -422,6 +605,8 @@ var createStatelessBridgeApi = () => {
422
605
 
423
606
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers.js
424
607
  var statelessApi = createStatelessBridgeApi();
608
+ var designStateApi = createDesignStateBridgeApi();
609
+ var appStateApi = createAppStateBridgeApi();
425
610
  var handleIncomingMessage = (event) => {
426
611
  const parent = window.parent;
427
612
  if (!parent || parent === window) {
@@ -448,16 +633,27 @@ var handleIncomingMessage = (event) => {
448
633
  dispatchAIGenerationUpdate(data.subscriptionId, data.update);
449
634
  return;
450
635
  }
636
+ if (isDesignStateUpdatePushMessage(data)) {
637
+ designStateApi.dispatch(data.updates);
638
+ return;
639
+ }
640
+ if (isAppStateUpdatePushMessage(data)) {
641
+ appStateApi.dispatch(data.updates);
642
+ return;
643
+ }
451
644
  };
452
645
  var bridgeHandlers = {
453
646
  ai: createAIApiProxy(),
454
647
  context: createApiProxy("context"),
455
648
  design: createApiProxy("design"),
649
+ designStore: designStateApi,
650
+ appStore: appStateApi,
456
651
  font: createApiProxy("font"),
457
652
  state: createApiProxy("state"),
458
653
  upload: createApiProxy("upload"),
459
654
  auth: createAuthBridgeApi(),
460
- stateless: statelessApi
655
+ stateless: statelessApi,
656
+ createBatch
461
657
  };
462
658
 
463
659
  // src/api/utils.ts
package/dist/kittl-sdk.js CHANGED
@@ -13,6 +13,12 @@
13
13
  var isAIGenerationUpdatePushMessage = (data) => {
14
14
  return typeof data === "object" && data !== null && "command" in data && data.command === "ai-generation-update" && "subscriptionId" in data && typeof data.subscriptionId === "string" && "update" in data && typeof data.update === "object" && data.update !== null;
15
15
  };
16
+ var isDesignStateUpdatePushMessage = (data) => {
17
+ return typeof data === "object" && data !== null && "command" in data && data.command === "design-state-update" && "updates" in data && Array.isArray(data.updates);
18
+ };
19
+ var isAppStateUpdatePushMessage = (data) => {
20
+ return typeof data === "object" && data !== null && "command" in data && data.command === "app-state-update" && "updates" in data && Array.isArray(data.updates);
21
+ };
16
22
 
17
23
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/shared/createApiProxyCore.js
18
24
  var buildMethodPath = (rootPrefix, pathSegments) => {
@@ -279,6 +285,71 @@
279
285
  };
280
286
  }
281
287
 
288
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/appState/index.js
289
+ var sendUnsubscribe = (selectorIds) => {
290
+ const message = {
291
+ command: "app-state-unsubscribe",
292
+ selectorIds
293
+ };
294
+ postMessageToParent(message);
295
+ };
296
+ var createAppStateBridgeApi = () => {
297
+ const localSubscriptions = /* @__PURE__ */ new Map();
298
+ async function subscribe(paths, callback) {
299
+ if (paths.length === 0) {
300
+ return () => {
301
+ };
302
+ }
303
+ const values = new Array(paths.length).fill(void 0);
304
+ const selectorIds = [];
305
+ const pathArrays = [];
306
+ for (const dotPath of paths) {
307
+ const segments = dotPath.split(".");
308
+ if (segments.some((s) => s === "")) {
309
+ throw new Error(
310
+ `Invalid app state path: '${dotPath}'. Path must be a non-empty dot-separated string.`
311
+ );
312
+ }
313
+ selectorIds.push(generateMessageId());
314
+ pathArrays.push(segments);
315
+ }
316
+ const messageId = generateMessageId();
317
+ const subscribeMessage = {
318
+ command: "app-state-subscribe",
319
+ messageId,
320
+ selectorIds,
321
+ paths: pathArrays
322
+ };
323
+ const response = await sendMessage(subscribeMessage);
324
+ if (!response.isOk) {
325
+ throw new Error(`app-state-subscribe failed: ${response.error.message}`);
326
+ }
327
+ for (let i = 0; i < selectorIds.length; i++) {
328
+ localSubscriptions.set(selectorIds[i], {
329
+ callback: (value) => {
330
+ values[i] = value;
331
+ callback(...values);
332
+ }
333
+ });
334
+ }
335
+ return () => {
336
+ for (const selectorId of selectorIds) {
337
+ localSubscriptions.delete(selectorId);
338
+ }
339
+ sendUnsubscribe(selectorIds);
340
+ };
341
+ }
342
+ const dispatch = (updates) => {
343
+ for (const { selectorId, value } of updates) {
344
+ const entry = localSubscriptions.get(selectorId);
345
+ if (entry) {
346
+ entry.callback(value);
347
+ }
348
+ }
349
+ };
350
+ return { subscribe, dispatch };
351
+ };
352
+
282
353
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/authBridge/index.js
283
354
  var hashPKCECode = async (input) => {
284
355
  const textAsBuffer = new TextEncoder().encode(input);
@@ -371,6 +442,118 @@
371
442
  };
372
443
  };
373
444
 
445
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/batch/index.js
446
+ var createBatch = async () => {
447
+ const response = await sendMessage({
448
+ command: "batch-create",
449
+ messageId: generateMessageId()
450
+ });
451
+ if (!response.isOk) {
452
+ throw response.error;
453
+ }
454
+ const { batchKey } = response.result;
455
+ const sendDesignCall = (dots, args) => sendMessage({
456
+ command: "sdk-call",
457
+ dots,
458
+ args,
459
+ messageId: generateMessageId(),
460
+ apiType: "design",
461
+ batchKey
462
+ });
463
+ const commit = async () => {
464
+ const res = await sendMessage({
465
+ command: "batch-commit",
466
+ messageId: generateMessageId(),
467
+ batchKey
468
+ });
469
+ if (!res.isOk) {
470
+ throw res.error;
471
+ }
472
+ };
473
+ const buildNode = (pathSegments) => {
474
+ const target = () => {
475
+ };
476
+ return new Proxy(target, {
477
+ get: (_t, prop) => {
478
+ if (typeof prop === "symbol" || prop === "then") return void 0;
479
+ if (prop === "commit") return commit;
480
+ return buildNode([...pathSegments, prop]);
481
+ },
482
+ apply: (_t, _this, args) => {
483
+ return sendDesignCall(pathSegments, args);
484
+ }
485
+ });
486
+ };
487
+ return buildNode([]);
488
+ };
489
+
490
+ // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/designState/index.js
491
+ var sendUnsubscribe2 = (selectorIds) => {
492
+ const message = {
493
+ command: "design-state-unsubscribe",
494
+ selectorIds
495
+ };
496
+ postMessageToParent(message);
497
+ };
498
+ var createDesignStateBridgeApi = () => {
499
+ const localSubscriptions = /* @__PURE__ */ new Map();
500
+ async function subscribe(paths, callback) {
501
+ if (paths.length === 0) {
502
+ return () => {
503
+ };
504
+ }
505
+ const values = new Array(paths.length).fill(void 0);
506
+ const selectorIds = [];
507
+ const pathArrays = [];
508
+ for (const dotPath of paths) {
509
+ const segments = dotPath.split(".");
510
+ if (segments.some((s) => s === "")) {
511
+ throw new Error(
512
+ `Invalid design state path: '${dotPath}'. Path must be a non-empty dot-separated string.`
513
+ );
514
+ }
515
+ selectorIds.push(generateMessageId());
516
+ pathArrays.push(segments);
517
+ }
518
+ const messageId = generateMessageId();
519
+ const subscribeMessage = {
520
+ command: "design-state-subscribe",
521
+ messageId,
522
+ selectorIds,
523
+ paths: pathArrays
524
+ };
525
+ const response = await sendMessage(subscribeMessage);
526
+ if (!response.isOk) {
527
+ throw new Error(
528
+ `design-state-subscribe failed: ${response.error.message}`
529
+ );
530
+ }
531
+ for (let i = 0; i < selectorIds.length; i++) {
532
+ localSubscriptions.set(selectorIds[i], {
533
+ callback: (value) => {
534
+ values[i] = value;
535
+ callback(...values);
536
+ }
537
+ });
538
+ }
539
+ return () => {
540
+ for (const selectorId of selectorIds) {
541
+ localSubscriptions.delete(selectorId);
542
+ }
543
+ sendUnsubscribe2(selectorIds);
544
+ };
545
+ }
546
+ const dispatch = (updates) => {
547
+ for (const { selectorId, value } of updates) {
548
+ const entry = localSubscriptions.get(selectorId);
549
+ if (entry) {
550
+ entry.callback(value);
551
+ }
552
+ }
553
+ };
554
+ return { subscribe, dispatch };
555
+ };
556
+
374
557
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers/stateless/index.js
375
558
  var createStatelessBridgeApi = () => {
376
559
  const subscribers = /* @__PURE__ */ new Map();
@@ -423,6 +606,8 @@
423
606
 
424
607
  // ../../packages/editor-core/sdk/sdk-bridge/dist/bridge/sandboxed/handlers.js
425
608
  var statelessApi = createStatelessBridgeApi();
609
+ var designStateApi = createDesignStateBridgeApi();
610
+ var appStateApi = createAppStateBridgeApi();
426
611
  var handleIncomingMessage = (event) => {
427
612
  const parent = window.parent;
428
613
  if (!parent || parent === window) {
@@ -449,16 +634,27 @@
449
634
  dispatchAIGenerationUpdate(data.subscriptionId, data.update);
450
635
  return;
451
636
  }
637
+ if (isDesignStateUpdatePushMessage(data)) {
638
+ designStateApi.dispatch(data.updates);
639
+ return;
640
+ }
641
+ if (isAppStateUpdatePushMessage(data)) {
642
+ appStateApi.dispatch(data.updates);
643
+ return;
644
+ }
452
645
  };
453
646
  var bridgeHandlers = {
454
647
  ai: createAIApiProxy(),
455
648
  context: createApiProxy("context"),
456
649
  design: createApiProxy("design"),
650
+ designStore: designStateApi,
651
+ appStore: appStateApi,
457
652
  font: createApiProxy("font"),
458
653
  state: createApiProxy("state"),
459
654
  upload: createApiProxy("upload"),
460
655
  auth: createAuthBridgeApi(),
461
- stateless: statelessApi
656
+ stateless: statelessApi,
657
+ createBatch
462
658
  };
463
659
 
464
660
  // src/api/utils.ts
package/dist/sdk.d.ts CHANGED
@@ -51,7 +51,7 @@ declare const BASIC_SHAPE_DEFAULT_VALUES: {
51
51
  locked?: boolean | undefined;
52
52
  hidden?: boolean | undefined;
53
53
  opacity?: number | undefined;
54
- stroke?: string;
54
+ stroke?: string | null;
55
55
  strokeWidth?: number;
56
56
  fill?: ColorInfo[] | undefined;
57
57
  scalingCorners?: boolean | undefined;
@@ -68,7 +68,7 @@ declare const BasicShapeType: {
68
68
  };
69
69
  declare const DEFAULT_VALUES$1: {
70
70
  globalCompositeOperation: BlendMode;
71
- stroke?: string;
71
+ stroke?: string | null;
72
72
  strokeWidth?: number;
73
73
  shadowOptions?: {
74
74
  color?: string | undefined | null;
@@ -123,7 +123,7 @@ declare const DEFAULT_VALUES$2: {
123
123
  offset?: number;
124
124
  angle?: number;
125
125
  };
126
- stroke?: string;
126
+ stroke?: string | null;
127
127
  strokeWidth?: number;
128
128
  opacity?: number | undefined;
129
129
  width: number;
@@ -166,7 +166,7 @@ declare const DEFAULT_VALUES: {
166
166
  presets?: LinkedPreset[] | undefined;
167
167
  opacity?: number | undefined;
168
168
  hiddenColors?: Record<string, NonNullable<Color>> | undefined;
169
- stroke?: string;
169
+ stroke?: string | null;
170
170
  strokeWidth?: number;
171
171
  fill?: ColorInfo[] | undefined;
172
172
  locked?: boolean | undefined;
@@ -226,7 +226,7 @@ declare const ILLUSTRATION_DEFAULT_VALUES: {
226
226
  gradients?: StateGradientInfo | undefined;
227
227
  presets?: LinkedPreset[] | undefined;
228
228
  opacity?: number | undefined;
229
- stroke?: string;
229
+ stroke?: string | null;
230
230
  strokeWidth?: number;
231
231
  fill?: ColorInfo[] | undefined;
232
232
  inLoadingStage?: boolean | undefined;
@@ -332,10 +332,9 @@ declare const PATH_TEXT_DEFAULT_VALUES: {
332
332
  type: ObjectType.PathText;
333
333
  };
334
334
  declare const RICH_TEXT_DEFAULT_VALUES: {
335
- activeTransformPlugin?: object | undefined;
336
335
  presets?: LinkedPreset[] | undefined;
337
336
  opacity?: number | undefined;
338
- stroke?: string;
337
+ stroke?: string | null;
339
338
  strokeWidth?: number;
340
339
  fill?: Color | undefined;
341
340
  locked?: boolean | undefined;
@@ -514,7 +513,8 @@ declare enum Origin {
514
513
  CANVAS = 2,
515
514
  UI = 4,
516
515
  VOLATILE = 8,
517
- EVENTS_SYNC = 16
516
+ EVENTS_SYNC = 16,
517
+ API = 32
518
518
  }
519
519
  declare enum TextAlignment {
520
520
  right = "right",
@@ -542,6 +542,7 @@ export interface AIGenerationInputSettings {
542
542
  id: string;
543
543
  };
544
544
  additionalParams?: Record<string, unknown>;
545
+ actionOrigin?: AIGenerationActionOrigin;
545
546
  type: AIGenerationContentType;
546
547
  }
547
548
  export interface AIGenerationOutputSettings {
@@ -578,6 +579,34 @@ export interface AsyncAIAPI {
578
579
  }
579
580
  export interface AsyncAppStateAPI extends WithAsync<AppStateAPI> {
580
581
  }
582
+ export interface AsyncAppStateSubscriptionAPI {
583
+ /**
584
+ * Subscribe to one or more paths in the app state.
585
+ * Each path is a dot-separated string like `'selectedObjectsIds'`.
586
+ * The callback receives the current value at each path as positional
587
+ * arguments whenever any subscribed value changes.
588
+ * Returns a single unsubscribe function that tears down all subscriptions.
589
+ *
590
+ * @example
591
+ * // Single path
592
+ * const unsub = await kittl.appStore.subscribe(
593
+ * ['selectedObjectsIds'],
594
+ * (ids) => console.log('selection changed:', ids)
595
+ * );
596
+ *
597
+ * // Multiple paths
598
+ * const unsub = await kittl.appStore.subscribe(
599
+ * ['selectedObjectsIds', 'activeTool'],
600
+ * (ids, tool) => console.log('changed:', ids, tool)
601
+ * );
602
+ * unsub();
603
+ */
604
+ subscribe<T extends readonly AppStateSelectorPath[]>(paths: [
605
+ ...T
606
+ ], callback: (...values: {
607
+ [K in keyof T]: T[K] extends string ? DeepValue<AppState, T[K]> | undefined : unknown;
608
+ }) => void): Promise<() => void>;
609
+ }
581
610
  export interface AsyncAuthAPI {
582
611
  startAuth: (request: AuthStartRequest) => Promise<SdkResult<AuthStartResult>>;
583
612
  exchangeCode: (request: AuthExchangeRequest) => Promise<SdkResult<AuthTokenResponse>>;
@@ -585,10 +614,41 @@ export interface AsyncAuthAPI {
585
614
  refreshToken: (request: AuthRefreshRequest) => Promise<SdkResult<AuthTokenResponse>>;
586
615
  logout: (request: AuthLogoutRequest) => Promise<SdkResult<void>>;
587
616
  }
617
+ export interface AsyncBatchDesignAPI extends AsyncDesignAPI {
618
+ commit: () => Promise<void>;
619
+ }
588
620
  export interface AsyncContextAPI extends WithAsync<ContextAPI> {
589
621
  }
590
622
  export interface AsyncDesignAPI extends WithAsync<WithOptsRemoved<DesignAPI>> {
591
623
  }
624
+ export interface AsyncDesignStateAPI {
625
+ /**
626
+ * Subscribe to one or more paths in the design state.
627
+ * Each path is a dot-separated string like `'objects.id1.width'`.
628
+ * The callback receives the current value at each path as positional
629
+ * arguments whenever any subscribed value changes.
630
+ * Returns a single unsubscribe function that tears down all subscriptions.
631
+ *
632
+ * @example
633
+ * // Single path
634
+ * const unsub = await kittl.designStore.subscribe(
635
+ * ['objects.id1.width'],
636
+ * (width) => console.log('width changed:', width)
637
+ * );
638
+ *
639
+ * // Multiple paths
640
+ * const unsub = await kittl.designStore.subscribe(
641
+ * ['objects.id1.width', 'objects.id1.height'],
642
+ * (width, height) => console.log('changed:', width, height)
643
+ * );
644
+ * unsub();
645
+ */
646
+ subscribe<T extends readonly DesignStateSelectorPath[]>(paths: [
647
+ ...T
648
+ ], callback: (...values: {
649
+ [K in keyof T]: T[K] extends string ? DeepValue<SelectorState, T[K]> | undefined : unknown;
650
+ }) => void): Promise<() => void>;
651
+ }
592
652
  export interface AsyncFontAPI extends WithAsync<FontAPI> {
593
653
  }
594
654
  export interface AsyncStatelessAPI {
@@ -837,6 +897,7 @@ export interface GetExportOptions {
837
897
  height: number;
838
898
  };
839
899
  };
900
+ removeArtboardBackground?: boolean;
840
901
  }
841
902
  export interface GetObjectParams {
842
903
  id: string;
@@ -906,6 +967,7 @@ export interface ImageGenerationStartedResult extends GenerationStartedResultCom
906
967
  type: typeof ResultType.IMAGE;
907
968
  }
908
969
  export interface KittlContext {
970
+ colorScheme: EditorColorScheme;
909
971
  dragAndDrop: {
910
972
  offset: DragAndDropOffset;
911
973
  };
@@ -916,6 +978,8 @@ export interface KittlSDK {
916
978
  onReady: (cb: () => void) => void;
917
979
  ai: AsyncAIAPI;
918
980
  design: AsyncDesignAPI;
981
+ designStore: AsyncDesignStateAPI;
982
+ appStore: AsyncAppStateSubscriptionAPI;
919
983
  context: AsyncContextAPI;
920
984
  dragAndDrop: PublicDragAndDropAPI;
921
985
  state: AsyncAppStateAPI;
@@ -923,6 +987,7 @@ export interface KittlSDK {
923
987
  upload: AsyncUploadAPI;
924
988
  stateless: AsyncStatelessAPI;
925
989
  font: AsyncFontAPI;
990
+ createBatch: () => Promise<AsyncBatchDesignAPI>;
926
991
  }
927
992
  export interface LayersAPI {
928
993
  moveTo(input: MoveToParams, opts?: DesignApiOptions): void;
@@ -1002,6 +1067,24 @@ export interface RemoveObjectParams {
1002
1067
  export interface RemoveObjectResult {
1003
1068
  removedObject: NormalizedObject;
1004
1069
  }
1070
+ export interface RichTextCompressedStylesV1 {
1071
+ version: "v1";
1072
+ [lineIndex: LineIndex]: {
1073
+ charsAt: CharacterIndex[];
1074
+ styles: Partial<RichTextSerializedCharacterStyle>;
1075
+ }[];
1076
+ }
1077
+ export interface RichTextCompressedStylesV2 {
1078
+ version: "v2";
1079
+ customStyles: Record<string, Partial<RichTextSerializedCharacterStyle>>;
1080
+ [lineIndex: LineIndex]: {
1081
+ charsAt: [
1082
+ CharacterIndex,
1083
+ SequenceLength
1084
+ ][];
1085
+ styleId: string;
1086
+ }[];
1087
+ }
1005
1088
  export interface RotateObjectParams {
1006
1089
  id: string;
1007
1090
  angle: number;
@@ -1168,6 +1251,7 @@ export interface WithObjectLayout {
1168
1251
  flipX: boolean;
1169
1252
  flipY: boolean;
1170
1253
  }
1254
+ export type AIGenerationActionOrigin = "COPILOT" | "RIGHT_PANEL" | "LEFT_PANEL" | "MICRO_APP" | "IMAGE_SETS" | "AI_CHAT" | "SMARTBOARD" | "AI_INPUT_GENERATE_IMAGE" | "AI_INPUT_REMIX_IMAGE" | "AI_INPUT_GENERATE_VIDEO" | "AI_HUB_GENERATE_IMAGE" | "AI_HUB_REMIX_IMAGE" | "AI_HUB_GENERATE_VIDEO" | "VIDEOBOARD";
1171
1255
  export type AIGenerationContentType = "image" | "video";
1172
1256
  export type AIGenerationModelTaskType = "IMAGE_TO_IMAGE" | "IMAGE_INPAINT" | "TEXT_TO_IMAGE" | "IMAGE_TO_VIDEO";
1173
1257
  export type APIOptions<T extends Record<string, unknown>> = {
@@ -1267,6 +1351,20 @@ export type AppState = {
1267
1351
  viewport: Viewport;
1268
1352
  highlightedObjectId: string | null;
1269
1353
  };
1354
+ /**
1355
+ * A dot-separated string path into the app state.
1356
+ * The first segment must be a valid top-level key of AppState.
1357
+ *
1358
+ * @example
1359
+ * 'selectedObjectsIds'
1360
+ * 'viewport.coords.tl.x'
1361
+ * 'activeTool.type'
1362
+ */
1363
+ export type AppStateSelectorPath = AppStateTopLevelKey | `${AppStateTopLevelKey}.${string}`;
1364
+ /**
1365
+ * Top-level keys of AppState that extensions can subscribe to.
1366
+ */
1367
+ export type AppStateTopLevelKey = keyof AppState;
1270
1368
  export type ArtboardLikeType = ObjectType.Artboard | ObjectType.MockupBoard | ObjectType.Smartboard | ObjectType.Videoboard;
1271
1369
  export type ArtboardOptions = StandardArtboardOptions | SmartboardOptions | MockupBoardOptions | VideoboardOptions;
1272
1370
  export type AvailableShadowOptions = Partial<Pick<ShadowOptions, "blur">> & Omit<ShadowOptions, "blur">;
@@ -1298,6 +1396,7 @@ export type BasicShapeType = (typeof BasicShapeType)[keyof typeof BasicShapeType
1298
1396
  export type BridgedSdkResult<T> = T extends SdkResult<infer _R, infer _E> ? T : SdkResult<T, Error>;
1299
1397
  export type Builtin = Date | Function | Uint8Array | RegExp | Map<unknown, unknown> | Set<unknown>;
1300
1398
  export type CanvasMode = "erase" | "crop" | "reframe" | "inpaint" | null;
1399
+ export type CharacterIndex = number;
1301
1400
  export type CloneArtboardParams = {
1302
1401
  boardId: string;
1303
1402
  position: CreateElementWithPositionAndSize["position"];
@@ -1344,8 +1443,34 @@ export type CreateShapeInput = CreateElementWithPositionAndSize & {
1344
1443
  export type DeepPartial<T> = {
1345
1444
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
1346
1445
  };
1446
+ /**
1447
+ * Resolves a dot-separated string path against a type `T`.
1448
+ *
1449
+ * For `Record<string, V>` intermediaries (e.g. `objects`), any string
1450
+ * key is accepted and the type continues into `V`.
1451
+ *
1452
+ * @example
1453
+ * DeepValue<SelectorState, 'objects.id1.width'> // number | undefined
1454
+ * DeepValue<SelectorState, 'config'> // DesignConfig
1455
+ * DeepValue<AppState, 'viewport.coords.tl.x'> // number
1456
+ */
1457
+ export type DeepValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? DeepValue<NonNullable<T[K]>, Rest> : T extends Record<string, infer V> ? DeepValue<NonNullable<V>, Rest> : undefined : P extends keyof T ? T[P] : T extends Record<string, infer V> ? V : undefined;
1347
1458
  export type DesignApiOptions = APIOptions<NormalizedDesignState>;
1348
1459
  export type DesignObjectId = string;
1460
+ /**
1461
+ * A dot-separated string path into the design state.
1462
+ * The first segment must be a valid top-level key of NormalizedDesignState.
1463
+ *
1464
+ * @example
1465
+ * 'objects.id1.width'
1466
+ * 'config.title'
1467
+ * 'boards.board1.backgroundColor'
1468
+ */
1469
+ export type DesignStateSelectorPath = DesignStateTopLevelKey | `${DesignStateTopLevelKey}.${string}`;
1470
+ /**
1471
+ * Top-level keys of NormalizedDesignState that extensions can subscribe to.
1472
+ */
1473
+ export type DesignStateTopLevelKey = keyof NormalizedDesignState;
1349
1474
  export type DesignStructureObject = {
1350
1475
  id?: StructureObjectId | null;
1351
1476
  meta?: StructureObjectMeta;
@@ -1355,11 +1480,16 @@ export type Dimensions = {
1355
1480
  width: number;
1356
1481
  height: number;
1357
1482
  };
1483
+ export type EditorColorScheme = "light" | "dark";
1358
1484
  export type ElementLocation = "origin" | "center";
1359
1485
  export type Expand<T> = T extends infer O ? {
1360
1486
  [K in keyof O]: O[K];
1361
1487
  } : never;
1362
1488
  export type FillMetaTarget = "border" | "fill";
1489
+ export type FlattenUnion<T> = UnionToIntersection<T extends unknown ? Partial<T> : never>;
1490
+ export type FontVariationAxis = OrAnyString<"wght" | "wdth" | "slnt" | "ital" | "opsz" | "GRAD">;
1491
+ export type FontVariationSettings = Partial<Record<FontVariationAxis, number>>;
1492
+ export type FontWeight = OrAnyString<"Regular" | "Bold" | "Light" | "Medium" | "Black" | "SemiBold" | "Italic" | "ExtraLight" | "Thin" | "ExtraBold" | "LightItalic" | "MediumItalic" | "SemiBoldItalic" | "BlackItalic" | "ExtraBoldItalic" | "ThinItalic" | "ExtraLightItalic" | "BoldItalic">;
1363
1493
  export type FullColor = {
1364
1494
  key: "fill" | (Exclude<string, StringColorKeysType> & {});
1365
1495
  value: Color;
@@ -1392,6 +1522,8 @@ export type GuideSerializedObject = typeof GUIDE_DEFAULT_VALUES & OrientationDir
1392
1522
  export type ID = string;
1393
1523
  export type IllustrationImageSerializedObject = typeof DEFAULT_VALUES$1 & {
1394
1524
  backgroundRemoved?: boolean | undefined;
1525
+ objectNameWithBackground?: string;
1526
+ backgroundRestorePathBoundary?: number | undefined;
1395
1527
  realWidth?: number | undefined;
1396
1528
  realHeight?: number | undefined;
1397
1529
  erasePaths?: {
@@ -1429,6 +1561,7 @@ export type InternalPatchArgs<T> = {
1429
1561
  patch: PatchTree<T> | PatchTree<T>[];
1430
1562
  origin: Origin;
1431
1563
  historyOrigin?: HistoryOrigins;
1564
+ transactionMeta?: TransactionMeta;
1432
1565
  };
1433
1566
  export type LayerIconType = "drawIcon";
1434
1567
  export type LayerType = Exclude<SerializableObjectType, ObjectType.Guide> | typeof structuralGroupType | typeof clippingMaskType | typeof backgroundType | typeof pathType;
@@ -1437,6 +1570,12 @@ export type LeftTopPosition = {
1437
1570
  left: number;
1438
1571
  top: number;
1439
1572
  };
1573
+ export type LineHeight = {
1574
+ value: number;
1575
+ unit: LineHeightUnit;
1576
+ };
1577
+ export type LineHeightUnit = "px" | "%";
1578
+ export type LineIndex = number;
1440
1579
  export type LinkedPreset = {
1441
1580
  id: string;
1442
1581
  libraryId: string;
@@ -1531,6 +1670,7 @@ export type NullablePathTextShadowOptions = PathTextShadowOptions | {
1531
1670
  type: null;
1532
1671
  };
1533
1672
  export type OnGenerationStatusUpdate = (update: GenerationStatusUpdate) => void | Promise<void>;
1673
+ export type OrAnyString<T extends string> = T | (string & {});
1534
1674
  export type OrientationConditional = {
1535
1675
  orientation: Orientation.HORIZONTAL;
1536
1676
  top: number;
@@ -1639,21 +1779,78 @@ export type RichTextBasePluginSerializedObject = {
1639
1779
  name: string;
1640
1780
  version: string;
1641
1781
  };
1782
+ export type RichTextCompressedColor = string | GradientObject | null;
1783
+ export type RichTextCompressedStyles = RichTextCompressedStylesV1 | RichTextCompressedStylesV2;
1642
1784
  export type RichTextDecorationPluginSerializedObject = RichTextBasePluginSerializedObject & {
1643
1785
  fillStyle: string;
1644
1786
  [key: string]: string | number;
1645
1787
  };
1788
+ export type RichTextHyperlinkSerializedObject = {
1789
+ id: string;
1790
+ url: string;
1791
+ };
1646
1792
  export type RichTextRenderPluginSerializedObject = RichTextBasePluginSerializedObject & {
1647
1793
  color: string;
1648
1794
  angle: number;
1649
1795
  offset: number;
1650
1796
  [key: string]: string | number;
1651
1797
  };
1798
+ export type RichTextResizeBehavior = "hug" | "none" | "hug-height";
1799
+ export type RichTextSerializedCharacterStyle = Partial<{
1800
+ fontFamily: string;
1801
+ fontWeight: FontWeight;
1802
+ fontSize: number;
1803
+ fill: RichTextCompressedColor;
1804
+ underline: boolean;
1805
+ linethrough: boolean;
1806
+ charSpacing: number;
1807
+ textCase: TextCase;
1808
+ lineHeightValue: LineHeight;
1809
+ hyperlinkId: string | null;
1810
+ preLinkFill: RichTextCompressedColor;
1811
+ fontVariationSettings: FontVariationSettings;
1812
+ fontFeatureSettings: Record<string, boolean | number>;
1813
+ }>;
1652
1814
  export type RichTextSerializedObject = typeof RICH_TEXT_DEFAULT_VALUES & {
1653
1815
  text: string;
1816
+ fontFamily: string;
1817
+ styles?: RichTextCompressedStyles;
1654
1818
  activeRenderPlugins?: RichTextRenderPluginSerializedObject[];
1655
1819
  activeDecorationPlugins?: RichTextDecorationPluginSerializedObject[];
1656
- [key: string]: unknown;
1820
+ activeTransformPlugin?: RichTextSerializedTransformPluginObject;
1821
+ fontSize?: number;
1822
+ fontWeight?: FontWeight;
1823
+ textAlign?: TextAlign;
1824
+ charSpacing?: number;
1825
+ underline?: boolean;
1826
+ linethrough?: boolean;
1827
+ fontVariationSettings?: FontVariationSettings;
1828
+ textCase?: TextCase;
1829
+ lineHeightValue?: LineHeight;
1830
+ untransformedWidth?: number;
1831
+ widthBeforeTransform?: number;
1832
+ resizeBehavior?: RichTextResizeBehavior;
1833
+ hyperlinkId?: string;
1834
+ preLinkFill?: string | GradientObject | null;
1835
+ fontFeatureSettings?: Record<string, boolean | number>;
1836
+ links?: RichTextHyperlinkSerializedObject[];
1837
+ volatileData?: {
1838
+ top: number;
1839
+ left: number;
1840
+ width: number;
1841
+ height: number;
1842
+ activeTransformPlugin: RichTextSerializedTransformPluginObject;
1843
+ key: string;
1844
+ };
1845
+ };
1846
+ export type RichTextSerializedTransformPluginObject = RichTextBasePluginSerializedObject & {
1847
+ type?: string;
1848
+ points: {
1849
+ x: number;
1850
+ y: number;
1851
+ }[];
1852
+ curveHeight?: number;
1853
+ directionInverted?: boolean;
1657
1854
  };
1658
1855
  export type ScreenCoordinates = {
1659
1856
  x: number;
@@ -1679,9 +1876,18 @@ export type SdkResultAsync<T, E = SdkError> = Promise<{
1679
1876
  error: E;
1680
1877
  }>;
1681
1878
  export type Selector<T, U = unknown> = (state: T) => U;
1879
+ /**
1880
+ * The design state shape exposed to string path selectors.
1881
+ * `objects` values are flattened so that variant-specific properties
1882
+ * (e.g. `width`, `fill`) are accessible without manual narrowing.
1883
+ */
1884
+ export type SelectorState = Omit<NormalizedDesignState, "objects"> & {
1885
+ objects: Record<string, FlattenUnion<NormalizedObject>>;
1886
+ };
1682
1887
  export type SendToParams = {
1683
1888
  boardOrObjectIds: string[];
1684
1889
  };
1890
+ export type SequenceLength = number;
1685
1891
  export type SerialisedPhotoFilter = ({
1686
1892
  type: ImageFilterType;
1687
1893
  } & PhotoFilterOptions[ImageFilterType]) | {
@@ -1775,13 +1981,15 @@ export type TempUserImageUpload = {
1775
1981
  objectId: string;
1776
1982
  mimeType: string;
1777
1983
  };
1984
+ export type TextAlign = "left" | "center" | "right" | "justify" | "justify-left" | "justify-center" | "justify-right" | "justify-legacy";
1985
+ export type TextCase = "none" | "uppercase";
1778
1986
  export type TextProperties = {
1779
1987
  fontFamily?: string;
1780
1988
  fontSize?: number;
1781
- fontWeight?: string | number;
1989
+ fontWeight?: string;
1782
1990
  fill?: Color;
1783
1991
  textAlign?: "left" | "center" | "right" | "justify";
1784
- lineHeight?: number;
1992
+ lineHeightValue?: LineHeight;
1785
1993
  resizeBehavior?: "none" | "hug" | "hug-height";
1786
1994
  charSpacing?: number;
1787
1995
  underline?: boolean;
@@ -1793,6 +2001,16 @@ export type TextProperties = {
1793
2001
  stroke?: string;
1794
2002
  strokeWidth?: number;
1795
2003
  };
2004
+ export type TransactionMeta = {
2005
+ isLocal: boolean;
2006
+ isUndoRedo: boolean;
2007
+ };
2008
+ /**
2009
+ * Collapses a union type into a single object type where:
2010
+ * - Properties shared by all members keep their original type.
2011
+ * - Properties that exist only on some members become optional.
2012
+ */
2013
+ export type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
1796
2014
  export type UpdateArtboardBackgroundParams = {
1797
2015
  id: string;
1798
2016
  objectName: string;
@@ -1882,6 +2100,7 @@ export type UpdateVideoPlaylistItemParams = {
1882
2100
  videoId: string;
1883
2101
  playlistItemId: string;
1884
2102
  playlistItem: Omit<VideoPlaylistItem, "id">;
2103
+ allowAspectRatioMismatch?: boolean;
1885
2104
  };
1886
2105
  export type UpdateVideoboardParams = {
1887
2106
  videoBoardId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kittl/sdk",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "license": "Apache-2.0",
5
5
  "private": false,
6
6
  "type": "module",
@@ -22,5 +22,8 @@
22
22
  "dist",
23
23
  "README.md",
24
24
  "LICENSE"
25
- ]
25
+ ],
26
+ "scripts": {
27
+ "deploy": "bash ../../scripts/npm-publish.sh"
28
+ }
26
29
  }