@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
@@ -1 +1 @@
1
- {"version":3,"file":"form-field-file-provider-constraints.frontend.utils.js","sourceRoot":"","sources":["../../../../../src/components/form/fields/form-field-file-provider-constraints.frontend.utils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,oCAAoC,GACrC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAiClC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,uCAAuC,CAAC,KAGvD;IACC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;YAC/C,OAAO,EAAE,YAAY,CAAC,OAAO;YAC7B,QAAQ,EAAE,YAAY,CAAC,QAAQ;SAChC,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GACZ,KAAK,CAAC,wBAAwB,EAAE,mCAAmC,EAAE,CACnE,2BAA2B,CAAC,oBAAoB,EAChD,yBAAyB,CAAC,YAAY,CACvC;QACD,KAAK,CAAC,wBAAwB;YAC5B,EAAE,wBAAwB,EAAE,CAAC,2BAA2B,CAAC,oBAAoB,CAAC;aAC7E,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAAyB,CAAC,YAAY,CAAC,CAAC,CAAC;IAEvF,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,uEAAuE;IACvE,EAAE;IACF,8EAA8E;IAC9E,wEAAwE;IACxE,6EAA6E;IAC7E,oCAAoC;IACpC,MAAM,cAAc,GAAG,oCAAoC,CAAC,SAAS,CACnE,QAAQ,EAAE,YAAY,IAAI,EAAE,CAC7B,CAAC;IACF,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,aAAa,CAAC;IAE5D,OAAO;QACL,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,IAAI,mBAAmB,CAAC,iBAAiB;QACxF,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,CAC/B,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAC9E;QACD,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC7B,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,IAAI,mBAAmB,CAAC,iBAAiB,CAAC;YAClE,CAAC,CAAC,YAAY,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC;AACD,iFAAiF","sourcesContent":["import type { z } from 'zod';\nimport {\n BUILTIN_PROVIDER_CAPABILITY,\n BUILTIN_PROVIDER_PROTOCOL,\n FrontendFilePickerPublicConfigSchema,\n} from '@wildo-ai/saas-models/public-runtime';\nimport {\n getFileMetadata,\n isTemplatableFileField,\n} from '@wildo-ai/zod-decorators';\nimport type { ProviderFilePickerConstraints } from '@wildo-ai/external-connectors-public/app';\n\ninterface FrontendFilePickerProviderModuleLike {\n protocols: ReadonlyArray<string>;\n publicConfig?: Readonly<Record<string, unknown>>;\n}\n\ninterface FrontendProviderRegistryLike {\n findByProviderCapabilityAndProtocol?: (\n providerCapability: string,\n providerProtocol: string,\n ) => FrontendFilePickerProviderModuleLike | undefined;\n listByProviderCapability?: (\n providerCapability: string,\n ) => ReadonlyArray<FrontendFilePickerProviderModuleLike>;\n}\n\n/** @wildo_source:part:start saas.frontend.form-fields.file-provider-constraints facet:layer:frontend facet:family:provider */\n/**\n * Constraints the framework's file form fields apply to the picker UI.\n * `maxSize` is BYTES (a provider's `maxFileSizeMb` is converted here).\n *\n * An ALIAS of the contract a provider's picker component receives, not a\n * separate interface, so the two cannot drift. They were separate for one\n * session and the size field was spelled differently on each side — both\n * optional, both bytes — which TypeScript accepts, because the weak-type check\n * is satisfied by the two names that DO match. Wiring the resolver into a picker\n * would have compiled and dropped the size cap, and a picker that accepts a file\n * the field rejects tells the user after they have chosen it.\n */\nexport type ResolvedFormFieldFileProviderConstraints = ProviderFilePickerConstraints;\n\n/**\n * Resolve the effective file constraints for one file field.\n *\n * Precedence — the field's own Zod file metadata ALWAYS wins; the registered\n * `FRONTEND_FILE_PICKER` + `FRONTEND_SDK` provider's `publicConfig` only\n * fills the gaps the schema left open:\n *\n * The provider's half is parsed through `FrontendFilePickerPublicConfigSchema`,\n * the capability's own named shape — not read key by key — so a misspelled key\n * contributes nothing rather than silently removing a constraint.\n *\n * - `allowedMimeTypes` ?? provider `acceptedMimeTypes`\n * - `maxSize` ?? provider `maxFileSizeMb` × 1024² (Mb → bytes)\n * - `maxFiles` ?? provider `maxSelectionCount` — and ONLY for `multiple`\n * fields; a single-file field never inherits a selection count.\n *\n * Templatable file fields short-circuit to schema metadata alone (their\n * files are framework-materialized, not user-picked). The provider lookup is\n * feature-detected, so an app with no file-picker provider simply falls back\n * to schema-only constraints — nothing throws.\n */\nexport function resolveFormFieldFileProviderConstraints(input: {\n schema: z.ZodTypeAny;\n frontendProviderRegistry?: FrontendProviderRegistryLike;\n}): ResolvedFormFieldFileProviderConstraints {\n const fileMetadata = getFileMetadata(input.schema);\n if (!fileMetadata) {\n return {};\n }\n\n if (isTemplatableFileField(input.schema)) {\n return {\n allowedMimeTypes: fileMetadata.allowedMimeTypes,\n maxSize: fileMetadata.maxSize,\n maxFiles: fileMetadata.maxFiles,\n };\n }\n\n const provider =\n input.frontendProviderRegistry?.findByProviderCapabilityAndProtocol?.(\n BUILTIN_PROVIDER_CAPABILITY.FRONTEND_FILE_PICKER,\n BUILTIN_PROVIDER_PROTOCOL.FRONTEND_SDK,\n ) ??\n input.frontendProviderRegistry\n ?.listByProviderCapability?.(BUILTIN_PROVIDER_CAPABILITY.FRONTEND_FILE_PICKER)\n .find((entry) => entry.protocols.includes(BUILTIN_PROVIDER_PROTOCOL.FRONTEND_SDK));\n\n // Parsed through the CAPABILITY's own named schema rather than read key by\n // key. The three hand readers this replaces agreed with the providers that\n // happened to be written beside them and with nothing else: a renamed or\n // mistyped key yielded `undefined`, the constraint silently disappeared, and\n // the picker accepted more than it should have with no error anywhere.\n //\n // A provider carrying its own keys is unaffected — the schema is loose, so it\n // reads the framework's fields and leaves everything else alone — and a\n // provider that got one of them WRONG now contributes nothing for that field\n // instead of contributing nonsense.\n const providerConfig = FrontendFilePickerPublicConfigSchema.safeParse(\n provider?.publicConfig ?? {},\n );\n const providerConstraints = providerConfig.success ? providerConfig.data : {};\n const providerMaxSizeMb = providerConstraints.maxFileSizeMb;\n\n return {\n allowedMimeTypes: fileMetadata.allowedMimeTypes ?? providerConstraints.acceptedMimeTypes,\n maxSize: fileMetadata.maxSize ?? (\n providerMaxSizeMb === undefined ? undefined : providerMaxSizeMb * 1024 * 1024\n ),\n maxFiles: fileMetadata.multiple\n ? (fileMetadata.maxFiles ?? providerConstraints.maxSelectionCount)\n : fileMetadata.maxFiles,\n };\n}\n/** @wildo_source:part:end saas.frontend.form-fields.file-provider-constraints */\n\n"]}
1
+ {"version":3,"file":"form-field-file-provider-constraints.frontend.utils.js","sourceRoot":"","sources":["../../../../../src/components/form/fields/form-field-file-provider-constraints.frontend.utils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,oCAAoC,GACrC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAiClC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,uCAAuC,CAAC,KAGvD;IACC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;YAC/C,OAAO,EAAE,YAAY,CAAC,OAAO;YAC7B,QAAQ,EAAE,YAAY,CAAC,QAAQ;SAChC,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GACZ,KAAK,CAAC,wBAAwB,EAAE,mCAAmC,EAAE,CACnE,2BAA2B,CAAC,oBAAoB,EAChD,yBAAyB,CAAC,YAAY,CACvC;QACD,KAAK,CAAC,wBAAwB;YAC5B,EAAE,wBAAwB,EAAE,CAAC,2BAA2B,CAAC,oBAAoB,CAAC;aAC7E,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAAyB,CAAC,YAAY,CAAC,CAAC,CAAC;IAEvF,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,uEAAuE;IACvE,EAAE;IACF,8EAA8E;IAC9E,wEAAwE;IACxE,6EAA6E;IAC7E,oCAAoC;IACpC,MAAM,cAAc,GAAG,oCAAoC,CAAC,SAAS,CACnE,QAAQ,EAAE,YAAY,IAAI,EAAE,CAC7B,CAAC;IACF,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,aAAa,CAAC;IAE5D,OAAO;QACL,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,IAAI,mBAAmB,CAAC,iBAAiB;QACxF,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,CAC/B,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAC9E;QACD,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC7B,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,IAAI,mBAAmB,CAAC,iBAAiB,CAAC;YAClE,CAAC,CAAC,YAAY,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC;AACD,iFAAiF","sourcesContent":["import type { z } from 'zod';\nimport {\n BUILTIN_PROVIDER_CAPABILITY,\n BUILTIN_PROVIDER_PROTOCOL,\n FrontendFilePickerPublicConfigSchema,\n} from '@wildo-ai/saas-models/public-runtime';\nimport {\n getFileMetadata,\n isTemplatableFileField,\n} from '@wildo-ai/zod-decorators';\nimport type { ProviderFilePickerConstraints } from '@wildo-ai/saas-models/public-runtime';\n\ninterface FrontendFilePickerProviderModuleLike {\n protocols: ReadonlyArray<string>;\n publicConfig?: Readonly<Record<string, unknown>>;\n}\n\ninterface FrontendProviderRegistryLike {\n findByProviderCapabilityAndProtocol?: (\n providerCapability: string,\n providerProtocol: string,\n ) => FrontendFilePickerProviderModuleLike | undefined;\n listByProviderCapability?: (\n providerCapability: string,\n ) => ReadonlyArray<FrontendFilePickerProviderModuleLike>;\n}\n\n/** @wildo_source:part:start saas.frontend.form-fields.file-provider-constraints facet:layer:frontend facet:family:provider */\n/**\n * Constraints the framework's file form fields apply to the picker UI.\n * `maxSize` is BYTES (a provider's `maxFileSizeMb` is converted here).\n *\n * An ALIAS of the contract a provider's picker component receives, not a\n * separate interface, so the two cannot drift. They were separate for one\n * session and the size field was spelled differently on each side — both\n * optional, both bytes — which TypeScript accepts, because the weak-type check\n * is satisfied by the two names that DO match. Wiring the resolver into a picker\n * would have compiled and dropped the size cap, and a picker that accepts a file\n * the field rejects tells the user after they have chosen it.\n */\nexport type ResolvedFormFieldFileProviderConstraints = ProviderFilePickerConstraints;\n\n/**\n * Resolve the effective file constraints for one file field.\n *\n * Precedence — the field's own Zod file metadata ALWAYS wins; the registered\n * `FRONTEND_FILE_PICKER` + `FRONTEND_SDK` provider's `publicConfig` only\n * fills the gaps the schema left open:\n *\n * The provider's half is parsed through `FrontendFilePickerPublicConfigSchema`,\n * the capability's own named shape — not read key by key — so a misspelled key\n * contributes nothing rather than silently removing a constraint.\n *\n * - `allowedMimeTypes` ?? provider `acceptedMimeTypes`\n * - `maxSize` ?? provider `maxFileSizeMb` × 1024² (Mb → bytes)\n * - `maxFiles` ?? provider `maxSelectionCount` — and ONLY for `multiple`\n * fields; a single-file field never inherits a selection count.\n *\n * Templatable file fields short-circuit to schema metadata alone (their\n * files are framework-materialized, not user-picked). The provider lookup is\n * feature-detected, so an app with no file-picker provider simply falls back\n * to schema-only constraints — nothing throws.\n */\nexport function resolveFormFieldFileProviderConstraints(input: {\n schema: z.ZodTypeAny;\n frontendProviderRegistry?: FrontendProviderRegistryLike;\n}): ResolvedFormFieldFileProviderConstraints {\n const fileMetadata = getFileMetadata(input.schema);\n if (!fileMetadata) {\n return {};\n }\n\n if (isTemplatableFileField(input.schema)) {\n return {\n allowedMimeTypes: fileMetadata.allowedMimeTypes,\n maxSize: fileMetadata.maxSize,\n maxFiles: fileMetadata.maxFiles,\n };\n }\n\n const provider =\n input.frontendProviderRegistry?.findByProviderCapabilityAndProtocol?.(\n BUILTIN_PROVIDER_CAPABILITY.FRONTEND_FILE_PICKER,\n BUILTIN_PROVIDER_PROTOCOL.FRONTEND_SDK,\n ) ??\n input.frontendProviderRegistry\n ?.listByProviderCapability?.(BUILTIN_PROVIDER_CAPABILITY.FRONTEND_FILE_PICKER)\n .find((entry) => entry.protocols.includes(BUILTIN_PROVIDER_PROTOCOL.FRONTEND_SDK));\n\n // Parsed through the CAPABILITY's own named schema rather than read key by\n // key. The three hand readers this replaces agreed with the providers that\n // happened to be written beside them and with nothing else: a renamed or\n // mistyped key yielded `undefined`, the constraint silently disappeared, and\n // the picker accepted more than it should have with no error anywhere.\n //\n // A provider carrying its own keys is unaffected — the schema is loose, so it\n // reads the framework's fields and leaves everything else alone — and a\n // provider that got one of them WRONG now contributes nothing for that field\n // instead of contributing nonsense.\n const providerConfig = FrontendFilePickerPublicConfigSchema.safeParse(\n provider?.publicConfig ?? {},\n );\n const providerConstraints = providerConfig.success ? providerConfig.data : {};\n const providerMaxSizeMb = providerConstraints.maxFileSizeMb;\n\n return {\n allowedMimeTypes: fileMetadata.allowedMimeTypes ?? providerConstraints.acceptedMimeTypes,\n maxSize: fileMetadata.maxSize ?? (\n providerMaxSizeMb === undefined ? undefined : providerMaxSizeMb * 1024 * 1024\n ),\n maxFiles: fileMetadata.multiple\n ? (fileMetadata.maxFiles ?? providerConstraints.maxSelectionCount)\n : fileMetadata.maxFiles,\n };\n}\n/** @wildo_source:part:end saas.frontend.form-fields.file-provider-constraints */\n\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"form-field-file.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/fields/form-field-file.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAGlD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kFAAkF,CAAA;AAEvH,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,sDAAsD,CAAA;AAUhH,OAAO,EAGL,SAAS,EAIT,kBAAkB,EAOnB,MAAM,0BAA0B,CAAA;AAUjC,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;IAC7G,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,EAAE,kBAAkB,CAAA;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAA;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,kBAAkB,CAAA;CACnC;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,GAAG;IAClF,cAAc,CAAC,EAAE,kBAAkB,CAAA;CACpC,GAAG,oBAAoB,CAAA;AAExB,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAA;AA6F7C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,iGAw1CvC,CAAA;AAGF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa;qBAl9CP,kBAAkB;+DA2/CnC,CAAA"}
1
+ {"version":3,"file":"form-field-file.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/fields/form-field-file.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAGlD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kFAAkF,CAAA;AAEvH,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,sDAAsD,CAAA;AAUhH,OAAO,EAGL,SAAS,EAIT,kBAAkB,EAOnB,MAAM,0BAA0B,CAAA;AAUjC,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;IAC7G,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,EAAE,kBAAkB,CAAA;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAA;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,kBAAkB,CAAA;CACnC;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,GAAG;IAClF,cAAc,CAAC,EAAE,kBAAkB,CAAA;CACpC,GAAG,oBAAoB,CAAA;AAExB,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAA;AA6F7C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,iGA04CvC,CAAA;AAGF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa;qBApgDP,kBAAkB;+DAqjDnC,CAAA"}
@@ -581,19 +581,61 @@ export const FormFieldFile_Preset_Default = React.forwardRef(({ schema, name, va
581
581
  * crop step and the upload pipeline are the ones already written here rather
582
582
  * than a second, provider-only path that would drift from them.
583
583
  *
584
- * The third, REMOTE_REFERENCE, deliberately does NOT. It is an opaque id only
585
- * the application backend can resolve, and the door it needs — an executor
586
- * that fetches on the user's behalf with the connected account's credential —
587
- * does not exist yet. So the field REFUSES it with a message instead of
588
- * dropping it silently: a user who picks a file and sees nothing happen has
589
- * no way to learn that the provider and the application disagree about who
590
- * fetches. A provider declares its delivery kind and the host has already
591
- * refused anything that contradicts that declaration, so this branch is a
592
- * capability gap, never a malformed selection.
584
+ * The third, REMOTE_REFERENCE, carries no bytes: the file STAYS at the vendor
585
+ * and only the application backend can resolve the id (#394 P5). It goes to
586
+ * the SAME endpoint an upload does, as a JSON body, and the backend verifies
587
+ * the reference at the vendor as this person, holds it to the field's
588
+ * constraints, and creates the row in the vendor's storage. What comes back
589
+ * is a fileId, exactly as an upload's, so the value is committed by the same
590
+ * code. The host has already refused any selection that contradicts the
591
+ * provider's declaration, and the chooser offered this provider only because
592
+ * the field accepts its storage — so a refusal here is the vendor's or the
593
+ * backend's, and is shown as one message.
593
594
  */
594
- const handleProviderSelections = React.useCallback(async (_providerRef, selections) => {
595
+ const linkRemoteSelections = React.useCallback(async (providerRef, selections) => {
596
+ const toLink = isMultiple ? selections : selections.slice(0, 1);
597
+ const uploadUrl = isMultiple ? endpoints.upload : resolveSingleFileUploadUrl(endpoints, currentFileId);
598
+ if (!uploadUrl) {
599
+ setInternalError(t('File uploads are unavailable for this field') ?? 'File uploads are unavailable for this field');
600
+ return;
601
+ }
602
+ setInternalError(undefined);
603
+ const results = await Promise.allSettled(toLink.map(async (selection) => {
604
+ const result = await httpOperations.linkRemoteReference(uploadUrl, {
605
+ remoteReference: {
606
+ providerRef,
607
+ externalId: selection.externalId,
608
+ ...(selection.displayName !== undefined ? { displayName: selection.displayName } : {}),
609
+ ...(selection.mimeType !== undefined ? { mimeType: selection.mimeType } : {}),
610
+ ...(selection.sizeBytes !== undefined ? { sizeBytes: selection.sizeBytes } : {}),
611
+ },
612
+ });
613
+ if (result.metadata) {
614
+ setFileMetadataMap(prev => {
615
+ const next = new Map(prev);
616
+ next.set(result.fileId, result.metadata);
617
+ return next;
618
+ });
619
+ }
620
+ return result.fileId;
621
+ }));
622
+ const linkedFileIds = results.flatMap((result) => (result.status === 'fulfilled' ? [result.value] : []));
623
+ if (linkedFileIds.length > 0) {
624
+ const newValue = isMultiple
625
+ ? { fileIds: [...currentFileIdsRef.current, ...linkedFileIds], updatedAt: new Date() }
626
+ : { fileId: linkedFileIds[0], updatedAt: new Date() };
627
+ if (!isControlled) {
628
+ setInternalValue(newValue);
629
+ }
630
+ onChange?.(newValue);
631
+ }
632
+ if (linkedFileIds.length < toLink.length) {
633
+ setInternalError(tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD_FILE, 'provider_link_failed'));
634
+ }
635
+ }, [currentFileId, endpoints, httpOperations, isControlled, isMultiple, onChange, t, tComponent]);
636
+ const handleProviderSelections = React.useCallback(async (providerRef, selections) => {
595
637
  const files = [];
596
- let sawRemoteReference = false;
638
+ const remoteReferences = [];
597
639
  let sawFetchFailure = false;
598
640
  for (const selection of selections) {
599
641
  if (selection.kind === ProviderFrontendSelectionDelivery.BROWSER_READABLE_FILE) {
@@ -619,11 +661,10 @@ export const FormFieldFile_Preset_Default = React.forwardRef(({ schema, name, va
619
661
  }
620
662
  continue;
621
663
  }
622
- sawRemoteReference = true;
664
+ remoteReferences.push(selection);
623
665
  }
624
- if (sawRemoteReference) {
625
- setInternalError(tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD_FILE, 'provider_selection_not_supported'));
626
- return;
666
+ if (remoteReferences.length > 0) {
667
+ await linkRemoteSelections(providerRef, remoteReferences);
627
668
  }
628
669
  if (sawFetchFailure && files.length === 0) {
629
670
  setInternalError(tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD_FILE, 'provider_fetch_failed'));
@@ -633,7 +674,7 @@ export const FormFieldFile_Preset_Default = React.forwardRef(({ schema, name, va
633
674
  return;
634
675
  setInternalError(sawFetchFailure ? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD_FILE, 'provider_fetch_failed') : undefined);
635
676
  handleFiles(files);
636
- }, [handleFiles, tComponent]);
677
+ }, [handleFiles, linkRemoteSelections, tComponent]);
637
678
  /*
638
679
  * A picker that failed and a picker that contradicted its own declaration
639
680
  * reach here as one message, because they are one thing to the person looking
@@ -946,7 +987,7 @@ export const FormFieldFile_Preset_Default = React.forwardRef(({ schema, name, va
946
987
  * name is an i18n KEY: the host cannot resolve it without depending on the
947
988
  * i18n service, and this field already has one.
948
989
  */
949
- const renderProviderPickers = () => (_jsx(ProviderFilePickerHost, { constraints: providerConstraints, onSelect: handleProviderSelections, onProviderFailure: handleProviderFailure, renderChooser: ({ choices, chosen, choose }) => (_jsx("div", { role: "group", className: "flex flex-wrap gap-item-xs mt-element", children: choices.map((choice) => (_jsx(Button, { type: "button", size: ButtonSize.SM, variant: choice.providerRef === chosen ? ButtonVariants_Variant.DEFAULT : ButtonVariants_Variant.OUTLINE, "aria-pressed": choice.providerRef === chosen, onClick: () => choose(choice.providerRef), children: t(choice.displayNameLabelKey) ?? choice.displayName ?? choice.providerRef }, choice.providerRef))) })) }));
990
+ const renderProviderPickers = () => (_jsx(ProviderFilePickerHost, { constraints: providerConstraints, acceptedStorages: fileSchemaMetadata?.storageAccepted, onSelect: handleProviderSelections, onProviderFailure: handleProviderFailure, renderChooser: ({ choices, chosen, choose }) => (_jsx("div", { role: "group", className: "flex flex-wrap gap-item-xs mt-element", children: choices.map((choice) => (_jsx(Button, { type: "button", size: ButtonSize.SM, variant: choice.providerRef === chosen ? ButtonVariants_Variant.DEFAULT : ButtonVariants_Variant.OUTLINE, "aria-pressed": choice.providerRef === chosen, onClick: () => choose(choice.providerRef), children: t(choice.displayNameLabelKey) ?? choice.displayName ?? choice.providerRef }, choice.providerRef))) })) }));
950
991
  if (!isReady)
951
992
  return null;
952
993
  return (_jsxs("div", { ref: ref, className: className, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: isMultiple, onChange: handleFileChange, className: "hidden", disabled: isUploadInteractionDisabled }), isMultiple ? (
@@ -992,6 +1033,14 @@ export const FormFieldFile = forwardRef(({ preset = CorePresetNames.DEFAULT, htt
992
1033
  }
993
1034
  throw new Error('upload_failed');
994
1035
  },
1036
+ linkRemoteReference: async (url, body) => {
1037
+ // Same route, same response shape as an upload — see `FileHttpOperations`.
1038
+ const response = await httpClient.post(url, body);
1039
+ if (response?.file?.fileId) {
1040
+ return { fileId: response.file.fileId, metadata: response.file };
1041
+ }
1042
+ throw new Error('link_failed');
1043
+ },
995
1044
  get: async (url) => {
996
1045
  return httpClient.get(url);
997
1046
  },