
Add your own integration through the same model
An application can supply a provider of its own instead of waiting for a vendor to join the engine. Its module declares what it offers and which runtime can use it.
Use the same discovery and configuration path as shipped providers, while keeping backend secrets and browser-safe behavior in their appropriate packages.
Example — Share upload defaults across the application
An application-owned file-picker provider declares accepted file types and size limits. Standard file fields can use those defaults while retaining stricter field-specific requirements.
For engineers
Wonder Todos’ application-owned frontend module is a real configuration provider:
Selected from file-picker.frontend-app.module.ts; surrounding declarations and imports are omitted.
export const ApplicationFilePickerFrontendAppProvider: FrontendAppProviderModule = {
// Identity (#328): an application-owned provider is APPLICATION-origin; a file picker binds no
// engine slot, so it is CATALOGUE (EXTENSION is for a substitute that fills an engine slot).
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',
},
};
APPLICATION records its origin. CATALOGUE is appropriate because this provider does not fill an engine service slot; an extension that does fill one has different tier semantics. The metadata does not supply a picker renderer: this example carries constraints consumed by standard file controls.
Make the module discoverable and reachable
The frontend contribution names a runtime import path, permitted frontend target and values-free entry derived from the module. Export the runtime module from the package entrypoint, declare its reference under the app frontend service’s providers, and run configuration synchronization. The served data and a browser startup module map must both be present for function-valued provider code to execute. Configuration synchronization supplies the data; it does not currently generate that frontend code map, which must be provided explicitly.
Backend-owned integrations instead expose a backend module and companion contribution through their package, declare their protocol runtime contract and secrets requirements, and install that package in each relevant runtime. The framework composition validates identity/tier/protocol coherence; those checks do not implement the vendor API for you.
A custom browser component that returns remote files also needs its declared delivery contract and the sanctioned host/checking path. Public configuration defaults are not server upload enforcement, and a custom direct mount owns the checks it bypasses. Keep the provider’s responsibility narrow and document which standard consumer actually reads each setting.