@wildo-ai/saas-frontend-lib 1.1.3 → 1.1.4

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 (127) hide show
  1. package/dist/esm/companion-exports.d.ts +1 -1
  2. package/dist/esm/companion-exports.d.ts.map +1 -1
  3. package/dist/esm/companion-exports.js +1 -1
  4. package/dist/esm/companion-exports.js.map +1 -1
  5. package/dist/esm/components/ai-elements/decision/approval.d.ts +13 -1
  6. package/dist/esm/components/ai-elements/decision/approval.d.ts.map +1 -1
  7. package/dist/esm/components/ai-elements/decision/approval.js.map +1 -1
  8. package/dist/esm/components/flows-actors/approval.d.ts.map +1 -1
  9. package/dist/esm/components/flows-actors/approval.js +12 -7
  10. package/dist/esm/components/flows-actors/approval.js.map +1 -1
  11. package/dist/esm/components/flows-actors/approval.labels.d.ts.map +1 -1
  12. package/dist/esm/components/flows-actors/approval.labels.js +3 -0
  13. package/dist/esm/components/flows-actors/approval.labels.js.map +1 -1
  14. package/dist/esm/components/flows-actors/execution-plan.js +1 -1
  15. package/dist/esm/components/flows-actors/execution-plan.js.map +1 -1
  16. package/dist/esm/components/flows-actors/task-memory.js +1 -1
  17. package/dist/esm/components/flows-actors/task-memory.js.map +1 -1
  18. package/dist/esm/components/form/automated/generated-relationship-field.hooks.d.ts +1 -1
  19. package/dist/esm/components/form/controls/number/slider.d.ts +1 -1
  20. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts +1 -1
  21. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts.map +1 -1
  22. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.js.map +1 -1
  23. package/dist/esm/components/form/fields/form-field-file.d.ts.map +1 -1
  24. package/dist/esm/components/form/fields/form-field-file.js +66 -17
  25. package/dist/esm/components/form/fields/form-field-file.js.map +1 -1
  26. package/dist/esm/components/form/fields/form-field-file.labels.js +2 -2
  27. package/dist/esm/components/form/fields/form-field-file.labels.js.map +1 -1
  28. package/dist/esm/components/form/form-field-types.d.ts +20 -0
  29. package/dist/esm/components/form/form-field-types.d.ts.map +1 -1
  30. package/dist/esm/components/form/form-field-types.js.map +1 -1
  31. package/dist/esm/components/navigation/NavigationItemBadge.d.ts +7 -1
  32. package/dist/esm/components/navigation/NavigationItemBadge.d.ts.map +1 -1
  33. package/dist/esm/components/navigation/NavigationItemBadge.js +29 -1
  34. package/dist/esm/components/navigation/NavigationItemBadge.js.map +1 -1
  35. package/dist/esm/components/navigation/menu-bar.d.ts +1 -1
  36. package/dist/esm/components/overlays/containers/OverlayContainer.d.ts.map +1 -1
  37. package/dist/esm/components/overlays/containers/OverlayContainer.js +36 -9
  38. package/dist/esm/components/overlays/containers/OverlayContainer.js.map +1 -1
  39. package/dist/esm/components/overlays/floating/context-menu.d.ts +1 -1
  40. package/dist/esm/components/overlays/floating/dropdown-menu.d.ts +1 -1
  41. package/dist/esm/components/resources/ResourceLayout_FilterChips.js +1 -1
  42. package/dist/esm/components/resources/ResourceLayout_FilterChips.js.map +1 -1
  43. package/dist/esm/components/resources/ResourceListItemRenderer.js +1 -1
  44. package/dist/esm/components/resources/ResourceListItemRenderer.js.map +1 -1
  45. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts +12 -0
  46. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts.map +1 -1
  47. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js +13 -1
  48. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js.map +1 -1
  49. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts +106 -49
  50. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts.map +1 -1
  51. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js +311 -109
  52. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js.map +1 -1
  53. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.d.ts.map +1 -1
  54. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js +32 -2
  55. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js.map +1 -1
  56. package/dist/esm/components/settings/SettingsHub.d.ts.map +1 -1
  57. package/dist/esm/components/settings/SettingsHub.js +30 -6
  58. package/dist/esm/components/settings/SettingsHub.js.map +1 -1
  59. package/dist/esm/components/views/onboarding-view/OnboardingView.d.ts.map +1 -1
  60. package/dist/esm/components/views/onboarding-view/OnboardingView.js +9 -2
  61. package/dist/esm/components/views/onboarding-view/OnboardingView.js.map +1 -1
  62. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts +16 -0
  63. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts.map +1 -1
  64. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js +17 -0
  65. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js.map +1 -1
  66. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.d.ts.map +1 -1
  67. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js +3 -2
  68. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js.map +1 -1
  69. package/dist/esm/core/billing/billing-launcher.js +1 -1
  70. package/dist/esm/core/billing/billing-launcher.js.map +1 -1
  71. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts +64 -4
  72. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts.map +1 -1
  73. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js +76 -4
  74. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js.map +1 -1
  75. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts +8 -0
  76. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts.map +1 -1
  77. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js +1 -0
  78. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js.map +1 -1
  79. package/dist/esm/core/config/chart-view.frontend.schemas.d.ts +8 -8
  80. package/dist/esm/core/config/composite-view.schemas.d.ts +4 -4
  81. package/dist/esm/core/config/engine-settings-destinations.d.ts +0 -69
  82. package/dist/esm/core/config/engine-settings-destinations.d.ts.map +1 -1
  83. package/dist/esm/core/config/engine-settings-destinations.js +35 -74
  84. package/dist/esm/core/config/engine-settings-destinations.js.map +1 -1
  85. package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts +10 -1
  86. package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts.map +1 -1
  87. package/dist/esm/core/config/settings-hub.frontend.schemas.js +9 -0
  88. package/dist/esm/core/config/settings-hub.frontend.schemas.js.map +1 -1
  89. package/dist/esm/core/config/useSettingsHubConfig.d.ts.map +1 -1
  90. package/dist/esm/core/config/useSettingsHubConfig.js +8 -1
  91. package/dist/esm/core/config/useSettingsHubConfig.js.map +1 -1
  92. package/dist/esm/core/events/events.frontend.schemas.d.ts +4 -4
  93. package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts +12 -1
  94. package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts.map +1 -1
  95. package/dist/esm/core/external-providers/ProviderFilePickerHost.js +15 -2
  96. package/dist/esm/core/external-providers/ProviderFilePickerHost.js.map +1 -1
  97. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts +1 -2
  98. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts.map +1 -1
  99. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.js.map +1 -1
  100. package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts +6 -1
  101. package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts.map +1 -1
  102. package/dist/esm/core/flows-actors/FlowsActorsContext.js +10 -2
  103. package/dist/esm/core/flows-actors/FlowsActorsContext.js.map +1 -1
  104. package/dist/esm/core/i18n/I18nContext.d.ts +23 -0
  105. package/dist/esm/core/i18n/I18nContext.d.ts.map +1 -1
  106. package/dist/esm/core/i18n/I18nContext.js +6 -1
  107. package/dist/esm/core/i18n/I18nContext.js.map +1 -1
  108. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts +75 -2
  109. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts.map +1 -1
  110. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js +52 -0
  111. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js.map +1 -1
  112. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts +3 -2
  113. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts.map +1 -1
  114. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js +57 -4
  115. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js.map +1 -1
  116. package/dist/esm/core/resources/ResourceReadCacheBridge.d.ts.map +1 -1
  117. package/dist/esm/core/resources/ResourceReadCacheBridge.js +130 -37
  118. package/dist/esm/core/resources/ResourceReadCacheBridge.js.map +1 -1
  119. package/dist/esm/core/resources/resources.frontend.schemas.d.ts +2 -2
  120. package/dist/esm/core/runtime/start-application.frontend.service.d.ts.map +1 -1
  121. package/dist/esm/core/runtime/start-application.frontend.service.js +17 -9
  122. package/dist/esm/core/runtime/start-application.frontend.service.js.map +1 -1
  123. package/dist/esm/core/security/UserOrgsContext.d.ts.map +1 -1
  124. package/dist/esm/core/security/UserOrgsContext.js +61 -5
  125. package/dist/esm/core/security/UserOrgsContext.js.map +1 -1
  126. package/dist/tsconfig.build.tsbuildinfo +1 -1
  127. package/package.json +6 -6
@@ -54,7 +54,22 @@ export declare enum ProviderComponentDiagnosticKind {
54
54
  * loader returning a MODULE NAMESPACE — `() => import('./Picker')` — where it
55
55
  * should return the component itself.
56
56
  */
57
- LOADED_VALUE_IS_NOT_A_COMPONENT = "LOADED_VALUE_IS_NOT_A_COMPONENT"
57
+ LOADED_VALUE_IS_NOT_A_COMPONENT = "LOADED_VALUE_IS_NOT_A_COMPONENT",
58
+ /**
59
+ * A live provider DECLARES a component for a capability and nothing supplies
60
+ * its loader — neither the module (`components[cap].load`) nor the facet
61
+ * library (`contributeProviderComponentLoaders`). The declaration is DATA a
62
+ * reviewer can read; without code behind it the chooser would offer a picker
63
+ * that cannot open. Not registered, and reported once at startup.
64
+ */
65
+ DECLARED_WITHOUT_LOADER = "DECLARED_WITHOUT_LOADER",
66
+ /**
67
+ * BOTH the module and the facet library supplied a loader for one
68
+ * `capability:providerRef`. The module's wins — it is the provider's own
69
+ * word — and the collision is reported, because the engine never authors both
70
+ * and two loaders for one declaration is the map-order ambiguity #380 removed.
71
+ */
72
+ LOADER_SUPPLIED_TWICE = "LOADER_SUPPLIED_TWICE"
58
73
  }
59
74
  export interface ProviderComponentDiagnostic {
60
75
  readonly kind: ProviderComponentDiagnosticKind;
@@ -113,16 +128,61 @@ interface ComponentBearingProviderModule {
113
128
  ref: string;
114
129
  };
115
130
  components?: Readonly<Record<string, ProviderFrontendComponentDescriptor & {
116
- load: ProviderComponentLoader;
131
+ load?: ProviderComponentLoader;
117
132
  }>>;
118
133
  }
119
134
  /**
120
- * Turns the live provider modules into registrations.
135
+ * A loader the FACET LIBRARY supplies for a component a provider module
136
+ * declares — the second of the two doors, and the one every engine-shipped
137
+ * component uses (#394).
138
+ *
139
+ * The provider module, in `@wildo-ai/external-connectors-public`, declares the
140
+ * DATA half (`components[cap].selectionDelivery`) and cannot name a loader that
141
+ * reaches a React component: that package is deliberately renderer-free, and it
142
+ * sits BELOW the component libraries in the layering, so a dynamic import from
143
+ * it would close a package cycle. The library that owns the component
144
+ * (`presets-components` for the app facet) contributes the loader here instead,
145
+ * from the same place it registers its presets. A provider PACKAGE that ships
146
+ * its own component still uses `components[cap].load` — both doors exist, the
147
+ * engine authors exactly one per declaration, and a collision is reported.
148
+ */
149
+ export interface ProviderComponentLoaderContribution {
150
+ readonly capability: ProviderCapability;
151
+ readonly providerRef: string;
152
+ readonly load: ProviderComponentLoader;
153
+ }
154
+ /**
155
+ * Registers loaders for provider components a facet library ships. Module-level
156
+ * and idempotent per key, like `ComponentRegistryService.register`: the app
157
+ * calls the library's registration entry once at startup, and a second
158
+ * contribution for one key replaces the first rather than duplicating it —
159
+ * the library is one author, and the last thing it said is what it means.
160
+ *
161
+ * A contribution for a provider the DATA channel does not declare live is
162
+ * SILENT, by the same rule as code without data in `hydrateFrontendProviderModules`:
163
+ * a bundle legitimately ships a picker an environment leaves off.
164
+ */
165
+ export declare function contributeProviderComponentLoaders(loaders: Iterable<ProviderComponentLoaderContribution>): void;
166
+ /** Every contributed loader, keyed `capability:providerRef`. Read at registry construction. */
167
+ export declare function listContributedProviderComponentLoaders(): ReadonlyMap<string, ProviderComponentLoaderContribution>;
168
+ /** Tests only: forget every contributed loader. */
169
+ export declare function _clearContributedProviderComponentLoaders(): void;
170
+ /**
171
+ * Turns the live provider modules into registrations, joining each declared
172
+ * component to its loader — from the module when it carries one, else from
173
+ * the facet library's contributions.
121
174
  *
122
175
  * Order follows the registry's iteration order, which is the order the service
123
176
  * declared its providers — so `listProviders` is stable across reloads and a
124
177
  * surface that shows a chooser does not reorder itself between renders.
178
+ *
179
+ * A declaration nothing can load is NOT registered: a chooser must offer only
180
+ * what can render. It is reported through `onDiagnostic` instead, once, at
181
+ * startup — which is the moment somebody can still fix it.
125
182
  */
126
- export declare function collectProviderComponentRegistrations(modules: Iterable<ComponentBearingProviderModule>): ProviderComponentRegistration[];
183
+ export declare function collectProviderComponentRegistrations(modules: Iterable<ComponentBearingProviderModule>, input?: {
184
+ readonly contributedLoaders?: ReadonlyMap<string, ProviderComponentLoaderContribution>;
185
+ readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;
186
+ }): ProviderComponentRegistration[];
127
187
  export {};
128
188
  //# sourceMappingURL=provider-component-registry.frontend.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-component-registry.frontend.service.d.ts","sourceRoot":"","sources":["../../../../src/core/components-registry/provider-component-registry.frontend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,sCAAsC,CAAC;AAEhG,qFAAqF;AACrF,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7D,kEAAkE;AAClE,oBAAY,+BAA+B;IACzC;;;;OAIG;IACH,sBAAsB,2BAA2B;IACjD,uGAAuG;IACvG,WAAW,gBAAgB;IAC3B;;;;OAIG;IACH,+BAA+B,oCAAoC;CACpE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,mCAAmC,CAAC;CAC1D;AAED,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AAE3D,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,aAAa,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACrE,0EAA0E;IAC1E,GAAG,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAClE;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,mCAAmC,GAAG,SAAS,CAAC;IAC/G;;;;OAIG;IACH,OAAO,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CACjG;AAoBD,wBAAgB,+BAA+B,CAAC,KAAK,CAAC,EAAE;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,6BAA6B,CAAC,CAAC;IACjE,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC3E,GAAG,yBAAyB,CAqG5B;AAED,sEAAsE;AACtE,UAAU,8BAA8B;IACtC,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,mCAAmC,GAAG;QAAE,IAAI,EAAE,uBAAuB,CAAA;KAAE,CAAC,CAAC,CAAC;CAChH;AAED;;;;;;GAMG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,QAAQ,CAAC,8BAA8B,CAAC,GAChD,6BAA6B,EAAE,CAkBjC"}
1
+ {"version":3,"file":"provider-component-registry.frontend.service.d.ts","sourceRoot":"","sources":["../../../../src/core/components-registry/provider-component-registry.frontend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,sCAAsC,CAAC;AAEhG,qFAAqF;AACrF,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7D,kEAAkE;AAClE,oBAAY,+BAA+B;IACzC;;;;OAIG;IACH,sBAAsB,2BAA2B;IACjD,uGAAuG;IACvG,WAAW,gBAAgB;IAC3B;;;;OAIG;IACH,+BAA+B,oCAAoC;IACnE;;;;;;OAMG;IACH,uBAAuB,4BAA4B;IACnD;;;;;OAKG;IACH,qBAAqB,0BAA0B;CAChD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,mCAAmC,CAAC;CAC1D;AAED,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AAE3D,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,aAAa,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACrE,0EAA0E;IAC1E,GAAG,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAClE;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,mCAAmC,GAAG,SAAS,CAAC;IAC/G;;;;OAIG;IACH,OAAO,CAAC,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CACjG;AAoBD,wBAAgB,+BAA+B,CAAC,KAAK,CAAC,EAAE;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,6BAA6B,CAAC,CAAC;IACjE,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC3E,GAAG,yBAAyB,CAqG5B;AAED,sEAAsE;AACtE,UAAU,8BAA8B;IACtC,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,mCAAmC,GAAG;QAAE,IAAI,CAAC,EAAE,uBAAuB,CAAA;KAAE,CAAC,CAAC,CAAC;CACjH;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;CACxC;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,QAAQ,CAAC,mCAAmC,CAAC,GAAG,IAAI,CAI/G;AAED,+FAA+F;AAC/F,wBAAgB,uCAAuC,IAAI,WAAW,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAElH;AAED,mDAAmD;AACnD,wBAAgB,yCAAyC,IAAI,IAAI,CAEhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,QAAQ,CAAC,8BAA8B,CAAC,EACjD,KAAK,CAAC,EAAE;IACN,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAAC;IACvF,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC3E,GACA,6BAA6B,EAAE,CAgDjC"}
@@ -51,6 +51,21 @@ export var ProviderComponentDiagnosticKind;
51
51
  * should return the component itself.
52
52
  */
53
53
  ProviderComponentDiagnosticKind["LOADED_VALUE_IS_NOT_A_COMPONENT"] = "LOADED_VALUE_IS_NOT_A_COMPONENT";
54
+ /**
55
+ * A live provider DECLARES a component for a capability and nothing supplies
56
+ * its loader — neither the module (`components[cap].load`) nor the facet
57
+ * library (`contributeProviderComponentLoaders`). The declaration is DATA a
58
+ * reviewer can read; without code behind it the chooser would offer a picker
59
+ * that cannot open. Not registered, and reported once at startup.
60
+ */
61
+ ProviderComponentDiagnosticKind["DECLARED_WITHOUT_LOADER"] = "DECLARED_WITHOUT_LOADER";
62
+ /**
63
+ * BOTH the module and the facet library supplied a loader for one
64
+ * `capability:providerRef`. The module's wins — it is the provider's own
65
+ * word — and the collision is reported, because the engine never authors both
66
+ * and two loaders for one declaration is the map-order ambiguity #380 removed.
67
+ */
68
+ ProviderComponentDiagnosticKind["LOADER_SUPPLIED_TWICE"] = "LOADER_SUPPLIED_TWICE";
54
69
  })(ProviderComponentDiagnosticKind || (ProviderComponentDiagnosticKind = {}));
55
70
  function isModuleNamespace(value) {
56
71
  return (typeof value === 'object'
@@ -156,21 +171,78 @@ export function createProviderComponentRegistry(input) {
156
171
  },
157
172
  };
158
173
  }
174
+ const contributedLoaders = new Map();
175
+ const loaderKeyOf = (capability, providerRef) => `${capability}:${providerRef}`;
176
+ /**
177
+ * Registers loaders for provider components a facet library ships. Module-level
178
+ * and idempotent per key, like `ComponentRegistryService.register`: the app
179
+ * calls the library's registration entry once at startup, and a second
180
+ * contribution for one key replaces the first rather than duplicating it —
181
+ * the library is one author, and the last thing it said is what it means.
182
+ *
183
+ * A contribution for a provider the DATA channel does not declare live is
184
+ * SILENT, by the same rule as code without data in `hydrateFrontendProviderModules`:
185
+ * a bundle legitimately ships a picker an environment leaves off.
186
+ */
187
+ export function contributeProviderComponentLoaders(loaders) {
188
+ for (const loader of loaders) {
189
+ contributedLoaders.set(loaderKeyOf(loader.capability, loader.providerRef), loader);
190
+ }
191
+ }
192
+ /** Every contributed loader, keyed `capability:providerRef`. Read at registry construction. */
193
+ export function listContributedProviderComponentLoaders() {
194
+ return contributedLoaders;
195
+ }
196
+ /** Tests only: forget every contributed loader. */
197
+ export function _clearContributedProviderComponentLoaders() {
198
+ contributedLoaders.clear();
199
+ }
159
200
  /**
160
- * Turns the live provider modules into registrations.
201
+ * Turns the live provider modules into registrations, joining each declared
202
+ * component to its loader — from the module when it carries one, else from
203
+ * the facet library's contributions.
161
204
  *
162
205
  * Order follows the registry's iteration order, which is the order the service
163
206
  * declared its providers — so `listProviders` is stable across reloads and a
164
207
  * surface that shows a chooser does not reorder itself between renders.
208
+ *
209
+ * A declaration nothing can load is NOT registered: a chooser must offer only
210
+ * what can render. It is reported through `onDiagnostic` instead, once, at
211
+ * startup — which is the moment somebody can still fix it.
165
212
  */
166
- export function collectProviderComponentRegistrations(modules) {
213
+ export function collectProviderComponentRegistrations(modules, input) {
167
214
  const registrations = [];
215
+ const contributed = input?.contributedLoaders ?? listContributedProviderComponentLoaders();
168
216
  for (const module of modules) {
169
217
  for (const [capability, declaration] of Object.entries(module.components ?? {})) {
218
+ const providerRef = module.metadata.ref;
219
+ const supplied = contributed.get(loaderKeyOf(capability, providerRef));
220
+ if (declaration.load !== undefined && supplied !== undefined) {
221
+ input?.onDiagnostic?.({
222
+ kind: ProviderComponentDiagnosticKind.LOADER_SUPPLIED_TWICE,
223
+ capability,
224
+ providerRef,
225
+ message: `Provider "${providerRef}" carries its own loader for "${capability}" AND the facet library contributed `
226
+ + "one. The module's is used; remove one of the two.",
227
+ });
228
+ }
229
+ const load = declaration.load ?? supplied?.load;
230
+ if (load === undefined) {
231
+ input?.onDiagnostic?.({
232
+ kind: ProviderComponentDiagnosticKind.DECLARED_WITHOUT_LOADER,
233
+ capability,
234
+ providerRef,
235
+ message: `Provider "${providerRef}" declares a "${capability}" component and nothing supplies its loader — `
236
+ + 'neither the module nor the facet library. It is not offered. An engine-shipped component is '
237
+ + 'registered by the facet library (presets-components for the app); a provider package supplies '
238
+ + '`components[capability].load`.',
239
+ });
240
+ continue;
241
+ }
170
242
  registrations.push({
171
243
  capability: capability,
172
- providerRef: module.metadata.ref,
173
- load: declaration.load,
244
+ providerRef,
245
+ load,
174
246
  // Only the declared half, never the whole declaration: `load` is already
175
247
  // carried beside it, and a registration holding the same function twice
176
248
  // is two places for one fact to go stale.
@@ -1 +1 @@
1
- {"version":3,"file":"provider-component-registry.frontend.service.js","sourceRoot":"","sources":["../../../../src/core/components-registry/provider-component-registry.frontend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Components contributed by PROVIDERS, keyed by the capability each fills.\n *\n * ## Why this is a sibling of `ComponentRegistryService` and not an extension\n *\n * The two index different vocabularies, and merging them would put an open one\n * into a key built for a closed one:\n *\n * - `ComponentRegistryService` keys `componentType:preset[:category]`, where\n * `FrontendComponentType` is a CLOSED enum the engine owns. Exactly one\n * component answers a key, resolution is synchronous, and a missing\n * registration is a startup refusal.\n * - This registry keys `capability:providerRef`, where `ProviderCapability`\n * is OPEN — an application extends it by TypeScript module augmentation.\n * SEVERAL providers may answer one capability, the component arrives\n * asynchronously, and none of it is required for the app to mount.\n *\n * Forcing provider components through the closed enum would mean an engine edit\n * for every new provider capability — precisely what the open vocabulary exists\n * to avoid — and would make \"which component answers this key\" ambiguous in a\n * registry whose whole contract is that it is not.\n *\n * It also keeps the blast radius honest. `ComponentRegistryService` has sixteen\n * consumers across four packages (re-measured 2026-09-06; the plan's figure of\n * eleven predates several of them), most of them outside this slice's territory.\n * A sibling registry touches none of them.\n *\n * ## Several providers, and no silent winner\n *\n * `listProviders` returns every provider offering a component for a capability,\n * in registration order, and nothing here picks one. That is deliberate: the\n * defect being fixed is that resolution WAS first-match, so a Drive picker and\n * a Dropbox picker could not coexist and the winner depended on map order. A\n * surface with two providers has a choice to present; a registry that answered\n * it would be making a product decision in a lookup table.\n */\n\nimport type React from 'react';\nimport type { ProviderCapability } from '@wildo-ai/saas-models';\nimport type { ProviderFrontendComponentDescriptor } from '@wildo-ai/saas-models/public-runtime';\n\n/** A loader as a provider module declares it: on demand, returning the component. */\nexport type ProviderComponentLoader = () => Promise<unknown>;\n\n/** Why a provider component could not be registered or loaded. */\nexport enum ProviderComponentDiagnosticKind {\n /**\n * A second registration arrived for one capability AND provider. The first is\n * kept: a duplicate is a wiring mistake, and swapping the live component\n * under a mounted surface would be worse than ignoring it.\n */\n DUPLICATE_REGISTRATION = 'DUPLICATE_REGISTRATION',\n /** The loader threw or rejected. That provider's component is unavailable; others are not affected. */\n LOAD_FAILED = 'LOAD_FAILED',\n /**\n * The loader resolved something that is not a component. Almost always a\n * loader returning a MODULE NAMESPACE — `() => import('./Picker')` — where it\n * should return the component itself.\n */\n LOADED_VALUE_IS_NOT_A_COMPONENT = 'LOADED_VALUE_IS_NOT_A_COMPONENT',\n}\n\nexport interface ProviderComponentDiagnostic {\n readonly kind: ProviderComponentDiagnosticKind;\n readonly capability: string;\n readonly providerRef: string;\n readonly message: string;\n readonly cause?: unknown;\n}\n\nexport interface ProviderComponentRegistration {\n readonly capability: ProviderCapability;\n readonly providerRef: string;\n readonly load: ProviderComponentLoader;\n /**\n * What the provider DECLARED about this component — today, what a selection\n * from it contains. Kept beside the loader rather than looked up from the\n * DATA entry at the use site, because a surface needs it BEFORE it decides to\n * load anything, and because the two would then be two sources for one fact.\n */\n readonly descriptor: ProviderFrontendComponentDescriptor;\n}\n\n/** A component type this registry will hand back once loaded. */\nexport type ProviderComponent = React.ComponentType<never>;\n\nexport interface ProviderComponentRegistry {\n /**\n * Every provider offering a component for this capability, in registration\n * order. Synchronous ON PURPOSE: a surface has to render its chooser before\n * any component is loaded, and awaiting here would make an empty frame.\n */\n listProviders(capability: ProviderCapability): ReadonlyArray<string>;\n /** Whether this exact provider offers a component for this capability. */\n has(capability: ProviderCapability, providerRef: string): boolean;\n /**\n * What the provider declared about its component, without loading it —\n * `undefined` when this provider offers none for this capability.\n *\n * Synchronous and separate from `resolve` on purpose: the framework routes a\n * selection according to what was DECLARED, and a routing decision that had to\n * await a download would mean downloading a picker to find out whether the\n * surface can use it.\n */\n describe(capability: ProviderCapability, providerRef: string): ProviderFrontendComponentDescriptor | undefined;\n /**\n * Loads one provider's component. The loader runs at most once per pair —\n * a chooser that mounts and unmounts must not re-download a picker — and a\n * failure is reported and returns `null` rather than throwing into a render.\n */\n resolve(capability: ProviderCapability, providerRef: string): Promise<ProviderComponent | null>;\n}\n\nfunction isModuleNamespace(value: unknown): boolean {\n return (\n typeof value === 'object'\n && value !== null\n && (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag] === 'Module'\n );\n}\n\n/**\n * A React component is a function, or an object for `memo` / `forwardRef` /\n * `lazy`. Anything else — a namespace, a string, a plain data object — cannot\n * be rendered, and finding out at render time means a blank surface with a\n * stack trace pointing at React rather than at the provider.\n */\nfunction looksLikeComponent(value: unknown): value is ProviderComponent {\n return typeof value === 'function' || (typeof value === 'object' && value !== null);\n}\n\nexport function createProviderComponentRegistry(input?: {\n readonly registrations?: Iterable<ProviderComponentRegistration>;\n readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;\n}): ProviderComponentRegistry {\n const raise = (diagnostic: ProviderComponentDiagnostic): void => {\n input?.onDiagnostic?.(diagnostic);\n };\n const loaders = new Map<string, ProviderComponentLoader>();\n const descriptors = new Map<string, ProviderFrontendComponentDescriptor>();\n const byCapability = new Map<string, string[]>();\n const loaded = new Map<string, Promise<ProviderComponent | null>>();\n const keyOf = (capability: string, providerRef: string): string => `${capability}:${providerRef}`;\n\n for (const registration of input?.registrations ?? []) {\n const key = keyOf(registration.capability, registration.providerRef);\n if (loaders.has(key)) {\n raise({\n kind: ProviderComponentDiagnosticKind.DUPLICATE_REGISTRATION,\n capability: registration.capability,\n providerRef: registration.providerRef,\n message:\n `Provider \"${registration.providerRef}\" registered a component for \"${registration.capability}\" `\n + 'more than once. The first registration is kept.',\n });\n continue;\n }\n\n loaders.set(key, registration.load);\n descriptors.set(key, registration.descriptor);\n const providers = byCapability.get(registration.capability) ?? [];\n providers.push(registration.providerRef);\n byCapability.set(registration.capability, providers);\n }\n\n return {\n listProviders(capability) {\n return byCapability.get(capability) ?? [];\n },\n\n has(capability, providerRef) {\n return loaders.has(keyOf(capability, providerRef));\n },\n\n describe(capability, providerRef) {\n return descriptors.get(keyOf(capability, providerRef));\n },\n\n resolve(capability, providerRef) {\n const key = keyOf(capability, providerRef);\n const cached = loaded.get(key);\n if (cached !== undefined) return cached;\n\n const load = loaders.get(key);\n if (load === undefined) return Promise.resolve(null);\n\n const pending = (async (): Promise<ProviderComponent | null> => {\n let value: unknown;\n try {\n value = await load();\n } catch (cause) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOAD_FAILED,\n capability,\n providerRef,\n message: `Provider \"${providerRef}\" failed to load its \"${capability}\" component.`,\n cause,\n });\n return null;\n }\n\n if (isModuleNamespace(value)) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOADED_VALUE_IS_NOT_A_COMPONENT,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" returned a MODULE for its \"${capability}\" component instead of the `\n + \"component itself. Write `async () => (await import('./Picker')).Picker` rather than \"\n + \"`() => import('./Picker')`.\",\n });\n return null;\n }\n\n if (!looksLikeComponent(value)) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOADED_VALUE_IS_NOT_A_COMPONENT,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" returned a ${typeof value} for its \"${capability}\" component. A React `\n + 'component is a function, or an object for memo / forwardRef / lazy.',\n });\n return null;\n }\n\n return value;\n })();\n\n // Cached even when it resolves to null: a loader that failed once must not\n // be retried on every render of a chooser that lists it.\n loaded.set(key, pending);\n return pending;\n },\n };\n}\n\n/** The shape this derivation needs off a hydrated provider module. */\ninterface ComponentBearingProviderModule {\n metadata: { ref: string };\n components?: Readonly<Record<string, ProviderFrontendComponentDescriptor & { load: ProviderComponentLoader }>>;\n}\n\n/**\n * Turns the live provider modules into registrations.\n *\n * Order follows the registry's iteration order, which is the order the service\n * declared its providers — so `listProviders` is stable across reloads and a\n * surface that shows a chooser does not reorder itself between renders.\n */\nexport function collectProviderComponentRegistrations(\n modules: Iterable<ComponentBearingProviderModule>,\n): ProviderComponentRegistration[] {\n const registrations: ProviderComponentRegistration[] = [];\n\n for (const module of modules) {\n for (const [capability, declaration] of Object.entries(module.components ?? {})) {\n registrations.push({\n capability: capability as ProviderCapability,\n providerRef: module.metadata.ref,\n load: declaration.load,\n // Only the declared half, never the whole declaration: `load` is already\n // carried beside it, and a registration holding the same function twice\n // is two places for one fact to go stale.\n descriptor: { selectionDelivery: declaration.selectionDelivery },\n });\n }\n }\n\n return registrations;\n}\n"]}
1
+ {"version":3,"file":"provider-component-registry.frontend.service.js","sourceRoot":"","sources":["../../../../src/core/components-registry/provider-component-registry.frontend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Components contributed by PROVIDERS, keyed by the capability each fills.\n *\n * ## Why this is a sibling of `ComponentRegistryService` and not an extension\n *\n * The two index different vocabularies, and merging them would put an open one\n * into a key built for a closed one:\n *\n * - `ComponentRegistryService` keys `componentType:preset[:category]`, where\n * `FrontendComponentType` is a CLOSED enum the engine owns. Exactly one\n * component answers a key, resolution is synchronous, and a missing\n * registration is a startup refusal.\n * - This registry keys `capability:providerRef`, where `ProviderCapability`\n * is OPEN — an application extends it by TypeScript module augmentation.\n * SEVERAL providers may answer one capability, the component arrives\n * asynchronously, and none of it is required for the app to mount.\n *\n * Forcing provider components through the closed enum would mean an engine edit\n * for every new provider capability — precisely what the open vocabulary exists\n * to avoid — and would make \"which component answers this key\" ambiguous in a\n * registry whose whole contract is that it is not.\n *\n * It also keeps the blast radius honest. `ComponentRegistryService` has sixteen\n * consumers across four packages (re-measured 2026-09-06; the plan's figure of\n * eleven predates several of them), most of them outside this slice's territory.\n * A sibling registry touches none of them.\n *\n * ## Several providers, and no silent winner\n *\n * `listProviders` returns every provider offering a component for a capability,\n * in registration order, and nothing here picks one. That is deliberate: the\n * defect being fixed is that resolution WAS first-match, so a Drive picker and\n * a Dropbox picker could not coexist and the winner depended on map order. A\n * surface with two providers has a choice to present; a registry that answered\n * it would be making a product decision in a lookup table.\n */\n\nimport type React from 'react';\nimport type { ProviderCapability } from '@wildo-ai/saas-models';\nimport type { ProviderFrontendComponentDescriptor } from '@wildo-ai/saas-models/public-runtime';\n\n/** A loader as a provider module declares it: on demand, returning the component. */\nexport type ProviderComponentLoader = () => Promise<unknown>;\n\n/** Why a provider component could not be registered or loaded. */\nexport enum ProviderComponentDiagnosticKind {\n /**\n * A second registration arrived for one capability AND provider. The first is\n * kept: a duplicate is a wiring mistake, and swapping the live component\n * under a mounted surface would be worse than ignoring it.\n */\n DUPLICATE_REGISTRATION = 'DUPLICATE_REGISTRATION',\n /** The loader threw or rejected. That provider's component is unavailable; others are not affected. */\n LOAD_FAILED = 'LOAD_FAILED',\n /**\n * The loader resolved something that is not a component. Almost always a\n * loader returning a MODULE NAMESPACE — `() => import('./Picker')` — where it\n * should return the component itself.\n */\n LOADED_VALUE_IS_NOT_A_COMPONENT = 'LOADED_VALUE_IS_NOT_A_COMPONENT',\n /**\n * A live provider DECLARES a component for a capability and nothing supplies\n * its loader — neither the module (`components[cap].load`) nor the facet\n * library (`contributeProviderComponentLoaders`). The declaration is DATA a\n * reviewer can read; without code behind it the chooser would offer a picker\n * that cannot open. Not registered, and reported once at startup.\n */\n DECLARED_WITHOUT_LOADER = 'DECLARED_WITHOUT_LOADER',\n /**\n * BOTH the module and the facet library supplied a loader for one\n * `capability:providerRef`. The module's wins — it is the provider's own\n * word — and the collision is reported, because the engine never authors both\n * and two loaders for one declaration is the map-order ambiguity #380 removed.\n */\n LOADER_SUPPLIED_TWICE = 'LOADER_SUPPLIED_TWICE',\n}\n\nexport interface ProviderComponentDiagnostic {\n readonly kind: ProviderComponentDiagnosticKind;\n readonly capability: string;\n readonly providerRef: string;\n readonly message: string;\n readonly cause?: unknown;\n}\n\nexport interface ProviderComponentRegistration {\n readonly capability: ProviderCapability;\n readonly providerRef: string;\n readonly load: ProviderComponentLoader;\n /**\n * What the provider DECLARED about this component — today, what a selection\n * from it contains. Kept beside the loader rather than looked up from the\n * DATA entry at the use site, because a surface needs it BEFORE it decides to\n * load anything, and because the two would then be two sources for one fact.\n */\n readonly descriptor: ProviderFrontendComponentDescriptor;\n}\n\n/** A component type this registry will hand back once loaded. */\nexport type ProviderComponent = React.ComponentType<never>;\n\nexport interface ProviderComponentRegistry {\n /**\n * Every provider offering a component for this capability, in registration\n * order. Synchronous ON PURPOSE: a surface has to render its chooser before\n * any component is loaded, and awaiting here would make an empty frame.\n */\n listProviders(capability: ProviderCapability): ReadonlyArray<string>;\n /** Whether this exact provider offers a component for this capability. */\n has(capability: ProviderCapability, providerRef: string): boolean;\n /**\n * What the provider declared about its component, without loading it —\n * `undefined` when this provider offers none for this capability.\n *\n * Synchronous and separate from `resolve` on purpose: the framework routes a\n * selection according to what was DECLARED, and a routing decision that had to\n * await a download would mean downloading a picker to find out whether the\n * surface can use it.\n */\n describe(capability: ProviderCapability, providerRef: string): ProviderFrontendComponentDescriptor | undefined;\n /**\n * Loads one provider's component. The loader runs at most once per pair —\n * a chooser that mounts and unmounts must not re-download a picker — and a\n * failure is reported and returns `null` rather than throwing into a render.\n */\n resolve(capability: ProviderCapability, providerRef: string): Promise<ProviderComponent | null>;\n}\n\nfunction isModuleNamespace(value: unknown): boolean {\n return (\n typeof value === 'object'\n && value !== null\n && (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag] === 'Module'\n );\n}\n\n/**\n * A React component is a function, or an object for `memo` / `forwardRef` /\n * `lazy`. Anything else — a namespace, a string, a plain data object — cannot\n * be rendered, and finding out at render time means a blank surface with a\n * stack trace pointing at React rather than at the provider.\n */\nfunction looksLikeComponent(value: unknown): value is ProviderComponent {\n return typeof value === 'function' || (typeof value === 'object' && value !== null);\n}\n\nexport function createProviderComponentRegistry(input?: {\n readonly registrations?: Iterable<ProviderComponentRegistration>;\n readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;\n}): ProviderComponentRegistry {\n const raise = (diagnostic: ProviderComponentDiagnostic): void => {\n input?.onDiagnostic?.(diagnostic);\n };\n const loaders = new Map<string, ProviderComponentLoader>();\n const descriptors = new Map<string, ProviderFrontendComponentDescriptor>();\n const byCapability = new Map<string, string[]>();\n const loaded = new Map<string, Promise<ProviderComponent | null>>();\n const keyOf = (capability: string, providerRef: string): string => `${capability}:${providerRef}`;\n\n for (const registration of input?.registrations ?? []) {\n const key = keyOf(registration.capability, registration.providerRef);\n if (loaders.has(key)) {\n raise({\n kind: ProviderComponentDiagnosticKind.DUPLICATE_REGISTRATION,\n capability: registration.capability,\n providerRef: registration.providerRef,\n message:\n `Provider \"${registration.providerRef}\" registered a component for \"${registration.capability}\" `\n + 'more than once. The first registration is kept.',\n });\n continue;\n }\n\n loaders.set(key, registration.load);\n descriptors.set(key, registration.descriptor);\n const providers = byCapability.get(registration.capability) ?? [];\n providers.push(registration.providerRef);\n byCapability.set(registration.capability, providers);\n }\n\n return {\n listProviders(capability) {\n return byCapability.get(capability) ?? [];\n },\n\n has(capability, providerRef) {\n return loaders.has(keyOf(capability, providerRef));\n },\n\n describe(capability, providerRef) {\n return descriptors.get(keyOf(capability, providerRef));\n },\n\n resolve(capability, providerRef) {\n const key = keyOf(capability, providerRef);\n const cached = loaded.get(key);\n if (cached !== undefined) return cached;\n\n const load = loaders.get(key);\n if (load === undefined) return Promise.resolve(null);\n\n const pending = (async (): Promise<ProviderComponent | null> => {\n let value: unknown;\n try {\n value = await load();\n } catch (cause) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOAD_FAILED,\n capability,\n providerRef,\n message: `Provider \"${providerRef}\" failed to load its \"${capability}\" component.`,\n cause,\n });\n return null;\n }\n\n if (isModuleNamespace(value)) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOADED_VALUE_IS_NOT_A_COMPONENT,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" returned a MODULE for its \"${capability}\" component instead of the `\n + \"component itself. Write `async () => (await import('./Picker')).Picker` rather than \"\n + \"`() => import('./Picker')`.\",\n });\n return null;\n }\n\n if (!looksLikeComponent(value)) {\n raise({\n kind: ProviderComponentDiagnosticKind.LOADED_VALUE_IS_NOT_A_COMPONENT,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" returned a ${typeof value} for its \"${capability}\" component. A React `\n + 'component is a function, or an object for memo / forwardRef / lazy.',\n });\n return null;\n }\n\n return value;\n })();\n\n // Cached even when it resolves to null: a loader that failed once must not\n // be retried on every render of a chooser that lists it.\n loaded.set(key, pending);\n return pending;\n },\n };\n}\n\n/** The shape this derivation needs off a hydrated provider module. */\ninterface ComponentBearingProviderModule {\n metadata: { ref: string };\n components?: Readonly<Record<string, ProviderFrontendComponentDescriptor & { load?: ProviderComponentLoader }>>;\n}\n\n/**\n * A loader the FACET LIBRARY supplies for a component a provider module\n * declares — the second of the two doors, and the one every engine-shipped\n * component uses (#394).\n *\n * The provider module, in `@wildo-ai/external-connectors-public`, declares the\n * DATA half (`components[cap].selectionDelivery`) and cannot name a loader that\n * reaches a React component: that package is deliberately renderer-free, and it\n * sits BELOW the component libraries in the layering, so a dynamic import from\n * it would close a package cycle. The library that owns the component\n * (`presets-components` for the app facet) contributes the loader here instead,\n * from the same place it registers its presets. A provider PACKAGE that ships\n * its own component still uses `components[cap].load` — both doors exist, the\n * engine authors exactly one per declaration, and a collision is reported.\n */\nexport interface ProviderComponentLoaderContribution {\n readonly capability: ProviderCapability;\n readonly providerRef: string;\n readonly load: ProviderComponentLoader;\n}\n\nconst contributedLoaders = new Map<string, ProviderComponentLoaderContribution>();\nconst loaderKeyOf = (capability: string, providerRef: string): string => `${capability}:${providerRef}`;\n\n/**\n * Registers loaders for provider components a facet library ships. Module-level\n * and idempotent per key, like `ComponentRegistryService.register`: the app\n * calls the library's registration entry once at startup, and a second\n * contribution for one key replaces the first rather than duplicating it —\n * the library is one author, and the last thing it said is what it means.\n *\n * A contribution for a provider the DATA channel does not declare live is\n * SILENT, by the same rule as code without data in `hydrateFrontendProviderModules`:\n * a bundle legitimately ships a picker an environment leaves off.\n */\nexport function contributeProviderComponentLoaders(loaders: Iterable<ProviderComponentLoaderContribution>): void {\n for (const loader of loaders) {\n contributedLoaders.set(loaderKeyOf(loader.capability, loader.providerRef), loader);\n }\n}\n\n/** Every contributed loader, keyed `capability:providerRef`. Read at registry construction. */\nexport function listContributedProviderComponentLoaders(): ReadonlyMap<string, ProviderComponentLoaderContribution> {\n return contributedLoaders;\n}\n\n/** Tests only: forget every contributed loader. */\nexport function _clearContributedProviderComponentLoaders(): void {\n contributedLoaders.clear();\n}\n\n/**\n * Turns the live provider modules into registrations, joining each declared\n * component to its loader — from the module when it carries one, else from\n * the facet library's contributions.\n *\n * Order follows the registry's iteration order, which is the order the service\n * declared its providers — so `listProviders` is stable across reloads and a\n * surface that shows a chooser does not reorder itself between renders.\n *\n * A declaration nothing can load is NOT registered: a chooser must offer only\n * what can render. It is reported through `onDiagnostic` instead, once, at\n * startup — which is the moment somebody can still fix it.\n */\nexport function collectProviderComponentRegistrations(\n modules: Iterable<ComponentBearingProviderModule>,\n input?: {\n readonly contributedLoaders?: ReadonlyMap<string, ProviderComponentLoaderContribution>;\n readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;\n },\n): ProviderComponentRegistration[] {\n const registrations: ProviderComponentRegistration[] = [];\n const contributed = input?.contributedLoaders ?? listContributedProviderComponentLoaders();\n\n for (const module of modules) {\n for (const [capability, declaration] of Object.entries(module.components ?? {})) {\n const providerRef = module.metadata.ref;\n const supplied = contributed.get(loaderKeyOf(capability, providerRef));\n\n if (declaration.load !== undefined && supplied !== undefined) {\n input?.onDiagnostic?.({\n kind: ProviderComponentDiagnosticKind.LOADER_SUPPLIED_TWICE,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" carries its own loader for \"${capability}\" AND the facet library contributed `\n + \"one. The module's is used; remove one of the two.\",\n });\n }\n\n const load = declaration.load ?? supplied?.load;\n if (load === undefined) {\n input?.onDiagnostic?.({\n kind: ProviderComponentDiagnosticKind.DECLARED_WITHOUT_LOADER,\n capability,\n providerRef,\n message:\n `Provider \"${providerRef}\" declares a \"${capability}\" component and nothing supplies its loader — `\n + 'neither the module nor the facet library. It is not offered. An engine-shipped component is '\n + 'registered by the facet library (presets-components for the app); a provider package supplies '\n + '`components[capability].load`.',\n });\n continue;\n }\n\n registrations.push({\n capability: capability as ProviderCapability,\n providerRef,\n load,\n // Only the declared half, never the whole declaration: `load` is already\n // carried beside it, and a registration holding the same function twice\n // is two places for one fact to go stale.\n descriptor: { selectionDelivery: declaration.selectionDelivery },\n });\n }\n }\n\n return registrations;\n}\n"]}
@@ -22,6 +22,7 @@
22
22
  * translation invisible.
23
23
  */
24
24
  import type { ProviderCapability } from '@wildo-ai/saas-models';
25
+ import type { FileStorageAccepted } from '@wildo-ai/saas-models/public-runtime';
25
26
  import type { ProviderComponent } from './provider-component-registry.frontend.service';
26
27
  export interface ProviderComponentChoice {
27
28
  readonly providerRef: string;
@@ -29,6 +30,13 @@ export interface ProviderComponentChoice {
29
30
  readonly displayNameLabelKey: string;
30
31
  /** The provider's authored fallback, when it has one. Still not a translation. */
31
32
  readonly displayName?: string;
33
+ /**
34
+ * The z_file storage this provider's picker fronts, from the served entry
35
+ * (#394 P5). A file field offers the picker only when its `storageAccepted`
36
+ * names this storage; a provider declaring none delivers bytes and is offered
37
+ * to every field.
38
+ */
39
+ readonly fileStorage?: FileStorageAccepted;
32
40
  }
33
41
  /**
34
42
  * The providers that are BOTH live for this service and carry a component for
@@ -1 +1 @@
1
- {"version":3,"file":"useProviderComponent.frontend.hooks.d.ts","sourceRoot":"","sources":["../../../../src/core/components-registry/useProviderComponent.frontend.hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAExF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,kBAAkB,GAC7B,aAAa,CAAC,uBAAuB,CAAC,CAcxC;AAED,qDAAqD;AACrD,oBAAY,uBAAuB;IACjC,8EAA8E;IAC9E,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,KAAK,UAAU;IACf;;;;OAIG;IACH,WAAW,gBAAgB;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,sBAAsB,CAiCxB"}
1
+ {"version":3,"file":"useProviderComponent.frontend.hooks.d.ts","sourceRoot":"","sources":["../../../../src/core/components-registry/useProviderComponent.frontend.hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAGhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAExF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC;CAC5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,kBAAkB,GAC7B,aAAa,CAAC,uBAAuB,CAAC,CAexC;AAED,qDAAqD;AACrD,oBAAY,uBAAuB;IACjC,8EAA8E;IAC9E,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,KAAK,UAAU;IACf;;;;OAIG;IACH,WAAW,gBAAgB;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,sBAAsB,CAiCxB"}
@@ -43,6 +43,7 @@ export function useProviderComponentChoices(capability) {
43
43
  providerRef,
44
44
  displayNameLabelKey: provider?.metadata.displayNameLabelKey ?? buildProviderDisplayNameLabelKey(providerRef),
45
45
  displayName: provider?.metadata.displayName,
46
+ fileStorage: provider?.fileStorage,
46
47
  };
47
48
  });
48
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useProviderComponent.frontend.hooks.js","sourceRoot":"","sources":["../../../../src/core/components-registry/useProviderComponent.frontend.hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,gCAAgC,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;AAWjF;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAA8B;IAE9B,MAAM,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,GAAG,cAAc,EAAE,CAAC;IAEjF,IAAI,yBAAyB,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAEvD,OAAO,yBAAyB,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QAC7E,MAAM,QAAQ,GAAG,wBAAwB,EAAE,gBAAgB,CAAC,WAAoB,CAAC,CAAC;QAClF,OAAO;YACL,WAAW;YACX,mBAAmB,EACjB,QAAQ,EAAE,QAAQ,CAAC,mBAAmB,IAAI,gCAAgC,CAAC,WAAW,CAAC;YACzF,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,WAAW;SAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAN,IAAY,uBAWX;AAXD,WAAY,uBAAuB;IACjC,8EAA8E;IAC9E,wCAAa,CAAA;IACb,8CAAmB,CAAA;IACnB,0CAAe,CAAA;IACf;;;;OAIG;IACH,sDAA2B,CAAA;AAC7B,CAAC,EAXW,uBAAuB,KAAvB,uBAAuB,QAWlC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAA8B,EAC9B,WAA+B;IAE/B,MAAM,EAAE,yBAAyB,EAAE,GAAG,cAAc,EAAE,CAAC;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,MAAM,EAAE,uBAAuB,CAAC,IAAI;QACpC,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,yBAAyB,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACzE,QAAQ,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,KAAK,yBAAyB,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACjF,0EAA0E;YAC1E,sEAAsE;YACtE,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,QAAQ,CACN,SAAS,KAAK,IAAI;gBAChB,CAAC,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE;gBAClE,CAAC,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,CACzD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAEzD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * Reading provider-contributed components from a React surface.\n *\n * Two hooks, split along the one line that matters: WHICH providers can fill a\n * capability is known synchronously and their component is not.\n *\n * - `useProviderComponentChoices` — the live providers offering a component\n * for a capability, in a stable order, with the label KEY each renders\n * under. Synchronous, so a surface can draw its chooser on the first frame\n * instead of flashing an empty one.\n * - `useProviderComponent` — the chosen provider's component, loaded on\n * demand, with an explicit status so a surface renders a pending state\n * rather than nothing.\n *\n * Neither hook picks a provider. That is the defect being fixed: resolution was\n * first-match, so two pickers could not coexist and the winner depended on map\n * order. When there are several, choosing is the surface's job — and a user's.\n *\n * Labels are KEYS, never text. A provider's display name is resolved through\n * the app i18n service at render time by whatever surface shows it; returning a\n * string here would freeze locale-bound copy into a hook and make a missing\n * translation invisible.\n */\n\nimport { useEffect, useState } from 'react';\nimport type { ProviderCapability } from '@wildo-ai/saas-models';\nimport { buildProviderDisplayNameLabelKey } from '@wildo-ai/saas-models/public-runtime';\nimport { useApplication } from '~wildo-frontend-lib/core/runtime/useApplication';\nimport type { ProviderComponent } from './provider-component-registry.frontend.service';\n\nexport interface ProviderComponentChoice {\n readonly providerRef: string;\n /** Resolve through the app i18n service; never render this key. */\n readonly displayNameLabelKey: string;\n /** The provider's authored fallback, when it has one. Still not a translation. */\n readonly displayName?: string;\n}\n\n/**\n * The providers that are BOTH live for this service and carry a component for\n * this capability.\n *\n * Both halves are required and they come from different channels: a provider\n * can be live with no code (an older bundle) or have code and not be live (an\n * environment that left it off). A surface must offer only what can actually\n * render.\n */\nexport function useProviderComponentChoices(\n capability: ProviderCapability,\n): ReadonlyArray<ProviderComponentChoice> {\n const { frontendProviderRegistry, providerComponentRegistry } = useApplication();\n\n if (providerComponentRegistry === undefined) return [];\n\n return providerComponentRegistry.listProviders(capability).map((providerRef) => {\n const provider = frontendProviderRegistry?.getProviderByRef(providerRef as never);\n return {\n providerRef,\n displayNameLabelKey:\n provider?.metadata.displayNameLabelKey ?? buildProviderDisplayNameLabelKey(providerRef),\n displayName: provider?.metadata.displayName,\n };\n });\n}\n\n/** Why a provider component is not on screen yet. */\nexport enum ProviderComponentStatus {\n /** No provider was chosen, or none offers a component for this capability. */\n NONE = 'NONE',\n LOADING = 'LOADING',\n READY = 'READY',\n /**\n * The loader failed or returned something unrenderable. The registry has\n * already reported why; a surface should fall back rather than retry, because\n * the registry will not run a failed loader again.\n */\n UNAVAILABLE = 'UNAVAILABLE',\n}\n\nexport interface ProviderComponentState {\n readonly status: ProviderComponentStatus;\n readonly Component: ProviderComponent | null;\n}\n\n/**\n * Loads one provider's component for a capability.\n *\n * Pass `undefined` for the ref while nothing is chosen — the hook does not\n * choose, and a surface with several providers must not load all of them\n * speculatively.\n */\nexport function useProviderComponent(\n capability: ProviderCapability,\n providerRef: string | undefined,\n): ProviderComponentState {\n const { providerComponentRegistry } = useApplication();\n const [state, setState] = useState<ProviderComponentState>({\n status: ProviderComponentStatus.NONE,\n Component: null,\n });\n\n useEffect(() => {\n if (providerComponentRegistry === undefined || providerRef === undefined) {\n setState({ status: ProviderComponentStatus.NONE, Component: null });\n return;\n }\n\n let current = true;\n setState({ status: ProviderComponentStatus.LOADING, Component: null });\n\n void providerComponentRegistry.resolve(capability, providerRef).then((Component) => {\n // A user can switch provider while one is still downloading. Without this\n // the slower answer would arrive last and replace the one they chose.\n if (!current) return;\n setState(\n Component === null\n ? { status: ProviderComponentStatus.UNAVAILABLE, Component: null }\n : { status: ProviderComponentStatus.READY, Component },\n );\n });\n\n return () => {\n current = false;\n };\n }, [capability, providerRef, providerComponentRegistry]);\n\n return state;\n}\n"]}
1
+ {"version":3,"file":"useProviderComponent.frontend.hooks.js","sourceRoot":"","sources":["../../../../src/core/components-registry/useProviderComponent.frontend.hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,EAAE,gCAAgC,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;AAkBjF;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAA8B;IAE9B,MAAM,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,GAAG,cAAc,EAAE,CAAC;IAEjF,IAAI,yBAAyB,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAEvD,OAAO,yBAAyB,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QAC7E,MAAM,QAAQ,GAAG,wBAAwB,EAAE,gBAAgB,CAAC,WAAoB,CAAC,CAAC;QAClF,OAAO;YACL,WAAW;YACX,mBAAmB,EACjB,QAAQ,EAAE,QAAQ,CAAC,mBAAmB,IAAI,gCAAgC,CAAC,WAAW,CAAC;YACzF,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,WAAW;YAC3C,WAAW,EAAE,QAAQ,EAAE,WAAW;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAN,IAAY,uBAWX;AAXD,WAAY,uBAAuB;IACjC,8EAA8E;IAC9E,wCAAa,CAAA;IACb,8CAAmB,CAAA;IACnB,0CAAe,CAAA;IACf;;;;OAIG;IACH,sDAA2B,CAAA;AAC7B,CAAC,EAXW,uBAAuB,KAAvB,uBAAuB,QAWlC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAA8B,EAC9B,WAA+B;IAE/B,MAAM,EAAE,yBAAyB,EAAE,GAAG,cAAc,EAAE,CAAC;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,MAAM,EAAE,uBAAuB,CAAC,IAAI;QACpC,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,yBAAyB,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACzE,QAAQ,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,KAAK,yBAAyB,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACjF,0EAA0E;YAC1E,sEAAsE;YACtE,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,QAAQ,CACN,SAAS,KAAK,IAAI;gBAChB,CAAC,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE;gBAClE,CAAC,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,CACzD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAEzD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * Reading provider-contributed components from a React surface.\n *\n * Two hooks, split along the one line that matters: WHICH providers can fill a\n * capability is known synchronously and their component is not.\n *\n * - `useProviderComponentChoices` — the live providers offering a component\n * for a capability, in a stable order, with the label KEY each renders\n * under. Synchronous, so a surface can draw its chooser on the first frame\n * instead of flashing an empty one.\n * - `useProviderComponent` — the chosen provider's component, loaded on\n * demand, with an explicit status so a surface renders a pending state\n * rather than nothing.\n *\n * Neither hook picks a provider. That is the defect being fixed: resolution was\n * first-match, so two pickers could not coexist and the winner depended on map\n * order. When there are several, choosing is the surface's job — and a user's.\n *\n * Labels are KEYS, never text. A provider's display name is resolved through\n * the app i18n service at render time by whatever surface shows it; returning a\n * string here would freeze locale-bound copy into a hook and make a missing\n * translation invisible.\n */\n\nimport { useEffect, useState } from 'react';\nimport type { ProviderCapability } from '@wildo-ai/saas-models';\nimport type { FileStorageAccepted } from '@wildo-ai/saas-models/public-runtime';\nimport { buildProviderDisplayNameLabelKey } from '@wildo-ai/saas-models/public-runtime';\nimport { useApplication } from '~wildo-frontend-lib/core/runtime/useApplication';\nimport type { ProviderComponent } from './provider-component-registry.frontend.service';\n\nexport interface ProviderComponentChoice {\n readonly providerRef: string;\n /** Resolve through the app i18n service; never render this key. */\n readonly displayNameLabelKey: string;\n /** The provider's authored fallback, when it has one. Still not a translation. */\n readonly displayName?: string;\n /**\n * The z_file storage this provider's picker fronts, from the served entry\n * (#394 P5). A file field offers the picker only when its `storageAccepted`\n * names this storage; a provider declaring none delivers bytes and is offered\n * to every field.\n */\n readonly fileStorage?: FileStorageAccepted;\n}\n\n/**\n * The providers that are BOTH live for this service and carry a component for\n * this capability.\n *\n * Both halves are required and they come from different channels: a provider\n * can be live with no code (an older bundle) or have code and not be live (an\n * environment that left it off). A surface must offer only what can actually\n * render.\n */\nexport function useProviderComponentChoices(\n capability: ProviderCapability,\n): ReadonlyArray<ProviderComponentChoice> {\n const { frontendProviderRegistry, providerComponentRegistry } = useApplication();\n\n if (providerComponentRegistry === undefined) return [];\n\n return providerComponentRegistry.listProviders(capability).map((providerRef) => {\n const provider = frontendProviderRegistry?.getProviderByRef(providerRef as never);\n return {\n providerRef,\n displayNameLabelKey:\n provider?.metadata.displayNameLabelKey ?? buildProviderDisplayNameLabelKey(providerRef),\n displayName: provider?.metadata.displayName,\n fileStorage: provider?.fileStorage,\n };\n });\n}\n\n/** Why a provider component is not on screen yet. */\nexport enum ProviderComponentStatus {\n /** No provider was chosen, or none offers a component for this capability. */\n NONE = 'NONE',\n LOADING = 'LOADING',\n READY = 'READY',\n /**\n * The loader failed or returned something unrenderable. The registry has\n * already reported why; a surface should fall back rather than retry, because\n * the registry will not run a failed loader again.\n */\n UNAVAILABLE = 'UNAVAILABLE',\n}\n\nexport interface ProviderComponentState {\n readonly status: ProviderComponentStatus;\n readonly Component: ProviderComponent | null;\n}\n\n/**\n * Loads one provider's component for a capability.\n *\n * Pass `undefined` for the ref while nothing is chosen — the hook does not\n * choose, and a surface with several providers must not load all of them\n * speculatively.\n */\nexport function useProviderComponent(\n capability: ProviderCapability,\n providerRef: string | undefined,\n): ProviderComponentState {\n const { providerComponentRegistry } = useApplication();\n const [state, setState] = useState<ProviderComponentState>({\n status: ProviderComponentStatus.NONE,\n Component: null,\n });\n\n useEffect(() => {\n if (providerComponentRegistry === undefined || providerRef === undefined) {\n setState({ status: ProviderComponentStatus.NONE, Component: null });\n return;\n }\n\n let current = true;\n setState({ status: ProviderComponentStatus.LOADING, Component: null });\n\n void providerComponentRegistry.resolve(capability, providerRef).then((Component) => {\n // A user can switch provider while one is still downloading. Without this\n // the slower answer would arrive last and replace the one they chose.\n if (!current) return;\n setState(\n Component === null\n ? { status: ProviderComponentStatus.UNAVAILABLE, Component: null }\n : { status: ProviderComponentStatus.READY, Component },\n );\n });\n\n return () => {\n current = false;\n };\n }, [capability, providerRef, providerComponentRegistry]);\n\n return state;\n}\n"]}
@@ -161,11 +161,11 @@ export declare const InsertedChartDeclarationSchema: z.ZodObject<{
161
161
  }>>;
162
162
  showLabel: z.ZodOptional<z.ZodBoolean>;
163
163
  labelPosition: z.ZodOptional<z.ZodEnum<{
164
+ center: "center";
164
165
  left: "left";
165
166
  right: "right";
166
167
  top: "top";
167
168
  bottom: "bottom";
168
- center: "center";
169
169
  inside: "inside";
170
170
  outside: "outside";
171
171
  }>>;
@@ -268,10 +268,10 @@ export declare const InsertedChartDeclarationSchema: z.ZodObject<{
268
268
  left: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
269
269
  top: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
270
270
  textAlign: z.ZodOptional<z.ZodEnum<{
271
+ center: "center";
271
272
  auto: "auto";
272
273
  left: "left";
273
274
  right: "right";
274
- center: "center";
275
275
  }>>;
276
276
  }, z.core.$strip>>;
277
277
  animationDuration: z.ZodOptional<z.ZodNumber>;
@@ -432,9 +432,9 @@ export declare const InsertedChartDeclarationSchema: z.ZodObject<{
432
432
  rightTop: "rightTop";
433
433
  }>>;
434
434
  funnelAlign: z.ZodOptional<z.ZodEnum<{
435
+ center: "center";
435
436
  left: "left";
436
437
  right: "right";
437
- center: "center";
438
438
  }>>;
439
439
  showLabel: z.ZodOptional<z.ZodBoolean>;
440
440
  left: z.ZodOptional<z.ZodString>;
@@ -514,9 +514,9 @@ export declare const InsertedChartDeclarationSchema: z.ZodObject<{
514
514
  radial: "radial";
515
515
  }>>;
516
516
  level2LabelAlign: z.ZodOptional<z.ZodEnum<{
517
+ center: "center";
517
518
  left: "left";
518
519
  right: "right";
519
- center: "center";
520
520
  }>>;
521
521
  level3LabelPosition: z.ZodOptional<z.ZodEnum<{
522
522
  inside: "inside";
@@ -688,11 +688,11 @@ export declare const ResolvedInsertedChartDescriptorSchema: z.ZodObject<{
688
688
  }>>;
689
689
  showLabel: z.ZodOptional<z.ZodBoolean>;
690
690
  labelPosition: z.ZodOptional<z.ZodEnum<{
691
+ center: "center";
691
692
  left: "left";
692
693
  right: "right";
693
694
  top: "top";
694
695
  bottom: "bottom";
695
- center: "center";
696
696
  inside: "inside";
697
697
  outside: "outside";
698
698
  }>>;
@@ -795,10 +795,10 @@ export declare const ResolvedInsertedChartDescriptorSchema: z.ZodObject<{
795
795
  left: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
796
796
  top: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
797
797
  textAlign: z.ZodOptional<z.ZodEnum<{
798
+ center: "center";
798
799
  auto: "auto";
799
800
  left: "left";
800
801
  right: "right";
801
- center: "center";
802
802
  }>>;
803
803
  }, z.core.$strip>>;
804
804
  animationDuration: z.ZodOptional<z.ZodNumber>;
@@ -959,9 +959,9 @@ export declare const ResolvedInsertedChartDescriptorSchema: z.ZodObject<{
959
959
  rightTop: "rightTop";
960
960
  }>>;
961
961
  funnelAlign: z.ZodOptional<z.ZodEnum<{
962
+ center: "center";
962
963
  left: "left";
963
964
  right: "right";
964
- center: "center";
965
965
  }>>;
966
966
  showLabel: z.ZodOptional<z.ZodBoolean>;
967
967
  left: z.ZodOptional<z.ZodString>;
@@ -1041,9 +1041,9 @@ export declare const ResolvedInsertedChartDescriptorSchema: z.ZodObject<{
1041
1041
  radial: "radial";
1042
1042
  }>>;
1043
1043
  level2LabelAlign: z.ZodOptional<z.ZodEnum<{
1044
+ center: "center";
1044
1045
  left: "left";
1045
1046
  right: "right";
1046
- center: "center";
1047
1047
  }>>;
1048
1048
  level3LabelPosition: z.ZodOptional<z.ZodEnum<{
1049
1049
  inside: "inside";
@@ -212,8 +212,6 @@ export declare const CompositeView_BaseFieldsSchema: z.ZodObject<{
212
212
  icon: z.ZodOptional<z.ZodCustom<IconLike, IconLike>>;
213
213
  adjacentZoneOnEmpty: z.ZodOptional<z.ZodEnum<typeof ZoneEmptyBehavior>>;
214
214
  zoneContentMaxWidth: z.ZodOptional<z.ZodEnum<{
215
- none: "none";
216
- content: "content";
217
215
  full: "full";
218
216
  sm: "sm";
219
217
  md: "md";
@@ -221,6 +219,8 @@ export declare const CompositeView_BaseFieldsSchema: z.ZodObject<{
221
219
  xl: "xl";
222
220
  measure: "measure";
223
221
  "centered-readable": "centered-readable";
222
+ content: "content";
223
+ none: "none";
224
224
  }>>;
225
225
  zoneContentFillsHeight: z.ZodOptional<z.ZodBoolean>;
226
226
  }, z.core.$strip>;
@@ -278,8 +278,6 @@ export declare const CompositeViewDefinitionBaseSchema: z.ZodIntersection<z.ZodD
278
278
  icon: z.ZodOptional<z.ZodCustom<IconLike, IconLike>>;
279
279
  adjacentZoneOnEmpty: z.ZodOptional<z.ZodEnum<typeof ZoneEmptyBehavior>>;
280
280
  zoneContentMaxWidth: z.ZodOptional<z.ZodEnum<{
281
- none: "none";
282
- content: "content";
283
281
  full: "full";
284
282
  sm: "sm";
285
283
  md: "md";
@@ -287,6 +285,8 @@ export declare const CompositeViewDefinitionBaseSchema: z.ZodIntersection<z.ZodD
287
285
  xl: "xl";
288
286
  measure: "measure";
289
287
  "centered-readable": "centered-readable";
288
+ content: "content";
289
+ none: "none";
290
290
  }>>;
291
291
  zoneContentFillsHeight: z.ZodOptional<z.ZodBoolean>;
292
292
  }, z.core.$strip>>;
@@ -1,71 +1,4 @@
1
1
  import type { SettingsDestination, SettingsHubConfig } from './settings-hub.frontend.schemas';
2
- /** @wildo_source:part:start saas.frontend.settings-hub.engine-destinations facet:layer:frontend facet:family:config facet:audience:app-developer */
3
- /**
4
- * Every settings destination the engine ships, as a named vocabulary.
5
- *
6
- * Exists because these refs are a CLOSED vocabulary that engine code addresses
7
- * by name — the billing command-menu entry opens `/settings/billing`, and any
8
- * future engine launcher will do the same. Before this enum, `'billing'` was a
9
- * bare literal in `billing-launcher.ts` with nothing tying it to the catalog
10
- * entry it names: rename the destination and the command silently resolves to
11
- * the hub's DEFAULT section instead of failing, so a menu item labelled
12
- * "Billing" would open Profile.
13
- *
14
- * **Engine code must address a destination through this enum. Application
15
- * config addresses one by string**, deliberately: a placement is authored data,
16
- * an application should not import an engine enum to write its own rail, and a
17
- * typo there is caught at DEV startup by `verifySettingsHubContent`.
18
- */
19
- export declare enum EngineSettingsDestinationRef {
20
- /** The signed-in user's own profile record. */
21
- PROFILE = "profile",
22
- /** Password, MFA, sessions — a bespoke engine panel. */
23
- SECURITY = "security",
24
- /** Theme and appearance preferences — a bespoke engine panel. */
25
- APPEARANCE = "appearance",
26
- /** The signed-in user's own preference record. */
27
- PREFERENCES = "preferences",
28
- /** Invitations addressed TO the signed-in user, across organizations they have not joined. */
29
- MY_INVITATIONS = "my-invitations",
30
- /** The current organization's own record. Org owner/admin only. */
31
- ORGANIZATION_GENERAL = "organization-general",
32
- /** Organization membership list, including INVITED rows. Org owner/admin only. */
33
- MEMBERS = "members",
34
- /** Billing home — subscription, plans, usage, invoices. Gated on the `billingEnabled` capability. */
35
- BILLING = "billing",
36
- /** Organization API keys. Org owner/admin only. */
37
- API_KEYS = "api-keys",
38
- /**
39
- * The tenant's OWN credentials toward third parties — its Slack workspace token, its CRM key.
40
- *
41
- * The mirror image of {@link API_KEYS} and easy to confuse with it: an API key is a credential
42
- * somebody uses to reach THIS application, and one of these is a credential this application uses
43
- * to reach somebody else ON THIS TENANT'S BEHALF. Same administrator, opposite direction.
44
- */
45
- PROVIDER_CREDENTIALS = "provider-credentials",
46
- /**
47
- * The signed-in person's OWN credentials toward third parties — their personal API key, the
48
- * account they connected themselves.
49
- *
50
- * Distinct from {@link PROVIDER_CREDENTIALS} by OWNER, not by feature, and the two must never be
51
- * merged into one screen. A tenant's credential is a shared integration an administrator
52
- * configures for everyone; this one is an individual's own account, which nobody else may see,
53
- * spend or remove. Putting them on one page would put a colleague's personal vendor token in an
54
- * administrator's view — and the resource's authorization refuses that, so the screen would show
55
- * an empty list nobody could explain.
56
- */
57
- MY_PROVIDER_CREDENTIALS = "my-provider-credentials",
58
- /** Single sign-on configuration and connections. */
59
- SSO = "sso",
60
- /** SCIM directory provisioning configuration and tokens. */
61
- SCIM = "scim",
62
- /** Audit-event streaming configuration and failed-delivery queue. */
63
- SIEM = "siem",
64
- /** Outbound webhook endpoints and delivery log. */
65
- WEBHOOKS = "webhooks",
66
- /** The organization's audit log. Org owner/admin only. */
67
- AUDIT_LOGS = "audit-logs"
68
- }
69
2
  /**
70
3
  * Every settings destination the engine ships, keyed by `ref`.
71
4
  *
@@ -75,8 +8,6 @@ export declare enum EngineSettingsDestinationRef {
75
8
  * meant to remove.
76
9
  */
77
10
  export declare const ENGINE_SETTINGS_DESTINATIONS: readonly SettingsDestination[];
78
- /** Every destination ref the engine ships — the set a placement is validated against. */
79
- export declare const ENGINE_SETTINGS_DESTINATION_REFS: ReadonlySet<string>;
80
11
  /**
81
12
  * The full placement set `wildo init` scaffolds into a new application's config.
82
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"engine-settings-destinations.d.ts","sourceRoot":"","sources":["../../../../src/core/config/engine-settings-destinations.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE9F,oJAAoJ;AACpJ;;;;;;;;;;;;;;;GAeG;AACH,oBAAY,4BAA4B;IACtC,+CAA+C;IAC/C,OAAO,YAAY;IACnB,wDAAwD;IACxD,QAAQ,aAAa;IACrB,iEAAiE;IACjE,UAAU,eAAe;IACzB,kDAAkD;IAClD,WAAW,gBAAgB;IAC3B,8FAA8F;IAC9F,cAAc,mBAAmB;IACjC,mEAAmE;IACnE,oBAAoB,yBAAyB;IAC7C,kFAAkF;IAClF,OAAO,YAAY;IACnB,qGAAqG;IACrG,OAAO,YAAY;IACnB,mDAAmD;IACnD,QAAQ,aAAa;IACrB;;;;;;OAMG;IACH,oBAAoB,yBAAyB;IAC7C;;;;;;;;;;OAUG;IACH,uBAAuB,4BAA4B;IACnD,oDAAoD;IACpD,GAAG,QAAQ;IACX,4DAA4D;IAC5D,IAAI,SAAS;IACb,qEAAqE;IACrE,IAAI,SAAS;IACb,mDAAmD;IACnD,QAAQ,aAAa;IACrB,0DAA0D;IAC1D,UAAU,eAAe;CAC1B;AA4BD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,mBAAmB,EA6QtE,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,gCAAgC,EAAE,WAAW,CAAC,MAAM,CAEhE,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBA0B1C,CAAC"}
1
+ {"version":3,"file":"engine-settings-destinations.d.ts","sourceRoot":"","sources":["../../../../src/core/config/engine-settings-destinations.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AA2B9F;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,mBAAmB,EA+RtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBA0B1C,CAAC"}