@get-bb/plugin-sdk 0.4.4 → 0.4.8

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.
@@ -57,6 +57,14 @@ function requireSlotId(kind, value) {
57
57
  }
58
58
  return value;
59
59
  }
60
+ function requireProviderId(kind, value) {
61
+ if (typeof value !== "string" || !PLUGIN_SLOT_ID_PATTERN.test(value)) {
62
+ throw new Error(
63
+ `${kind}: "providerId" must match ${String(PLUGIN_SLOT_ID_PATTERN)}, got ${JSON.stringify(value)}`
64
+ );
65
+ }
66
+ return value;
67
+ }
60
68
  function requireMessageDirectiveId(kind, value) {
61
69
  if (typeof value !== "string" || !PLUGIN_MESSAGE_DIRECTIVE_ID_PATTERN.test(value)) {
62
70
  throw new Error(
@@ -243,6 +251,318 @@ function collectComposerCustomization(registration, seenIds, onRejected) {
243
251
  }
244
252
  }
245
253
 
254
+ // src/internal/plugin-app-collector.ts
255
+ function collectPluginAppRegistrations(definition, onComposerCustomizationRejected = (reason) => console.warn(reason)) {
256
+ const collected = {
257
+ homepageSections: [],
258
+ settingsSections: [],
259
+ navPanels: [],
260
+ threadPanelActions: [],
261
+ newThreadPanelActions: [],
262
+ composerCustomizations: [],
263
+ pendingInteractions: [],
264
+ sidebarFooterActions: [],
265
+ threadLists: [],
266
+ threadHeaderActions: [],
267
+ fileOpeners: [],
268
+ messageDirectives: [],
269
+ messageActions: [],
270
+ providerIcons: [],
271
+ contentScripts: []
272
+ };
273
+ const seenIds = {
274
+ homepageSection: /* @__PURE__ */ new Set(),
275
+ settingsSection: /* @__PURE__ */ new Set(),
276
+ navPanel: /* @__PURE__ */ new Set(),
277
+ threadPanelAction: /* @__PURE__ */ new Set(),
278
+ newThreadPanelAction: /* @__PURE__ */ new Set(),
279
+ composerCustomization: /* @__PURE__ */ new Set(),
280
+ pendingInteraction: /* @__PURE__ */ new Set(),
281
+ sidebarFooterAction: /* @__PURE__ */ new Set(),
282
+ threadList: /* @__PURE__ */ new Set(),
283
+ threadHeaderAction: /* @__PURE__ */ new Set(),
284
+ fileOpener: /* @__PURE__ */ new Set(),
285
+ messageDirective: /* @__PURE__ */ new Set(),
286
+ messageAction: /* @__PURE__ */ new Set(),
287
+ providerIcon: /* @__PURE__ */ new Set(),
288
+ contentScript: /* @__PURE__ */ new Set()
289
+ };
290
+ definition.setup({
291
+ slots: {
292
+ homepageSection(registration) {
293
+ const kind = "slots.homepageSection";
294
+ const id = requireSlotId(kind, registration?.id);
295
+ requireUniqueId(kind, seenIds.homepageSection, id);
296
+ collected.homepageSections.push({
297
+ id,
298
+ title: requireNonEmptyString(kind, "title", registration.title),
299
+ component: requireComponent(kind, registration.component)
300
+ });
301
+ },
302
+ settingsSection(registration) {
303
+ const kind = "slots.settingsSection";
304
+ const id = requireSlotId(kind, registration?.id);
305
+ requireUniqueId(kind, seenIds.settingsSection, id);
306
+ const title = requireOptionalString(kind, "title", registration.title);
307
+ const description = requireOptionalString(
308
+ kind,
309
+ "description",
310
+ registration.description
311
+ );
312
+ collected.settingsSections.push({
313
+ id,
314
+ ...title !== void 0 ? { title } : {},
315
+ ...description !== void 0 ? { description } : {},
316
+ component: requireComponent(kind, registration.component)
317
+ });
318
+ },
319
+ navPanel(registration) {
320
+ const kind = "slots.navPanel";
321
+ const id = requireSlotId(kind, registration?.id);
322
+ requireUniqueId(kind, seenIds.navPanel, id);
323
+ const path = requireNonEmptyString(kind, "path", registration.path);
324
+ if (!PLUGIN_SLOT_ID_PATTERN.test(path)) {
325
+ throw new Error(
326
+ `${kind}: "path" must match ${String(PLUGIN_SLOT_ID_PATTERN)} (it becomes a URL segment), got ${JSON.stringify(path)}`
327
+ );
328
+ }
329
+ if (registration.headerContent !== void 0 && typeof registration.headerContent !== "function") {
330
+ throw new Error(
331
+ `${kind}: "headerContent" must be a React component function when set`
332
+ );
333
+ }
334
+ if (registration.experimental_sidebarAccessory !== void 0 && typeof registration.experimental_sidebarAccessory !== "function") {
335
+ throw new Error(
336
+ `${kind}: "experimental_sidebarAccessory" must be a React component function when set`
337
+ );
338
+ }
339
+ const experimentalFixedTabs = (() => {
340
+ if (registration.experimental_fixedTabs === void 0) return [];
341
+ if (!Array.isArray(registration.experimental_fixedTabs)) {
342
+ throw new Error(
343
+ `${kind}: "experimental_fixedTabs" must be an array when set`
344
+ );
345
+ }
346
+ const seenFixedTabIds = /* @__PURE__ */ new Set();
347
+ return registration.experimental_fixedTabs.map((value, index) => {
348
+ const fixedTabKind = `${kind}.experimental_fixedTabs[${index}]`;
349
+ const fixedTab = value;
350
+ const id2 = requireSlotId(fixedTabKind, fixedTab?.id);
351
+ requireUniqueId(fixedTabKind, seenFixedTabIds, id2);
352
+ const layout = fixedTab?.layout;
353
+ if (layout !== void 0 && layout !== "padded" && layout !== "flush") {
354
+ throw new Error(
355
+ `${fixedTabKind}: "layout" must be "padded" or "flush" when set`
356
+ );
357
+ }
358
+ return {
359
+ id: id2,
360
+ title: requireNonEmptyString(
361
+ fixedTabKind,
362
+ "title",
363
+ fixedTab?.title
364
+ ),
365
+ icon: requireNonEmptyString(
366
+ fixedTabKind,
367
+ "icon",
368
+ fixedTab?.icon
369
+ ),
370
+ component: requireComponent(fixedTabKind, fixedTab?.component),
371
+ ...layout === void 0 ? {} : { layout }
372
+ };
373
+ });
374
+ })();
375
+ collected.navPanels.push({
376
+ id,
377
+ title: requireNonEmptyString(kind, "title", registration.title),
378
+ icon: requireNonEmptyString(kind, "icon", registration.icon),
379
+ path,
380
+ component: requireComponent(kind, registration.component),
381
+ ...experimentalFixedTabs.length > 0 ? { experimental_fixedTabs: experimentalFixedTabs } : {},
382
+ ...registration.experimental_sidebarAccessory !== void 0 ? {
383
+ experimental_sidebarAccessory: registration.experimental_sidebarAccessory
384
+ } : {},
385
+ ...registration.headerContent !== void 0 ? { headerContent: registration.headerContent } : {}
386
+ });
387
+ },
388
+ threadPanelAction(registration) {
389
+ const kind = "slots.threadPanelAction";
390
+ const id = requireSlotId(kind, registration?.id);
391
+ requireUniqueId(kind, seenIds.threadPanelAction, id);
392
+ if (registration.run !== void 0 && typeof registration.run !== "function") {
393
+ throw new Error(`${kind}: "run" must be a function when set`);
394
+ }
395
+ if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
396
+ throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
397
+ }
398
+ collected.threadPanelActions.push({
399
+ id,
400
+ title: requireNonEmptyString(kind, "title", registration.title),
401
+ ...registration.icon !== void 0 ? {
402
+ icon: requireNonEmptyString(kind, "icon", registration.icon)
403
+ } : {},
404
+ component: requireComponent(kind, registration.component),
405
+ ...registration.layout !== void 0 ? { layout: registration.layout } : {},
406
+ ...registration.run !== void 0 ? { run: registration.run } : {}
407
+ });
408
+ },
409
+ experimental_newThreadPanelAction(registration) {
410
+ const kind = "slots.experimental_newThreadPanelAction";
411
+ const id = requireSlotId(kind, registration?.id);
412
+ requireUniqueId(kind, seenIds.newThreadPanelAction, id);
413
+ if (registration.run !== void 0 && typeof registration.run !== "function") {
414
+ throw new Error(`${kind}: "run" must be a function when set`);
415
+ }
416
+ if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
417
+ throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
418
+ }
419
+ collected.newThreadPanelActions.push({
420
+ id,
421
+ title: requireNonEmptyString(kind, "title", registration.title),
422
+ ...registration.icon !== void 0 ? {
423
+ icon: requireNonEmptyString(kind, "icon", registration.icon)
424
+ } : {},
425
+ component: requireComponent(kind, registration.component),
426
+ ...registration.layout !== void 0 ? { layout: registration.layout } : {},
427
+ ...registration.run !== void 0 ? { run: registration.run } : {}
428
+ });
429
+ },
430
+ pendingInteraction(registration) {
431
+ const kind = "slots.pendingInteraction";
432
+ const id = requireSlotId(kind, registration?.id);
433
+ requireUniqueId(kind, seenIds.pendingInteraction, id);
434
+ collected.pendingInteractions.push({
435
+ id,
436
+ component: requireComponent(kind, registration.component)
437
+ });
438
+ },
439
+ sidebarFooterAction(registration) {
440
+ const kind = "slots.sidebarFooterAction";
441
+ const id = requireSlotId(kind, registration?.id);
442
+ requireUniqueId(kind, seenIds.sidebarFooterAction, id);
443
+ if (typeof registration.run !== "function") {
444
+ throw new Error(`${kind}: "run" must be a function`);
445
+ }
446
+ collected.sidebarFooterActions.push({
447
+ id,
448
+ title: requireNonEmptyString(kind, "title", registration.title),
449
+ icon: requireNonEmptyString(kind, "icon", registration.icon),
450
+ run: registration.run
451
+ });
452
+ },
453
+ experimental_threadList(registration) {
454
+ const kind = "slots.experimental_threadList";
455
+ const id = requireSlotId(kind, registration?.id);
456
+ requireUniqueId(kind, seenIds.threadList, id);
457
+ const description = requireOptionalString(
458
+ kind,
459
+ "description",
460
+ registration.description
461
+ );
462
+ collected.threadLists.push({
463
+ id,
464
+ title: requireNonEmptyString(kind, "title", registration.title),
465
+ ...description !== void 0 ? { description } : {},
466
+ component: requireComponent(kind, registration.component)
467
+ });
468
+ },
469
+ experimental_threadHeaderAction(registration) {
470
+ const kind = "slots.experimental_threadHeaderAction";
471
+ const id = requireSlotId(kind, registration?.id);
472
+ requireUniqueId(kind, seenIds.threadHeaderAction, id);
473
+ collected.threadHeaderActions.push({
474
+ id,
475
+ title: requireNonEmptyString(kind, "title", registration.title),
476
+ component: requireComponent(kind, registration.component)
477
+ });
478
+ },
479
+ fileOpener(registration) {
480
+ const kind = "slots.fileOpener";
481
+ const id = requireSlotId(kind, registration?.id);
482
+ requireUniqueId(kind, seenIds.fileOpener, id);
483
+ const rawExtensions = registration?.extensions;
484
+ if (!Array.isArray(rawExtensions) || rawExtensions.length === 0) {
485
+ throw new Error(
486
+ `${kind}: "extensions" must be a non-empty array of lowercase extensions without the dot`
487
+ );
488
+ }
489
+ const extensions = rawExtensions.map((extension) => {
490
+ if (typeof extension !== "string" || !/^[a-z0-9]+$/.test(extension)) {
491
+ throw new Error(
492
+ `${kind}: extensions must be lowercase alphanumerics without the dot, got ${JSON.stringify(extension)}`
493
+ );
494
+ }
495
+ return extension;
496
+ });
497
+ collected.fileOpeners.push({
498
+ id,
499
+ title: requireNonEmptyString(kind, "title", registration.title),
500
+ extensions,
501
+ component: requireComponent(kind, registration.component)
502
+ });
503
+ },
504
+ messageDirective(registration) {
505
+ const kind = "slots.messageDirective";
506
+ const id = requireMessageDirectiveId(kind, registration?.id);
507
+ requireUniqueId(kind, seenIds.messageDirective, id);
508
+ collected.messageDirectives.push({
509
+ id,
510
+ component: requireComponent(kind, registration.component)
511
+ });
512
+ },
513
+ messageAction(registration) {
514
+ const kind = "slots.messageAction";
515
+ const id = requireSlotId(kind, registration?.id);
516
+ requireUniqueId(kind, seenIds.messageAction, id);
517
+ if (typeof registration.run !== "function") {
518
+ throw new Error(`${kind}: "run" must be a function`);
519
+ }
520
+ collected.messageActions.push({
521
+ id,
522
+ title: requireNonEmptyString(kind, "title", registration.title),
523
+ ...registration.icon !== void 0 ? {
524
+ icon: requireNonEmptyString(kind, "icon", registration.icon)
525
+ } : {},
526
+ run: registration.run
527
+ });
528
+ },
529
+ experimental_providerIcon(registration) {
530
+ const kind = "slots.experimental_providerIcon";
531
+ const providerId = requireProviderId(kind, registration?.providerId);
532
+ requireUniqueId(kind, seenIds.providerIcon, providerId);
533
+ collected.providerIcons.push({
534
+ providerId,
535
+ icon: requireComponent(kind, registration.icon)
536
+ });
537
+ }
538
+ },
539
+ composer: {
540
+ customize(registration) {
541
+ const customization = collectComposerCustomization(
542
+ registration,
543
+ seenIds.composerCustomization,
544
+ onComposerCustomizationRejected
545
+ );
546
+ if (customization !== null) {
547
+ collected.composerCustomizations.push(customization);
548
+ }
549
+ }
550
+ },
551
+ contentScripts: {
552
+ register(registration) {
553
+ const kind = "contentScripts.register";
554
+ const id = requireSlotId(kind, registration?.id);
555
+ requireUniqueId(kind, seenIds.contentScript, id);
556
+ if (typeof registration.mount !== "function") {
557
+ throw new Error(`${kind}: "mount" must be a function`);
558
+ }
559
+ collected.contentScripts.push({ id, mount: registration.mount });
560
+ }
561
+ }
562
+ });
563
+ return collected;
564
+ }
565
+
246
566
  // src/testing/app.tsx
247
567
  import { jsx, jsxs } from "react/jsx-runtime";
248
568
  function SlotLifecycleGuard({
@@ -513,262 +833,6 @@ function installTestPluginRuntime() {
513
833
  pluginSdkApp: testPluginSdkApp
514
834
  };
515
835
  }
516
- function collectRegistrations(definition) {
517
- const captured = {
518
- homepageSections: [],
519
- settingsSections: [],
520
- navPanels: [],
521
- threadPanelActions: [],
522
- newThreadPanelActions: [],
523
- composerCustomizations: [],
524
- pendingInteractions: [],
525
- sidebarFooterActions: [],
526
- threadLists: [],
527
- threadHeaderActions: [],
528
- fileOpeners: [],
529
- messageDirectives: [],
530
- messageActions: [],
531
- contentScripts: []
532
- };
533
- const seenIds = {
534
- homepageSection: /* @__PURE__ */ new Set(),
535
- settingsSection: /* @__PURE__ */ new Set(),
536
- navPanel: /* @__PURE__ */ new Set(),
537
- threadPanelAction: /* @__PURE__ */ new Set(),
538
- newThreadPanelAction: /* @__PURE__ */ new Set(),
539
- composerCustomization: /* @__PURE__ */ new Set(),
540
- pendingInteraction: /* @__PURE__ */ new Set(),
541
- sidebarFooterAction: /* @__PURE__ */ new Set(),
542
- threadList: /* @__PURE__ */ new Set(),
543
- threadHeaderAction: /* @__PURE__ */ new Set(),
544
- fileOpener: /* @__PURE__ */ new Set(),
545
- messageDirective: /* @__PURE__ */ new Set(),
546
- messageAction: /* @__PURE__ */ new Set(),
547
- contentScript: /* @__PURE__ */ new Set()
548
- };
549
- definition.setup({
550
- slots: {
551
- homepageSection(registration) {
552
- const kind = "slots.homepageSection";
553
- const id = requireSlotId(kind, registration?.id);
554
- requireUniqueId(kind, seenIds.homepageSection, id);
555
- captured.homepageSections.push({
556
- id,
557
- title: requireNonEmptyString(kind, "title", registration.title),
558
- component: requireComponent(kind, registration.component)
559
- });
560
- },
561
- settingsSection(registration) {
562
- const kind = "slots.settingsSection";
563
- const id = requireSlotId(kind, registration?.id);
564
- requireUniqueId(kind, seenIds.settingsSection, id);
565
- const title = requireOptionalString(kind, "title", registration.title);
566
- const description = requireOptionalString(
567
- kind,
568
- "description",
569
- registration.description
570
- );
571
- captured.settingsSections.push({
572
- id,
573
- ...title !== void 0 ? { title } : {},
574
- ...description !== void 0 ? { description } : {},
575
- component: requireComponent(kind, registration.component)
576
- });
577
- },
578
- navPanel(registration) {
579
- const kind = "slots.navPanel";
580
- const id = requireSlotId(kind, registration?.id);
581
- requireUniqueId(kind, seenIds.navPanel, id);
582
- const path = requireNonEmptyString(kind, "path", registration.path);
583
- if (!PLUGIN_SLOT_ID_PATTERN.test(path)) {
584
- throw new Error(
585
- `${kind}: "path" must match ${String(PLUGIN_SLOT_ID_PATTERN)} (it becomes a URL segment), got ${JSON.stringify(path)}`
586
- );
587
- }
588
- if (registration.headerContent !== void 0 && typeof registration.headerContent !== "function") {
589
- throw new Error(
590
- `${kind}: "headerContent" must be a React component function when set`
591
- );
592
- }
593
- if (registration.experimental_sidebarAccessory !== void 0 && typeof registration.experimental_sidebarAccessory !== "function") {
594
- throw new Error(
595
- `${kind}: "experimental_sidebarAccessory" must be a React component function when set`
596
- );
597
- }
598
- captured.navPanels.push({
599
- id,
600
- title: requireNonEmptyString(kind, "title", registration.title),
601
- icon: requireNonEmptyString(kind, "icon", registration.icon),
602
- path,
603
- component: requireComponent(kind, registration.component),
604
- ...registration.experimental_sidebarAccessory !== void 0 ? {
605
- experimental_sidebarAccessory: registration.experimental_sidebarAccessory
606
- } : {},
607
- ...registration.headerContent !== void 0 ? { headerContent: registration.headerContent } : {}
608
- });
609
- },
610
- threadPanelAction(registration) {
611
- const kind = "slots.threadPanelAction";
612
- const id = requireSlotId(kind, registration?.id);
613
- requireUniqueId(kind, seenIds.threadPanelAction, id);
614
- if (registration.run !== void 0 && typeof registration.run !== "function") {
615
- throw new Error(`${kind}: "run" must be a function when set`);
616
- }
617
- if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
618
- throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
619
- }
620
- captured.threadPanelActions.push({
621
- id,
622
- title: requireNonEmptyString(kind, "title", registration.title),
623
- ...registration.icon !== void 0 ? { icon: requireNonEmptyString(kind, "icon", registration.icon) } : {},
624
- component: requireComponent(kind, registration.component),
625
- ...registration.layout !== void 0 ? { layout: registration.layout } : {},
626
- ...registration.run !== void 0 ? { run: registration.run } : {}
627
- });
628
- },
629
- experimental_newThreadPanelAction(registration) {
630
- const kind = "slots.experimental_newThreadPanelAction";
631
- const id = requireSlotId(kind, registration?.id);
632
- requireUniqueId(kind, seenIds.newThreadPanelAction, id);
633
- if (registration.run !== void 0 && typeof registration.run !== "function") {
634
- throw new Error(`${kind}: "run" must be a function when set`);
635
- }
636
- if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
637
- throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
638
- }
639
- captured.newThreadPanelActions.push({
640
- id,
641
- title: requireNonEmptyString(kind, "title", registration.title),
642
- ...registration.icon !== void 0 ? { icon: requireNonEmptyString(kind, "icon", registration.icon) } : {},
643
- component: requireComponent(kind, registration.component),
644
- ...registration.layout !== void 0 ? { layout: registration.layout } : {},
645
- ...registration.run !== void 0 ? { run: registration.run } : {}
646
- });
647
- },
648
- pendingInteraction(registration) {
649
- const kind = "slots.pendingInteraction";
650
- const id = requireSlotId(kind, registration?.id);
651
- requireUniqueId(kind, seenIds.pendingInteraction, id);
652
- captured.pendingInteractions.push({
653
- id,
654
- component: requireComponent(kind, registration.component)
655
- });
656
- },
657
- sidebarFooterAction(registration) {
658
- const kind = "slots.sidebarFooterAction";
659
- const id = requireSlotId(kind, registration?.id);
660
- requireUniqueId(kind, seenIds.sidebarFooterAction, id);
661
- if (typeof registration.run !== "function") {
662
- throw new Error(`${kind}: "run" must be a function`);
663
- }
664
- captured.sidebarFooterActions.push({
665
- id,
666
- title: requireNonEmptyString(kind, "title", registration.title),
667
- icon: requireNonEmptyString(kind, "icon", registration.icon),
668
- run: registration.run
669
- });
670
- },
671
- experimental_threadList(registration) {
672
- const kind = "slots.experimental_threadList";
673
- const id = requireSlotId(kind, registration?.id);
674
- requireUniqueId(kind, seenIds.threadList, id);
675
- const description = requireOptionalString(
676
- kind,
677
- "description",
678
- registration.description
679
- );
680
- captured.threadLists.push({
681
- id,
682
- title: requireNonEmptyString(kind, "title", registration.title),
683
- ...description !== void 0 ? { description } : {},
684
- component: requireComponent(kind, registration.component)
685
- });
686
- },
687
- experimental_threadHeaderAction(registration) {
688
- const kind = "slots.experimental_threadHeaderAction";
689
- const id = requireSlotId(kind, registration?.id);
690
- requireUniqueId(kind, seenIds.threadHeaderAction, id);
691
- captured.threadHeaderActions.push({
692
- id,
693
- title: requireNonEmptyString(kind, "title", registration.title),
694
- component: requireComponent(kind, registration.component)
695
- });
696
- },
697
- fileOpener(registration) {
698
- const kind = "slots.fileOpener";
699
- const id = requireSlotId(kind, registration?.id);
700
- requireUniqueId(kind, seenIds.fileOpener, id);
701
- const rawExtensions = registration?.extensions;
702
- if (!Array.isArray(rawExtensions) || rawExtensions.length === 0) {
703
- throw new Error(
704
- `${kind}: "extensions" must be a non-empty array of lowercase extensions without the dot`
705
- );
706
- }
707
- const extensions = rawExtensions.map((extension) => {
708
- if (typeof extension !== "string" || !/^[a-z0-9]+$/.test(extension)) {
709
- throw new Error(
710
- `${kind}: extensions must be lowercase alphanumerics without the dot, got ${JSON.stringify(extension)}`
711
- );
712
- }
713
- return extension;
714
- });
715
- captured.fileOpeners.push({
716
- id,
717
- title: requireNonEmptyString(kind, "title", registration.title),
718
- extensions,
719
- component: requireComponent(kind, registration.component)
720
- });
721
- },
722
- messageDirective(registration) {
723
- const kind = "slots.messageDirective";
724
- const id = requireMessageDirectiveId(kind, registration?.id);
725
- requireUniqueId(kind, seenIds.messageDirective, id);
726
- captured.messageDirectives.push({
727
- id,
728
- component: requireComponent(kind, registration.component)
729
- });
730
- },
731
- messageAction(registration) {
732
- const kind = "slots.messageAction";
733
- const id = requireSlotId(kind, registration?.id);
734
- requireUniqueId(kind, seenIds.messageAction, id);
735
- if (typeof registration.run !== "function") {
736
- throw new Error(`${kind}: "run" must be a function`);
737
- }
738
- captured.messageActions.push({
739
- id,
740
- title: requireNonEmptyString(kind, "title", registration.title),
741
- ...registration.icon !== void 0 ? { icon: requireNonEmptyString(kind, "icon", registration.icon) } : {},
742
- run: registration.run
743
- });
744
- }
745
- },
746
- composer: {
747
- customize(registration) {
748
- const customization = collectComposerCustomization(
749
- registration,
750
- seenIds.composerCustomization,
751
- (reason) => console.warn(reason)
752
- );
753
- if (customization !== null) {
754
- captured.composerCustomizations.push(customization);
755
- }
756
- }
757
- },
758
- contentScripts: {
759
- register(registration) {
760
- const kind = "contentScripts.register";
761
- const id = requireSlotId(kind, registration?.id);
762
- requireUniqueId(kind, seenIds.contentScript, id);
763
- if (typeof registration.mount !== "function") {
764
- throw new Error(`${kind}: "mount" must be a function`);
765
- }
766
- captured.contentScripts.push({ id, mount: registration.mount });
767
- }
768
- }
769
- });
770
- return captured;
771
- }
772
836
  async function loadPluginApp(source) {
773
837
  installTestPluginRuntime();
774
838
  const resolved = typeof source === "function" ? await source() : source;
@@ -778,7 +842,7 @@ async function loadPluginApp(source) {
778
842
  "the bundle's default export is not definePluginApp(...) from @get-bb/plugin-sdk/app"
779
843
  );
780
844
  }
781
- return collectRegistrations(definition);
845
+ return collectPluginAppRegistrations(definition);
782
846
  }
783
847
  async function mountPluginContentScripts(app, options) {
784
848
  const controller = new AbortController();