
Give file selection a shared application default
File selection should feel consistent across an application. Wildo gives standard file fields and custom upload views a shared provider contract for accepted types, size and selection count.
A field can state its own requirements without changing every picker. The provider supplies browser defaults, while the resource schema and backend continue to own the upload rules.
Example — One default for attachments, a stricter avatar
The application offers images and PDFs up to 25 MB in its general picker. A profile’s avatar field can still require an image under 2 MB. The narrower field definition takes precedence without a second custom picker.
For engineers
Declare a frontend provider module
Wonder Todos defines its picker as a FrontendAppProviderModule. The capability and protocol identify its role; publicConfig contains browser-visible defaults, not credentials. Imports and the identity comment are omitted.
export const ApplicationFilePickerFrontendAppProvider: FrontendAppProviderModule = {
metadata: defineProviderMetadata({
ref: 'wonderTodosFilePicker',
packageName: '@wonder-todos/main-app',
tier: ProviderTier.CATALOGUE,
origin: { kind: ProviderOriginKind.APPLICATION },
}),
providerCapabilities: [BUILTIN_PROVIDER_CAPABILITY.FRONTEND_FILE_PICKER],
protocols: [BUILTIN_PROVIDER_PROTOCOL.FRONTEND_SDK],
publicConfig: {
acceptedMimeTypes: ['image/*', 'application/pdf'],
maxFileSizeMb: 25,
maxSelectionCount: 10,
uploadNamespace: 'task-attachments',
},
};
Make the provider reachable in the application
Export the module through the frontend provider entrypoint, include its contribution in frontend/src/provider-contributions.ts, and declare the same reference under the frontend service’s provider scope in wildo.saas.config.ts. Derive contribution fields from the module so identity and defaults stay aligned.
Framework file fields resolve FRONTEND_FILE_PICKER with FRONTEND_SDK. A custom view should use that registry contract too, rather than maintaining a second table of size and MIME limits.
Let the field override the default
The resolver below shows the precedence directly. Provider megabytes are converted to bytes once; the provider’s selection limit is used only for a multi-file field. Earlier lookup and validation code is omitted.
return {
allowedMimeTypes: fileMetadata.allowedMimeTypes ?? providerConstraints.acceptedMimeTypes,
maxSize: fileMetadata.maxSize ?? (
providerMaxSizeMb === undefined ? undefined : providerMaxSizeMb * 1024 * 1024
),
maxFiles: fileMetadata.multiple
? (fileMetadata.maxFiles ?? providerConstraints.maxSelectionCount)
: fileMetadata.maxFiles,
};
Keep remote selection explicit
A connected provider picker may deliver local File objects or remote references, according to its declared delivery contract. The host checks that declaration before forwarding the selection. A remote reference still needs a matching backend storage provider accepted by the field; a browser picker alone does not make a cloud drive a working storage destination.
Connect the module to the running frontend
Start with wildo compose add-file-picker-provider in the application. Its module is only the first piece: export it through the frontend-provider entrypoint, contribute it to the companion, then select that provider in the frontend service configuration.
Wonder Todos derives the contribution from the module so its advertised capabilities and runtime configuration cannot drift into separate copies:
function buildFilePickerContribution(): ProviderCompanionContribution {
return {
ref: ApplicationFilePickerFrontendAppProvider.metadata.ref,
runtimeImportPath: '@wonder-todos/main-app/frontend-providers',
runtimeTargets: [{ kind: 'frontendService', serviceType: AppFrontendType.SAAS_APP }],
engineCapabilities: [],
providerCapabilities: [...ApplicationFilePickerFrontendAppProvider.providerCapabilities],
protocols: [...ApplicationFilePickerFrontendAppProvider.protocols],
secretsContractShape: [],
frontendEntry: {
metadata: ApplicationFilePickerFrontendAppProvider.metadata,
providerCapabilities: [...ApplicationFilePickerFrontendAppProvider.providerCapabilities],
protocols: [...ApplicationFilePickerFrontendAppProvider.protocols],
publicConfig: ApplicationFilePickerFrontendAppProvider.publicConfig,
},
sourceModuleId: 'tasks-manager',
};
}
This function belongs in frontend/src/provider-contributions.ts, alongside the application’s contribution list. ProviderCompanionContribution and AppFrontendType come from @wildo-ai/saas-models; the provider is imported from the local provider entrypoint. Include the returned contribution in that list.
| Surface | What must agree |
|---|---|
| Frontend provider entrypoint | The package’s ./frontend-providers export reaches the module |
| Companion contribution | runtimeImportPath reaches that export; sourceModuleId identifies the owning module |
| Service selection | providers.scopes.frontendServices.app.providers.<ref> selects the same ref, capability and protocol |
| Field declaration | Explicit MIME, size and selection limits take precedence over provider defaults |
Configuration sync checks contribution reachability. After sync, verify the provider is selected for the actual frontend service: exporting a module alone does not activate it. Keep credentials out of publicConfig; these values are delivered to the browser.