skybridge 0.0.0-dev.97bc523 → 0.0.0-dev.97c9984

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.
Files changed (137) hide show
  1. package/README.md +1 -9
  2. package/dist/cli/build-helpers.d.ts +5 -1
  3. package/dist/cli/build-helpers.js +30 -10
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +58 -3
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.d.ts +1 -0
  11. package/dist/cli/build-steps.test.js +52 -0
  12. package/dist/cli/build-steps.test.js.map +1 -0
  13. package/dist/cli/header.d.ts +1 -1
  14. package/dist/cli/run-plain.d.ts +18 -0
  15. package/dist/cli/run-plain.js +89 -0
  16. package/dist/cli/run-plain.js.map +1 -0
  17. package/dist/cli/use-nodemon.d.ts +14 -0
  18. package/dist/cli/use-nodemon.js +71 -60
  19. package/dist/cli/use-nodemon.js.map +1 -1
  20. package/dist/cli/use-typescript-check.d.ts +8 -2
  21. package/dist/cli/use-typescript-check.js +70 -67
  22. package/dist/cli/use-typescript-check.js.map +1 -1
  23. package/dist/commands/build.d.ts +0 -2
  24. package/dist/commands/build.js +2 -61
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/dev.d.ts +1 -0
  27. package/dist/commands/dev.js +32 -0
  28. package/dist/commands/dev.js.map +1 -1
  29. package/dist/server/auth/providers/custom.d.ts +6 -0
  30. package/dist/server/auth/providers/custom.js +7 -4
  31. package/dist/server/auth/providers/custom.js.map +1 -1
  32. package/dist/server/auth/providers/custom.test.js +21 -0
  33. package/dist/server/auth/providers/custom.test.js.map +1 -1
  34. package/dist/server/auth/providers/descope.js +4 -2
  35. package/dist/server/auth/providers/descope.js.map +1 -1
  36. package/dist/server/auth/providers/descope.test.js +12 -10
  37. package/dist/server/auth/providers/descope.test.js.map +1 -1
  38. package/dist/server/index.d.ts +2 -1
  39. package/dist/server/index.js +2 -1
  40. package/dist/server/index.js.map +1 -1
  41. package/dist/server/server.d.ts +29 -5
  42. package/dist/server/server.js +132 -125
  43. package/dist/server/server.js.map +1 -1
  44. package/dist/server/skills-integration.test.d.ts +1 -0
  45. package/dist/server/skills-integration.test.js +63 -0
  46. package/dist/server/skills-integration.test.js.map +1 -0
  47. package/dist/server/skills.d.ts +23 -0
  48. package/dist/server/skills.js +178 -0
  49. package/dist/server/skills.js.map +1 -0
  50. package/dist/server/skills.test.d.ts +1 -0
  51. package/dist/server/skills.test.js +210 -0
  52. package/dist/server/skills.test.js.map +1 -0
  53. package/dist/server/view-name.test-d.d.ts +1 -0
  54. package/dist/server/view-name.test-d.js +8 -0
  55. package/dist/server/view-name.test-d.js.map +1 -0
  56. package/dist/server/view-resource-resolution.test.js +93 -10
  57. package/dist/server/view-resource-resolution.test.js.map +1 -1
  58. package/dist/test/view.test.js +70 -102
  59. package/dist/test/view.test.js.map +1 -1
  60. package/dist/web/bridges/adaptor.d.ts +51 -0
  61. package/dist/web/bridges/adaptor.js +330 -0
  62. package/dist/web/bridges/adaptor.js.map +1 -0
  63. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  64. package/dist/web/bridges/adaptor.test.js +208 -0
  65. package/dist/web/bridges/adaptor.test.js.map +1 -0
  66. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
  67. package/dist/web/bridges/apps-sdk/bridge.js +15 -4
  68. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  69. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  70. package/dist/web/bridges/apps-sdk/index.js +0 -1
  71. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  72. package/dist/web/bridges/get-adaptor.d.ts +4 -4
  73. package/dist/web/bridges/get-adaptor.js +6 -11
  74. package/dist/web/bridges/get-adaptor.js.map +1 -1
  75. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  76. package/dist/web/bridges/get-adaptor.test.js +32 -0
  77. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  78. package/dist/web/bridges/mcp-app/bridge.d.ts +13 -2
  79. package/dist/web/bridges/mcp-app/bridge.js +46 -4
  80. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  81. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  82. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  83. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  84. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  85. package/dist/web/bridges/mcp-app/index.js +0 -1
  86. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  87. package/dist/web/bridges/mcp-app/view-tools.test.js +5 -6
  88. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  89. package/dist/web/bridges/types.d.ts +10 -0
  90. package/dist/web/bridges/types.js +14 -1
  91. package/dist/web/bridges/types.js.map +1 -1
  92. package/dist/web/bridges/types.test.d.ts +1 -0
  93. package/dist/web/bridges/types.test.js +19 -0
  94. package/dist/web/bridges/types.test.js.map +1 -0
  95. package/dist/web/components/modal-provider.d.ts +1 -1
  96. package/dist/web/components/modal-provider.js +4 -3
  97. package/dist/web/components/modal-provider.js.map +1 -1
  98. package/dist/web/create-store.test.js +8 -5
  99. package/dist/web/create-store.test.js.map +1 -1
  100. package/dist/web/data-llm.d.ts +1 -1
  101. package/dist/web/data-llm.test.js +17 -5
  102. package/dist/web/data-llm.test.js.map +1 -1
  103. package/dist/web/hooks/use-call-tool.test.js +37 -23
  104. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  105. package/dist/web/hooks/use-display-mode.test.js +56 -20
  106. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  107. package/dist/web/hooks/use-download.test.js +11 -3
  108. package/dist/web/hooks/use-download.test.js.map +1 -1
  109. package/dist/web/hooks/use-files.test.js +10 -2
  110. package/dist/web/hooks/use-files.test.js.map +1 -1
  111. package/dist/web/hooks/use-layout.test.js +59 -26
  112. package/dist/web/hooks/use-layout.test.js.map +1 -1
  113. package/dist/web/hooks/use-open-external.test.js +13 -3
  114. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  115. package/dist/web/hooks/use-request-close.test.js +35 -40
  116. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  117. package/dist/web/hooks/use-request-modal.test.js +10 -0
  118. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  119. package/dist/web/hooks/use-request-size.test.js +35 -53
  120. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  121. package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
  122. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  123. package/dist/web/hooks/use-tool-info.test.js +37 -27
  124. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  125. package/dist/web/hooks/use-user.test.js +81 -35
  126. package/dist/web/hooks/use-user.test.js.map +1 -1
  127. package/dist/web/hooks/use-view-state.test.js +6 -2
  128. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  129. package/dist/web/plugin/plugin.js +0 -1
  130. package/dist/web/plugin/plugin.js.map +1 -1
  131. package/package.json +21 -20
  132. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
  133. package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
  134. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  135. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
  136. package/dist/web/bridges/mcp-app/adaptor.js +0 -283
  137. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
@@ -11,6 +11,7 @@ import { createApp } from "./express.js";
11
11
  import { createMiddlewareEntry } from "./metric.js";
12
12
  import { buildMiddlewareChain, getHandlerMaps } from "./middleware.js";
13
13
  import { resolveServerOrigin } from "./requestOrigin.js";
14
+ import { discoverSkills, registerSkills, SKILLS_EXTENSION_KEY, } from "./skills.js";
14
15
  import { templateHelper } from "./templateHelper.js";
15
16
  const mergeWithUnion = (target, source) => {
16
17
  return mergeWith(target, source, (targetVal, sourceVal) => {
@@ -19,6 +20,20 @@ const mergeWithUnion = (target, source) => {
19
20
  }
20
21
  });
21
22
  };
23
+ const SKILLS_DIR = "src/skills";
24
+ /**
25
+ * Normalize an `x-forwarded-prefix` value into a leading-slash, no-trailing-slash
26
+ * path. Takes the first hop of a comma-separated proxy chain.
27
+ * "/v1/", "v1", "/v1, /internal" → "/v1"; "", "/", undefined → "".
28
+ */
29
+ function normalizeForwardedPrefix(raw) {
30
+ const firstHop = raw?.split(",")[0]?.trim() ?? "";
31
+ const trimmed = firstHop.replace(/\/+$/, "");
32
+ if (trimmed === "") {
33
+ return "";
34
+ }
35
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
36
+ }
22
37
  /**
23
38
  * Drop the query string from a `ui://` view URI, leaving the bare path. The
24
39
  * `?v=` cache key is the only query we append, so a plain split is enough and
@@ -92,6 +107,27 @@ let pendingBuildManifest = null;
92
107
  export function __setBuildManifest(manifest) {
93
108
  pendingBuildManifest = manifest;
94
109
  }
110
+ let pendingSkillsManifest = null;
111
+ export function __setSkillsManifest(manifest) {
112
+ pendingSkillsManifest = manifest;
113
+ }
114
+ // Pure and `this`-free so it can run inside the `super(...)` call, before `this`
115
+ // exists — the capability must be present for the `initialize` response.
116
+ function withSkillsCapability(options, skybridgeOptions) {
117
+ if (!skybridgeOptions?.skills) {
118
+ return options;
119
+ }
120
+ return {
121
+ ...options,
122
+ capabilities: {
123
+ ...options?.capabilities,
124
+ extensions: {
125
+ ...options?.capabilities?.extensions,
126
+ [SKILLS_EXTENSION_KEY]: { directoryRead: true },
127
+ },
128
+ },
129
+ };
130
+ }
95
131
  export class McpServer extends McpServerBaseOmitted {
96
132
  /**
97
133
  * The underlying Express app. Use this to extend the HTTP server with
@@ -124,9 +160,10 @@ export class McpServer extends McpServerBaseOmitted {
124
160
  serverInfo;
125
161
  serverOptions;
126
162
  constructor(serverInfo, options, skybridgeOptions) {
127
- super(serverInfo, options);
163
+ const mergedOptions = withSkillsCapability(options, skybridgeOptions);
164
+ super(serverInfo, mergedOptions);
128
165
  this.serverInfo = serverInfo;
129
- this.serverOptions = options;
166
+ this.serverOptions = mergedOptions;
130
167
  this.express = express();
131
168
  this.express.use(express.json(skybridgeOptions?.json));
132
169
  if (skybridgeOptions?.oauth) {
@@ -141,6 +178,19 @@ export class McpServer extends McpServerBaseOmitted {
141
178
  this.setViteManifest(pendingBuildManifest);
142
179
  pendingBuildManifest = null;
143
180
  }
181
+ this.setupSkills(Boolean(skybridgeOptions?.skills));
182
+ }
183
+ setupSkills(enabled) {
184
+ const manifest = pendingSkillsManifest;
185
+ pendingSkillsManifest = null;
186
+ if (!enabled) {
187
+ return;
188
+ }
189
+ const skills = manifest ?? discoverSkills(SKILLS_DIR);
190
+ if (skills.length === 0) {
191
+ console.warn(`skybridge: the "skills" option is enabled but no skills were found in "${SKILLS_DIR}". Add a <name>/SKILL.md there, or remove the option.`);
192
+ }
193
+ registerSkills(this, skills);
144
194
  }
145
195
  use(pathOrHandler, ...handlers) {
146
196
  // Branching is load-bearing: Express's `app.use` overloads can't be
@@ -236,7 +286,7 @@ export class McpServer extends McpServerBaseOmitted {
236
286
  const result = (await next());
237
287
  for (const content of result.contents ?? []) {
238
288
  if (typeof content.uri === "string" &&
239
- stripQuery(content.uri) === path) {
289
+ stripQuery(content.uri) === stripQuery(canonical)) {
240
290
  content.uri = requested;
241
291
  }
242
292
  }
@@ -383,6 +433,11 @@ export class McpServer extends McpServerBaseOmitted {
383
433
  };
384
434
  const isClaude = header("user-agent") === "Claude-User";
385
435
  const serverUrl = resolveServerOrigin(header);
436
+ // Path prefix the proxy routed this request under (e.g. `foo.com/v1`). Read
437
+ // per-request so one process can serve many hosts/prefixes at once: the
438
+ // origin is recovered from x-forwarded-host, the prefix from
439
+ // x-forwarded-prefix. Empty when served at the origin root.
440
+ const assetsBasePath = normalizeForwardedPrefix(header("x-forwarded-prefix"));
386
441
  const connectDomains = [serverUrl];
387
442
  if (!isProduction) {
388
443
  const wsUrl = new URL(serverUrl);
@@ -403,135 +458,77 @@ export class McpServer extends McpServerBaseOmitted {
403
458
  .slice(0, 32);
404
459
  contentMetaOverrides = { domain: `${hash}.claudemcpcontent.com` };
405
460
  }
406
- return { serverUrl, connectDomains, contentMetaOverrides };
461
+ return { serverUrl, assetsBasePath, connectDomains, contentMetaOverrides };
407
462
  }
408
463
  registerViewResources(toolName, view, toolMeta) {
409
- const hosts = view.hosts ?? ["apps-sdk", "mcp-app"];
410
464
  // Append a content-derived version param so hosts (e.g. ChatGPT) bust
411
465
  // their cache when the bundle changes, but keep the URI stable across
412
466
  // `tools/list` calls when the bundle hasn't changed.
413
467
  const versionParam = this.computeViewVersionParam(view.component);
414
- if (hosts.includes("apps-sdk")) {
415
- const viewResource = {
416
- hostType: "mcp-app",
417
- uri: `ui://views/apps-sdk/${view.component}.html${versionParam}`,
418
- mimeType: "text/html;profile=mcp-app",
419
- buildContentMeta: ({ resourceDomains, connectDomains, domain, baseUriDomains }, overrides) => {
420
- const defaults = {
421
- ui: {
422
- csp: {
423
- resourceDomains,
424
- connectDomains,
425
- baseUriDomains,
426
- },
427
- domain,
468
+ const viewResource = {
469
+ hostType: "mcp-app",
470
+ uri: `ui://views/ext-apps/${view.component}.html${versionParam}`,
471
+ mimeType: "text/html;profile=mcp-app",
472
+ buildContentMeta: ({ resourceDomains, connectDomains, domain, baseUriDomains }, overrides) => {
473
+ const defaults = {
474
+ ui: {
475
+ csp: {
476
+ resourceDomains,
477
+ connectDomains,
478
+ baseUriDomains,
428
479
  },
429
- };
430
- const fromView = {
431
- ui: {
432
- ...(view.description && { description: view.description }),
433
- ...(view.prefersBorder !== undefined && {
434
- prefersBorder: view.prefersBorder,
480
+ domain,
481
+ },
482
+ };
483
+ const fromView = {
484
+ ui: {
485
+ ...(view.description && { description: view.description }),
486
+ ...(view.prefersBorder !== undefined && {
487
+ prefersBorder: view.prefersBorder,
488
+ }),
489
+ ...(view.domain && { domain: view.domain }),
490
+ csp: {
491
+ ...(view.csp?.resourceDomains && {
492
+ resourceDomains: view.csp.resourceDomains,
435
493
  }),
436
- ...(view.domain && { domain: view.domain }),
437
- csp: {
438
- ...(view.csp?.resourceDomains && {
439
- resourceDomains: view.csp.resourceDomains,
440
- }),
441
- ...(view.csp?.connectDomains && {
442
- connectDomains: view.csp.connectDomains,
443
- }),
444
- ...(view.csp?.frameDomains && {
445
- frameDomains: view.csp.frameDomains,
446
- }),
447
- ...(view.csp?.baseUriDomains && {
448
- baseUriDomains: view.csp.baseUriDomains,
449
- }),
450
- ...(view.csp?.redirectDomains && {
451
- redirectDomains: view.csp.redirectDomains,
452
- }),
453
- },
454
- },
455
- };
456
- const base = mergeWithUnion(mergeWithUnion(defaults, fromView), {
457
- ui: overrides,
458
- });
459
- if (view._meta) {
460
- return { ...base, ...view._meta };
461
- }
462
- return base;
463
- },
464
- };
465
- this.registerViewResource({
466
- name: toolName,
467
- viewResource,
468
- view,
469
- });
470
- toolMeta["openai/outputTemplate"] = viewResource.uri;
471
- // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
472
- toolMeta["ui/resourceUri"] = viewResource.uri;
473
- toolMeta.ui = { ...toolMeta.ui, resourceUri: viewResource.uri };
474
- }
475
- if (hosts.includes("mcp-app")) {
476
- const viewResource = {
477
- hostType: "mcp-app",
478
- uri: `ui://views/ext-apps/${view.component}.html${versionParam}`,
479
- mimeType: "text/html;profile=mcp-app",
480
- buildContentMeta: ({ resourceDomains, connectDomains, domain, baseUriDomains }, overrides) => {
481
- const defaults = {
482
- ui: {
483
- csp: {
484
- resourceDomains,
485
- connectDomains,
486
- baseUriDomains,
487
- },
488
- domain,
489
- },
490
- };
491
- const fromView = {
492
- ui: {
493
- ...(view.description && { description: view.description }),
494
- ...(view.prefersBorder !== undefined && {
495
- prefersBorder: view.prefersBorder,
494
+ ...(view.csp?.connectDomains && {
495
+ connectDomains: view.csp.connectDomains,
496
+ }),
497
+ ...(view.csp?.frameDomains && {
498
+ frameDomains: view.csp.frameDomains,
499
+ }),
500
+ ...(view.csp?.baseUriDomains && {
501
+ baseUriDomains: view.csp.baseUriDomains,
496
502
  }),
497
- ...(view.domain && { domain: view.domain }),
498
- csp: {
499
- ...(view.csp?.resourceDomains && {
500
- resourceDomains: view.csp.resourceDomains,
501
- }),
502
- ...(view.csp?.connectDomains && {
503
- connectDomains: view.csp.connectDomains,
504
- }),
505
- ...(view.csp?.frameDomains && {
506
- frameDomains: view.csp.frameDomains,
507
- }),
508
- ...(view.csp?.baseUriDomains && {
509
- baseUriDomains: view.csp.baseUriDomains,
510
- }),
511
- ...(view.csp?.redirectDomains && {
512
- redirectDomains: view.csp.redirectDomains,
513
- }),
514
- },
515
503
  },
516
- };
517
- const base = mergeWithUnion(mergeWithUnion(defaults, fromView), {
518
- ui: overrides,
519
- });
520
- if (view._meta) {
521
- return { ...base, ...view._meta };
522
- }
523
- return base;
524
- },
525
- };
526
- this.registerViewResource({
527
- name: toolName,
528
- viewResource,
529
- view,
530
- });
531
- // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
532
- toolMeta["ui/resourceUri"] = viewResource.uri;
533
- toolMeta.ui = { ...toolMeta.ui, resourceUri: viewResource.uri };
534
- }
504
+ },
505
+ };
506
+ const ui = mergeWithUnion(mergeWithUnion(defaults, fromView), {
507
+ ui: overrides,
508
+ });
509
+ const base = {
510
+ ...ui,
511
+ ...(view.description && {
512
+ "openai/widgetDescription": view.description,
513
+ }),
514
+ ...(view.csp?.redirectDomains && {
515
+ "openai/widgetCSP": { redirect_domains: view.csp.redirectDomains },
516
+ }),
517
+ };
518
+ if (view._meta) {
519
+ return { ...base, ...view._meta };
520
+ }
521
+ return base;
522
+ },
523
+ };
524
+ this.registerViewResource({ name: toolName, viewResource, view });
525
+ // Advertise via the MCP Apps standard pointer only — ChatGPT renders from
526
+ // ui.resourceUri (verified), and not emitting openai/outputTemplate lets us
527
+ // retire the legacy apps-sdk resource later. The legacy apps-sdk URL is still
528
+ // served (see registerViewResource) so already-published apps keep resolving.
529
+ // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
530
+ toolMeta["ui/resourceUri"] = viewResource.uri;
531
+ toolMeta.ui = { ...toolMeta.ui, resourceUri: viewResource.uri };
535
532
  }
536
533
  registerViewResource({ name, viewResource, view, }) {
537
534
  const { hostType, uri: viewUri, mimeType, buildContentMeta } = viewResource;
@@ -546,19 +543,24 @@ export class McpServer extends McpServerBaseOmitted {
546
543
  };
547
544
  this.viewMetaBuilders.set(viewUri, buildMeta);
548
545
  this.viewUriByPath.set(stripQuery(viewUri), viewUri);
546
+ this.serveLegacyAppsSdkUrl(view.component, viewUri);
549
547
  this.registerResource(name, viewUri, { description: view.description }, async (uri, extra) => {
550
548
  const isProduction = process.env.NODE_ENV === "production";
551
- const { serverUrl } = this.resolveViewRequestContext(extra);
549
+ const { serverUrl, assetsBasePath } = this.resolveViewRequestContext(extra);
550
+ // The view resolves all assets (template imports + runtime lazy chunks
551
+ // via `window.skybridge.serverUrl`) against this base, so it carries the
552
+ // proxy path prefix. CSP domains in `buildMeta` stay the bare origin.
553
+ const viewBase = `${serverUrl}${assetsBasePath}`;
552
554
  const html = isProduction
553
555
  ? templateHelper.renderProduction({
554
556
  hostType,
555
- serverUrl,
557
+ serverUrl: viewBase,
556
558
  viewFile: this.lookupViewFile(view.component),
557
559
  styleFile: this.lookupDistFile("style.css") ?? "",
558
560
  })
559
561
  : templateHelper.renderDevelopment({
560
562
  hostType,
561
- serverUrl,
563
+ serverUrl: viewBase,
562
564
  viewName: view.component,
563
565
  });
564
566
  return {
@@ -568,6 +570,11 @@ export class McpServer extends McpServerBaseOmitted {
568
570
  };
569
571
  });
570
572
  }
573
+ serveLegacyAppsSdkUrl(component, canonicalUri) {
574
+ this.viewUriByPath.set(`ui://views/apps-sdk/${component}.html`, canonicalUri);
575
+ this.viewUriByPath.set(`ui://widgets/apps-sdk/${component}.html`, canonicalUri);
576
+ this.viewUriByPath.set(`ui://widgets/ext-apps/${component}.html`, canonicalUri);
577
+ }
571
578
  wrapHandler(cb, { attachViewUUID }) {
572
579
  return async (args, extra) => {
573
580
  const result = await cb(args, extra);