@get-bb/plugin-sdk 0.4.6 → 0.4.9
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/README.md +8 -0
- package/bundled-types/bb-plugin-sdk-app.d.ts +375 -112
- package/bundled-types/bb-plugin-sdk-host.d.ts +124 -0
- package/bundled-types/bb-plugin-sdk-internal-composer-customization-validation.d.ts +6 -1
- package/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +154 -2
- package/bundled-types/bb-plugin-sdk-internal-plugin-app-collector.d.ts +39 -0
- package/bundled-types/bb-plugin-sdk-provider-bridge.d.ts +4042 -0
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +4 -1
- package/bundled-types/bb-plugin-sdk-testing-host.d.ts +47 -0
- package/bundled-types/bb-plugin-sdk-testing.d.ts +19 -2
- package/bundled-types/bb-plugin-sdk.d.ts +6179 -5252
- package/dist/app.js +4 -0
- package/dist/host.js +13 -0
- package/dist/index.js +13 -1
- package/dist/internal/composer-customization-validation.js +9 -0
- package/dist/internal/host-policy.js +389 -18
- package/dist/internal/plugin-app-collector.js +555 -0
- package/dist/provider-bridge.js +6096 -0
- package/dist/testing/app.js +399 -257
- package/dist/testing/host.js +165 -0
- package/dist/testing/index.js +530 -27
- package/package.json +33 -4
package/dist/testing/app.js
CHANGED
|
@@ -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,354 @@ 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
|
+
sourceCodeRenderers: [],
|
|
269
|
+
diffRenderers: [],
|
|
270
|
+
messageDirectives: [],
|
|
271
|
+
messageActions: [],
|
|
272
|
+
providerIcons: [],
|
|
273
|
+
contentScripts: []
|
|
274
|
+
};
|
|
275
|
+
const seenIds = {
|
|
276
|
+
homepageSection: /* @__PURE__ */ new Set(),
|
|
277
|
+
settingsSection: /* @__PURE__ */ new Set(),
|
|
278
|
+
navPanel: /* @__PURE__ */ new Set(),
|
|
279
|
+
threadPanelAction: /* @__PURE__ */ new Set(),
|
|
280
|
+
newThreadPanelAction: /* @__PURE__ */ new Set(),
|
|
281
|
+
composerCustomization: /* @__PURE__ */ new Set(),
|
|
282
|
+
pendingInteraction: /* @__PURE__ */ new Set(),
|
|
283
|
+
sidebarFooterAction: /* @__PURE__ */ new Set(),
|
|
284
|
+
threadList: /* @__PURE__ */ new Set(),
|
|
285
|
+
threadHeaderAction: /* @__PURE__ */ new Set(),
|
|
286
|
+
fileOpener: /* @__PURE__ */ new Set(),
|
|
287
|
+
sourceCodeRenderer: /* @__PURE__ */ new Set(),
|
|
288
|
+
diffRenderer: /* @__PURE__ */ new Set(),
|
|
289
|
+
messageDirective: /* @__PURE__ */ new Set(),
|
|
290
|
+
messageAction: /* @__PURE__ */ new Set(),
|
|
291
|
+
providerIcon: /* @__PURE__ */ new Set(),
|
|
292
|
+
contentScript: /* @__PURE__ */ new Set()
|
|
293
|
+
};
|
|
294
|
+
definition.setup({
|
|
295
|
+
slots: {
|
|
296
|
+
homepageSection(registration) {
|
|
297
|
+
const kind = "slots.homepageSection";
|
|
298
|
+
const id = requireSlotId(kind, registration?.id);
|
|
299
|
+
requireUniqueId(kind, seenIds.homepageSection, id);
|
|
300
|
+
collected.homepageSections.push({
|
|
301
|
+
id,
|
|
302
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
303
|
+
component: requireComponent(kind, registration.component)
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
settingsSection(registration) {
|
|
307
|
+
const kind = "slots.settingsSection";
|
|
308
|
+
const id = requireSlotId(kind, registration?.id);
|
|
309
|
+
requireUniqueId(kind, seenIds.settingsSection, id);
|
|
310
|
+
const title = requireOptionalString(kind, "title", registration.title);
|
|
311
|
+
const description = requireOptionalString(
|
|
312
|
+
kind,
|
|
313
|
+
"description",
|
|
314
|
+
registration.description
|
|
315
|
+
);
|
|
316
|
+
collected.settingsSections.push({
|
|
317
|
+
id,
|
|
318
|
+
...title !== void 0 ? { title } : {},
|
|
319
|
+
...description !== void 0 ? { description } : {},
|
|
320
|
+
component: requireComponent(kind, registration.component)
|
|
321
|
+
});
|
|
322
|
+
},
|
|
323
|
+
navPanel(registration) {
|
|
324
|
+
const kind = "slots.navPanel";
|
|
325
|
+
const id = requireSlotId(kind, registration?.id);
|
|
326
|
+
requireUniqueId(kind, seenIds.navPanel, id);
|
|
327
|
+
const path = requireNonEmptyString(kind, "path", registration.path);
|
|
328
|
+
if (!PLUGIN_SLOT_ID_PATTERN.test(path)) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`${kind}: "path" must match ${String(PLUGIN_SLOT_ID_PATTERN)} (it becomes a URL segment), got ${JSON.stringify(path)}`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
if (registration.headerContent !== void 0 && typeof registration.headerContent !== "function") {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`${kind}: "headerContent" must be a React component function when set`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
if (registration.experimental_sidebarAccessory !== void 0 && typeof registration.experimental_sidebarAccessory !== "function") {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`${kind}: "experimental_sidebarAccessory" must be a React component function when set`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
const experimentalFixedTabs = (() => {
|
|
344
|
+
if (registration.experimental_fixedTabs === void 0) return [];
|
|
345
|
+
if (!Array.isArray(registration.experimental_fixedTabs)) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
`${kind}: "experimental_fixedTabs" must be an array when set`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
const seenFixedTabIds = /* @__PURE__ */ new Set();
|
|
351
|
+
return registration.experimental_fixedTabs.map((value, index) => {
|
|
352
|
+
const fixedTabKind = `${kind}.experimental_fixedTabs[${index}]`;
|
|
353
|
+
const fixedTab = value;
|
|
354
|
+
const id2 = requireSlotId(fixedTabKind, fixedTab?.id);
|
|
355
|
+
requireUniqueId(fixedTabKind, seenFixedTabIds, id2);
|
|
356
|
+
const layout = fixedTab?.layout;
|
|
357
|
+
if (layout !== void 0 && layout !== "padded" && layout !== "flush") {
|
|
358
|
+
throw new Error(
|
|
359
|
+
`${fixedTabKind}: "layout" must be "padded" or "flush" when set`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
id: id2,
|
|
364
|
+
title: requireNonEmptyString(
|
|
365
|
+
fixedTabKind,
|
|
366
|
+
"title",
|
|
367
|
+
fixedTab?.title
|
|
368
|
+
),
|
|
369
|
+
icon: requireNonEmptyString(
|
|
370
|
+
fixedTabKind,
|
|
371
|
+
"icon",
|
|
372
|
+
fixedTab?.icon
|
|
373
|
+
),
|
|
374
|
+
component: requireComponent(fixedTabKind, fixedTab?.component),
|
|
375
|
+
...layout === void 0 ? {} : { layout }
|
|
376
|
+
};
|
|
377
|
+
});
|
|
378
|
+
})();
|
|
379
|
+
collected.navPanels.push({
|
|
380
|
+
id,
|
|
381
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
382
|
+
icon: requireNonEmptyString(kind, "icon", registration.icon),
|
|
383
|
+
path,
|
|
384
|
+
component: requireComponent(kind, registration.component),
|
|
385
|
+
...experimentalFixedTabs.length > 0 ? { experimental_fixedTabs: experimentalFixedTabs } : {},
|
|
386
|
+
...registration.experimental_sidebarAccessory !== void 0 ? {
|
|
387
|
+
experimental_sidebarAccessory: registration.experimental_sidebarAccessory
|
|
388
|
+
} : {},
|
|
389
|
+
...registration.headerContent !== void 0 ? { headerContent: registration.headerContent } : {}
|
|
390
|
+
});
|
|
391
|
+
},
|
|
392
|
+
threadPanelAction(registration) {
|
|
393
|
+
const kind = "slots.threadPanelAction";
|
|
394
|
+
const id = requireSlotId(kind, registration?.id);
|
|
395
|
+
requireUniqueId(kind, seenIds.threadPanelAction, id);
|
|
396
|
+
if (registration.run !== void 0 && typeof registration.run !== "function") {
|
|
397
|
+
throw new Error(`${kind}: "run" must be a function when set`);
|
|
398
|
+
}
|
|
399
|
+
if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
|
|
400
|
+
throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
|
|
401
|
+
}
|
|
402
|
+
collected.threadPanelActions.push({
|
|
403
|
+
id,
|
|
404
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
405
|
+
...registration.icon !== void 0 ? {
|
|
406
|
+
icon: requireNonEmptyString(kind, "icon", registration.icon)
|
|
407
|
+
} : {},
|
|
408
|
+
component: requireComponent(kind, registration.component),
|
|
409
|
+
...registration.layout !== void 0 ? { layout: registration.layout } : {},
|
|
410
|
+
...registration.run !== void 0 ? { run: registration.run } : {}
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
experimental_newThreadPanelAction(registration) {
|
|
414
|
+
const kind = "slots.experimental_newThreadPanelAction";
|
|
415
|
+
const id = requireSlotId(kind, registration?.id);
|
|
416
|
+
requireUniqueId(kind, seenIds.newThreadPanelAction, id);
|
|
417
|
+
if (registration.run !== void 0 && typeof registration.run !== "function") {
|
|
418
|
+
throw new Error(`${kind}: "run" must be a function when set`);
|
|
419
|
+
}
|
|
420
|
+
if (registration.layout !== void 0 && registration.layout !== "padded" && registration.layout !== "flush") {
|
|
421
|
+
throw new Error(`${kind}: "layout" must be "padded" or "flush"`);
|
|
422
|
+
}
|
|
423
|
+
collected.newThreadPanelActions.push({
|
|
424
|
+
id,
|
|
425
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
426
|
+
...registration.icon !== void 0 ? {
|
|
427
|
+
icon: requireNonEmptyString(kind, "icon", registration.icon)
|
|
428
|
+
} : {},
|
|
429
|
+
component: requireComponent(kind, registration.component),
|
|
430
|
+
...registration.layout !== void 0 ? { layout: registration.layout } : {},
|
|
431
|
+
...registration.run !== void 0 ? { run: registration.run } : {}
|
|
432
|
+
});
|
|
433
|
+
},
|
|
434
|
+
pendingInteraction(registration) {
|
|
435
|
+
const kind = "slots.pendingInteraction";
|
|
436
|
+
const id = requireSlotId(kind, registration?.id);
|
|
437
|
+
requireUniqueId(kind, seenIds.pendingInteraction, id);
|
|
438
|
+
collected.pendingInteractions.push({
|
|
439
|
+
id,
|
|
440
|
+
component: requireComponent(kind, registration.component)
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
sidebarFooterAction(registration) {
|
|
444
|
+
const kind = "slots.sidebarFooterAction";
|
|
445
|
+
const id = requireSlotId(kind, registration?.id);
|
|
446
|
+
requireUniqueId(kind, seenIds.sidebarFooterAction, id);
|
|
447
|
+
if (typeof registration.run !== "function") {
|
|
448
|
+
throw new Error(`${kind}: "run" must be a function`);
|
|
449
|
+
}
|
|
450
|
+
collected.sidebarFooterActions.push({
|
|
451
|
+
id,
|
|
452
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
453
|
+
icon: requireNonEmptyString(kind, "icon", registration.icon),
|
|
454
|
+
run: registration.run
|
|
455
|
+
});
|
|
456
|
+
},
|
|
457
|
+
experimental_threadList(registration) {
|
|
458
|
+
const kind = "slots.experimental_threadList";
|
|
459
|
+
const id = requireSlotId(kind, registration?.id);
|
|
460
|
+
requireUniqueId(kind, seenIds.threadList, id);
|
|
461
|
+
const description = requireOptionalString(
|
|
462
|
+
kind,
|
|
463
|
+
"description",
|
|
464
|
+
registration.description
|
|
465
|
+
);
|
|
466
|
+
collected.threadLists.push({
|
|
467
|
+
id,
|
|
468
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
469
|
+
...description !== void 0 ? { description } : {},
|
|
470
|
+
component: requireComponent(kind, registration.component)
|
|
471
|
+
});
|
|
472
|
+
},
|
|
473
|
+
experimental_threadHeaderAction(registration) {
|
|
474
|
+
const kind = "slots.experimental_threadHeaderAction";
|
|
475
|
+
const id = requireSlotId(kind, registration?.id);
|
|
476
|
+
requireUniqueId(kind, seenIds.threadHeaderAction, id);
|
|
477
|
+
collected.threadHeaderActions.push({
|
|
478
|
+
id,
|
|
479
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
480
|
+
component: requireComponent(kind, registration.component)
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
fileOpener(registration) {
|
|
484
|
+
const kind = "slots.fileOpener";
|
|
485
|
+
const id = requireSlotId(kind, registration?.id);
|
|
486
|
+
requireUniqueId(kind, seenIds.fileOpener, id);
|
|
487
|
+
const rawExtensions = registration?.extensions;
|
|
488
|
+
if (!Array.isArray(rawExtensions) || rawExtensions.length === 0) {
|
|
489
|
+
throw new Error(
|
|
490
|
+
`${kind}: "extensions" must be a non-empty array of lowercase extensions without the dot`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
const extensions = rawExtensions.map((extension) => {
|
|
494
|
+
if (typeof extension !== "string" || !/^[a-z0-9]+$/.test(extension)) {
|
|
495
|
+
throw new Error(
|
|
496
|
+
`${kind}: extensions must be lowercase alphanumerics without the dot, got ${JSON.stringify(extension)}`
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
return extension;
|
|
500
|
+
});
|
|
501
|
+
collected.fileOpeners.push({
|
|
502
|
+
id,
|
|
503
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
504
|
+
extensions,
|
|
505
|
+
component: requireComponent(kind, registration.component)
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
experimental_sourceCodeRenderer(registration) {
|
|
509
|
+
const kind = "slots.experimental_sourceCodeRenderer";
|
|
510
|
+
const id = requireSlotId(kind, registration?.id);
|
|
511
|
+
requireUniqueId(kind, seenIds.sourceCodeRenderer, id);
|
|
512
|
+
const description = requireOptionalString(
|
|
513
|
+
kind,
|
|
514
|
+
"description",
|
|
515
|
+
registration.description
|
|
516
|
+
);
|
|
517
|
+
collected.sourceCodeRenderers.push({
|
|
518
|
+
id,
|
|
519
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
520
|
+
...description !== void 0 ? { description } : {},
|
|
521
|
+
component: requireComponent(kind, registration.component)
|
|
522
|
+
});
|
|
523
|
+
},
|
|
524
|
+
experimental_diffRenderer(registration) {
|
|
525
|
+
const kind = "slots.experimental_diffRenderer";
|
|
526
|
+
const id = requireSlotId(kind, registration?.id);
|
|
527
|
+
requireUniqueId(kind, seenIds.diffRenderer, id);
|
|
528
|
+
const description = requireOptionalString(
|
|
529
|
+
kind,
|
|
530
|
+
"description",
|
|
531
|
+
registration.description
|
|
532
|
+
);
|
|
533
|
+
collected.diffRenderers.push({
|
|
534
|
+
id,
|
|
535
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
536
|
+
...description !== void 0 ? { description } : {},
|
|
537
|
+
component: requireComponent(kind, registration.component)
|
|
538
|
+
});
|
|
539
|
+
},
|
|
540
|
+
messageDirective(registration) {
|
|
541
|
+
const kind = "slots.messageDirective";
|
|
542
|
+
const id = requireMessageDirectiveId(kind, registration?.id);
|
|
543
|
+
requireUniqueId(kind, seenIds.messageDirective, id);
|
|
544
|
+
collected.messageDirectives.push({
|
|
545
|
+
id,
|
|
546
|
+
component: requireComponent(kind, registration.component)
|
|
547
|
+
});
|
|
548
|
+
},
|
|
549
|
+
messageAction(registration) {
|
|
550
|
+
const kind = "slots.messageAction";
|
|
551
|
+
const id = requireSlotId(kind, registration?.id);
|
|
552
|
+
requireUniqueId(kind, seenIds.messageAction, id);
|
|
553
|
+
if (typeof registration.run !== "function") {
|
|
554
|
+
throw new Error(`${kind}: "run" must be a function`);
|
|
555
|
+
}
|
|
556
|
+
collected.messageActions.push({
|
|
557
|
+
id,
|
|
558
|
+
title: requireNonEmptyString(kind, "title", registration.title),
|
|
559
|
+
...registration.icon !== void 0 ? {
|
|
560
|
+
icon: requireNonEmptyString(kind, "icon", registration.icon)
|
|
561
|
+
} : {},
|
|
562
|
+
run: registration.run
|
|
563
|
+
});
|
|
564
|
+
},
|
|
565
|
+
experimental_providerIcon(registration) {
|
|
566
|
+
const kind = "slots.experimental_providerIcon";
|
|
567
|
+
const providerId = requireProviderId(kind, registration?.providerId);
|
|
568
|
+
requireUniqueId(kind, seenIds.providerIcon, providerId);
|
|
569
|
+
collected.providerIcons.push({
|
|
570
|
+
providerId,
|
|
571
|
+
icon: requireComponent(kind, registration.icon)
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
composer: {
|
|
576
|
+
customize(registration) {
|
|
577
|
+
const customization = collectComposerCustomization(
|
|
578
|
+
registration,
|
|
579
|
+
seenIds.composerCustomization,
|
|
580
|
+
onComposerCustomizationRejected
|
|
581
|
+
);
|
|
582
|
+
if (customization !== null) {
|
|
583
|
+
collected.composerCustomizations.push(customization);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
contentScripts: {
|
|
588
|
+
register(registration) {
|
|
589
|
+
const kind = "contentScripts.register";
|
|
590
|
+
const id = requireSlotId(kind, registration?.id);
|
|
591
|
+
requireUniqueId(kind, seenIds.contentScript, id);
|
|
592
|
+
if (typeof registration.mount !== "function") {
|
|
593
|
+
throw new Error(`${kind}: "mount" must be a function`);
|
|
594
|
+
}
|
|
595
|
+
collected.contentScripts.push({ id, mount: registration.mount });
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
return collected;
|
|
600
|
+
}
|
|
601
|
+
|
|
246
602
|
// src/testing/app.tsx
|
|
247
603
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
248
604
|
function SlotLifecycleGuard({
|
|
@@ -390,6 +746,46 @@ function TestNewThreadComposer({
|
|
|
390
746
|
}
|
|
391
747
|
);
|
|
392
748
|
}
|
|
749
|
+
function TestSourceCode({
|
|
750
|
+
content,
|
|
751
|
+
path,
|
|
752
|
+
overflow = "scroll",
|
|
753
|
+
highlightedLines = null,
|
|
754
|
+
className
|
|
755
|
+
}) {
|
|
756
|
+
return /* @__PURE__ */ jsx(
|
|
757
|
+
"pre",
|
|
758
|
+
{
|
|
759
|
+
"data-testid": "bb-source-code",
|
|
760
|
+
"data-path": path,
|
|
761
|
+
"data-overflow": overflow,
|
|
762
|
+
"data-highlighted-lines": highlightedLines === null ? "" : `${highlightedLines.start}-${highlightedLines.end}`,
|
|
763
|
+
className,
|
|
764
|
+
children: content
|
|
765
|
+
}
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
function TestDiff({
|
|
769
|
+
patch,
|
|
770
|
+
path,
|
|
771
|
+
view = "unified",
|
|
772
|
+
overflow = "scroll",
|
|
773
|
+
showLineNumbers = true,
|
|
774
|
+
className
|
|
775
|
+
}) {
|
|
776
|
+
return /* @__PURE__ */ jsx(
|
|
777
|
+
"pre",
|
|
778
|
+
{
|
|
779
|
+
"data-testid": "bb-diff",
|
|
780
|
+
"data-path": path,
|
|
781
|
+
"data-view": view,
|
|
782
|
+
"data-overflow": overflow,
|
|
783
|
+
"data-show-line-numbers": showLineNumbers ? "true" : "false",
|
|
784
|
+
className,
|
|
785
|
+
children: patch
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
393
789
|
var testPluginSdkApp = {
|
|
394
790
|
definePluginApp,
|
|
395
791
|
useRpc() {
|
|
@@ -452,6 +848,8 @@ var testPluginSdkApp = {
|
|
|
452
848
|
ThreadChat: TestThreadChat,
|
|
453
849
|
Markdown: TestMarkdown,
|
|
454
850
|
experimental_NewThreadComposer: TestNewThreadComposer,
|
|
851
|
+
experimental_SourceCode: TestSourceCode,
|
|
852
|
+
experimental_Diff: TestDiff,
|
|
455
853
|
experimental_useSidebarThreads() {
|
|
456
854
|
return useSlotEnv("experimental_useSidebarThreads").sidebarThreads;
|
|
457
855
|
},
|
|
@@ -513,262 +911,6 @@ function installTestPluginRuntime() {
|
|
|
513
911
|
pluginSdkApp: testPluginSdkApp
|
|
514
912
|
};
|
|
515
913
|
}
|
|
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
914
|
async function loadPluginApp(source) {
|
|
773
915
|
installTestPluginRuntime();
|
|
774
916
|
const resolved = typeof source === "function" ? await source() : source;
|
|
@@ -778,7 +920,7 @@ async function loadPluginApp(source) {
|
|
|
778
920
|
"the bundle's default export is not definePluginApp(...) from @get-bb/plugin-sdk/app"
|
|
779
921
|
);
|
|
780
922
|
}
|
|
781
|
-
return
|
|
923
|
+
return collectPluginAppRegistrations(definition);
|
|
782
924
|
}
|
|
783
925
|
async function mountPluginContentScripts(app, options) {
|
|
784
926
|
const controller = new AbortController();
|