Skip to content

registerProvider — provider registry ​

Imported from the facade: import { registerProvider } from "@/framework/facade.js".

Registers an implementation under a key so the framework — or your own code — can ask for it later. This is how an application replaces a framework default (auth today, payments or SMS drivers tomorrow) without the framework importing application code. See Providers.

Functions ​

FunctionSignatureDescription
registerProvider(key, impl) => implRegisters an implementation under a key and returns it
registerAuthProvider(provider) => providerTyped shorthand for the auth key
registerNotificationProvider(provider) => providerTyped shorthand for the notification key
hasProvider(key) => booleanReports whether an implementation is registered
clearProvider(key) => voidRemoves an implementation — mainly useful in tests
clearAuthProvider() => voidRemoves the auth provider — mainly useful in tests
clearNotificationProvider() => voidRemoves the notification provider — mainly useful in tests
listProviders() => string[]Lists every registered key

Use cases ​

Replace the built-in auth ​

ts
// src/providers/auth.ts
import { registerAuthProvider } from "@/framework/facade.js";
import type { AuthProvider } from "@/framework/facade.js";

const authProvider: AuthProvider = {
  async getUserById(id) {
    return { id, email: "user@example.com", tenantId: 42, plan: "pro" };
  },
  async findRefreshToken(jti) {
    return { id: 1, jti, revoked: false, expiresAt: new Date() };
  },
  async getUserContact(userId) {
    return { email: "user@example.com", name: "User" };
  }
};

registerAuthProvider(authProvider);

Files in src/providers/ are imported automatically at boot — no import of this module is needed anywhere else.

Replace notification storage ​

ts
// src/providers/notification.ts
import { registerNotificationProvider } from "@/framework/facade.js";
import type { NotificationProvider } from "@/framework/facade.js";

const notificationProvider: NotificationProvider = {
  async create(target, input) {
    // persist and return a NotificationRecord
  },
  async list(target, options) {},
  async unreadCount(target) {},
  async markRead(target, id) {},
  async markAllRead(target) {},
  async remove(target, id) {}
};

registerNotificationProvider(notificationProvider);

A registered notification provider always wins over the generated src/modules/notification store. Mail and realtime remain in the runtime, so notify({ broadcast, mail }) keeps working.

Register your own contract ​

ts
// src/providers/payment.ts
import { registerProvider } from "@/framework/facade.js";

export const payment = registerProvider("payment", {
  async charge(order) {
    return { id: "ch_123", status: "paid" };
  }
});

Register from a module ​

ts
// src/modules/billing/providers.ts
import { registerProvider } from "@/framework/facade.js";

registerProvider("billing", {
  async invoice(order) {
    return { id: "inv_1" };
  }
});

Module provider files are imported at boot too, so a module can ship its own implementation.

AuthProvider contract ​

MethodRequiredPurpose
getUserById(id)YesLoads a user. Extra fields are passed through to the auth context.
findRefreshToken(jti)YesLoads a stored refresh token by its JWT id.
revokeRefreshToken(id)NoRevokes a refresh token. deleteRefreshToken(id) also works.
getAuthContext(user, payload)NoShapes the object handlers receive as auth.
getUserContact(userId)NoFinds the email/name of a user — used by notify().

Every id in the contract (AuthProviderUser.id, AuthUserContext.id, refresh-token ids, and the getUserById / getUserContact arguments) is number | string, so a UUID-backed auth provider is fully supported.

NotificationProvider contract ​

MethodRequiredPurpose
create(target, input)YesStore one notification and return it.
list(target, options)YesReturn { data, total, unread, page, perPage }.
unreadCount(target)YesReturn the unread count.
markRead(target, id)YesMark one read; return whether it existed.
markAllRead(target)YesMark all read; return how many changed.
remove(target, id)YesDelete one; return whether it existed.
deleteForTarget(target)NoDelete everything owned by a target.

Notes ​

  • The facade is the framework's public API. Never import from @/framework/... internals.
  • When no auth provider is registered, the framework falls back to the built-in one from src/modules/auth. When that module was deleted as well, the auth middleware logs a warning and lets the request through instead of crashing.
  • Registration happens before routes are mounted, so a provider is available to route guards, middleware and seeders.

Released under the MIT License.