@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
@@ -26,78 +26,23 @@
26
26
  *
27
27
  * Sub-tab labels stay on the target: they describe the destination's internal
28
28
  * structure, not its position in the rail.
29
- */
30
- import { CoreFeature, CoreResourceOperation, CoreResourceType, CORE_ORG_ROLES, ResourcePrimaryScope } from '@wildo-ai/saas-models';
31
- import { SettingsPanelRef, SettingsSectionTargetKind } from './settings-hub.frontend.schemas.js';
32
- /** @wildo_source:part:start saas.frontend.settings-hub.engine-destinations facet:layer:frontend facet:family:config facet:audience:app-developer */
33
- /**
34
- * Every settings destination the engine ships, as a named vocabulary.
35
29
  *
36
- * Exists because these refs are a CLOSED vocabulary that engine code addresses
37
- * by name — the billing command-menu entry opens `/settings/billing`, and any
38
- * future engine launcher will do the same. Before this enum, `'billing'` was a
39
- * bare literal in `billing-launcher.ts` with nothing tying it to the catalog
40
- * entry it names: rename the destination and the command silently resolves to
41
- * the hub's DEFAULT section instead of failing, so a menu item labelled
42
- * "Billing" would open Profile.
30
+ * ## The refs themselves live in `@wildo-ai/saas-models`
43
31
  *
44
- * **Engine code must address a destination through this enum. Application
45
- * config addresses one by string**, deliberately: a placement is authored data,
46
- * an application should not import an engine enum to write its own rail, and a
47
- * typo there is caught at DEV startup by `verifySettingsHubContent`.
32
+ * `EngineSettingsDestinationRef` and `ENGINE_SETTINGS_DESTINATION_REFS` are declared in
33
+ * `saas-models` (`frontend-definitions/settings-destination-ref.definitions.ts`); this file
34
+ * declares only what each ref MEANS. The split exists because the ref vocabulary has a
35
+ * backend-side consumer this package can never serve: `validatePlacementPlan`'s `UNKNOWN_SUBJECT`
36
+ * hard floor is held by the app-creation semantic authority, which must not depend on
37
+ * `saas-frontend-lib`. Everything that names a component, a panel or a sub-tab stayed here; the
38
+ * sixteen ids did not.
39
+ *
40
+ * The enum is deliberately NOT re-exported from this module, from the package root, or from
41
+ * `companion-exports`: a symbol reachable through two public doors is a symbol whose two doors
42
+ * drift. Every consumer — including this package's own — imports it from `@wildo-ai/saas-models`.
48
43
  */
49
- export var EngineSettingsDestinationRef;
50
- (function (EngineSettingsDestinationRef) {
51
- /** The signed-in user's own profile record. */
52
- EngineSettingsDestinationRef["PROFILE"] = "profile";
53
- /** Password, MFA, sessions — a bespoke engine panel. */
54
- EngineSettingsDestinationRef["SECURITY"] = "security";
55
- /** Theme and appearance preferences — a bespoke engine panel. */
56
- EngineSettingsDestinationRef["APPEARANCE"] = "appearance";
57
- /** The signed-in user's own preference record. */
58
- EngineSettingsDestinationRef["PREFERENCES"] = "preferences";
59
- /** Invitations addressed TO the signed-in user, across organizations they have not joined. */
60
- EngineSettingsDestinationRef["MY_INVITATIONS"] = "my-invitations";
61
- /** The current organization's own record. Org owner/admin only. */
62
- EngineSettingsDestinationRef["ORGANIZATION_GENERAL"] = "organization-general";
63
- /** Organization membership list, including INVITED rows. Org owner/admin only. */
64
- EngineSettingsDestinationRef["MEMBERS"] = "members";
65
- /** Billing home — subscription, plans, usage, invoices. Gated on the `billingEnabled` capability. */
66
- EngineSettingsDestinationRef["BILLING"] = "billing";
67
- /** Organization API keys. Org owner/admin only. */
68
- EngineSettingsDestinationRef["API_KEYS"] = "api-keys";
69
- /**
70
- * The tenant's OWN credentials toward third parties — its Slack workspace token, its CRM key.
71
- *
72
- * The mirror image of {@link API_KEYS} and easy to confuse with it: an API key is a credential
73
- * somebody uses to reach THIS application, and one of these is a credential this application uses
74
- * to reach somebody else ON THIS TENANT'S BEHALF. Same administrator, opposite direction.
75
- */
76
- EngineSettingsDestinationRef["PROVIDER_CREDENTIALS"] = "provider-credentials";
77
- /**
78
- * The signed-in person's OWN credentials toward third parties — their personal API key, the
79
- * account they connected themselves.
80
- *
81
- * Distinct from {@link PROVIDER_CREDENTIALS} by OWNER, not by feature, and the two must never be
82
- * merged into one screen. A tenant's credential is a shared integration an administrator
83
- * configures for everyone; this one is an individual's own account, which nobody else may see,
84
- * spend or remove. Putting them on one page would put a colleague's personal vendor token in an
85
- * administrator's view — and the resource's authorization refuses that, so the screen would show
86
- * an empty list nobody could explain.
87
- */
88
- EngineSettingsDestinationRef["MY_PROVIDER_CREDENTIALS"] = "my-provider-credentials";
89
- /** Single sign-on configuration and connections. */
90
- EngineSettingsDestinationRef["SSO"] = "sso";
91
- /** SCIM directory provisioning configuration and tokens. */
92
- EngineSettingsDestinationRef["SCIM"] = "scim";
93
- /** Audit-event streaming configuration and failed-delivery queue. */
94
- EngineSettingsDestinationRef["SIEM"] = "siem";
95
- /** Outbound webhook endpoints and delivery log. */
96
- EngineSettingsDestinationRef["WEBHOOKS"] = "webhooks";
97
- /** The organization's audit log. Org owner/admin only. */
98
- EngineSettingsDestinationRef["AUDIT_LOGS"] = "audit-logs";
99
- })(EngineSettingsDestinationRef || (EngineSettingsDestinationRef = {}));
100
- /** @wildo_source:part:end saas.frontend.settings-hub.engine-destinations */
44
+ import { CoreFeature, CoreResourceOperation, CoreResourceType, CORE_ORG_ROLES, EngineSettingsDestinationRef, ResourcePrimaryScope } from '@wildo-ai/saas-models';
45
+ import { SettingsPanelRef, SettingsSectionTargetKind } from './settings-hub.frontend.schemas.js';
101
46
  /** Org-management destinations are visible to organization owners and admins. */
102
47
  const ORG_MANAGEMENT_ROLES = [CORE_ORG_ROLES.ORG_OWNER, CORE_ORG_ROLES.ORG_ADMIN];
103
48
  /**
@@ -262,10 +207,28 @@ export const ENGINE_SETTINGS_DESTINATIONS = [
262
207
  // has connected one.
263
208
  ref: EngineSettingsDestinationRef.PROVIDER_CREDENTIALS,
264
209
  requiredRoles: ORG_MANAGEMENT_ROLES,
210
+ // TWO tabs, for the person-scope destination's reason: "Connect" is a flow out to a vendor and
211
+ // has no resource behind it, while "Credentials" is the ordinary list of what the tenant HAS.
212
+ // Connect comes first because it is where the connection callback returns, carrying the outcome
213
+ // it has to render.
265
214
  target: {
266
- kind: SettingsSectionTargetKind.RESOURCE_OPERATION,
267
- resourceType: CoreResourceType.ORG_PROVIDER_CREDENTIALS,
268
- operation: CoreResourceOperation.LIST,
215
+ kind: SettingsSectionTargetKind.SUB_TABS,
216
+ subTabs: [
217
+ {
218
+ ref: 'connect',
219
+ label: 'Connect',
220
+ target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.ORGANIZATION_CONNECTED_ACCOUNTS },
221
+ },
222
+ {
223
+ ref: 'credentials',
224
+ label: 'Credentials',
225
+ target: {
226
+ kind: SettingsSectionTargetKind.RESOURCE_OPERATION,
227
+ resourceType: CoreResourceType.ORG_PROVIDER_CREDENTIALS,
228
+ operation: CoreResourceOperation.LIST,
229
+ },
230
+ },
231
+ ],
269
232
  },
270
233
  },
271
234
  // ── Organization · enterprise credentials & compliance ─────────
@@ -398,8 +361,6 @@ export const ENGINE_SETTINGS_DESTINATIONS = [
398
361
  },
399
362
  },
400
363
  ];
401
- /** Every destination ref the engine ships — the set a placement is validated against. */
402
- export const ENGINE_SETTINGS_DESTINATION_REFS = new Set(ENGINE_SETTINGS_DESTINATIONS.map(destination => destination.ref));
403
364
  /**
404
365
  * The full placement set `wildo init` scaffolds into a new application's config.
405
366
  *
@@ -1 +1 @@
1
- {"version":3,"file":"engine-settings-destinations.js","sourceRoot":"","sources":["../../../../src/core/config/engine-settings-destinations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACnI,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAG9F,oJAAoJ;AACpJ;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAN,IAAY,4BAiDX;AAjDD,WAAY,4BAA4B;IACtC,+CAA+C;IAC/C,mDAAmB,CAAA;IACnB,wDAAwD;IACxD,qDAAqB,CAAA;IACrB,iEAAiE;IACjE,yDAAyB,CAAA;IACzB,kDAAkD;IAClD,2DAA2B,CAAA;IAC3B,8FAA8F;IAC9F,iEAAiC,CAAA;IACjC,mEAAmE;IACnE,6EAA6C,CAAA;IAC7C,kFAAkF;IAClF,mDAAmB,CAAA;IACnB,qGAAqG;IACrG,mDAAmB,CAAA;IACnB,mDAAmD;IACnD,qDAAqB,CAAA;IACrB;;;;;;OAMG;IACH,6EAA6C,CAAA;IAC7C;;;;;;;;;;OAUG;IACH,mFAAmD,CAAA;IACnD,oDAAoD;IACpD,2CAAW,CAAA;IACX,4DAA4D;IAC5D,6CAAa,CAAA;IACb,qEAAqE;IACrE,6CAAa,CAAA;IACb,mDAAmD;IACnD,qDAAqB,CAAA;IACrB,0DAA0D;IAC1D,yDAAyB,CAAA;AAC3B,CAAC,EAjDW,4BAA4B,KAA5B,4BAA4B,QAiDvC;AACD,4EAA4E;AAE5E,iFAAiF;AACjF,MAAM,oBAAoB,GAAa,CAAC,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;AAE5F;;;;;GAKG;AACH,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAC5C,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAC9C,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAC9C,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAmC;IAC1E,kEAAkE;IAClE;QACE,GAAG,EAAE,4BAA4B,CAAC,OAAO;QACzC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,kBAAkB;YACjD,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,QAAQ;QAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EAAE;KAC9F;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,UAAU;QAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,UAAU,EAAE;KAChG;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,WAAW;QAC7C,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,qBAAqB;YACpD,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD;QACE,oFAAoF;QACpF,kFAAkF;QAClF,iFAAiF;QACjF,kFAAkF;QAClF,yFAAyF;QACzF,GAAG,EAAE,4BAA4B,CAAC,cAAc;QAChD,MAAM,EAAE,EAAE,IAAI,EAAE,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,WAAW,EAAE;KACjG;IACD;QACE,0DAA0D;QAC1D,EAAE;QACF,2FAA2F;QAC3F,6FAA6F;QAC7F,8FAA8F;QAC9F,2FAA2F;QAC3F,kBAAkB;QAClB,EAAE;QACF,6FAA6F;QAC7F,+FAA+F;QAC/F,gFAAgF;QAChF,GAAG,EAAE,4BAA4B,CAAC,uBAAuB;QACzD,gGAAgG;QAChG,EAAE;QACF,gGAAgG;QAChG,gGAAgG;QAChG,iGAAiG;QACjG,mBAAmB;QACnB,EAAE;QACF,iGAAiG;QACjG,kGAAkG;QAClG,0FAA0F;QAC1F,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,QAAQ;YACxC,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,SAAS;oBACd,KAAK,EAAE,SAAS;oBAChB,MAAM,EAAE,EAAE,IAAI,EAAE,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,kBAAkB,EAAE;iBACxG;gBACD;oBACE,GAAG,EAAE,aAAa;oBAClB,KAAK,EAAE,aAAa;oBACpB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,yBAAyB;wBACxD,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;aACF;SACF;KACF;IACD,kEAAkE;IAClE;QACE,GAAG,EAAE,4BAA4B,CAAC,oBAAoB;QACtD,aAAa,EAAE,oBAAoB;QACnC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,aAAa;YAC5C,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD;QACE,8EAA8E;QAC9E,gFAAgF;QAChF,0EAA0E;QAC1E,wEAAwE;QACxE,GAAG,EAAE,4BAA4B,CAAC,OAAO;QACzC,aAAa,EAAE,oBAAoB;QACnC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,oBAAoB;YACnD,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,OAAO;QACzC,aAAa,EAAE,oBAAoB;QACnC,mBAAmB,EAAE,EAAE,oBAAoB,EAAE,CAAC,0BAA0B,CAAC,EAAE;QAC3E,wEAAwE;QACxE,wEAAwE;QACxE,2EAA2E;QAC3E,2EAA2E;QAC3E,6EAA6E;QAC7E,gDAAgD;QAChD,MAAM,EAAE,EAAE,IAAI,EAAE,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,OAAO,EAAE;KAC7F;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,QAAQ;QAC1C,aAAa,EAAE,oBAAoB;QACnC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,YAAY;YAC3C,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD;QACE,4FAA4F;QAC5F,qFAAqF;QACrF,gGAAgG;QAChG,mFAAmF;QACnF,EAAE;QACF,gGAAgG;QAChG,+FAA+F;QAC/F,gGAAgG;QAChG,qBAAqB;QACrB,GAAG,EAAE,4BAA4B,CAAC,oBAAoB;QACtD,aAAa,EAAE,oBAAoB;QACnC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,wBAAwB;YACvD,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;IACD,kEAAkE;IAClE,kEAAkE;IAClE,sEAAsE;IACtE,2EAA2E;IAC3E;QACE,GAAG,EAAE,4BAA4B,CAAC,GAAG;QACrC,aAAa,EAAE,oBAAoB;QACnC,mBAAmB,EAAE,EAAE,oBAAoB,EAAE,CAAC,sBAAsB,CAAC,EAAE;QACvE,oBAAoB,EAAE,WAAW,CAAC,cAAc;QAChD,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,QAAQ;YACxC,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,mBAAmB;oBACxB,KAAK,EAAE,eAAe;oBACtB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,uBAAuB;wBACtD,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;gBACD;oBACE,GAAG,EAAE,iBAAiB;oBACtB,KAAK,EAAE,aAAa;oBACpB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,4BAA4B;wBAC3D,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;aACF;SACF;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,IAAI;QACtC,aAAa,EAAE,oBAAoB;QACnC,mBAAmB,EAAE,EAAE,oBAAoB,EAAE,CAAC,uBAAuB,CAAC,EAAE;QACxE,oBAAoB,EAAE,WAAW,CAAC,sBAAsB;QACxD,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,QAAQ;YACxC,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,mBAAmB;oBACxB,KAAK,EAAE,cAAc;oBACrB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,qCAAqC;wBACpE,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;gBACD;oBACE,GAAG,EAAE,aAAa;oBAClB,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,wBAAwB;wBACvD,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;aACF;SACF;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,IAAI;QACtC,aAAa,EAAE,oBAAoB;QACnC,mBAAmB,EAAE,EAAE,oBAAoB,EAAE,CAAC,uBAAuB,CAAC,EAAE;QACxE,oBAAoB,EAAE,WAAW,CAAC,qBAAqB;QACvD,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,QAAQ;YACxC,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,aAAa;oBAClB,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,+BAA+B;wBAC9D,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;gBACD;oBACE,GAAG,EAAE,wBAAwB;oBAC7B,KAAK,EAAE,mBAAmB;oBAC1B,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,8BAA8B;wBAC7D,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;aACF;SACF;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,QAAQ;QAC1C,aAAa,EAAE,oBAAoB;QACnC,mBAAmB,EAAE,EAAE,oBAAoB,EAAE,CAAC,2BAA2B,CAAC,EAAE;QAC5E,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;QACtD,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,QAAQ;YACxC,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,oBAAoB;oBACzB,KAAK,EAAE,WAAW;oBAClB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,2BAA2B;wBAC1D,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;gBACD;oBACE,GAAG,EAAE,uBAAuB;oBAC5B,KAAK,EAAE,cAAc;oBACrB,MAAM,EAAE;wBACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;wBAClD,YAAY,EAAE,gBAAgB,CAAC,qCAAqC;wBACpE,SAAS,EAAE,qBAAqB,CAAC,IAAI;qBACtC;iBACF;aACF;SACF;KACF;IACD;QACE,GAAG,EAAE,4BAA4B,CAAC,UAAU;QAC5C,aAAa,EAAE,oBAAoB;QACnC,MAAM,EAAE;YACN,IAAI,EAAE,yBAAyB,CAAC,kBAAkB;YAClD,YAAY,EAAE,gBAAgB,CAAC,UAAU;YACzC,SAAS,EAAE,qBAAqB,CAAC,IAAI;SACtC;KACF;CACF,CAAC;AAEF,yFAAyF;AACzF,MAAM,CAAC,MAAM,gCAAgC,GAAwB,IAAI,GAAG,CAC1E,4BAA4B,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CACjE,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAsB;IAC7D,UAAU,EAAE;QACV,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,oBAAoB,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE;QACrF,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,oBAAoB,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE;KACpG;IACD,UAAU,EAAE;QACV,EAAE,cAAc,EAAE,4BAA4B,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE;QAC5G,EAAE,cAAc,EAAE,4BAA4B,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE;QAC9G,EAAE,cAAc,EAAE,4BAA4B,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE;QAClH,EAAE,cAAc,EAAE,4BAA4B,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE;QACpH,EAAE,cAAc,EAAE,4BAA4B,CAAC,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE;QACvH,gGAAgG;QAChG,kDAAkD;QAClD,EAAE,cAAc,EAAE,4BAA4B,CAAC,uBAAuB,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE;QACvI,EAAE,cAAc,EAAE,4BAA4B,CAAC,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE;QAC9H,EAAE,cAAc,EAAE,4BAA4B,CAAC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE;QACjH,EAAE,cAAc,EAAE,4BAA4B,CAAC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE;QACjH,EAAE,cAAc,EAAE,4BAA4B,CAAC,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE;QACnH,EAAE,cAAc,EAAE,4BAA4B,CAAC,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE;QACzI,EAAE,cAAc,EAAE,4BAA4B,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE;QACpH,EAAE,cAAc,EAAE,4BAA4B,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE;QACxH,EAAE,cAAc,EAAE,4BAA4B,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE;QACtH,EAAE,cAAc,EAAE,4BAA4B,CAAC,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE;QACnH,EAAE,cAAc,EAAE,4BAA4B,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;KACxH;IACD,iBAAiB,EAAE,SAAS;CAC7B,CAAC","sourcesContent":["/**\n * The engine's settings DESTINATION catalog — addressable, and deliberately unplaced.\n *\n * Each entry says what a settings surface IS: its target, and the gating that\n * decides whether the current principal may see it at all. **No entry carries a\n * `categoryRef`, an `order` or a `label`**, because those are placement, and\n * placement belongs to the application (`SettingsPlacement`).\n *\n * This file replaced `settings-hub.frontend.defaults.ts`, which shipped a fully\n * PLACED hub as a framework default. That default was the reason an application\n * could not add, remove, reorder or rename a settings section: the render path\n * read the framework's arrangement, so an application had no arrangement of its\n * own to read. Splitting destination from placement keeps the engine owning what\n * a destination MEANS while the application owns where it sits — and makes\n * \"remove this section\" expressible, which under a merged default it was not.\n *\n * Gating notes carried over from the previous default, because they are\n * destination facts rather than placement facts:\n *\n * - Account destinations are `USER_SELF`-shaped and always available to an\n * authenticated user; the category's scope does the hiding.\n * - Organization destinations gate on org owner/admin roles, and several\n * additionally on a runtime capability, so an application that excludes the\n * backing resource surfaces nothing. This is the \"face to right management of\n * the user\" gating — a member who cannot manage the org sees no such section.\n *\n * Sub-tab labels stay on the target: they describe the destination's internal\n * structure, not its position in the rail.\n */\nimport { CoreFeature, CoreResourceOperation, CoreResourceType, CORE_ORG_ROLES, ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport { SettingsPanelRef, SettingsSectionTargetKind } from './settings-hub.frontend.schemas';\nimport type { SettingsDestination, SettingsHubConfig } from './settings-hub.frontend.schemas';\n\n/** @wildo_source:part:start saas.frontend.settings-hub.engine-destinations facet:layer:frontend facet:family:config facet:audience:app-developer */\n/**\n * Every settings destination the engine ships, as a named vocabulary.\n *\n * Exists because these refs are a CLOSED vocabulary that engine code addresses\n * by name — the billing command-menu entry opens `/settings/billing`, and any\n * future engine launcher will do the same. Before this enum, `'billing'` was a\n * bare literal in `billing-launcher.ts` with nothing tying it to the catalog\n * entry it names: rename the destination and the command silently resolves to\n * the hub's DEFAULT section instead of failing, so a menu item labelled\n * \"Billing\" would open Profile.\n *\n * **Engine code must address a destination through this enum. Application\n * config addresses one by string**, deliberately: a placement is authored data,\n * an application should not import an engine enum to write its own rail, and a\n * typo there is caught at DEV startup by `verifySettingsHubContent`.\n */\nexport enum EngineSettingsDestinationRef {\n /** The signed-in user's own profile record. */\n PROFILE = 'profile',\n /** Password, MFA, sessions — a bespoke engine panel. */\n SECURITY = 'security',\n /** Theme and appearance preferences — a bespoke engine panel. */\n APPEARANCE = 'appearance',\n /** The signed-in user's own preference record. */\n PREFERENCES = 'preferences',\n /** Invitations addressed TO the signed-in user, across organizations they have not joined. */\n MY_INVITATIONS = 'my-invitations',\n /** The current organization's own record. Org owner/admin only. */\n ORGANIZATION_GENERAL = 'organization-general',\n /** Organization membership list, including INVITED rows. Org owner/admin only. */\n MEMBERS = 'members',\n /** Billing home — subscription, plans, usage, invoices. Gated on the `billingEnabled` capability. */\n BILLING = 'billing',\n /** Organization API keys. Org owner/admin only. */\n API_KEYS = 'api-keys',\n /**\n * The tenant's OWN credentials toward third parties — its Slack workspace token, its CRM key.\n *\n * The mirror image of {@link API_KEYS} and easy to confuse with it: an API key is a credential\n * somebody uses to reach THIS application, and one of these is a credential this application uses\n * to reach somebody else ON THIS TENANT'S BEHALF. Same administrator, opposite direction.\n */\n PROVIDER_CREDENTIALS = 'provider-credentials',\n /**\n * The signed-in person's OWN credentials toward third parties — their personal API key, the\n * account they connected themselves.\n *\n * Distinct from {@link PROVIDER_CREDENTIALS} by OWNER, not by feature, and the two must never be\n * merged into one screen. A tenant's credential is a shared integration an administrator\n * configures for everyone; this one is an individual's own account, which nobody else may see,\n * spend or remove. Putting them on one page would put a colleague's personal vendor token in an\n * administrator's view — and the resource's authorization refuses that, so the screen would show\n * an empty list nobody could explain.\n */\n MY_PROVIDER_CREDENTIALS = 'my-provider-credentials',\n /** Single sign-on configuration and connections. */\n SSO = 'sso',\n /** SCIM directory provisioning configuration and tokens. */\n SCIM = 'scim',\n /** Audit-event streaming configuration and failed-delivery queue. */\n SIEM = 'siem',\n /** Outbound webhook endpoints and delivery log. */\n WEBHOOKS = 'webhooks',\n /** The organization's audit log. Org owner/admin only. */\n AUDIT_LOGS = 'audit-logs',\n}\n/** @wildo_source:part:end saas.frontend.settings-hub.engine-destinations */\n\n/** Org-management destinations are visible to organization owners and admins. */\nconst ORG_MANAGEMENT_ROLES: string[] = [CORE_ORG_ROLES.ORG_OWNER, CORE_ORG_ROLES.ORG_ADMIN];\n\n/**\n * Runtime capability key for \"billing is enabled for this app\". Wired in\n * `useLauncherRuntimeAvailabilityContext` (`runtimeCapabilities.billingEnabled`);\n * there is no enum for capability keys yet, so the launcher-config string is the\n * single source of truth.\n */\nconst BILLING_ENABLED_CAPABILITY = 'billingEnabled';\n\n/**\n * Runtime capability keys for the enterprise-config features. Unlike billing\n * (which reads `appConfig.billing.enabled`), these have no app-config toggle —\n * they are wired in `useLauncherRuntimeAvailabilityContext` from\n * resource-registration presence (`hasResource(ORGANIZATION_*_CONFIG)`), so a\n * destination auto-hides when its app excludes the resource and otherwise\n * degrades to org-admin role gating. Keep these string literals in sync with the\n * keys emitted there.\n */\nconst SSO_ENABLED_CAPABILITY = 'ssoEnabled';\nconst SCIM_ENABLED_CAPABILITY = 'scimEnabled';\nconst SIEM_ENABLED_CAPABILITY = 'siemEnabled';\nconst WEBHOOKS_ENABLED_CAPABILITY = 'webhooksEnabled';\n\n/**\n * Every settings destination the engine ships, keyed by `ref`.\n *\n * An application places these by ref. A placement naming a ref absent from this\n * catalog is refused at DEV startup rather than silently dropped — a settings\n * section that quietly fails to appear is indistinguishable from one an author\n * meant to remove.\n */\nexport const ENGINE_SETTINGS_DESTINATIONS: readonly SettingsDestination[] = [\n // ── Account ────────────────────────────────────────────────────\n {\n ref: EngineSettingsDestinationRef.PROFILE,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_SELF_PROFILES,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: EngineSettingsDestinationRef.SECURITY,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.SECURITY },\n },\n {\n ref: EngineSettingsDestinationRef.APPEARANCE,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.APPEARANCE },\n },\n {\n ref: EngineSettingsDestinationRef.PREFERENCES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_SELF_PREFERENCES,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n // The caller's OWN received invitations (Approach P) — their own INVITED membership\n // rows across orgs they haven't joined yet. Distinct from the org-admin's view of\n // sent invites, which are now just INVITED-status rows in the 'members' list (no\n // separate org 'invitations' section). No `requiredRoles`: any authenticated user\n // can act on invitations addressed to them (authorized server-side by userId-ownership).\n ref: EngineSettingsDestinationRef.MY_INVITATIONS,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.INVITATIONS },\n },\n {\n // Where a PERSON connects their own third-party accounts.\n //\n // No `requiredRoles`, and that is the substantive difference from the organization sibling\n // rather than an omission. Every authenticated user owns their own connections; the resource\n // declares `APP_USER` on every variant and no administrative variant at all, so authorization\n // is by OWNERSHIP and adding a role gate here could only ever hide the screen from someone\n // entitled to it.\n //\n // No `runtimeAvailability` gate either, for the organization destination's reason: gating on\n // \"the application declared a provider\" would hide the screen exactly when somebody is looking\n // for it, since providers are declared whether or not anyone has connected one.\n ref: EngineSettingsDestinationRef.MY_PROVIDER_CREDENTIALS,\n // TWO tabs, because the screen answers two questions and one of them has no resource behind it.\n //\n // \"Connect\" is the catalogue — what this person MAY connect — and it is a bespoke panel because\n // connecting is a flow out to a vendor rather than a row somebody creates. \"Credentials\" is the\n // ordinary resource list: what they HAVE connected, plus the pasted keys that never went through\n // a vendor at all.\n //\n // Connect comes FIRST deliberately. On the day somebody opens this screen for the first time the\n // list is empty, and an empty table is the least informative thing to greet them with; it is also\n // the tab the connection callback returns them to, carrying the outcome it has to render.\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'connect',\n label: 'Connect',\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.CONNECTED_ACCOUNTS },\n },\n {\n ref: 'credentials',\n label: 'Credentials',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n // ── Organization ───────────────────────────────────────────────\n {\n ref: EngineSettingsDestinationRef.ORGANIZATION_GENERAL,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATIONS,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n // NOTE: no separate org-level \"invitations\" destination — invitations are now\n // INVITED-status rows inside the ORGANIZATION_MEMBERS junction, so they surface\n // in this list (filter by status) rather than a parallel destination. The\n // invitee's own pending invitations live in the 'my-invitations' panel.\n ref: EngineSettingsDestinationRef.MEMBERS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_MEMBERS,\n operation: CoreResourceOperation.LIST,\n },\n },\n {\n ref: EngineSettingsDestinationRef.BILLING,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [BILLING_ENABLED_CAPABILITY] },\n // THE billing home — a bespoke panel over the aggregated BillingContext\n // state (subscription, plans + checkout, usage, invoices, portal link).\n // Deliberately NOT per-resource LIST sub-tabs: the billing child resources\n // are routed under the billing account (`REQUIRES_CONTEXT`), so org-scoped\n // generic panels cannot address them, while the aggregated state endpoint is\n // org-addressable and auto-creates the account.\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.BILLING },\n },\n {\n ref: EngineSettingsDestinationRef.API_KEYS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORG_API_KEYS,\n operation: CoreResourceOperation.LIST,\n },\n },\n {\n // Where a tenant connects its OWN third-party accounts. Until this existed the resource had\n // backend doors, an encrypted store, migrations and audit events, and no way for the\n // administrator it is FOR to reach any of it — so every tenant kept acting as the application's\n // own third-party principal, which is the defect the resource was built to remove.\n //\n // No `runtimeAvailability` gate: unlike SSO or SIEM this needs no capability to be switched on,\n // and gating it on \"the application declared a provider\" would hide the screen exactly when an\n // operator is looking for it, since an application declares providers whether or not any tenant\n // has connected one.\n ref: EngineSettingsDestinationRef.PROVIDER_CREDENTIALS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORG_PROVIDER_CREDENTIALS,\n operation: CoreResourceOperation.LIST,\n },\n },\n // ── Organization · enterprise credentials & compliance ─────────\n // Each gates on org-admin role + a per-feature runtime capability\n // (resource-registration presence). Multi-resource domains split into\n // sub-tabs pairing the singleton config (READ) with its collection (LIST).\n {\n ref: EngineSettingsDestinationRef.SSO,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SSO_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.SINGLE_SIGN_ON,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'sso-configuration',\n label: 'Configuration',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SSO_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'sso-connections',\n label: 'Connections',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SSO_CONNECTIONS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.SCIM,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SCIM_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.DIRECTORY_PROVISIONING,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'scim-provisioning',\n label: 'Provisioning',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SCIM_PROVISIONING_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'scim-tokens',\n label: 'Tokens',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SCIM_TOKENS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.SIEM,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SIEM_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.SECURITY_EVENT_EXPORT,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'siem-export',\n label: 'Export',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SIEM_EXPORT_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'siem-failed-deliveries',\n label: 'Failed deliveries',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SIEM_DELIVERY_DLQ,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.WEBHOOKS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [WEBHOOKS_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.M2M_WEBHOOK_DELIVERY,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'webhooks-endpoints',\n label: 'Endpoints',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_WEBHOOK_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'webhooks-delivery-log',\n label: 'Delivery log',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.AUDIT_LOGS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.AUDIT_LOGS,\n operation: CoreResourceOperation.LIST,\n },\n },\n];\n\n/** Every destination ref the engine ships — the set a placement is validated against. */\nexport const ENGINE_SETTINGS_DESTINATION_REFS: ReadonlySet<string> = new Set(\n ENGINE_SETTINGS_DESTINATIONS.map(destination => destination.ref),\n);\n\n/**\n * The full placement set `wildo init` scaffolds into a new application's config.\n *\n * **This is GENERATION INPUT, not a runtime fallback.** Nothing in the render\n * path may read it — `resolveSettingsHubConfig()` resolves the application's own\n * authored config and nothing else. The distinction is the entire point of the\n * split: a scaffold is a starting arrangement an author edits and owns, whereas\n * a default is an arrangement that reasserts itself and cannot be edited away.\n *\n * It places every engine destination so a new application starts complete and\n * edits DOWN, which is the direction that surfaces what exists. Starting empty\n * would hide the catalog behind documentation.\n *\n * The `label`s here are the English strings the previous framework default\n * carried, and they are NOT a temporary convenience to be removed once label\n * generation runs. The companion feeds each authored label to the labellize\n * prompt as that key's `purpose`, so it is the wording INTENT generation\n * translates — delete it and the model falls back to inventing from the ref.\n */\nexport const SCAFFOLD_SETTINGS_HUB_CONFIG: SettingsHubConfig = {\n categories: [\n { ref: 'account', label: 'Account', scope: ResourcePrimaryScope.USER_SELF, order: 0 },\n { ref: 'organization', label: 'Organization', scope: ResourcePrimaryScope.ORGANIZATIONS, order: 1 },\n ],\n placements: [\n { destinationRef: EngineSettingsDestinationRef.PROFILE, categoryRef: 'account', label: 'Profile', order: 0 },\n { destinationRef: EngineSettingsDestinationRef.SECURITY, categoryRef: 'account', label: 'Security', order: 1 },\n { destinationRef: EngineSettingsDestinationRef.APPEARANCE, categoryRef: 'account', label: 'Appearance', order: 2 },\n { destinationRef: EngineSettingsDestinationRef.PREFERENCES, categoryRef: 'account', label: 'Preferences', order: 3 },\n { destinationRef: EngineSettingsDestinationRef.MY_INVITATIONS, categoryRef: 'account', label: 'Invitations', order: 4 },\n // Same label as the organization placement below, deliberately: it is the same feature, and the\n // CATEGORY is what says whose accounts these are.\n { destinationRef: EngineSettingsDestinationRef.MY_PROVIDER_CREDENTIALS, categoryRef: 'account', label: 'Connected accounts', order: 5 },\n { destinationRef: EngineSettingsDestinationRef.ORGANIZATION_GENERAL, categoryRef: 'organization', label: 'General', order: 0 },\n { destinationRef: EngineSettingsDestinationRef.MEMBERS, categoryRef: 'organization', label: 'Members', order: 1 },\n { destinationRef: EngineSettingsDestinationRef.BILLING, categoryRef: 'organization', label: 'Billing', order: 3 },\n { destinationRef: EngineSettingsDestinationRef.API_KEYS, categoryRef: 'organization', label: 'API keys', order: 4 },\n { destinationRef: EngineSettingsDestinationRef.PROVIDER_CREDENTIALS, categoryRef: 'organization', label: 'Connected accounts', order: 5 },\n { destinationRef: EngineSettingsDestinationRef.SSO, categoryRef: 'organization', label: 'Single sign-on', order: 6 },\n { destinationRef: EngineSettingsDestinationRef.SCIM, categoryRef: 'organization', label: 'User provisioning', order: 7 },\n { destinationRef: EngineSettingsDestinationRef.SIEM, categoryRef: 'organization', label: 'Audit streaming', order: 8 },\n { destinationRef: EngineSettingsDestinationRef.WEBHOOKS, categoryRef: 'organization', label: 'Webhooks', order: 9 },\n { destinationRef: EngineSettingsDestinationRef.AUDIT_LOGS, categoryRef: 'organization', label: 'Audit log', order: 10 },\n ],\n defaultSectionRef: 'profile',\n};\n"]}
1
+ {"version":3,"file":"engine-settings-destinations.js","sourceRoot":"","sources":["../../../../src/core/config/engine-settings-destinations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The engine's settings DESTINATION catalog — addressable, and deliberately unplaced.\n *\n * Each entry says what a settings surface IS: its target, and the gating that\n * decides whether the current principal may see it at all. **No entry carries a\n * `categoryRef`, an `order` or a `label`**, because those are placement, and\n * placement belongs to the application (`SettingsPlacement`).\n *\n * This file replaced `settings-hub.frontend.defaults.ts`, which shipped a fully\n * PLACED hub as a framework default. That default was the reason an application\n * could not add, remove, reorder or rename a settings section: the render path\n * read the framework's arrangement, so an application had no arrangement of its\n * own to read. Splitting destination from placement keeps the engine owning what\n * a destination MEANS while the application owns where it sits — and makes\n * \"remove this section\" expressible, which under a merged default it was not.\n *\n * Gating notes carried over from the previous default, because they are\n * destination facts rather than placement facts:\n *\n * - Account destinations are `USER_SELF`-shaped and always available to an\n * authenticated user; the category's scope does the hiding.\n * - Organization destinations gate on org owner/admin roles, and several\n * additionally on a runtime capability, so an application that excludes the\n * backing resource surfaces nothing. This is the \"face to right management of\n * the user\" gating — a member who cannot manage the org sees no such section.\n *\n * Sub-tab labels stay on the target: they describe the destination's internal\n * structure, not its position in the rail.\n *\n * ## The refs themselves live in `@wildo-ai/saas-models`\n *\n * `EngineSettingsDestinationRef` and `ENGINE_SETTINGS_DESTINATION_REFS` are declared in\n * `saas-models` (`frontend-definitions/settings-destination-ref.definitions.ts`); this file\n * declares only what each ref MEANS. The split exists because the ref vocabulary has a\n * backend-side consumer this package can never serve: `validatePlacementPlan`'s `UNKNOWN_SUBJECT`\n * hard floor is held by the app-creation semantic authority, which must not depend on\n * `saas-frontend-lib`. Everything that names a component, a panel or a sub-tab stayed here; the\n * sixteen ids did not.\n *\n * The enum is deliberately NOT re-exported from this module, from the package root, or from\n * `companion-exports`: a symbol reachable through two public doors is a symbol whose two doors\n * drift. Every consumer — including this package's own — imports it from `@wildo-ai/saas-models`.\n */\nimport { CoreFeature, CoreResourceOperation, CoreResourceType, CORE_ORG_ROLES, EngineSettingsDestinationRef, ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport { SettingsPanelRef, SettingsSectionTargetKind } from './settings-hub.frontend.schemas';\nimport type { SettingsDestination, SettingsHubConfig } from './settings-hub.frontend.schemas';\n\n/** Org-management destinations are visible to organization owners and admins. */\nconst ORG_MANAGEMENT_ROLES: string[] = [CORE_ORG_ROLES.ORG_OWNER, CORE_ORG_ROLES.ORG_ADMIN];\n\n/**\n * Runtime capability key for \"billing is enabled for this app\". Wired in\n * `useLauncherRuntimeAvailabilityContext` (`runtimeCapabilities.billingEnabled`);\n * there is no enum for capability keys yet, so the launcher-config string is the\n * single source of truth.\n */\nconst BILLING_ENABLED_CAPABILITY = 'billingEnabled';\n\n/**\n * Runtime capability keys for the enterprise-config features. Unlike billing\n * (which reads `appConfig.billing.enabled`), these have no app-config toggle —\n * they are wired in `useLauncherRuntimeAvailabilityContext` from\n * resource-registration presence (`hasResource(ORGANIZATION_*_CONFIG)`), so a\n * destination auto-hides when its app excludes the resource and otherwise\n * degrades to org-admin role gating. Keep these string literals in sync with the\n * keys emitted there.\n */\nconst SSO_ENABLED_CAPABILITY = 'ssoEnabled';\nconst SCIM_ENABLED_CAPABILITY = 'scimEnabled';\nconst SIEM_ENABLED_CAPABILITY = 'siemEnabled';\nconst WEBHOOKS_ENABLED_CAPABILITY = 'webhooksEnabled';\n\n/**\n * Every settings destination the engine ships, keyed by `ref`.\n *\n * An application places these by ref. A placement naming a ref absent from this\n * catalog is refused at DEV startup rather than silently dropped — a settings\n * section that quietly fails to appear is indistinguishable from one an author\n * meant to remove.\n */\nexport const ENGINE_SETTINGS_DESTINATIONS: readonly SettingsDestination[] = [\n // ── Account ────────────────────────────────────────────────────\n {\n ref: EngineSettingsDestinationRef.PROFILE,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_SELF_PROFILES,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: EngineSettingsDestinationRef.SECURITY,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.SECURITY },\n },\n {\n ref: EngineSettingsDestinationRef.APPEARANCE,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.APPEARANCE },\n },\n {\n ref: EngineSettingsDestinationRef.PREFERENCES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_SELF_PREFERENCES,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n // The caller's OWN received invitations (Approach P) — their own INVITED membership\n // rows across orgs they haven't joined yet. Distinct from the org-admin's view of\n // sent invites, which are now just INVITED-status rows in the 'members' list (no\n // separate org 'invitations' section). No `requiredRoles`: any authenticated user\n // can act on invitations addressed to them (authorized server-side by userId-ownership).\n ref: EngineSettingsDestinationRef.MY_INVITATIONS,\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.INVITATIONS },\n },\n {\n // Where a PERSON connects their own third-party accounts.\n //\n // No `requiredRoles`, and that is the substantive difference from the organization sibling\n // rather than an omission. Every authenticated user owns their own connections; the resource\n // declares `APP_USER` on every variant and no administrative variant at all, so authorization\n // is by OWNERSHIP and adding a role gate here could only ever hide the screen from someone\n // entitled to it.\n //\n // No `runtimeAvailability` gate either, for the organization destination's reason: gating on\n // \"the application declared a provider\" would hide the screen exactly when somebody is looking\n // for it, since providers are declared whether or not anyone has connected one.\n ref: EngineSettingsDestinationRef.MY_PROVIDER_CREDENTIALS,\n // TWO tabs, because the screen answers two questions and one of them has no resource behind it.\n //\n // \"Connect\" is the catalogue — what this person MAY connect — and it is a bespoke panel because\n // connecting is a flow out to a vendor rather than a row somebody creates. \"Credentials\" is the\n // ordinary resource list: what they HAVE connected, plus the pasted keys that never went through\n // a vendor at all.\n //\n // Connect comes FIRST deliberately. On the day somebody opens this screen for the first time the\n // list is empty, and an empty table is the least informative thing to greet them with; it is also\n // the tab the connection callback returns them to, carrying the outcome it has to render.\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'connect',\n label: 'Connect',\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.CONNECTED_ACCOUNTS },\n },\n {\n ref: 'credentials',\n label: 'Credentials',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n // ── Organization ───────────────────────────────────────────────\n {\n ref: EngineSettingsDestinationRef.ORGANIZATION_GENERAL,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATIONS,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n // NOTE: no separate org-level \"invitations\" destination — invitations are now\n // INVITED-status rows inside the ORGANIZATION_MEMBERS junction, so they surface\n // in this list (filter by status) rather than a parallel destination. The\n // invitee's own pending invitations live in the 'my-invitations' panel.\n ref: EngineSettingsDestinationRef.MEMBERS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_MEMBERS,\n operation: CoreResourceOperation.LIST,\n },\n },\n {\n ref: EngineSettingsDestinationRef.BILLING,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [BILLING_ENABLED_CAPABILITY] },\n // THE billing home — a bespoke panel over the aggregated BillingContext\n // state (subscription, plans + checkout, usage, invoices, portal link).\n // Deliberately NOT per-resource LIST sub-tabs: the billing child resources\n // are routed under the billing account (`REQUIRES_CONTEXT`), so org-scoped\n // generic panels cannot address them, while the aggregated state endpoint is\n // org-addressable and auto-creates the account.\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.BILLING },\n },\n {\n ref: EngineSettingsDestinationRef.API_KEYS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORG_API_KEYS,\n operation: CoreResourceOperation.LIST,\n },\n },\n {\n // Where a tenant connects its OWN third-party accounts. Until this existed the resource had\n // backend doors, an encrypted store, migrations and audit events, and no way for the\n // administrator it is FOR to reach any of it — so every tenant kept acting as the application's\n // own third-party principal, which is the defect the resource was built to remove.\n //\n // No `runtimeAvailability` gate: unlike SSO or SIEM this needs no capability to be switched on,\n // and gating it on \"the application declared a provider\" would hide the screen exactly when an\n // operator is looking for it, since an application declares providers whether or not any tenant\n // has connected one.\n ref: EngineSettingsDestinationRef.PROVIDER_CREDENTIALS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n // TWO tabs, for the person-scope destination's reason: \"Connect\" is a flow out to a vendor and\n // has no resource behind it, while \"Credentials\" is the ordinary list of what the tenant HAS.\n // Connect comes first because it is where the connection callback returns, carrying the outcome\n // it has to render.\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'connect',\n label: 'Connect',\n target: { kind: SettingsSectionTargetKind.ENGINE_PANEL, panelRef: SettingsPanelRef.ORGANIZATION_CONNECTED_ACCOUNTS },\n },\n {\n ref: 'credentials',\n label: 'Credentials',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORG_PROVIDER_CREDENTIALS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n // ── Organization · enterprise credentials & compliance ─────────\n // Each gates on org-admin role + a per-feature runtime capability\n // (resource-registration presence). Multi-resource domains split into\n // sub-tabs pairing the singleton config (READ) with its collection (LIST).\n {\n ref: EngineSettingsDestinationRef.SSO,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SSO_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.SINGLE_SIGN_ON,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'sso-configuration',\n label: 'Configuration',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SSO_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'sso-connections',\n label: 'Connections',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SSO_CONNECTIONS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.SCIM,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SCIM_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.DIRECTORY_PROVISIONING,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'scim-provisioning',\n label: 'Provisioning',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SCIM_PROVISIONING_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'scim-tokens',\n label: 'Tokens',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SCIM_TOKENS,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.SIEM,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [SIEM_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.SECURITY_EVENT_EXPORT,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'siem-export',\n label: 'Export',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SIEM_EXPORT_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'siem-failed-deliveries',\n label: 'Failed deliveries',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_SIEM_DELIVERY_DLQ,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.WEBHOOKS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n runtimeAvailability: { requiredCapabilities: [WEBHOOKS_ENABLED_CAPABILITY] },\n entitlementFeatureId: CoreFeature.M2M_WEBHOOK_DELIVERY,\n target: {\n kind: SettingsSectionTargetKind.SUB_TABS,\n subTabs: [\n {\n ref: 'webhooks-endpoints',\n label: 'Endpoints',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_WEBHOOK_CONFIG,\n operation: CoreResourceOperation.READ,\n },\n },\n {\n ref: 'webhooks-delivery-log',\n label: 'Delivery log',\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG,\n operation: CoreResourceOperation.LIST,\n },\n },\n ],\n },\n },\n {\n ref: EngineSettingsDestinationRef.AUDIT_LOGS,\n requiredRoles: ORG_MANAGEMENT_ROLES,\n target: {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION,\n resourceType: CoreResourceType.AUDIT_LOGS,\n operation: CoreResourceOperation.LIST,\n },\n },\n];\n\n/**\n * The full placement set `wildo init` scaffolds into a new application's config.\n *\n * **This is GENERATION INPUT, not a runtime fallback.** Nothing in the render\n * path may read it — `resolveSettingsHubConfig()` resolves the application's own\n * authored config and nothing else. The distinction is the entire point of the\n * split: a scaffold is a starting arrangement an author edits and owns, whereas\n * a default is an arrangement that reasserts itself and cannot be edited away.\n *\n * It places every engine destination so a new application starts complete and\n * edits DOWN, which is the direction that surfaces what exists. Starting empty\n * would hide the catalog behind documentation.\n *\n * The `label`s here are the English strings the previous framework default\n * carried, and they are NOT a temporary convenience to be removed once label\n * generation runs. The companion feeds each authored label to the labellize\n * prompt as that key's `purpose`, so it is the wording INTENT generation\n * translates — delete it and the model falls back to inventing from the ref.\n */\nexport const SCAFFOLD_SETTINGS_HUB_CONFIG: SettingsHubConfig = {\n categories: [\n { ref: 'account', label: 'Account', scope: ResourcePrimaryScope.USER_SELF, order: 0 },\n { ref: 'organization', label: 'Organization', scope: ResourcePrimaryScope.ORGANIZATIONS, order: 1 },\n ],\n placements: [\n { destinationRef: EngineSettingsDestinationRef.PROFILE, categoryRef: 'account', label: 'Profile', order: 0 },\n { destinationRef: EngineSettingsDestinationRef.SECURITY, categoryRef: 'account', label: 'Security', order: 1 },\n { destinationRef: EngineSettingsDestinationRef.APPEARANCE, categoryRef: 'account', label: 'Appearance', order: 2 },\n { destinationRef: EngineSettingsDestinationRef.PREFERENCES, categoryRef: 'account', label: 'Preferences', order: 3 },\n { destinationRef: EngineSettingsDestinationRef.MY_INVITATIONS, categoryRef: 'account', label: 'Invitations', order: 4 },\n // Same label as the organization placement below, deliberately: it is the same feature, and the\n // CATEGORY is what says whose accounts these are.\n { destinationRef: EngineSettingsDestinationRef.MY_PROVIDER_CREDENTIALS, categoryRef: 'account', label: 'Connected accounts', order: 5 },\n { destinationRef: EngineSettingsDestinationRef.ORGANIZATION_GENERAL, categoryRef: 'organization', label: 'General', order: 0 },\n { destinationRef: EngineSettingsDestinationRef.MEMBERS, categoryRef: 'organization', label: 'Members', order: 1 },\n { destinationRef: EngineSettingsDestinationRef.BILLING, categoryRef: 'organization', label: 'Billing', order: 3 },\n { destinationRef: EngineSettingsDestinationRef.API_KEYS, categoryRef: 'organization', label: 'API keys', order: 4 },\n { destinationRef: EngineSettingsDestinationRef.PROVIDER_CREDENTIALS, categoryRef: 'organization', label: 'Connected accounts', order: 5 },\n { destinationRef: EngineSettingsDestinationRef.SSO, categoryRef: 'organization', label: 'Single sign-on', order: 6 },\n { destinationRef: EngineSettingsDestinationRef.SCIM, categoryRef: 'organization', label: 'User provisioning', order: 7 },\n { destinationRef: EngineSettingsDestinationRef.SIEM, categoryRef: 'organization', label: 'Audit streaming', order: 8 },\n { destinationRef: EngineSettingsDestinationRef.WEBHOOKS, categoryRef: 'organization', label: 'Webhooks', order: 9 },\n { destinationRef: EngineSettingsDestinationRef.AUDIT_LOGS, categoryRef: 'organization', label: 'Audit log', order: 10 },\n ],\n defaultSectionRef: 'profile',\n};\n"]}
@@ -88,7 +88,16 @@ export declare enum SettingsPanelRef {
88
88
  * Paired with, never replacing, the credential list: this panel answers what MAY be connected and
89
89
  * the list answers what IS, and the empty answer to the second is exactly when the first matters.
90
90
  */
91
- CONNECTED_ACCOUNTS = "connected-accounts"
91
+ CONNECTED_ACCOUNTS = "connected-accounts",
92
+ /**
93
+ * The same act at the TENANT's scope: connecting an account the whole organization acts as.
94
+ *
95
+ * A distinct ref rather than a parameterised one, because a settings destination resolves a ref to
96
+ * a panel and carries no arguments — and because the two must never be reachable from each other's
97
+ * screen. The component behind them IS shared: the act is identical, and duplicating it would
98
+ * guarantee the two drift. What is never shared is the data.
99
+ */
100
+ ORGANIZATION_CONNECTED_ACCOUNTS = "organization-connected-accounts"
92
101
  }
93
102
  /** Renders a framework-owned bespoke panel. */
94
103
  export interface SettingsEnginePanelTarget {
@@ -1 +1 @@
1
- {"version":3,"file":"settings-hub.frontend.schemas.d.ts","sourceRoot":"","sources":["../../../../src/core/config/settings-hub.frontend.schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-hub.frontend.schemas.d.ts","sourceRoot":"","sources":["../../../../src/core/config/settings-hub.frontend.schemas.ts"],"names":[],"mappings":"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"}
@@ -94,6 +94,15 @@ export var SettingsPanelRef;
94
94
  * the list answers what IS, and the empty answer to the second is exactly when the first matters.
95
95
  */
96
96
  SettingsPanelRef["CONNECTED_ACCOUNTS"] = "connected-accounts";
97
+ /**
98
+ * The same act at the TENANT's scope: connecting an account the whole organization acts as.
99
+ *
100
+ * A distinct ref rather than a parameterised one, because a settings destination resolves a ref to
101
+ * a panel and carries no arguments — and because the two must never be reachable from each other's
102
+ * screen. The component behind them IS shared: the act is identical, and duplicating it would
103
+ * guarantee the two drift. What is never shared is the data.
104
+ */
105
+ SettingsPanelRef["ORGANIZATION_CONNECTED_ACCOUNTS"] = "organization-connected-accounts";
97
106
  })(SettingsPanelRef || (SettingsPanelRef = {}));
98
107
  /** @wildo_source:part:end saas.frontend.settings-hub.placement */
99
108
  //# sourceMappingURL=settings-hub.frontend.schemas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-hub.frontend.schemas.js","sourceRoot":"","sources":["../../../../src/core/config/settings-hub.frontend.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,mEAAmE;AACnE,+DAA+D;AAC/D,mEAAmE;AAEnE;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,yBASX;AATD,WAAY,yBAAyB;IACnC,iEAAiE;IACjE,0DAA6B,CAAA;IAC7B,+FAA+F;IAC/F,sEAAyC,CAAA;IACzC,sFAAsF;IACtF,kEAAqC,CAAA;IACrC,0GAA0G;IAC1G,kDAAqB,CAAA;AACvB,CAAC,EATW,yBAAyB,KAAzB,yBAAyB,QASpC;AAED,mEAAmE;AACnE,6DAA6D;AAC7D,mEAAmE;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,CAAN,IAAY,gBAiCX;AAjCD,WAAY,gBAAgB;IAC1B,wGAAwG;IACxG,yCAAqB,CAAA;IACrB,qEAAqE;IACrE,6CAAyB,CAAA;IACzB,oFAAoF;IACpF,+CAA2B,CAAA;IAC3B;;;;;;;;;;;OAWG;IACH,uCAAmB,CAAA;IACnB;;;;;;;;;;;OAWG;IACH,6DAAyC,CAAA;AAC3C,CAAC,EAjCW,gBAAgB,KAAhB,gBAAgB,QAiC3B;AAgRD,kEAAkE","sourcesContent":["/**\n * Settings Hub — Declarative Section Registry\n *\n * The Settings Hub is the framework's single point of configuration: one overlay\n * surface that consolidates every settings destination (account, security,\n * appearance, organization, members, billing, …) behind a vertical `Tabs` rail\n * grouped by category. Many entry points (user dropdown, sidebar, command menu)\n * all converge on this one hub; links differ only by which section they pre-open.\n *\n * This file owns the **config-time** registry contract. It is declaration-first\n * and mirrors `launcher-items.frontend.schemas.ts`:\n * - `SettingsSectionTarget` is an interface-based discriminated union on `kind`\n * (exactly like `LauncherItemRef`), because section targets are config-time\n * descriptors resolved by the runtime — not Zod-validated wire payloads.\n * - The framework seeds a default `SettingsHubConfig`; apps merge/extend it\n * (same model as the sidebar/launcher config).\n *\n * Runtime concerns live elsewhere:\n * - `NavigationContentType.SETTINGS_HUB` (navigation.schemas.ts) — what renders\n * in the overlay zone.\n * - `SettingsHub` component (components/settings/) — resolves a section's target\n * to a rendered panel.\n *\n * @see launcher-items.frontend.schemas.ts — the sibling launcher registry this mirrors\n * @see .claude/plans/unified-settings-hub.md — design + layer trace\n */\n\nimport { ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport type { RequiredFeaturesConfig } from '@wildo-ai/saas-models';\nimport type { LauncherRuntimeAvailabilityConfig } from './launcher-items.frontend.schemas';\n\n// ════════════════════════════════════════════════════════════════\n// Section Target Kind — discriminant for SettingsSectionTarget\n// ════════════════════════════════════════════════════════════════\n\n/**\n * What a settings section renders in its content panel.\n *\n * Discriminant for the `SettingsSectionTarget` union. The default for\n * data-backed settings is `RESOURCE_OPERATION` (reuse the auto-rendered\n * resource surface); `ENGINE_PANEL` is reserved for the few sections whose\n * bespoke layout earns it (Security, Appearance).\n */\nexport enum SettingsSectionTargetKind {\n /** A framework-owned bespoke panel (Security, Appearance, …). */\n ENGINE_PANEL = 'engine_panel',\n /** An auto-rendered resource-operation surface (members, API tokens, billing, preferences). */\n RESOURCE_OPERATION = 'resource_operation',\n /** An app-registered custom React component (resolved via the component registry). */\n CUSTOM_COMPONENT = 'custom_component',\n /** A section that itself splits into horizontal sub-tabs (e.g. Teams → Members / Roles & Permissions). */\n SUB_TABS = 'sub_tabs',\n}\n\n// ════════════════════════════════════════════════════════════════\n// Engine Panel Ref — framework-owned bespoke settings panels\n// ════════════════════════════════════════════════════════════════\n\n/**\n * Framework-provided settings panels with bespoke (non-CRUD) layout.\n *\n * Closed enum — only framework panels belong here. Most settings sections should\n * be `RESOURCE_OPERATION` targets instead; a panel earns a slot here only when a\n * standard resource surface cannot express it (multi-factor enrollment flows,\n * theme/dark-mode toggles, …).\n *\n * The runtime maps each ref to a registered panel component in the\n * `SettingsHub` resolver.\n */\nexport enum SettingsPanelRef {\n /** Password, MFA enrollment, passkeys, identity links (wraps the former `AppPage_SecuritySettings`). */\n SECURITY = 'security',\n /** Theme, dark-mode, density and other look-and-feel preferences. */\n APPEARANCE = 'appearance',\n /** The caller's own pending org invitations — accept/reject in-app (Approach P). */\n INVITATIONS = 'invitations',\n /**\n * The billing home: subscription status, plan catalog + checkout, usage,\n * invoices and the provider portal link — composed from the BillingContext\n * aggregated state (`GET_STATE`), NOT from per-resource LIST surfaces.\n *\n * Bespoke on purpose: the billing child resources (subscriptions, invoice\n * refs, usage records) are routed UNDER the billing account\n * (`REQUIRES_CONTEXT`), so a generic org-scoped `RESOURCE_OPERATION` panel\n * cannot build their URLs. The aggregated billing state is org-addressable\n * and auto-creates the account, which makes it the correct settings-surface\n * data source.\n */\n BILLING = 'billing',\n /**\n * Where a person CONNECTS one of their own third-party accounts.\n *\n * Bespoke because connecting is not a row somebody creates: it is a flow that leaves the\n * application, obtains consent at a vendor, and returns with a grant nobody typed. The generic\n * resource surface can list, inspect and delete the resulting credentials perfectly — it simply has\n * no mechanism for an ACTION of that shape, which is why the whole outbound-authorization lane had\n * no surface that could begin it until this existed.\n *\n * Paired with, never replacing, the credential list: this panel answers what MAY be connected and\n * the list answers what IS, and the empty answer to the second is exactly when the first matters.\n */\n CONNECTED_ACCOUNTS = 'connected-accounts',\n}\n\n// ════════════════════════════════════════════════════════════════\n// Section Target — discriminated union on `kind`\n// ════════════════════════════════════════════════════════════════\n\n/** Renders a framework-owned bespoke panel. */\nexport interface SettingsEnginePanelTarget {\n kind: SettingsSectionTargetKind.ENGINE_PANEL;\n panelRef: SettingsPanelRef;\n}\n\n/**\n * Renders an auto-generated resource-operation surface inside the section panel.\n * Resolved against the resource registry exactly like a launcher\n * `RESOURCE_OPERATION` target.\n */\nexport interface SettingsResourceOperationTarget {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION;\n resourceType: string;\n operation: string;\n operationVariant?: string;\n}\n\n/** Renders an app-registered custom React component (resolved by `componentRef`). */\nexport interface SettingsCustomComponentTarget {\n kind: SettingsSectionTargetKind.CUSTOM_COMPONENT;\n componentRef: string;\n}\n\n/**\n * Leaf targets renderable directly in a panel. Sub-tabs may only point at leaf\n * targets — sub-tabs cannot nest further sub-tabs (one level of in-section\n * tabbing, matching the BetterStack reference).\n */\nexport type SettingsLeafTarget =\n | SettingsEnginePanelTarget\n | SettingsResourceOperationTarget\n | SettingsCustomComponentTarget;\n\n/**\n * One horizontal sub-tab within a section (e.g. the \"Members\" / \"Roles &\n * Permissions\" tabs inside a Teams section).\n */\nexport interface SettingsSubTab {\n /** Sub-tab reference — app-defined, used for i18n + the `value` of the inner Tabs. */\n ref: string;\n /** Display label (i18n ref). */\n label: string;\n /** Optional icon ref for the sub-tab trigger. */\n icon?: string;\n /** What this sub-tab renders. Sub-tabs hold leaf targets only. */\n target: SettingsLeafTarget;\n}\n\n/** Splits a section into horizontal sub-tabs rendered above the panel content. */\nexport interface SettingsSubTabsTarget {\n kind: SettingsSectionTargetKind.SUB_TABS;\n subTabs: SettingsSubTab[];\n}\n\n/**\n * What a settings section renders. Discriminated on `kind`; the `SettingsHub`\n * resolver dispatches on it to produce the panel content.\n */\nexport type SettingsSectionTarget = SettingsLeafTarget | SettingsSubTabsTarget;\n\n// ════════════════════════════════════════════════════════════════\n// Category — the rail group\n// ════════════════════════════════════════════════════════════════\n\n/**\n * A category groups sections in the vertical rail (the `Account` / `Organization`\n * group headers in the BetterStack reference). Rendered as a label + separator\n * inside the `TabsList` — NOT a separate nav widget (the `Tabs` primitive stays\n * the section mechanism).\n *\n * `scope` ties the category to a primary-scope axis so the runtime can hide it\n * when the scope is unavailable — e.g. an `ORGANIZATIONS` category is hidden when\n * no organization is selected. It is derived against `AppScope`, not authored\n * per-user.\n */\nexport interface SettingsCategory {\n /** Category reference — app-defined, referenced by `SettingsSection.categoryRef`. */\n ref: string;\n /** Group header label (i18n ref). */\n label: string;\n /**\n * Primary scope this category belongs to. Drives rail grouping order and\n * scope-gated visibility (org categories hide when no org is selected).\n * Omit for a scope-agnostic category.\n */\n scope?: ResourcePrimaryScope;\n /** Optional icon ref for the group header. */\n icon?: string;\n /** Sort order among categories in the rail (lower = higher). */\n order?: number;\n}\n\n// ════════════════════════════════════════════════════════════════\n// Section — one vertical tab in the rail\n// ════════════════════════════════════════════════════════════════\n\n/** @wildo_source:part:start saas.frontend.settings-hub.placement facet:layer:frontend facet:family:config facet:audience:app-developer */\n/**\n * An addressable settings DESTINATION — what a settings surface *is*, with no\n * opinion on where it appears.\n *\n * This is the half the engine ships (`ENGINE_SETTINGS_DESTINATIONS`). It carries\n * the target and the gating stack, and deliberately carries **no `categoryRef`,\n * no `order` and no `label`**: those are placement, and placement is the\n * application's decision (`SettingsPlacement`).\n *\n * The split exists because the engine shipping a PLACED hub is what made the\n * settings rail unauthorable — an application could not add, remove, reorder or\n * rename a section without the framework agreeing. Splitting destination from\n * placement lets the engine keep owning what a destination MEANS (its target,\n * its roles, its entitlement) while the application owns where it sits.\n */\nexport interface SettingsDestination {\n /** Destination reference — the `/settings/:sectionRef` URL segment and the id a placement names. */\n ref: string;\n /** What the destination renders in its content panel. */\n target: SettingsSectionTarget;\n /** Declarative runtime capability gating (same contract as launcher items). */\n runtimeAvailability?: LauncherRuntimeAvailabilityConfig;\n /** Feature flags required to surface this destination (plan/subscription gating). */\n requiredFeatures?: RequiredFeaturesConfig;\n /** RBAC roles required to surface this destination (OR semantics). */\n requiredRoles?: string[];\n /** Optional CoreFeature id this destination's content is ENTITLED by (soft gate — renders an upgrade prompt). */\n entitlementFeatureId?: string;\n}\n\n/**\n * An application's explicit PLACEMENT of one destination in its settings rail.\n *\n * Authored in the application's own config. Nothing is placed implicitly: a\n * destination the application does not place does not render, which is the whole\n * point — \"we should just place things\", with no automatic inference.\n *\n * `label` is optional and is an OVERRIDE. The resolved label otherwise comes from\n * the `settings_hub.sections.<ref>.label` key, so a placed section is localizable\n * without the application authoring an English string.\n *\n * That namespace and its resolver (`tSettingsHubSection`) EXIST and already fall\n * back to the authored label. What does not exist is anything that generates the\n * units: `LabellingTypes.SETTINGS_HUB` is declared with an empty pattern and the\n * companion plans nothing for it, so today every rail label is the authored\n * English string. R9 is a wiring job, not a new mechanism.\n */\nexport interface SettingsPlacement {\n /** The {@link SettingsDestination.ref} being placed. Refused at DEV startup when unknown. */\n destinationRef: string;\n /** Which category (rail group) this destination sits under. */\n categoryRef: string;\n /** Sort order within the category (lower = higher). */\n order?: number;\n /** Optional icon ref for the rail entry. */\n icon?: string;\n /** Rail label override. Omit to take `settings_hub.sections.<ref>.label`. */\n label?: string;\n}\n/** @wildo_source:part:end saas.frontend.settings-hub.placement */\n\n/**\n * A settings section is one entry in the vertical rail (one `TabsTrigger`) —\n * the RESOLVED union of a {@link SettingsDestination} and the\n * {@link SettingsPlacement} that placed it.\n *\n * Produced by `resolveSettingsHubConfig()`; never authored directly. It\n * belongs to a category, addresses a target, and reuses the existing launcher\n * gating stack:\n * - `runtimeAvailability` — survives the app-shell filtering pass (capabilities).\n * - `requiredFeatures` — plan/subscription gating once resolved.\n * - `requiredRoles` — RBAC gating (e.g. org-admin-only sections).\n *\n * `ref` is the URL-addressable section id (`/settings/:sectionRef`).\n */\nexport interface SettingsSection {\n /** Section reference — app-defined; the `/settings/:sectionRef` URL segment + Tabs `value`. */\n ref: string;\n /** Which category (rail group) this section sits under. */\n categoryRef: string;\n /** Rail label (i18n ref). */\n label: string;\n /** Optional icon ref for the rail entry. */\n icon?: string;\n /** Sort order within the category (lower = higher). */\n order?: number;\n /** What the section renders in its content panel. */\n target: SettingsSectionTarget;\n /** Declarative runtime capability gating (same contract as launcher items). */\n runtimeAvailability?: LauncherRuntimeAvailabilityConfig;\n /**\n * Feature flags required to surface this section (plan/subscription gating).\n *\n * Uses the framework-canonical {@link RequiredFeaturesConfig} contract shared\n * with views and resource operations — shorthand `string[]` (OR semantics) or\n * the full `{ features, mode: 'OR' | 'AND' }` form. `limitChecks` are not\n * evaluated for section visibility (a section is shown or hidden, never\n * \"over-limit\"); use {@link requiredRoles} / capabilities for hard gating.\n */\n requiredFeatures?: RequiredFeaturesConfig;\n /**\n * RBAC roles required to surface this section (OR semantics — the user needs\n * ANY one of these roles). Evaluated against the merged app-level + current-\n * organization role set, the same effective surface the rest of the frontend\n * gating layer resolves (see `buildFeaturePolicyRoles`). Org-management\n * sections gate on `[CORE_ORG_ROLES.ORG_OWNER, CORE_ORG_ROLES.ORG_ADMIN]`.\n */\n requiredRoles?: string[];\n /**\n * Optional CoreFeature id this section's content is ENTITLED by. Distinct from\n * {@link requiredFeatures} (a HARD hide-gate): when set, the section still\n * SURVIVES (per `runtimeAvailability`/roles) and its body is wrapped in a\n * `FeatureGate` so an OFFERED-but-not-yet-entitled feature renders the\n * policy-driven upgrade/add-on prompt (`unavailabilityPolicy`) instead of\n * vanishing. Pair with a `runtimeAvailability.requiredCapabilities` gate whose\n * capability is the plan-independent \"app offers X\" signal, so a feature the\n * app does NOT offer at all is hidden outright while an offered one prompts.\n */\n entitlementFeatureId?: string;\n}\n\n// ════════════════════════════════════════════════════════════════\n// Hub Config — the registry root\n// ════════════════════════════════════════════════════════════════\n\n/** @wildo_source:part:start saas.frontend.settings-hub.placement */\n/**\n * The AUTHORED Settings Hub registry — an application's own settings rail.\n *\n * The framework ships destinations (`ENGINE_SETTINGS_DESTINATIONS`), never a\n * placed hub. This is the application's half: which categories exist, and which\n * destinations are placed where. `wildo init` scaffolds the full destination list\n * as placements so a new application starts complete and edits down.\n *\n * Resolve it with `resolveSettingsHubConfig()` to get the rendered\n * {@link SettingsSection} list; the render path never reads this shape directly.\n */\nexport interface SettingsHubConfig {\n /** Rail groups, in render order (also orderable via `SettingsCategory.order`). */\n categories: SettingsCategory[];\n /**\n * Every destination this application places, and where.\n *\n * A destination that appears in no placement does not render. That is\n * deliberate: absence is how an application removes a settings section, and it\n * must not be second-guessed by a merge against a framework default.\n */\n placements: SettingsPlacement[];\n /**\n * Section opened when the hub is launched without an explicit section\n * (`/settings` with no `:sectionRef`). Falls back to the first section of the\n * first category when omitted.\n */\n defaultSectionRef?: string;\n}\n\n/**\n * The RESOLVED hub — categories plus fully-resolved sections, ready to render.\n *\n * Distinct from {@link SettingsHubConfig} (what an application AUTHORS) because\n * conflating the two is what let a placed default ship from the engine. A\n * consumer that renders takes this; a consumer that configures takes the other.\n */\nexport interface ResolvedSettingsHubConfig {\n categories: SettingsCategory[];\n sections: SettingsSection[];\n defaultSectionRef?: string;\n}\n/** @wildo_source:part:end saas.frontend.settings-hub.placement */\n"]}
1
+ {"version":3,"file":"settings-hub.frontend.schemas.js","sourceRoot":"","sources":["../../../../src/core/config/settings-hub.frontend.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,mEAAmE;AACnE,+DAA+D;AAC/D,mEAAmE;AAEnE;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,yBASX;AATD,WAAY,yBAAyB;IACnC,iEAAiE;IACjE,0DAA6B,CAAA;IAC7B,+FAA+F;IAC/F,sEAAyC,CAAA;IACzC,sFAAsF;IACtF,kEAAqC,CAAA;IACrC,0GAA0G;IAC1G,kDAAqB,CAAA;AACvB,CAAC,EATW,yBAAyB,KAAzB,yBAAyB,QASpC;AAED,mEAAmE;AACnE,6DAA6D;AAC7D,mEAAmE;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,CAAN,IAAY,gBA0CX;AA1CD,WAAY,gBAAgB;IAC1B,wGAAwG;IACxG,yCAAqB,CAAA;IACrB,qEAAqE;IACrE,6CAAyB,CAAA;IACzB,oFAAoF;IACpF,+CAA2B,CAAA;IAC3B;;;;;;;;;;;OAWG;IACH,uCAAmB,CAAA;IACnB;;;;;;;;;;;OAWG;IACH,6DAAyC,CAAA;IACzC;;;;;;;OAOG;IACH,uFAAmE,CAAA;AACrE,CAAC,EA1CW,gBAAgB,KAAhB,gBAAgB,QA0C3B;AAgRD,kEAAkE","sourcesContent":["/**\n * Settings Hub — Declarative Section Registry\n *\n * The Settings Hub is the framework's single point of configuration: one overlay\n * surface that consolidates every settings destination (account, security,\n * appearance, organization, members, billing, …) behind a vertical `Tabs` rail\n * grouped by category. Many entry points (user dropdown, sidebar, command menu)\n * all converge on this one hub; links differ only by which section they pre-open.\n *\n * This file owns the **config-time** registry contract. It is declaration-first\n * and mirrors `launcher-items.frontend.schemas.ts`:\n * - `SettingsSectionTarget` is an interface-based discriminated union on `kind`\n * (exactly like `LauncherItemRef`), because section targets are config-time\n * descriptors resolved by the runtime — not Zod-validated wire payloads.\n * - The framework seeds a default `SettingsHubConfig`; apps merge/extend it\n * (same model as the sidebar/launcher config).\n *\n * Runtime concerns live elsewhere:\n * - `NavigationContentType.SETTINGS_HUB` (navigation.schemas.ts) — what renders\n * in the overlay zone.\n * - `SettingsHub` component (components/settings/) — resolves a section's target\n * to a rendered panel.\n *\n * @see launcher-items.frontend.schemas.ts — the sibling launcher registry this mirrors\n * @see .claude/plans/unified-settings-hub.md — design + layer trace\n */\n\nimport { ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport type { RequiredFeaturesConfig } from '@wildo-ai/saas-models';\nimport type { LauncherRuntimeAvailabilityConfig } from './launcher-items.frontend.schemas';\n\n// ════════════════════════════════════════════════════════════════\n// Section Target Kind — discriminant for SettingsSectionTarget\n// ════════════════════════════════════════════════════════════════\n\n/**\n * What a settings section renders in its content panel.\n *\n * Discriminant for the `SettingsSectionTarget` union. The default for\n * data-backed settings is `RESOURCE_OPERATION` (reuse the auto-rendered\n * resource surface); `ENGINE_PANEL` is reserved for the few sections whose\n * bespoke layout earns it (Security, Appearance).\n */\nexport enum SettingsSectionTargetKind {\n /** A framework-owned bespoke panel (Security, Appearance, …). */\n ENGINE_PANEL = 'engine_panel',\n /** An auto-rendered resource-operation surface (members, API tokens, billing, preferences). */\n RESOURCE_OPERATION = 'resource_operation',\n /** An app-registered custom React component (resolved via the component registry). */\n CUSTOM_COMPONENT = 'custom_component',\n /** A section that itself splits into horizontal sub-tabs (e.g. Teams → Members / Roles & Permissions). */\n SUB_TABS = 'sub_tabs',\n}\n\n// ════════════════════════════════════════════════════════════════\n// Engine Panel Ref — framework-owned bespoke settings panels\n// ════════════════════════════════════════════════════════════════\n\n/**\n * Framework-provided settings panels with bespoke (non-CRUD) layout.\n *\n * Closed enum — only framework panels belong here. Most settings sections should\n * be `RESOURCE_OPERATION` targets instead; a panel earns a slot here only when a\n * standard resource surface cannot express it (multi-factor enrollment flows,\n * theme/dark-mode toggles, …).\n *\n * The runtime maps each ref to a registered panel component in the\n * `SettingsHub` resolver.\n */\nexport enum SettingsPanelRef {\n /** Password, MFA enrollment, passkeys, identity links (wraps the former `AppPage_SecuritySettings`). */\n SECURITY = 'security',\n /** Theme, dark-mode, density and other look-and-feel preferences. */\n APPEARANCE = 'appearance',\n /** The caller's own pending org invitations — accept/reject in-app (Approach P). */\n INVITATIONS = 'invitations',\n /**\n * The billing home: subscription status, plan catalog + checkout, usage,\n * invoices and the provider portal link — composed from the BillingContext\n * aggregated state (`GET_STATE`), NOT from per-resource LIST surfaces.\n *\n * Bespoke on purpose: the billing child resources (subscriptions, invoice\n * refs, usage records) are routed UNDER the billing account\n * (`REQUIRES_CONTEXT`), so a generic org-scoped `RESOURCE_OPERATION` panel\n * cannot build their URLs. The aggregated billing state is org-addressable\n * and auto-creates the account, which makes it the correct settings-surface\n * data source.\n */\n BILLING = 'billing',\n /**\n * Where a person CONNECTS one of their own third-party accounts.\n *\n * Bespoke because connecting is not a row somebody creates: it is a flow that leaves the\n * application, obtains consent at a vendor, and returns with a grant nobody typed. The generic\n * resource surface can list, inspect and delete the resulting credentials perfectly — it simply has\n * no mechanism for an ACTION of that shape, which is why the whole outbound-authorization lane had\n * no surface that could begin it until this existed.\n *\n * Paired with, never replacing, the credential list: this panel answers what MAY be connected and\n * the list answers what IS, and the empty answer to the second is exactly when the first matters.\n */\n CONNECTED_ACCOUNTS = 'connected-accounts',\n /**\n * The same act at the TENANT's scope: connecting an account the whole organization acts as.\n *\n * A distinct ref rather than a parameterised one, because a settings destination resolves a ref to\n * a panel and carries no arguments — and because the two must never be reachable from each other's\n * screen. The component behind them IS shared: the act is identical, and duplicating it would\n * guarantee the two drift. What is never shared is the data.\n */\n ORGANIZATION_CONNECTED_ACCOUNTS = 'organization-connected-accounts',\n}\n\n// ════════════════════════════════════════════════════════════════\n// Section Target — discriminated union on `kind`\n// ════════════════════════════════════════════════════════════════\n\n/** Renders a framework-owned bespoke panel. */\nexport interface SettingsEnginePanelTarget {\n kind: SettingsSectionTargetKind.ENGINE_PANEL;\n panelRef: SettingsPanelRef;\n}\n\n/**\n * Renders an auto-generated resource-operation surface inside the section panel.\n * Resolved against the resource registry exactly like a launcher\n * `RESOURCE_OPERATION` target.\n */\nexport interface SettingsResourceOperationTarget {\n kind: SettingsSectionTargetKind.RESOURCE_OPERATION;\n resourceType: string;\n operation: string;\n operationVariant?: string;\n}\n\n/** Renders an app-registered custom React component (resolved by `componentRef`). */\nexport interface SettingsCustomComponentTarget {\n kind: SettingsSectionTargetKind.CUSTOM_COMPONENT;\n componentRef: string;\n}\n\n/**\n * Leaf targets renderable directly in a panel. Sub-tabs may only point at leaf\n * targets — sub-tabs cannot nest further sub-tabs (one level of in-section\n * tabbing, matching the BetterStack reference).\n */\nexport type SettingsLeafTarget =\n | SettingsEnginePanelTarget\n | SettingsResourceOperationTarget\n | SettingsCustomComponentTarget;\n\n/**\n * One horizontal sub-tab within a section (e.g. the \"Members\" / \"Roles &\n * Permissions\" tabs inside a Teams section).\n */\nexport interface SettingsSubTab {\n /** Sub-tab reference — app-defined, used for i18n + the `value` of the inner Tabs. */\n ref: string;\n /** Display label (i18n ref). */\n label: string;\n /** Optional icon ref for the sub-tab trigger. */\n icon?: string;\n /** What this sub-tab renders. Sub-tabs hold leaf targets only. */\n target: SettingsLeafTarget;\n}\n\n/** Splits a section into horizontal sub-tabs rendered above the panel content. */\nexport interface SettingsSubTabsTarget {\n kind: SettingsSectionTargetKind.SUB_TABS;\n subTabs: SettingsSubTab[];\n}\n\n/**\n * What a settings section renders. Discriminated on `kind`; the `SettingsHub`\n * resolver dispatches on it to produce the panel content.\n */\nexport type SettingsSectionTarget = SettingsLeafTarget | SettingsSubTabsTarget;\n\n// ════════════════════════════════════════════════════════════════\n// Category — the rail group\n// ════════════════════════════════════════════════════════════════\n\n/**\n * A category groups sections in the vertical rail (the `Account` / `Organization`\n * group headers in the BetterStack reference). Rendered as a label + separator\n * inside the `TabsList` — NOT a separate nav widget (the `Tabs` primitive stays\n * the section mechanism).\n *\n * `scope` ties the category to a primary-scope axis so the runtime can hide it\n * when the scope is unavailable — e.g. an `ORGANIZATIONS` category is hidden when\n * no organization is selected. It is derived against `AppScope`, not authored\n * per-user.\n */\nexport interface SettingsCategory {\n /** Category reference — app-defined, referenced by `SettingsSection.categoryRef`. */\n ref: string;\n /** Group header label (i18n ref). */\n label: string;\n /**\n * Primary scope this category belongs to. Drives rail grouping order and\n * scope-gated visibility (org categories hide when no org is selected).\n * Omit for a scope-agnostic category.\n */\n scope?: ResourcePrimaryScope;\n /** Optional icon ref for the group header. */\n icon?: string;\n /** Sort order among categories in the rail (lower = higher). */\n order?: number;\n}\n\n// ════════════════════════════════════════════════════════════════\n// Section — one vertical tab in the rail\n// ════════════════════════════════════════════════════════════════\n\n/** @wildo_source:part:start saas.frontend.settings-hub.placement facet:layer:frontend facet:family:config facet:audience:app-developer */\n/**\n * An addressable settings DESTINATION — what a settings surface *is*, with no\n * opinion on where it appears.\n *\n * This is the half the engine ships (`ENGINE_SETTINGS_DESTINATIONS`). It carries\n * the target and the gating stack, and deliberately carries **no `categoryRef`,\n * no `order` and no `label`**: those are placement, and placement is the\n * application's decision (`SettingsPlacement`).\n *\n * The split exists because the engine shipping a PLACED hub is what made the\n * settings rail unauthorable — an application could not add, remove, reorder or\n * rename a section without the framework agreeing. Splitting destination from\n * placement lets the engine keep owning what a destination MEANS (its target,\n * its roles, its entitlement) while the application owns where it sits.\n */\nexport interface SettingsDestination {\n /** Destination reference — the `/settings/:sectionRef` URL segment and the id a placement names. */\n ref: string;\n /** What the destination renders in its content panel. */\n target: SettingsSectionTarget;\n /** Declarative runtime capability gating (same contract as launcher items). */\n runtimeAvailability?: LauncherRuntimeAvailabilityConfig;\n /** Feature flags required to surface this destination (plan/subscription gating). */\n requiredFeatures?: RequiredFeaturesConfig;\n /** RBAC roles required to surface this destination (OR semantics). */\n requiredRoles?: string[];\n /** Optional CoreFeature id this destination's content is ENTITLED by (soft gate — renders an upgrade prompt). */\n entitlementFeatureId?: string;\n}\n\n/**\n * An application's explicit PLACEMENT of one destination in its settings rail.\n *\n * Authored in the application's own config. Nothing is placed implicitly: a\n * destination the application does not place does not render, which is the whole\n * point — \"we should just place things\", with no automatic inference.\n *\n * `label` is optional and is an OVERRIDE. The resolved label otherwise comes from\n * the `settings_hub.sections.<ref>.label` key, so a placed section is localizable\n * without the application authoring an English string.\n *\n * That namespace and its resolver (`tSettingsHubSection`) EXIST and already fall\n * back to the authored label. What does not exist is anything that generates the\n * units: `LabellingTypes.SETTINGS_HUB` is declared with an empty pattern and the\n * companion plans nothing for it, so today every rail label is the authored\n * English string. R9 is a wiring job, not a new mechanism.\n */\nexport interface SettingsPlacement {\n /** The {@link SettingsDestination.ref} being placed. Refused at DEV startup when unknown. */\n destinationRef: string;\n /** Which category (rail group) this destination sits under. */\n categoryRef: string;\n /** Sort order within the category (lower = higher). */\n order?: number;\n /** Optional icon ref for the rail entry. */\n icon?: string;\n /** Rail label override. Omit to take `settings_hub.sections.<ref>.label`. */\n label?: string;\n}\n/** @wildo_source:part:end saas.frontend.settings-hub.placement */\n\n/**\n * A settings section is one entry in the vertical rail (one `TabsTrigger`) —\n * the RESOLVED union of a {@link SettingsDestination} and the\n * {@link SettingsPlacement} that placed it.\n *\n * Produced by `resolveSettingsHubConfig()`; never authored directly. It\n * belongs to a category, addresses a target, and reuses the existing launcher\n * gating stack:\n * - `runtimeAvailability` — survives the app-shell filtering pass (capabilities).\n * - `requiredFeatures` — plan/subscription gating once resolved.\n * - `requiredRoles` — RBAC gating (e.g. org-admin-only sections).\n *\n * `ref` is the URL-addressable section id (`/settings/:sectionRef`).\n */\nexport interface SettingsSection {\n /** Section reference — app-defined; the `/settings/:sectionRef` URL segment + Tabs `value`. */\n ref: string;\n /** Which category (rail group) this section sits under. */\n categoryRef: string;\n /** Rail label (i18n ref). */\n label: string;\n /** Optional icon ref for the rail entry. */\n icon?: string;\n /** Sort order within the category (lower = higher). */\n order?: number;\n /** What the section renders in its content panel. */\n target: SettingsSectionTarget;\n /** Declarative runtime capability gating (same contract as launcher items). */\n runtimeAvailability?: LauncherRuntimeAvailabilityConfig;\n /**\n * Feature flags required to surface this section (plan/subscription gating).\n *\n * Uses the framework-canonical {@link RequiredFeaturesConfig} contract shared\n * with views and resource operations — shorthand `string[]` (OR semantics) or\n * the full `{ features, mode: 'OR' | 'AND' }` form. `limitChecks` are not\n * evaluated for section visibility (a section is shown or hidden, never\n * \"over-limit\"); use {@link requiredRoles} / capabilities for hard gating.\n */\n requiredFeatures?: RequiredFeaturesConfig;\n /**\n * RBAC roles required to surface this section (OR semantics — the user needs\n * ANY one of these roles). Evaluated against the merged app-level + current-\n * organization role set, the same effective surface the rest of the frontend\n * gating layer resolves (see `buildFeaturePolicyRoles`). Org-management\n * sections gate on `[CORE_ORG_ROLES.ORG_OWNER, CORE_ORG_ROLES.ORG_ADMIN]`.\n */\n requiredRoles?: string[];\n /**\n * Optional CoreFeature id this section's content is ENTITLED by. Distinct from\n * {@link requiredFeatures} (a HARD hide-gate): when set, the section still\n * SURVIVES (per `runtimeAvailability`/roles) and its body is wrapped in a\n * `FeatureGate` so an OFFERED-but-not-yet-entitled feature renders the\n * policy-driven upgrade/add-on prompt (`unavailabilityPolicy`) instead of\n * vanishing. Pair with a `runtimeAvailability.requiredCapabilities` gate whose\n * capability is the plan-independent \"app offers X\" signal, so a feature the\n * app does NOT offer at all is hidden outright while an offered one prompts.\n */\n entitlementFeatureId?: string;\n}\n\n// ════════════════════════════════════════════════════════════════\n// Hub Config — the registry root\n// ════════════════════════════════════════════════════════════════\n\n/** @wildo_source:part:start saas.frontend.settings-hub.placement */\n/**\n * The AUTHORED Settings Hub registry — an application's own settings rail.\n *\n * The framework ships destinations (`ENGINE_SETTINGS_DESTINATIONS`), never a\n * placed hub. This is the application's half: which categories exist, and which\n * destinations are placed where. `wildo init` scaffolds the full destination list\n * as placements so a new application starts complete and edits down.\n *\n * Resolve it with `resolveSettingsHubConfig()` to get the rendered\n * {@link SettingsSection} list; the render path never reads this shape directly.\n */\nexport interface SettingsHubConfig {\n /** Rail groups, in render order (also orderable via `SettingsCategory.order`). */\n categories: SettingsCategory[];\n /**\n * Every destination this application places, and where.\n *\n * A destination that appears in no placement does not render. That is\n * deliberate: absence is how an application removes a settings section, and it\n * must not be second-guessed by a merge against a framework default.\n */\n placements: SettingsPlacement[];\n /**\n * Section opened when the hub is launched without an explicit section\n * (`/settings` with no `:sectionRef`). Falls back to the first section of the\n * first category when omitted.\n */\n defaultSectionRef?: string;\n}\n\n/**\n * The RESOLVED hub — categories plus fully-resolved sections, ready to render.\n *\n * Distinct from {@link SettingsHubConfig} (what an application AUTHORS) because\n * conflating the two is what let a placed default ship from the engine. A\n * consumer that renders takes this; a consumer that configures takes the other.\n */\nexport interface ResolvedSettingsHubConfig {\n categories: SettingsCategory[];\n sections: SettingsSection[];\n defaultSectionRef?: string;\n}\n/** @wildo_source:part:end saas.frontend.settings-hub.placement */\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useSettingsHubConfig.d.ts","sourceRoot":"","sources":["../../../../src/core/config/useSettingsHubConfig.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,yBAAyB,EAEzB,iBAAiB,EAElB,MAAM,iCAAiC,CAAC;AAQzC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,yBAAyB,CA0C3G;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,EAAE,CAO5F;AAED,wBAAgB,oBAAoB,IAAI,yBAAyB,CAGhE"}
1
+ {"version":3,"file":"useSettingsHubConfig.d.ts","sourceRoot":"","sources":["../../../../src/core/config/useSettingsHubConfig.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,yBAAyB,EAEzB,iBAAiB,EAElB,MAAM,iCAAiC,CAAC;AAQzC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,yBAAyB,CA0C3G;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,EAAE,CAO5F;AAED,wBAAgB,oBAAoB,IAAI,yBAAyB,CAShE"}
@@ -14,6 +14,7 @@
14
14
  * with it. Here, an unplaced destination does not render — absence is how a
15
15
  * section is removed, and nothing reasserts it.
16
16
  */
17
+ import { useMemo } from 'react';
17
18
  import { ENGINE_SETTINGS_DESTINATIONS } from './engine-settings-destinations.js';
18
19
  import { useUI } from '../../core/ui/useUI.js';
19
20
  /** Catalog lookup by ref, built once — resolution runs on every hub render. */
@@ -89,6 +90,12 @@ export function findUnknownDestinationRefs(authored) {
89
90
  }
90
91
  export function useSettingsHubConfig() {
91
92
  const { settingsHub } = useUI();
92
- return resolveSettingsHubConfig(settingsHub);
93
+ // Memoised on the authored config, NOT recomputed per render. Resolution
94
+ // builds a fresh object graph every call, so an unmemoised return made the
95
+ // hub's config a new identity on every render — and the hub keys a
96
+ // `useEffect` on that identity to follow URL-driven section changes. The
97
+ // effect therefore fired after every render and re-asserted the default
98
+ // section, which silently undid the user's own rail click.
99
+ return useMemo(() => resolveSettingsHubConfig(settingsHub), [settingsHub]);
93
100
  }
94
101
  //# sourceMappingURL=useSettingsHubConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSettingsHubConfig.js","sourceRoot":"","sources":["../../../../src/core/config/useSettingsHubConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAO9E,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAE1D,+EAA+E;AAC/E,MAAM,mBAAmB,GAA6C,IAAI,GAAG,CAC3E,4BAA4B,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAChF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAAuC;IAC9E,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,4EAA4E;YAC5E,gEAAgE;YAChE,EAAE;YACF,iEAAiE;YACjE,sEAAsE;YACtE,yEAAyE;YACzE,uEAAuE;YACvE,wEAAwE;YACxE,mEAAmE;YACnE,oEAAoE;YACpE,iEAAiE;YACjE,iBAAiB;YACjB,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,WAAW,CAAC,GAAG;YACzC,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,mBAAmB,EAAE,WAAW,CAAC,mBAAmB;YACpD,gBAAgB,EAAE,WAAW,CAAC,gBAAgB;YAC9C,aAAa,EAAE,WAAW,CAAC,aAAa;YACxC,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;SACvD,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,QAAQ;QACR,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;KAC9C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAuC;IAChF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,QAAQ,CAAC,UAAU;SACvB,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC;SAC1C,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC;IAChC,OAAO,wBAAwB,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["/**\n * Resolves an application's authored Settings Hub config into the rendered shape.\n *\n * Resolution is the join between the two halves of the placement split: the\n * engine's destination catalog (`ENGINE_SETTINGS_DESTINATIONS` — what a settings\n * surface IS) and the application's placements (where each one sits). Neither\n * half renders alone.\n *\n * There is deliberately **no framework default and no merge**. An earlier\n * revision returned `DEFAULT_SETTINGS_HUB_CONFIG`, a fully placed hub the engine\n * owned, and that is precisely why an application could not remove or reorder a\n * settings section: the render path read the framework's arrangement, so an\n * application's absence of an arrangement was indistinguishable from agreement\n * with it. Here, an unplaced destination does not render — absence is how a\n * section is removed, and nothing reasserts it.\n */\nimport { ENGINE_SETTINGS_DESTINATIONS } from './engine-settings-destinations';\nimport type {\n ResolvedSettingsHubConfig,\n SettingsDestination,\n SettingsHubConfig,\n SettingsSection,\n} from './settings-hub.frontend.schemas';\nimport { useUI } from '~wildo-frontend-lib/core/ui/useUI';\n\n/** Catalog lookup by ref, built once — resolution runs on every hub render. */\nconst DESTINATIONS_BY_REF: ReadonlyMap<string, SettingsDestination> = new Map(\n ENGINE_SETTINGS_DESTINATIONS.map(destination => [destination.ref, destination]),\n);\n\n/**\n * Pure (React-free) resolution — the single source of truth shared by\n * {@link useSettingsHubConfig} (render path) and the DEV-startup\n * `verifySettingsHubContent` pass.\n *\n * Keeping resolution here, not inlined in the hook, is what lets the verifier\n * check the EXACT config the hub renders. Do not inline it into either caller:\n * the moment the two derive their config separately, the verifier starts\n * attesting to something nobody renders.\n *\n * A placement naming a ref absent from the catalog is DROPPED here and reported\n * by the verifier rather than throwing. Resolution runs on the render path, and\n * a hard throw there would take down the whole hub over one bad ref; the DEV\n * startup pass is where an author is present to read the diagnostic.\n */\nexport function resolveSettingsHubConfig(authored: SettingsHubConfig | undefined): ResolvedSettingsHubConfig {\n if (authored === undefined) {\n return { categories: [], sections: [] };\n }\n\n const sections: SettingsSection[] = [];\n for (const placement of authored.placements) {\n const destination = DESTINATIONS_BY_REF.get(placement.destinationRef);\n if (destination === undefined) {\n continue;\n }\n sections.push({\n ref: destination.ref,\n categoryRef: placement.categoryRef,\n // The authored label, falling back to the ref so an unlabelled placement is\n // visibly wrong in the rail rather than rendering an empty tab.\n //\n // It is NOT superseded by label generation, and deleting it is a\n // regression rather than a tidy-up. `tSettingsHubSection(ref, label)`\n // takes this as the fallback when no key exists — and, more importantly,\n // the companion feeds this exact string to the labellize prompt as the\n // key's `purpose`. Generating without it made the model invent from the\n // ref: \"User provisioning\" became \"SCIM\", \"Audit streaming\" became\n // \"SIEM\", and a generated key WINS over the fallback, so the rail's\n // wording changed. The authored string is the intent; generation\n // translates it.\n label: placement.label ?? destination.ref,\n icon: placement.icon,\n order: placement.order,\n target: destination.target,\n runtimeAvailability: destination.runtimeAvailability,\n requiredFeatures: destination.requiredFeatures,\n requiredRoles: destination.requiredRoles,\n entitlementFeatureId: destination.entitlementFeatureId,\n });\n }\n\n return {\n categories: authored.categories,\n sections,\n defaultSectionRef: authored.defaultSectionRef,\n };\n}\n\n/**\n * Every destination ref an authored config places that the catalog does not\n * ship. Reported by `verifySettingsHubContent`; see the note on\n * {@link resolveSettingsHubConfig} for why resolution drops rather than throws.\n */\nexport function findUnknownDestinationRefs(authored: SettingsHubConfig | undefined): string[] {\n if (authored === undefined) {\n return [];\n }\n return authored.placements\n .map(placement => placement.destinationRef)\n .filter(ref => !DESTINATIONS_BY_REF.has(ref));\n}\n\nexport function useSettingsHubConfig(): ResolvedSettingsHubConfig {\n const { settingsHub } = useUI();\n return resolveSettingsHubConfig(settingsHub);\n}\n"]}
1
+ {"version":3,"file":"useSettingsHubConfig.js","sourceRoot":"","sources":["../../../../src/core/config/useSettingsHubConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAO9E,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAE1D,+EAA+E;AAC/E,MAAM,mBAAmB,GAA6C,IAAI,GAAG,CAC3E,4BAA4B,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAChF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAAuC;IAC9E,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,4EAA4E;YAC5E,gEAAgE;YAChE,EAAE;YACF,iEAAiE;YACjE,sEAAsE;YACtE,yEAAyE;YACzE,uEAAuE;YACvE,wEAAwE;YACxE,mEAAmE;YACnE,oEAAoE;YACpE,iEAAiE;YACjE,iBAAiB;YACjB,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,WAAW,CAAC,GAAG;YACzC,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,mBAAmB,EAAE,WAAW,CAAC,mBAAmB;YACpD,gBAAgB,EAAE,WAAW,CAAC,gBAAgB;YAC9C,aAAa,EAAE,WAAW,CAAC,aAAa;YACxC,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;SACvD,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,QAAQ;QACR,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;KAC9C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAuC;IAChF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,QAAQ,CAAC,UAAU;SACvB,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC;SAC1C,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC;IAChC,yEAAyE;IACzE,2EAA2E;IAC3E,mEAAmE;IACnE,yEAAyE;IACzE,wEAAwE;IACxE,2DAA2D;IAC3D,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,wBAAwB,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/**\n * Resolves an application's authored Settings Hub config into the rendered shape.\n *\n * Resolution is the join between the two halves of the placement split: the\n * engine's destination catalog (`ENGINE_SETTINGS_DESTINATIONS` — what a settings\n * surface IS) and the application's placements (where each one sits). Neither\n * half renders alone.\n *\n * There is deliberately **no framework default and no merge**. An earlier\n * revision returned `DEFAULT_SETTINGS_HUB_CONFIG`, a fully placed hub the engine\n * owned, and that is precisely why an application could not remove or reorder a\n * settings section: the render path read the framework's arrangement, so an\n * application's absence of an arrangement was indistinguishable from agreement\n * with it. Here, an unplaced destination does not render — absence is how a\n * section is removed, and nothing reasserts it.\n */\nimport { useMemo } from 'react';\nimport { ENGINE_SETTINGS_DESTINATIONS } from './engine-settings-destinations';\nimport type {\n ResolvedSettingsHubConfig,\n SettingsDestination,\n SettingsHubConfig,\n SettingsSection,\n} from './settings-hub.frontend.schemas';\nimport { useUI } from '~wildo-frontend-lib/core/ui/useUI';\n\n/** Catalog lookup by ref, built once — resolution runs on every hub render. */\nconst DESTINATIONS_BY_REF: ReadonlyMap<string, SettingsDestination> = new Map(\n ENGINE_SETTINGS_DESTINATIONS.map(destination => [destination.ref, destination]),\n);\n\n/**\n * Pure (React-free) resolution — the single source of truth shared by\n * {@link useSettingsHubConfig} (render path) and the DEV-startup\n * `verifySettingsHubContent` pass.\n *\n * Keeping resolution here, not inlined in the hook, is what lets the verifier\n * check the EXACT config the hub renders. Do not inline it into either caller:\n * the moment the two derive their config separately, the verifier starts\n * attesting to something nobody renders.\n *\n * A placement naming a ref absent from the catalog is DROPPED here and reported\n * by the verifier rather than throwing. Resolution runs on the render path, and\n * a hard throw there would take down the whole hub over one bad ref; the DEV\n * startup pass is where an author is present to read the diagnostic.\n */\nexport function resolveSettingsHubConfig(authored: SettingsHubConfig | undefined): ResolvedSettingsHubConfig {\n if (authored === undefined) {\n return { categories: [], sections: [] };\n }\n\n const sections: SettingsSection[] = [];\n for (const placement of authored.placements) {\n const destination = DESTINATIONS_BY_REF.get(placement.destinationRef);\n if (destination === undefined) {\n continue;\n }\n sections.push({\n ref: destination.ref,\n categoryRef: placement.categoryRef,\n // The authored label, falling back to the ref so an unlabelled placement is\n // visibly wrong in the rail rather than rendering an empty tab.\n //\n // It is NOT superseded by label generation, and deleting it is a\n // regression rather than a tidy-up. `tSettingsHubSection(ref, label)`\n // takes this as the fallback when no key exists — and, more importantly,\n // the companion feeds this exact string to the labellize prompt as the\n // key's `purpose`. Generating without it made the model invent from the\n // ref: \"User provisioning\" became \"SCIM\", \"Audit streaming\" became\n // \"SIEM\", and a generated key WINS over the fallback, so the rail's\n // wording changed. The authored string is the intent; generation\n // translates it.\n label: placement.label ?? destination.ref,\n icon: placement.icon,\n order: placement.order,\n target: destination.target,\n runtimeAvailability: destination.runtimeAvailability,\n requiredFeatures: destination.requiredFeatures,\n requiredRoles: destination.requiredRoles,\n entitlementFeatureId: destination.entitlementFeatureId,\n });\n }\n\n return {\n categories: authored.categories,\n sections,\n defaultSectionRef: authored.defaultSectionRef,\n };\n}\n\n/**\n * Every destination ref an authored config places that the catalog does not\n * ship. Reported by `verifySettingsHubContent`; see the note on\n * {@link resolveSettingsHubConfig} for why resolution drops rather than throws.\n */\nexport function findUnknownDestinationRefs(authored: SettingsHubConfig | undefined): string[] {\n if (authored === undefined) {\n return [];\n }\n return authored.placements\n .map(placement => placement.destinationRef)\n .filter(ref => !DESTINATIONS_BY_REF.has(ref));\n}\n\nexport function useSettingsHubConfig(): ResolvedSettingsHubConfig {\n const { settingsHub } = useUI();\n // Memoised on the authored config, NOT recomputed per render. Resolution\n // builds a fresh object graph every call, so an unmemoised return made the\n // hub's config a new identity on every render — and the hub keys a\n // `useEffect` on that identity to follow URL-driven section changes. The\n // effect therefore fired after every render and re-asserted the default\n // section, which silently undid the user's own rail click.\n return useMemo(() => resolveSettingsHubConfig(settingsHub), [settingsHub]);\n}\n"]}
@@ -200,10 +200,10 @@ export declare const FrontendEventErrorOccuredSchema: z.ZodObject<{
200
200
  }, z.core.$strip>;
201
201
  export declare const FrontendEventAuthLogoutRequiredSchema: z.ZodObject<{
202
202
  reason: z.ZodEnum<{
203
- manual: "manual";
204
203
  authentication_error: "authentication_error";
205
204
  session_expired: "session_expired";
206
205
  token_invalid: "token_invalid";
206
+ manual: "manual";
207
207
  }>;
208
208
  errorType: z.ZodOptional<z.ZodString>;
209
209
  timestamp: z.ZodCoercedDate<unknown>;
@@ -903,8 +903,8 @@ export declare const FrontendEvent_MilestoneAchievedSchema: z.ZodObject<{
903
903
  featureRef: z.ZodOptional<z.ZodString>;
904
904
  guidanceFlowRef: z.ZodOptional<z.ZodString>;
905
905
  celebrationLevel: z.ZodOptional<z.ZodEnum<{
906
- medium: "medium";
907
906
  low: "low";
907
+ medium: "medium";
908
908
  high: "high";
909
909
  }>>;
910
910
  }, z.core.$strip>;
@@ -1315,10 +1315,10 @@ export declare const FrontendEventSchemas: {
1315
1315
  }, z.core.$strip>;
1316
1316
  readonly auth_logout_required: z.ZodObject<{
1317
1317
  reason: z.ZodEnum<{
1318
- manual: "manual";
1319
1318
  authentication_error: "authentication_error";
1320
1319
  session_expired: "session_expired";
1321
1320
  token_invalid: "token_invalid";
1321
+ manual: "manual";
1322
1322
  }>;
1323
1323
  errorType: z.ZodOptional<z.ZodString>;
1324
1324
  timestamp: z.ZodCoercedDate<unknown>;
@@ -1972,8 +1972,8 @@ export declare const FrontendEventSchemas: {
1972
1972
  featureRef: z.ZodOptional<z.ZodString>;
1973
1973
  guidanceFlowRef: z.ZodOptional<z.ZodString>;
1974
1974
  celebrationLevel: z.ZodOptional<z.ZodEnum<{
1975
- medium: "medium";
1976
1975
  low: "low";
1976
+ medium: "medium";
1977
1977
  high: "high";
1978
1978
  }>>;
1979
1979
  }, z.core.$strip>;
@@ -29,11 +29,22 @@
29
29
  * translation becomes invisible.
30
30
  */
31
31
  import React from 'react';
32
- import type { ProviderFilePickerConstraints, ProviderFileSelection } from '@wildo-ai/external-connectors-public/app';
32
+ import type { FileStorageAccepted } from '@wildo-ai/saas-models/public-runtime';
33
+ import type { ProviderFilePickerConstraints, ProviderFileSelection } from '@wildo-ai/saas-models/public-runtime';
33
34
  import { type ProviderComponentChoice } from '../../core/components-registry/useProviderComponent.frontend.hooks';
34
35
  import { type ProviderFileSelectionRejection } from './provider-file-selection.frontend.utils';
35
36
  export interface ProviderFilePickerHostProps {
36
37
  readonly constraints: ProviderFilePickerConstraints;
38
+ /**
39
+ * The field's `z_file({ storageAccepted })` (#394 P5). A provider whose picker
40
+ * fronts a storage (a `REMOTE_REFERENCE` picker — the file stays at the
41
+ * vendor) is offered only when this names that storage, because the link it
42
+ * produces lands in that storage and the backend refuses it otherwise. A
43
+ * provider declaring no storage delivers bytes into the field's own storage
44
+ * and is offered regardless. Undefined — the field declared nothing — accepts
45
+ * no vendor storage: the default storage is the framework's.
46
+ */
47
+ readonly acceptedStorages?: ReadonlyArray<FileStorageAccepted>;
37
48
  /**
38
49
  * Called with selections that have already been checked against the chosen
39
50
  * provider's declaration, so every `kind` here is the one that provider said
@@ -1 +1 @@
1
- {"version":3,"file":"ProviderFilePickerHost.d.ts","sourceRoot":"","sources":["../../../../src/core/external-providers/ProviderFilePickerHost.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAGzE,OAAO,KAAK,EACV,6BAA6B,EAE7B,qBAAqB,EACtB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,kFAAkF,CAAC;AAC1F,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,0CAA0C,CAAC;AAIlD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,6BAA6B,CAAC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,qBAAqB,EAAE,GAAG,IAAI,CAAC;IAClF,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB;;;;OAIG;IACH,iBAAiB,CAAC,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,8BAA8B,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7J;;;;OAIG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;QACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KACnC,GAAG,KAAK,CAAC,SAAS,CAAC;CACrB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAwFpG"}
1
+ {"version":3,"file":"ProviderFilePickerHost.d.ts","sourceRoot":"","sources":["../../../../src/core/external-providers/ProviderFilePickerHost.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAGzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,KAAK,EACV,6BAA6B,EAE7B,qBAAqB,EACtB,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,kFAAkF,CAAC;AAC1F,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,0CAA0C,CAAC;AAIlD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,6BAA6B,CAAC;IACpD;;;;;;;;OAQG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,qBAAqB,EAAE,GAAG,IAAI,CAAC;IAClF,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB;;;;OAIG;IACH,iBAAiB,CAAC,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,8BAA8B,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7J;;;;OAIG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;QACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KACnC,GAAG,KAAK,CAAC,SAAS,CAAC;CACrB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAwGpG"}