@glassly/engine 0.3.4-dev.704 → 0.3.5-dev.705

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 (47) hide show
  1. package/build/generated/releaseMetadata.js +4 -4
  2. package/build/generated/releaseMetadata.js.map +1 -1
  3. package/build/index.d.ts +1 -1
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +1 -1
  6. package/build/index.js.map +1 -1
  7. package/build/services/AppRegistry.d.ts +3 -1
  8. package/build/services/AppRegistry.d.ts.map +1 -1
  9. package/build/services/AppRegistry.js +5 -2
  10. package/build/services/AppRegistry.js.map +1 -1
  11. package/build/services/LocalMiniappRuntime.d.ts +32 -0
  12. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  13. package/build/services/LocalMiniappRuntime.js +332 -1
  14. package/build/services/LocalMiniappRuntime.js.map +1 -1
  15. package/build/services/MiniappLauncher.d.ts.map +1 -1
  16. package/build/services/MiniappLauncher.js +2 -0
  17. package/build/services/MiniappLauncher.js.map +1 -1
  18. package/build/services/MiniappWidgetMode.d.ts +24 -0
  19. package/build/services/MiniappWidgetMode.d.ts.map +1 -0
  20. package/build/services/MiniappWidgetMode.js +58 -0
  21. package/build/services/MiniappWidgetMode.js.map +1 -0
  22. package/build/services/manifestActions.d.ts +8 -1
  23. package/build/services/manifestActions.d.ts.map +1 -1
  24. package/build/services/manifestActions.js +29 -0
  25. package/build/services/manifestActions.js.map +1 -1
  26. package/build/services/widgetPlacements.d.ts +43 -0
  27. package/build/services/widgetPlacements.d.ts.map +1 -0
  28. package/build/services/widgetPlacements.js +83 -0
  29. package/build/services/widgetPlacements.js.map +1 -0
  30. package/build/stores/apps.d.ts +3 -1
  31. package/build/stores/apps.d.ts.map +1 -1
  32. package/build/stores/apps.js +37 -11
  33. package/build/stores/apps.js.map +1 -1
  34. package/build/types/applet.d.ts +16 -0
  35. package/build/types/applet.d.ts.map +1 -1
  36. package/build/types/applet.js.map +1 -1
  37. package/package.json +7 -7
  38. package/src/generated/releaseMetadata.ts +4 -4
  39. package/src/index.ts +1 -0
  40. package/src/services/AppRegistry.ts +8 -2
  41. package/src/services/LocalMiniappRuntime.ts +362 -2
  42. package/src/services/MiniappLauncher.ts +3 -0
  43. package/src/services/MiniappWidgetMode.ts +62 -0
  44. package/src/services/manifestActions.ts +29 -1
  45. package/src/services/widgetPlacements.ts +121 -0
  46. package/src/stores/apps.ts +45 -11
  47. package/src/types/applet.ts +18 -0
@@ -51,6 +51,9 @@ import { MiniappIcons } from "./MiniappIcons";
51
51
  import { pairedControllersFrom, readyControllersKey } from "./controllers";
52
52
  import { DERIVED_SETTINGS_KEYS, SETTINGS_BRIDGE_KEYS, controllersSettingFrom, isDerivedSettingsKey, selectSettingsBridgeKeys, validateSettingsSet, } from "./settingsBridge";
53
53
  import { mayUsePermission } from "./miniappPermissions";
54
+ import { miniappRunningRegistry } from "./MiniappRunningRegistry";
55
+ import { miniappWidgetMode } from "./MiniappWidgetMode";
56
+ import { dropHost as dropWidgetHost, dropProvider as dropWidgetProvider, emptyWidgetPlacements, frameOf as widgetFrameOf, hostsOf as widgetHostsOf, isProviderPlaced, placedProviders, placementOf, placeWidget, setFrame as setWidgetFrame, unplaceWidget, } from "./widgetPlacements";
54
57
  import { activeDashboard, addDashboardApp, displayViewsFor, isDashboardApp, isOverlayApp, onOverlayAppsChange, removeDashboardApp, setOverlayViewer, } from "./pages/overlayApps";
55
58
  import { pagesEligible } from "./pages/pageEligibility";
56
59
  import nativeNavigationService from "./NativeNavigationService";
@@ -227,6 +230,7 @@ const PERMISSION_TYPE_TO_CANONICAL = {
227
230
  SPEAKERS: "speakers",
228
231
  MANAGE_MINIAPPS: "manageMiniapps",
229
232
  PLATFORM_SETTINGS: "platformSettings",
233
+ HOST_WIDGETS: "hostWidgets",
230
234
  };
231
235
  /**
232
236
  * User API keys (Settings > API Keys) a miniapp may read via
@@ -329,6 +333,7 @@ const ALL_CANONICAL_PERMISSIONS = [
329
333
  "displayMirror",
330
334
  "manageMiniapps",
331
335
  "platformSettings",
336
+ "hostWidgets",
332
337
  ];
333
338
  /**
334
339
  * Build the {location, microphone, camera, notifications, calendar, apiKeys}
@@ -1075,6 +1080,8 @@ class LocalMiniappRuntime {
1075
1080
  // current on-glasses frame, this clears the glasses (or restores the
1076
1081
  // core app's saved frame).
1077
1082
  localDisplayManager.onUnmount(packageName);
1083
+ // As a widget host its placements go; as a provider its boxes are forgotten.
1084
+ this.onWidgetPartyGone(packageName);
1078
1085
  this.connectedApps.delete(packageName);
1079
1086
  this.recomputeMicRequirements();
1080
1087
  if (releasedMicGateOverride) {
@@ -1466,6 +1473,24 @@ class LocalMiniappRuntime {
1466
1473
  case MiniappRequestType.ACTION_RESULT:
1467
1474
  this.handleActionResult(packageName, payload);
1468
1475
  break;
1476
+ case MiniappRequestType.WIDGETS_LIST:
1477
+ this.handleWidgetsList(packageName, requestId);
1478
+ break;
1479
+ case MiniappRequestType.WIDGET_PLACE:
1480
+ void this.handleWidgetPlace(packageName, payload, requestId);
1481
+ break;
1482
+ case MiniappRequestType.WIDGET_UNPLACE:
1483
+ void this.handleWidgetUnplace(packageName, payload, requestId);
1484
+ break;
1485
+ case MiniappRequestType.WIDGET_SEND:
1486
+ void this.handleWidgetSend(packageName, payload, requestId);
1487
+ break;
1488
+ case MiniappRequestType.WIDGET_UPDATE:
1489
+ this.handleWidgetUpdate(packageName, payload);
1490
+ break;
1491
+ case MiniappRequestType.WIDGET_RESULT:
1492
+ this.handleWidgetResult(packageName, payload);
1493
+ break;
1469
1494
  case MiniappRequestType.SYSTEM_EXIT:
1470
1495
  void this.handleSystemExit(packageName, requestId);
1471
1496
  break;
@@ -1791,7 +1816,9 @@ class LocalMiniappRuntime {
1791
1816
  }
1792
1817
  /** The app holding `gesture` (the most recent claimer), or null when it is unclaimed. */
1793
1818
  gestureClaimant(gesture) {
1794
- return gestureClaimant(this.gestureClaims, gesture);
1819
+ const claimant = gestureClaimant(this.gestureClaims, gesture);
1820
+ // A widget-only app hears no touch input; its claim waits until the wearer opens it.
1821
+ return claimant !== null && miniappWidgetMode.isWidgetOnly(claimant) ? null : claimant;
1795
1822
  }
1796
1823
  /** Has this app registered the gesture, even if a later claimant currently receives it? */
1797
1824
  hasGestureClaim(packageName, gesture) {
@@ -2055,6 +2082,10 @@ class LocalMiniappRuntime {
2055
2082
  console.log(`${LOG_TAG}: dropping display from unmounted app ${packageName}`);
2056
2083
  return;
2057
2084
  }
2085
+ if (miniappWidgetMode.isWidgetOnly(packageName)) {
2086
+ this.sendResult(packageName, requestId, true);
2087
+ return;
2088
+ }
2058
2089
  if (!payload.layout || typeof payload.layout !== "object") {
2059
2090
  this.sendResult(packageName, requestId, false, undefined, {
2060
2091
  code: MiniappErrorCode.INTERNAL,
@@ -2093,6 +2124,11 @@ class LocalMiniappRuntime {
2093
2124
  this.sendResult(packageName, requestId, true, { status: "blocked", reason: "app stopped" });
2094
2125
  return;
2095
2126
  }
2127
+ // A widget-only app draws through its widget alone.
2128
+ if (miniappWidgetMode.isWidgetOnly(packageName)) {
2129
+ this.sendResult(packageName, requestId, true, { status: "blocked", reason: "widget mode" });
2130
+ return;
2131
+ }
2096
2132
  if (!Array.isArray(payload.elements)) {
2097
2133
  this.sendResult(packageName, requestId, false, undefined, {
2098
2134
  code: MiniappErrorCode.INTERNAL,
@@ -4971,6 +5007,9 @@ class LocalMiniappRuntime {
4971
5007
  for (const packageName of matchedSubs) {
4972
5008
  if (only !== undefined && packageName !== only)
4973
5009
  continue;
5010
+ // The wearer's touches reach a widget-only app through its host's widget events alone.
5011
+ if (normalizedStream === MiniappStreamType.TOUCH_EVENT && miniappWidgetMode.isWidgetOnly(packageName))
5012
+ continue;
4974
5013
  let transcriptionRoute;
4975
5014
  if (normalizedStream.startsWith("transcription:") && transcriptionSource) {
4976
5015
  const routes = this.appTranscriptionRoutesForEvent(packageName, normalizedStream);
@@ -5413,6 +5452,298 @@ class LocalMiniappRuntime {
5413
5452
  // Best-effort: a failed stop leaves the app running, which is safe.
5414
5453
  }
5415
5454
  }
5455
+ // ---------------------------------------------------------------------------
5456
+ // Dashboard widgets (session.widgets): a provider serves widgets it declares,
5457
+ // a host with HOST_WIDGETS places them. The provider runs in widget mode
5458
+ // while anything of it is placed and stops once nothing is.
5459
+ // ---------------------------------------------------------------------------
5460
+ widgetPlacements = emptyWidgetPlacements();
5461
+ /** Outstanding widget event calls, keyed by host-generated callId. */
5462
+ widgetCalls = new Map();
5463
+ widgetCallSeq = 0;
5464
+ /** Elements per widget frame; a card is small, and the link is slow. */
5465
+ static WIDGET_FRAME_ELEMENT_CAP = 64;
5466
+ requireWidgetHost(packageName, requestId, op) {
5467
+ return this.requirePermission(packageName, requestId, "HOST_WIDGETS", `to ${op} widgets`);
5468
+ }
5469
+ declaredWidget(app, widgetId) {
5470
+ return (app.widgets ?? []).find((widget) => widget.id === widgetId);
5471
+ }
5472
+ /** The target app and its declared widget, or a reply to the host saying why not. */
5473
+ widgetTarget(hostPackageName, payload, requestId) {
5474
+ const target = payload.packageName;
5475
+ const widgetId = payload.widgetId;
5476
+ const app = target ? this.interopApps().find((a) => a.packageName === target) : undefined;
5477
+ if (!target || !app) {
5478
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5479
+ code: MiniappErrorCode.APP_NOT_FOUND,
5480
+ message: `Miniapp not found: ${target ?? "(missing packageName)"}`,
5481
+ });
5482
+ return null;
5483
+ }
5484
+ if (!widgetId || !this.declaredWidget(app, widgetId)) {
5485
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5486
+ code: MiniappErrorCode.WIDGET_NOT_FOUND,
5487
+ message: `${target} does not declare widget "${widgetId ?? "(missing widgetId)"}"`,
5488
+ });
5489
+ return null;
5490
+ }
5491
+ return { app, widgetId };
5492
+ }
5493
+ handleWidgetsList(hostPackageName, requestId) {
5494
+ if (!this.requireWidgetHost(hostPackageName, requestId, "list"))
5495
+ return;
5496
+ const rows = [];
5497
+ for (const app of this.interopApps()) {
5498
+ if (!app.packageName || app.packageName === hostPackageName || app.packageName.includes("@empty"))
5499
+ continue;
5500
+ for (const widget of app.widgets ?? []) {
5501
+ rows.push({
5502
+ packageName: app.packageName,
5503
+ appName: app.name,
5504
+ id: widget.id,
5505
+ name: widget.name,
5506
+ sizes: widget.sizes,
5507
+ defaultSize: widget.defaultSize,
5508
+ running: app.running,
5509
+ compatible: app.compatibility?.isCompatible !== false,
5510
+ });
5511
+ }
5512
+ }
5513
+ this.sendResult(hostPackageName, requestId, true, rows);
5514
+ }
5515
+ parseWidgetBox(raw) {
5516
+ const box = raw;
5517
+ if (!box || typeof box !== "object")
5518
+ return null;
5519
+ if (box.size !== "XS" && box.size !== "SM" && box.size !== "MD" && box.size !== "LG")
5520
+ return null;
5521
+ const width = Number(box.width);
5522
+ const height = Number(box.height);
5523
+ if (!(width > 0) || !(height > 0))
5524
+ return null;
5525
+ return { size: box.size, width: Math.round(width), height: Math.round(height) };
5526
+ }
5527
+ sendWidgetCall(providerPackageName, widgetId, call) {
5528
+ const callId = `wdg-${Date.now().toString(36)}-${this.widgetCallSeq++}`;
5529
+ this.sendToMiniapp(providerPackageName, {
5530
+ type: MiniappResponseType.WIDGET_CALL,
5531
+ callId,
5532
+ widgetId,
5533
+ kind: call.kind,
5534
+ ...(call.kind === "box" ? { box: call.box } : { event: call.event }),
5535
+ });
5536
+ return callId;
5537
+ }
5538
+ /**
5539
+ * session.widgets.place: record the host's box, wake the provider in widget
5540
+ * mode when it is not running, hand it the box, and answer with the last
5541
+ * frame the provider pushed for the widget.
5542
+ */
5543
+ async handleWidgetPlace(hostPackageName, payload, requestId) {
5544
+ if (!this.requireWidgetHost(hostPackageName, requestId, "place"))
5545
+ return;
5546
+ const target = this.widgetTarget(hostPackageName, payload, requestId);
5547
+ if (!target)
5548
+ return;
5549
+ const { app, widgetId } = target;
5550
+ const box = this.parseWidgetBox(payload.box);
5551
+ if (!box) {
5552
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5553
+ code: MiniappErrorCode.INVALID_ARGUMENT,
5554
+ message: "place needs a box {size, width, height}",
5555
+ });
5556
+ return;
5557
+ }
5558
+ if (app.compatibility && app.compatibility.isCompatible === false) {
5559
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5560
+ code: MiniappErrorCode.APP_NOT_COMPATIBLE,
5561
+ message: `${app.packageName} is not compatible with the connected glasses`,
5562
+ });
5563
+ return;
5564
+ }
5565
+ const provider = app.packageName;
5566
+ // Record the placement before the wake so the spawn lands in widget mode
5567
+ // and an unplace racing it cannot stop the provider early.
5568
+ this.widgetPlacements = placeWidget(this.widgetPlacements, { hostPackageName, providerPackageName: provider, widgetId, box });
5569
+ miniappWidgetMode.setPlaced(provider, true);
5570
+ if (!miniappRunningRegistry.has(provider))
5571
+ miniappWidgetMode.setWidgetOnly(provider, true);
5572
+ try {
5573
+ await this.wakeInteropApp(provider);
5574
+ }
5575
+ catch (e) {
5576
+ this.widgetPlacements = unplaceWidget(this.widgetPlacements, hostPackageName, provider, widgetId);
5577
+ void this.settleWidgetProvider(provider);
5578
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5579
+ code: MiniappErrorCode.WAKE_FAILED,
5580
+ message: e?.message ?? `failed to wake ${provider}`,
5581
+ });
5582
+ return;
5583
+ }
5584
+ // The host may have unplaced it during the wake.
5585
+ if (placementOf(this.widgetPlacements, hostPackageName, provider, widgetId) && this.connectedApps.has(provider)) {
5586
+ this.sendWidgetCall(provider, widgetId, { kind: "box", box });
5587
+ }
5588
+ this.sendResult(hostPackageName, requestId, true, { frame: widgetFrameOf(this.widgetPlacements, provider, widgetId) });
5589
+ }
5590
+ async handleWidgetUnplace(hostPackageName, payload, requestId) {
5591
+ if (!this.requireWidgetHost(hostPackageName, requestId, "unplace"))
5592
+ return;
5593
+ const target = this.widgetTarget(hostPackageName, payload, requestId);
5594
+ if (!target)
5595
+ return;
5596
+ const provider = target.app.packageName;
5597
+ const had = placementOf(this.widgetPlacements, hostPackageName, provider, target.widgetId);
5598
+ this.widgetPlacements = unplaceWidget(this.widgetPlacements, hostPackageName, provider, target.widgetId);
5599
+ this.sendResult(hostPackageName, requestId, true);
5600
+ if (!had)
5601
+ return;
5602
+ if (this.connectedApps.has(provider) && widgetHostsOf(this.widgetPlacements, provider, target.widgetId).length === 0) {
5603
+ this.sendWidgetCall(provider, target.widgetId, { kind: "box", box: null });
5604
+ }
5605
+ await this.settleWidgetProvider(provider);
5606
+ }
5607
+ /** A provider with nothing placed and no wearer-opened run of its own stops. */
5608
+ async settleWidgetProvider(providerPackageName) {
5609
+ if (isProviderPlaced(this.widgetPlacements, providerPackageName))
5610
+ return;
5611
+ miniappWidgetMode.setPlaced(providerPackageName, false);
5612
+ if (!miniappWidgetMode.isWidgetOnly(providerPackageName))
5613
+ return;
5614
+ // Widget mode stays set until the context is gone, so the tray never
5615
+ // sees the stopping app as a normal one.
5616
+ try {
5617
+ await this.stopInteropApp(providerPackageName);
5618
+ }
5619
+ catch (err) {
5620
+ console.warn(`${LOG_TAG}: stopping widget provider ${providerPackageName} failed`, err);
5621
+ }
5622
+ }
5623
+ /** session.widgets.send: forward input to a placed widget and relay the provider's answer. */
5624
+ async handleWidgetSend(hostPackageName, payload, requestId) {
5625
+ if (!this.requireWidgetHost(hostPackageName, requestId, "send"))
5626
+ return;
5627
+ const target = this.widgetTarget(hostPackageName, payload, requestId);
5628
+ if (!target)
5629
+ return;
5630
+ const provider = target.app.packageName;
5631
+ const event = payload.event;
5632
+ if (!event || typeof event !== "object" || typeof event.type !== "string") {
5633
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5634
+ code: MiniappErrorCode.INVALID_ARGUMENT,
5635
+ message: "send needs an event with a string type",
5636
+ });
5637
+ return;
5638
+ }
5639
+ if (!placementOf(this.widgetPlacements, hostPackageName, provider, target.widgetId)) {
5640
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5641
+ code: MiniappErrorCode.WIDGET_NOT_PLACED,
5642
+ message: `${hostPackageName} has not placed ${provider}/${target.widgetId}`,
5643
+ });
5644
+ return;
5645
+ }
5646
+ // Floored at 6 s for the same reason as actions: a provider just woken
5647
+ // buffers the call for 5 s while it registers.
5648
+ const timeoutMs = Math.min(Math.max(Number(payload.timeoutMs) || 5_000, 6_000), 30_000);
5649
+ try {
5650
+ await this.wakeInteropApp(provider);
5651
+ }
5652
+ catch (e) {
5653
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5654
+ code: MiniappErrorCode.WAKE_FAILED,
5655
+ message: e?.message ?? `failed to wake ${provider}`,
5656
+ });
5657
+ return;
5658
+ }
5659
+ if (!this.connectedApps.has(provider)) {
5660
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5661
+ code: MiniappErrorCode.WAKE_FAILED,
5662
+ message: `${provider} disconnected before the event could be delivered`,
5663
+ });
5664
+ return;
5665
+ }
5666
+ const callId = this.sendWidgetCall(provider, target.widgetId, { kind: "event", event });
5667
+ const timer = BgTimer.setTimeout(() => {
5668
+ this.widgetCalls.delete(callId);
5669
+ this.sendResult(hostPackageName, requestId, false, undefined, {
5670
+ code: MiniappErrorCode.ACTION_TIMEOUT,
5671
+ message: `widget event "${event.type}" timed out after ${timeoutMs}ms`,
5672
+ });
5673
+ }, timeoutMs);
5674
+ this.widgetCalls.set(callId, { hostPackageName, providerPackageName: provider, hostRequestId: requestId, timer });
5675
+ }
5676
+ /** Provider → host: a WIDGET_RESULT for a pending send; box acknowledgements have no pending call and are dropped. */
5677
+ handleWidgetResult(providerPackageName, payload) {
5678
+ const callId = payload.callId;
5679
+ if (!callId)
5680
+ return;
5681
+ const pending = this.widgetCalls.get(callId);
5682
+ if (!pending || pending.providerPackageName !== providerPackageName)
5683
+ return;
5684
+ this.widgetCalls.delete(callId);
5685
+ BgTimer.clearTimeout(pending.timer);
5686
+ if (payload.ok === true) {
5687
+ const result = payload.result;
5688
+ if (this.actionPayloadTooLarge(result)) {
5689
+ this.sendResult(pending.hostPackageName, pending.hostRequestId, false, undefined, {
5690
+ code: MiniappErrorCode.PAYLOAD_TOO_LARGE,
5691
+ message: "widget event result exceeded the 256 KB cap",
5692
+ });
5693
+ return;
5694
+ }
5695
+ this.sendResult(pending.hostPackageName, pending.hostRequestId, true, result ?? null);
5696
+ }
5697
+ else {
5698
+ const error = payload.error ?? {
5699
+ code: MiniappErrorCode.INTERNAL,
5700
+ message: "widget event handler error",
5701
+ };
5702
+ this.sendResult(pending.hostPackageName, pending.hostRequestId, false, undefined, error);
5703
+ }
5704
+ }
5705
+ /** Provider → host, one-shot: cache the frame and push it to every host holding the widget. */
5706
+ handleWidgetUpdate(providerPackageName, payload) {
5707
+ const widgetId = payload.widgetId;
5708
+ const elements = payload.elements;
5709
+ if (!widgetId || !Array.isArray(elements))
5710
+ return;
5711
+ const app = this.interopApps().find((a) => a.packageName === providerPackageName);
5712
+ if (!app || !this.declaredWidget(app, widgetId))
5713
+ return;
5714
+ if (elements.length > LocalMiniappRuntime.WIDGET_FRAME_ELEMENT_CAP || this.actionPayloadTooLarge(elements)) {
5715
+ console.warn(`${LOG_TAG}: dropping oversized widget frame from ${providerPackageName}/${widgetId}`);
5716
+ return;
5717
+ }
5718
+ this.widgetPlacements = setWidgetFrame(this.widgetPlacements, providerPackageName, widgetId, elements);
5719
+ for (const host of widgetHostsOf(this.widgetPlacements, providerPackageName, widgetId)) {
5720
+ this.sendToMiniapp(host, { type: MiniappResponseType.WIDGET_FRAME, packageName: providerPackageName, widgetId, elements });
5721
+ }
5722
+ }
5723
+ /** A miniapp disconnected: as a host its placements go, as a provider its boxes are forgotten and its frames kept. */
5724
+ onWidgetPartyGone(packageName) {
5725
+ const providersBefore = placedProviders(this.widgetPlacements);
5726
+ this.widgetPlacements = dropWidgetHost(this.widgetPlacements, packageName);
5727
+ this.widgetPlacements = dropWidgetProvider(this.widgetPlacements, packageName);
5728
+ miniappWidgetMode.setPlaced(packageName, false);
5729
+ miniappWidgetMode.setWidgetOnly(packageName, false);
5730
+ for (const [callId, pending] of Array.from(this.widgetCalls)) {
5731
+ if (pending.hostPackageName !== packageName && pending.providerPackageName !== packageName)
5732
+ continue;
5733
+ this.widgetCalls.delete(callId);
5734
+ BgTimer.clearTimeout(pending.timer);
5735
+ if (pending.providerPackageName === packageName) {
5736
+ this.sendResult(pending.hostPackageName, pending.hostRequestId, false, undefined, {
5737
+ code: MiniappErrorCode.WAKE_FAILED,
5738
+ message: `${packageName} stopped before answering`,
5739
+ });
5740
+ }
5741
+ }
5742
+ for (const provider of providersBefore) {
5743
+ if (provider !== packageName)
5744
+ void this.settleWidgetProvider(provider);
5745
+ }
5746
+ }
5416
5747
  /** True iff `value` serializes larger than the action payload cap. */
5417
5748
  actionPayloadTooLarge(value) {
5418
5749
  try {