@stina/extension-api 0.26.0 → 0.28.0

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/src/runtime.ts CHANGED
@@ -25,8 +25,6 @@ import type {
25
25
  ChatInstructionMessage,
26
26
  StorageAPI,
27
27
  SecretsAPI,
28
- Query,
29
- QueryOptions,
30
28
  LogAPI,
31
29
  AIProvider,
32
30
  Tool,
@@ -51,6 +49,14 @@ import type {
51
49
 
52
50
  import { generateMessageId } from './messages.js'
53
51
 
52
+ import {
53
+ buildExtensionStorageAPI,
54
+ buildUserStorageAPI,
55
+ buildExtensionSecretsAPI,
56
+ buildUserSecretsAPI,
57
+ createExecutionContext,
58
+ } from './runtime/index.js'
59
+
54
60
  // ============================================================================
55
61
  // Environment Detection and Message Port
56
62
  // ============================================================================
@@ -329,136 +335,11 @@ function handleSettingsChanged(key: string, value: unknown): void {
329
335
  }
330
336
  }
331
337
 
332
- /**
333
- * Build extension-scoped storage API
334
- */
335
- function buildExtensionStorageAPI(): StorageAPI {
336
- return {
337
- async put<T extends object>(collection: string, id: string, data: T): Promise<void> {
338
- return sendRequest<void>('storage.put', { collection, id, data })
339
- },
340
- async get<T>(collection: string, id: string): Promise<T | undefined> {
341
- return sendRequest<T | undefined>('storage.get', { collection, id })
342
- },
343
- async delete(collection: string, id: string): Promise<boolean> {
344
- return sendRequest<boolean>('storage.delete', { collection, id })
345
- },
346
- async find<T>(collection: string, query?: Query, options?: QueryOptions): Promise<T[]> {
347
- return sendRequest<T[]>('storage.find', { collection, query, options })
348
- },
349
- async findOne<T>(collection: string, query: Query): Promise<T | undefined> {
350
- return sendRequest<T | undefined>('storage.findOne', { collection, query })
351
- },
352
- async count(collection: string, query?: Query): Promise<number> {
353
- return sendRequest<number>('storage.count', { collection, query })
354
- },
355
- async putMany<T extends object>(collection: string, docs: Array<{ id: string; data: T }>): Promise<void> {
356
- return sendRequest<void>('storage.putMany', { collection, docs })
357
- },
358
- async deleteMany(collection: string, query: Query): Promise<number> {
359
- return sendRequest<number>('storage.deleteMany', { collection, query })
360
- },
361
- async dropCollection(collection: string): Promise<void> {
362
- return sendRequest<void>('storage.dropCollection', { collection })
363
- },
364
- async listCollections(): Promise<string[]> {
365
- return sendRequest<string[]>('storage.listCollections', {})
366
- },
367
- }
368
- }
369
-
370
- /**
371
- * Build user-scoped storage API
372
- */
373
- function buildUserStorageAPI(userId: string): StorageAPI {
374
- return {
375
- async put<T extends object>(collection: string, id: string, data: T): Promise<void> {
376
- return sendRequest<void>('storage.putForUser', { userId, collection, id, data })
377
- },
378
- async get<T>(collection: string, id: string): Promise<T | undefined> {
379
- return sendRequest<T | undefined>('storage.getForUser', { userId, collection, id })
380
- },
381
- async delete(collection: string, id: string): Promise<boolean> {
382
- return sendRequest<boolean>('storage.deleteForUser', { userId, collection, id })
383
- },
384
- async find<T>(collection: string, query?: Query, options?: QueryOptions): Promise<T[]> {
385
- return sendRequest<T[]>('storage.findForUser', { userId, collection, query, options })
386
- },
387
- async findOne<T>(collection: string, query: Query): Promise<T | undefined> {
388
- return sendRequest<T | undefined>('storage.findOneForUser', { userId, collection, query })
389
- },
390
- async count(collection: string, query?: Query): Promise<number> {
391
- return sendRequest<number>('storage.countForUser', { userId, collection, query })
392
- },
393
- async putMany<T extends object>(collection: string, docs: Array<{ id: string; data: T }>): Promise<void> {
394
- return sendRequest<void>('storage.putManyForUser', { userId, collection, docs })
395
- },
396
- async deleteMany(collection: string, query: Query): Promise<number> {
397
- return sendRequest<number>('storage.deleteManyForUser', { userId, collection, query })
398
- },
399
- async dropCollection(collection: string): Promise<void> {
400
- return sendRequest<void>('storage.dropCollectionForUser', { userId, collection })
401
- },
402
- async listCollections(): Promise<string[]> {
403
- return sendRequest<string[]>('storage.listCollectionsForUser', { userId })
404
- },
405
- }
406
- }
407
-
408
- /**
409
- * Build extension-scoped secrets API
410
- */
411
- function buildExtensionSecretsAPI(): SecretsAPI {
412
- return {
413
- async set(key: string, value: string): Promise<void> {
414
- return sendRequest<void>('secrets.set', { key, value })
415
- },
416
- async get(key: string): Promise<string | undefined> {
417
- return sendRequest<string | undefined>('secrets.get', { key })
418
- },
419
- async delete(key: string): Promise<boolean> {
420
- return sendRequest<boolean>('secrets.delete', { key })
421
- },
422
- async list(): Promise<string[]> {
423
- return sendRequest<string[]>('secrets.list', {})
424
- },
425
- }
426
- }
427
-
428
- /**
429
- * Build user-scoped secrets API
430
- */
431
- function buildUserSecretsAPI(userId: string): SecretsAPI {
432
- return {
433
- async set(key: string, value: string): Promise<void> {
434
- return sendRequest<void>('secrets.setForUser', { userId, key, value })
435
- },
436
- async get(key: string): Promise<string | undefined> {
437
- return sendRequest<string | undefined>('secrets.getForUser', { userId, key })
438
- },
439
- async delete(key: string): Promise<boolean> {
440
- return sendRequest<boolean>('secrets.deleteForUser', { userId, key })
441
- },
442
- async list(): Promise<string[]> {
443
- return sendRequest<string[]>('secrets.listForUser', { userId })
444
- },
445
- }
446
- }
338
+ // Storage and Secrets APIs are now in runtime/storageApi.ts and runtime/secretsApi.ts
339
+ // ExecutionContext builder is in runtime/executionContext.ts
447
340
 
448
341
  async function handleSchedulerFire(payload: SchedulerFirePayload): Promise<void> {
449
- // Create request-scoped execution context with storage and secrets
450
- const execContext: ExecutionContext = {
451
- userId: payload.userId,
452
- extension: {
453
- id: extensionContext!.extension.id,
454
- version: extensionContext!.extension.version,
455
- storagePath: extensionContext!.extension.storagePath,
456
- },
457
- storage: buildExtensionStorageAPI(),
458
- userStorage: payload.userId ? buildUserStorageAPI(payload.userId) : buildExtensionStorageAPI(),
459
- secrets: buildExtensionSecretsAPI(),
460
- userSecrets: payload.userId ? buildUserSecretsAPI(payload.userId) : buildExtensionSecretsAPI(),
461
- }
342
+ const execContext = createExecutionContext(sendRequest, extensionContext!, payload.userId)
462
343
 
463
344
  // Run callbacks concurrently to avoid blocking
464
345
  const results = await Promise.allSettled(
@@ -624,19 +505,7 @@ async function handleToolExecuteRequest(
624
505
  }
625
506
 
626
507
  try {
627
- // Create request-scoped execution context with storage and secrets
628
- const execContext: ExecutionContext = {
629
- userId: payload.userId,
630
- extension: {
631
- id: extensionContext!.extension.id,
632
- version: extensionContext!.extension.version,
633
- storagePath: extensionContext!.extension.storagePath,
634
- },
635
- storage: buildExtensionStorageAPI(),
636
- userStorage: payload.userId ? buildUserStorageAPI(payload.userId) : buildExtensionStorageAPI(),
637
- secrets: buildExtensionSecretsAPI(),
638
- userSecrets: payload.userId ? buildUserSecretsAPI(payload.userId) : buildExtensionSecretsAPI(),
639
- }
508
+ const execContext = createExecutionContext(sendRequest, extensionContext!, payload.userId)
640
509
 
641
510
  const result = await tool.execute(payload.params, execContext)
642
511
 
@@ -679,19 +548,7 @@ async function handleActionExecuteRequest(
679
548
  }
680
549
 
681
550
  try {
682
- // Create request-scoped execution context with storage and secrets
683
- const execContext: ExecutionContext = {
684
- userId: payload.userId,
685
- extension: {
686
- id: extensionContext!.extension.id,
687
- version: extensionContext!.extension.version,
688
- storagePath: extensionContext!.extension.storagePath,
689
- },
690
- storage: buildExtensionStorageAPI(),
691
- userStorage: payload.userId ? buildUserStorageAPI(payload.userId) : buildExtensionStorageAPI(),
692
- secrets: buildExtensionSecretsAPI(),
693
- userSecrets: payload.userId ? buildUserSecretsAPI(payload.userId) : buildExtensionSecretsAPI(),
694
- }
551
+ const execContext = createExecutionContext(sendRequest, extensionContext!, payload.userId)
695
552
 
696
553
  const result = await action.execute(payload.params, execContext)
697
554
 
@@ -966,12 +823,12 @@ function buildContext(
966
823
 
967
824
  // Add storage API if permitted (new collection-based storage)
968
825
  if (hasPermission('storage.collections')) {
969
- ;(context as { storage: StorageAPI }).storage = buildExtensionStorageAPI()
826
+ ;(context as { storage: StorageAPI }).storage = buildExtensionStorageAPI(sendRequest)
970
827
  }
971
828
 
972
829
  // Add secrets API if permitted
973
830
  if (hasPermission('secrets.manage')) {
974
- ;(context as { secrets: SecretsAPI }).secrets = buildExtensionSecretsAPI()
831
+ ;(context as { secrets: SecretsAPI }).secrets = buildExtensionSecretsAPI(sendRequest)
975
832
  }
976
833
 
977
834
  // Add background workers API if permitted
@@ -1024,10 +881,10 @@ function buildContext(
1024
881
  error: (message, data) =>
1025
882
  postMessage({ type: 'log', payload: { level: 'error', message: `[${taskId}] ${message}`, data } }),
1026
883
  }),
1027
- createStorageAPI: () => buildExtensionStorageAPI(),
1028
- createUserStorageAPI: (userId) => buildUserStorageAPI(userId),
1029
- createSecretsAPI: () => buildExtensionSecretsAPI(),
1030
- createUserSecretsAPI: (userId) => buildUserSecretsAPI(userId),
884
+ createStorageAPI: () => buildExtensionStorageAPI(sendRequest),
885
+ createUserStorageAPI: (userId) => buildUserStorageAPI(sendRequest, userId),
886
+ createSecretsAPI: () => buildExtensionSecretsAPI(sendRequest),
887
+ createUserSecretsAPI: (userId) => buildUserSecretsAPI(sendRequest, userId),
1031
888
  })
1032
889
  }
1033
890
 
@@ -251,6 +251,17 @@ export const SelectPropsSchema = z
251
251
  .passthrough()
252
252
  .describe('Select component')
253
253
 
254
+ export const IconPickerPropsSchema = z
255
+ .object({
256
+ component: z.literal('IconPicker'),
257
+ label: z.string().optional().describe('Picker label'),
258
+ value: z.string().optional().describe('Currently selected icon name'),
259
+ onChangeAction: ExtensionActionRefSchema.describe('Action to call on change'),
260
+ style: ExtensionComponentStyleSchema.optional(),
261
+ })
262
+ .passthrough()
263
+ .describe('IconPicker component')
264
+
254
265
  export const VerticalStackPropsSchema = z
255
266
  .object({
256
267
  component: z.literal('VerticalStack'),
@@ -449,6 +460,7 @@ export type ButtonProps = z.infer<typeof ButtonPropsSchema>
449
460
  export type TextInputProps = z.infer<typeof TextInputPropsSchema>
450
461
  export type DateTimeInputProps = z.infer<typeof DateTimeInputPropsSchema>
451
462
  export type SelectProps = z.infer<typeof SelectPropsSchema>
463
+ export type IconPickerProps = z.infer<typeof IconPickerPropsSchema>
452
464
  export type VerticalStackProps = z.infer<typeof VerticalStackPropsSchema>
453
465
  export type HorizontalStackProps = z.infer<typeof HorizontalStackPropsSchema>
454
466
  export type GridProps = z.infer<typeof GridPropsSchema>
@@ -113,6 +113,7 @@ export {
113
113
  TextInputPropsSchema,
114
114
  DateTimeInputPropsSchema,
115
115
  SelectPropsSchema,
116
+ IconPickerPropsSchema,
116
117
  VerticalStackPropsSchema,
117
118
  HorizontalStackPropsSchema,
118
119
  GridPropsSchema,
@@ -145,6 +146,7 @@ export {
145
146
  type TextInputProps,
146
147
  type DateTimeInputProps,
147
148
  type SelectProps,
149
+ type IconPickerProps,
148
150
  type VerticalStackProps,
149
151
  type HorizontalStackProps,
150
152
  type GridProps,
@@ -283,6 +283,14 @@ export interface SelectProps extends ExtensionComponentData {
283
283
  onChangeAction: ExtensionActionRef
284
284
  }
285
285
 
286
+ /** The extension API properties for the IconPicker component. */
287
+ export interface IconPickerProps extends ExtensionComponentData {
288
+ component: 'IconPicker'
289
+ label?: string
290
+ value?: string
291
+ onChangeAction: ExtensionActionRef
292
+ }
293
+
286
294
  /** The extension API properties for the VerticalStack component. */
287
295
  export interface VerticalStackProps extends ExtensionComponentData {
288
296
  component: 'VerticalStack'