@molecule/api-bonds-default-express

Feature · bonds-default · API (Node) · v1.1.1 · Apache-2.0

Default API bond setup for Express apps — per-concern setup functions plus a consolidated setup, wiring the byte-identical bond configuration (config-env, database, jwt, middleware, password, secrets, device, two-factor, and more) shared across the molecule fleet.

npm install @molecule/api-bonds-default-express

npm · Source on GitHub

How it works

@molecule/api-bonds-default-express is a ready-made bonds-default feature for the API (Node) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.

// api/src/bonds/index.ts — wire defaults at startup, then validate:
import { validateBonds } from '@molecule/api-bond'
import {
  setupConfigEnv,
  setupDatabasePostgresql,
  setupEmailsMailgun,
  setupJwtJsonwebtoken,
  setupSecretsEnv,
} from '@molecule/api-bonds-default-express'

async function setupBonds(): Promise<void> {
  setupConfigEnv()
  setupSecretsEnv()
  setupDatabasePostgresql()
  setupJwtJsonwebtoken()
  setupEmailsMailgun()
  validateBonds()
}

Works with: @molecule/api-analytics, @molecule/api-bond, @molecule/api-cache-memory, @molecule/api-config, @molecule/api-config-env, @molecule/api-database, @molecule/api-database-postgresql, @molecule/api-emails, @molecule/api-emails-capture, @molecule/api-emails-mailgun, @molecule/api-entitlements, @molecule/api-geolocation-nominatim, @molecule/api-i18n, @molecule/api-jwt, @molecule/api-jwt-jsonwebtoken, @molecule/api-logger, @molecule/api-middleware-body-parser, @molecule/api-middleware-body-parser-express, @molecule/api-middleware-cookie-parser, @molecule/api-middleware-cookie-parser-express, @molecule/api-middleware-cors, @molecule/api-middleware-cors-express, @molecule/api-middleware-validation, @molecule/api-password, @molecule/api-password-bcrypt, @molecule/api-payments, @molecule/api-payments-stripe, @molecule/api-push-capture, @molecule/api-queue, @molecule/api-queue-memory, @molecule/api-resource, @molecule/api-resource-device, @molecule/api-resource-payment, @molecule/api-resource-user, @molecule/api-search, @molecule/api-search-meilisearch, @molecule/api-search-postgres, @molecule/api-secrets, @molecule/api-secrets-env, @molecule/api-server-default-express, @molecule/api-two-factor, @molecule/api-two-factor-otplib, @molecule/api-uploads, @molecule/api-uploads-filesystem, @molecule/api-uploads-s3

Reference

@molecule/api-bonds-default-express — default API bond wirings and shared route/handler plumbing for Express-based apps.

Two halves:

  1. setup<Name>() bond wirings (40+): one function per default provider (setupConfigEnv, setupDatabasePostgresql, setupJwtJsonwebtoken, setupEmailsMailgun, setupUploadsS3, setupRealtimeSocketio, setupAiAnthropic, …) so per-app api/src/bonds/<name>.ts files are 1-line re-exports and bonds/index.ts just calls them in order.
  2. Shared Express plumbing: createBillingRouter (the fleet's Stripe billing endpoints), the mountDefaultUserAuthRoutes / mountDefaultDeviceRoutes / other mountDefault*Routes helpers, handler guards (requireAuth, requireUser, requireOwnership, getUserId, validationError, internalError), zod param schemas, trackAuthEvent, and a createMigrator re-export.

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Quick Start

// api/src/bonds/index.ts — wire defaults at startup, then validate:
import { validateBonds } from '@molecule/api-bond'
import {
  setupConfigEnv,
  setupDatabasePostgresql,
  setupEmailsMailgun,
  setupJwtJsonwebtoken,
  setupSecretsEnv,
} from '@molecule/api-bonds-default-express'

async function setupBonds(): Promise<void> {
  setupConfigEnv()
  setupSecretsEnv()
  setupDatabasePostgresql()
  setupJwtJsonwebtoken()
  setupEmailsMailgun()
  validateBonds()
}
// api/src/routes/billing.ts — the fleet-standard billing endpoints
// (POST /checkout, POST /cancel, GET /status, GET /tiers), mounted by
// the app router at /billing (the real file default-exports the router):
import { createBillingRouter } from '@molecule/api-bonds-default-express'

// Your app owns these (typically in api/src/tiers.ts):
interface AppLimits {
  seats: number
}
const getPricingTiers = () => [] // your tiers, each with a stripePriceId + limits
const appPlanKeys = { free: 'free', pro: 'pro' }

const billingRouter = createBillingRouter<AppLimits>({
  getPricingTiers,
  planKeys: appPlanKeys,
})

Type

feature

Installation

npm install @molecule/api-bonds-default-express @molecule/api-ai-anthropic @molecule/api-ai-embeddings @molecule/api-ai-embeddings-openai @molecule/api-ai-openai @molecule/api-ai-speech @molecule/api-ai-speech-openai @molecule/api-ai-vector-store @molecule/api-ai-vector-store-pgvector @molecule/api-analytics @molecule/api-audit @molecule/api-audit-database @molecule/api-bond @molecule/api-cache @molecule/api-cache-memory @molecule/api-cache-redis @molecule/api-config @molecule/api-config-env @molecule/api-cron @molecule/api-cron-node-cron @molecule/api-database @molecule/api-database-pglite @molecule/api-database-postgresql @molecule/api-emails @molecule/api-emails-capture @molecule/api-emails-mailgun @molecule/api-encryption @molecule/api-encryption-aes @molecule/api-entitlements @molecule/api-error-tracking @molecule/api-error-tracking-console @molecule/api-error-tracking-sentry @molecule/api-geolocation @molecule/api-geolocation-google @molecule/api-geolocation-mapbox @molecule/api-geolocation-nominatim @molecule/api-http @molecule/api-http-fetch @molecule/api-i18n @molecule/api-image @molecule/api-image-sharp @molecule/api-import-export @molecule/api-import-export-csv @molecule/api-jwt @molecule/api-jwt-jsonwebtoken @molecule/api-logger @molecule/api-media-streaming @molecule/api-media-streaming-hls @molecule/api-middleware-body-parser @molecule/api-middleware-body-parser-express @molecule/api-middleware-cookie-parser @molecule/api-middleware-cookie-parser-express @molecule/api-middleware-cors @molecule/api-middleware-cors-express @molecule/api-middleware-validation @molecule/api-notifications-webhook @molecule/api-password @molecule/api-password-bcrypt @molecule/api-payments @molecule/api-payments-capture @molecule/api-payments-stripe @molecule/api-pdf @molecule/api-pdf-pdfkit @molecule/api-permissions @molecule/api-permissions-custom @molecule/api-push-capture @molecule/api-push-notifications @molecule/api-push-notifications-web-push @molecule/api-queue @molecule/api-queue-memory @molecule/api-queue-redis @molecule/api-rate-limit @molecule/api-rate-limit-memory @molecule/api-realtime @molecule/api-realtime-socketio @molecule/api-realtime-sse @molecule/api-realtime-ws @molecule/api-reporting @molecule/api-reporting-database @molecule/api-resource @molecule/api-resource-device @molecule/api-resource-payment @molecule/api-resource-user @molecule/api-search @molecule/api-search-meilisearch @molecule/api-search-postgres @molecule/api-secrets @molecule/api-secrets-env @molecule/api-server-default-express @molecule/api-two-factor @molecule/api-two-factor-otplib @molecule/api-uploads @molecule/api-uploads-filesystem @molecule/api-uploads-s3 @molecule/api-webhook @molecule/api-webhook-http @molecule/api-workflow @molecule/api-workflow-database express zod
npm install -D @types/express

API

Types

AuthzResult

Result of an ownership check. ok: true carries the resolved row; ok: false carries the HTTP status the handler should return — always 404 to avoid leaking row existence to non-owners (the "no IDOR" rule).

type AuthzResult<T> = { ok: true; row: T } | { ok: false; status: 404 }

Functions

createMigrator(migrationsDir)

Returns a runMigrations() function bound to the given directory.

function createMigrator(migrationsDir: string): () => Promise<void>
  • migrationsDir — Absolute path to the directory containing ordered *.sql migration files. Resolve via join(new URL('.', import.meta.url).pathname, '../../migrations') from the app's scripts/migrate.ts.

Returns: A no-arg runMigrations() that creates the database (if missing) and applies every migration file in lexical order.

createBillingRouter(opts)

Factory for the default billing router. The router exposes four endpoints: POST /checkout, POST /cancel, GET /status, GET /tiers.

function createBillingRouter(opts: {
  getPricingTiers: () => ReadonlyArray<PricingTier>
  planKeys: { free: string } & Record<string, string>
}): Router

getUserId(res)

Read the JWT session userId off res.locals.session. Returns null when there is no session (the auth middleware never ran, or the request is unauthenticated).

function getUserId(res: Response<any, Record<string, any>>): string | null

requireUser(res)

Like getUserId but writes a 401 + returns null when there's no session. Use at the top of handler bodies to bail early:

const userId = requireUser(res)
if (!userId) return
function requireUser(res: Response<any, Record<string, any>>): string | null

getParamId(req, name?)

Read a route param as a string, defending against the Express type union string | string[] (multi-value when the same param key appears more than once). Defaults to 'id'.

function getParamId(
  req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
  name?: string,
): string

requireOwnership(table, id, userId)

Look up a row by id and verify the caller owns it via owner_id. Returns the row on success, 404 when missing OR owned by a different user (so attackers can't probe row existence).

function requireOwnership(table: string, id: string, userId: string): Promise<AuthzResult<T>>

requireUserOwnership(table, id, userId)

Variant of requireOwnership for tables that scope by user_id instead of owner_id (notifications, user-bound preferences, etc.).

function requireUserOwnership(table: string, id: string, userId: string): Promise<AuthzResult<T>>

requireAuth(_req, res, next)

Express middleware that 401s any request lacking res.locals.session.userId. Drop-in for the fleet's 51 inline requireAuth copies.

function requireAuth(
  _req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
  res: Response<any, Record<string, any>>,
  next: NextFunction,
): void

validationError(res, issues)

Standard 400 response for zod / schema validation failures. Used by ~21 fleet apps' api/src/lib/authz.ts files.

function validationError(res: Response<any, Record<string, any>>, issues: unknown): void

internalError(res, error?)

Standard 500 response that logs the underlying cause before responding with a generic message. Always pass the original error so silent catches don't ship to prod under green tests.

function internalError(res: Response<any, Record<string, any>>, error?: unknown): void

trackAuthEvent(eventName)

Emits an analytics event AND a log entry for an auth-related mutation (signup, login, password reset, plan change, etc.). Logs at info on success and warn on auth failure (4xx) so security signal is captured.

Replaces the per-app api/src/middleware/auth-analytics.ts shipped by 10 fleet apps.

function trackAuthEvent(
  eventName: string,
): RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>

createMigratorPglite(migrationsDir, extraDirs)

Returns a runMigrations() that applies every *.sql file in migrationsDir, in lexical order, to @molecule/api-database-pglite's default pool — the pool setupDatabasePglite() bonds, so the schema lands in the database the app queries (an in-memory PGlite database exists only inside that one instance). Same files and same "already exists is a warning, anything else fails the boot" contract as createMigrator; there is no CREATE DATABASE step.

Further directories run after it, each in its own lexical order — e.g. a scaffolded app's __setup__/ (resource-package DDL such as payments.sql) after migrations/, the order the scaffolded Postgres runner uses. A directory that does not exist counts as empty.

function createMigratorPglite(migrationsDir: string, extraDirs?: string[]): () => Promise<void>
  • migrationsDir — Absolute path to the app's migrations/ directory.
  • extraDirs — Absolute paths of further *.sql directories to apply after it, in order.

Returns: A no-arg migration runner.

mountDefaultDeviceRoutes(router, device)

Mounts the standard device routes:

  • GET /devices/push/public-key (public — the VAPID public key browsers need for pushManager.subscribe({ applicationServerKey }); bond-gated 404/503 when no push provider is bonded/configured)
  • GET /devices (auth+query)
  • GET /devices/:id (authUser+read)
  • PATCH /devices/:id (authUser+update)
  • DELETE /devices/:id (authUser+del)
function mountDefaultDeviceRoutes(router: Router, device: DeviceRequestHandlerMap): void

mountDefaultUserAuthRoutes(router, user)

Mounts the public auth endpoints:

  • POST /users (create)
  • POST /users/log-in (rateLimitAuth + logIn)
  • POST /users/forgot-password (rateLimitAuth + forgotPassword)

The credential-bearing routes are fronted by user.rateLimitAuth — the default IP+account brute-force throttle from @molecule/api-resource-user — so generated apps are not left with unthrottled password / TOTP-via-login guessing. The limiter degrades open (logs a warning) when no rate-limit provider is bonded, so apps that opt out still boot.

function mountDefaultUserAuthRoutes(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserOAuthLoginRoute(router, user)

Optional OAuth routes — BOTH halves of the flow:

  • GET /users/oauth/:provider (rateLimitAuth + oauthAuthorize) — initiation: sets the CSRF oauth_state + PKCE oauth_verifier httpOnly cookies and 302-redirects to the bonded provider's authorization URL. Without this half the state cookie logInOAuth validates is never set, so every callback fails 403 (this is exactly how the generated-app fleet shipped an exchange endpoint with no way to start the dance). The GET carries the same rateLimitAuth throttle as the POST: it has no body, so only the generous per-IP bucket applies — an abuse ceiling on cookie-mint/ redirect flooding that a legitimate login (one GET + one POST) never approaches. A trip is a 429 JSON on a top-level navigation, which is acceptable for that ceiling.
  • POST /users/log-in/oauth (rateLimitAuth + logInOAuth) — callback exchange: verifies state + code with the bonded provider and logs the user in.

Only mount when the app wires an oauth bond. Handlers check the bond registry at request time, so an unbonded provider yields a clean 404.

function mountDefaultUserOAuthLoginRoute(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserResetPasswordRoute(router, user)

Optional reset-password route: POST /users/reset-password (rateLimitAuth + resetPassword). Only mount when the app uses the pkg's resetPassword handler rather than a custom local handler.

function mountDefaultUserResetPasswordRoute(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserCrudRoutes(router, user)

Mounts the authed-self user CRUD routes:

  • GET /users/me (auth+readSelf) — session restore; MUST precede /users/:id
  • GET /users/:id (authSelf+read)
  • PATCH /users/:id (authSelf+update)
  • DELETE /users/:id (authSelf+del)
function mountDefaultUserCrudRoutes(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserSecurityRoutes(router, user)

Mounts password + 2FA security routes:

  • PATCH /users/:id/password (authSelf+updatePassword)
  • POST /users/:id/verify-two-factor (authSelf + rateLimitTwoFactor + verifyTwoFactor)

The 2FA verification route carries a stricter limiter (user.rateLimitTwoFactor) that temp-locks the second factor per account after consecutive misses.

function mountDefaultUserSecurityRoutes(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserBillingRoutes(router, user)

Mounts plan/billing routes:

  • PATCH /users/:id/plan (authSelf+updatePlan)
  • POST /users/payment-notification/:provider (requireWebhookAuthenticity+handlePaymentNotification)

The notification route is public (providers POST to it), so it is gated by requireWebhookAuthenticity: signature-verifying webhook providers (Stripe) pass through, while unsigned server-to-server providers (Apple/Google) require a shared secret — the endpoint is not open by default.

function mountDefaultUserBillingRoutes(router: Router, user: UserRequestHandlerMap): void

mountDefaultUserVerifyPaymentRoutes(router, user)

Optional payment-verification routes for apps that support client-driven payment confirmation (Apple/Google receipt verify).

Both verbs require authSelf ([M3-1]): the handler mutates and returns the :id user, so an unauthenticated / cross-user call must not reach it. The permissive global verifyMiddleware() never blocks, so per-route authSelf is the gate. authSelf does NOT break the Stripe Checkout success_url callback — that is a top-level browser navigation which carries the sameSite:'lax' session cookie — and in-handler customer/checkout-session binding remains as defense-in-depth. This mirrors the hardened declarative route table (resources/user/src/routes.ts) and molecule-dev's live router; the fix had not been propagated to this mounter, which the generated-app fleet uses.

  • GET /users/:id/verify-payment/:provider (authSelf+verifyPayment)
  • POST /users/:id/verify-payment/:provider (authSelf+verifyPayment)
function mountDefaultUserVerifyPaymentRoutes(router: Router, user: UserRequestHandlerMap): void

setupConfigEnv()

Wires @molecule/api-config-env to @molecule/api-config.

function setupConfigEnv(): void

setupDatabasePostgresql()

Wires @molecule/api-database-postgresql to @molecule/api-database.

function setupDatabasePostgresql(): void

setupDatabasePglite()

Wires @molecule/api-database-pglite (real Postgres compiled to WebAssembly, in-process) to @molecule/api-database — the database half of the zero-server "browser" profile. Same SQL, placeholders and error codes as the postgresql bond, so app code and migrations do not change.

Binds the pglite package's DEFAULT pool, whose data directory comes from PGLITE_DATA_DIR (memory://, idb://<name>, or a filesystem path; the bond's Node default is ./data/pglite). Run migrations with createMigratorPglite, which targets the same default pool — an in-memory database exists only inside that one instance, so the migrator and the app must share it.

@molecule/api-database-pglite is an OPTIONAL peer, imported lazily, so a postgres-only app never needs it installed.

function setupDatabasePglite(): Promise<void>

setupJwtJsonwebtoken()

Wires @molecule/api-jwt-jsonwebtoken to @molecule/api-jwt.

function setupJwtJsonwebtoken(): void

setupMiddlewareBodyParserExpress()

Wires @molecule/api-middleware-body-parser-express to @molecule/api-middleware-body-parser.

function setupMiddlewareBodyParserExpress(): void

setupMiddlewareCookieParserExpress()

Wires @molecule/api-middleware-cookie-parser-express to @molecule/api-middleware-cookie-parser.

function setupMiddlewareCookieParserExpress(): void

setupMiddlewareCorsExpress()

Wires @molecule/api-middleware-cors-express to @molecule/api-middleware-cors.

function setupMiddlewareCorsExpress(): void

setupPasswordBcrypt()

Wires @molecule/api-password-bcrypt to @molecule/api-password.

function setupPasswordBcrypt(): void

setupSecretsEnv()

Wires @molecule/api-secrets-env to @molecule/api-secrets.

function setupSecretsEnv(): void

setupServiceDevice()

Registers the device service from @molecule/api-resource-device on the bond system.

function setupServiceDevice(): void

setupTwoFactorOtplib()

Wires @molecule/api-two-factor-otplib to @molecule/api-two-factor.

function setupTwoFactorOtplib(): void

setupEmailsMailgun()

Wires @molecule/api-emails-mailgun to @molecule/api-emails.

function setupEmailsMailgun(): void

setupEmailsCapture()

Wires @molecule/api-emails-capture to @molecule/api-emails unconditionally — every message is captured in memory instead of sent. Unlike setupEmailsMailgun's development fallback, this does not depend on NODE_ENV or on which env vars are missing, so a profile that selects it always gets it.

function setupEmailsCapture(): void

setupPaymentsStripe()

Registers @molecule/api-payments-stripe as a named 'stripe' payments provider.

function setupPaymentsStripe(): void

setupPaymentsCapture()

Registers @molecule/api-payments-capture (a payments vendor simulated in memory: checkouts complete at once, signed local webhooks) under the name 'stripe' — the name setupPaymentsStripe uses — so the billing router, the /users/:id/verify-payment/stripe and /users/payment-notification/stripe routes, and the plan catalogue's platformKey work unchanged. Grants plans without taking money: bond it in a development / browser profile only, never in production.

@molecule/api-payments-capture is an OPTIONAL peer, imported lazily.

function setupPaymentsCapture(): Promise<void>

setupServicePayment()

Registers the plan + paymentRecord services from @molecule/api-resource-payment.

function setupServicePayment(): void

setupSearchMeilisearch()

Wires @molecule/api-search-meilisearch to @molecule/api-search.

function setupSearchMeilisearch(): void

setupUploadsS3()

Wires @molecule/api-uploads-s3 to @molecule/api-uploads.

function setupUploadsS3(): void

setupImageSharp()

Wires @molecule/api-image-sharp to @molecule/api-image.

function setupImageSharp(): Promise<void>

setupPermissionsCustom()

Wires @molecule/api-permissions-custom to @molecule/api-permissions.

function setupPermissionsCustom(): Promise<void>

setupReportingDatabase()

Wires @molecule/api-reporting-database to @molecule/api-reporting.

function setupReportingDatabase(): Promise<void>

setupRealtimeSocketio()

Wires @molecule/api-realtime-socketio to @molecule/api-realtime.

function setupRealtimeSocketio(): Promise<void>

setupRealtimeWs()

Wires @molecule/api-realtime-ws to @molecule/api-realtime.

function setupRealtimeWs(): Promise<void>

setupRealtimeSse()

Wires @molecule/api-realtime-sse to @molecule/api-realtime.

function setupRealtimeSse(): Promise<void>

setupCronNodeCron()

Wires @molecule/api-cron-node-cron to @molecule/api-cron.

function setupCronNodeCron(): Promise<void>

setupEncryptionAes()

Wires @molecule/api-encryption-aes to @molecule/api-encryption.

function setupEncryptionAes(): Promise<void>

setupPushNotificationsWebPush()

Wires @molecule/api-push-notifications-web-push to @molecule/api-push-notifications.

function setupPushNotificationsWebPush(): Promise<void>

setupImportExportCsv()

Wires @molecule/api-import-export-csv to @molecule/api-import-export.

function setupImportExportCsv(): Promise<void>

setupAiAnthropic()

Registers @molecule/api-ai-anthropic as a named 'anthropic' AI provider.

function setupAiAnthropic(): Promise<void>

setupAuditDatabase()

Wires @molecule/api-audit-database to @molecule/api-audit.

function setupAuditDatabase(): Promise<void>

setupPdfPdfkit()

Wires @molecule/api-pdf-pdfkit to @molecule/api-pdf.

function setupPdfPdfkit(): Promise<void>

setupApiAnalyticsDefault()

Wires a no-op default analytics provider so @molecule/api-analytics calls succeed.

function setupApiAnalyticsDefault(): Promise<void>

setupGeolocationMapbox()

Wires @molecule/api-geolocation-mapbox to @molecule/api-geolocation.

function setupGeolocationMapbox(): Promise<void>

setupErrorTrackingSentry()

Wires @molecule/api-error-tracking-sentry to @molecule/api-error-tracking.

Safe to wire unconditionally: without SENTRY_DSN the Sentry provider is a documented no-op (the boot config report flags the missing key), so an app that hasn't configured Sentry yet boots and runs untouched.

function setupErrorTrackingSentry(): Promise<void>

setupErrorTrackingConsole()

Wires @molecule/api-error-tracking-console to @molecule/api-error-tracking.

Zero-credential development default: captures are logged as structured lines through the bonded logger instead of being sent to a remote service.

function setupErrorTrackingConsole(): Promise<void>

setupCacheRedis()

Wires @molecule/api-cache-redis to @molecule/api-cache.

function setupCacheRedis(): Promise<void>

setupQueueMemory()

Wires @molecule/api-queue-memory to @molecule/api-queue — the zero-credential in-process queue (single-process/dev; swap to redis/rabbitmq/sqs for multi-instance production).

function setupQueueMemory(): Promise<void>

setupQueueRedis()

Wires @molecule/api-queue-redis to @molecule/api-queue. Outside production, when REDIS_URL is absent, falls back to @molecule/api-queue-memory — the zero-credential in-process queue — so queue-backed features (background jobs, async delivery workers) run out of the box, mirroring setupCacheRedis.

function setupQueueRedis(): Promise<void>

setupAiOpenai()

Registers @molecule/api-ai-openai as a named 'openai' AI provider.

function setupAiOpenai(): Promise<void>

setupAiEmbeddingsOpenai()

Wires @molecule/api-ai-embeddings-openai to @molecule/api-ai-embeddings.

function setupAiEmbeddingsOpenai(): Promise<void>

setupWebhookHttp()

Wires @molecule/api-webhook-http to @molecule/api-webhook.

function setupWebhookHttp(): Promise<void>

setupAiVectorStorePgvector()

Wires @molecule/api-ai-vector-store-pgvector to @molecule/api-ai-vector-store.

function setupAiVectorStorePgvector(): Promise<void>

setupAiSpeechOpenai()

Wires @molecule/api-ai-speech-openai to @molecule/api-ai-speech.

function setupAiSpeechOpenai(): Promise<void>

setupWorkflowDatabase()

Wires @molecule/api-workflow-database to @molecule/api-workflow.

function setupWorkflowDatabase(): Promise<void>

setupHttpFetch()

Wires @molecule/api-http-fetch to @molecule/api-http.

function setupHttpFetch(): Promise<void>

setupNotificationsWebhook()

Registers @molecule/api-notifications-webhook as a named 'webhook' notifications provider.

function setupNotificationsWebhook(): Promise<void>

setupGeolocationGoogle()

Wires @molecule/api-geolocation-google to @molecule/api-geolocation.

function setupGeolocationGoogle(): Promise<void>

setupMediaStreamingHls()

Wires @molecule/api-media-streaming-hls to @molecule/api-media-streaming.

function setupMediaStreamingHls(): Promise<void>

setupRateLimitMemory()

Wires @molecule/api-rate-limit-memory to @molecule/api-rate-limit.

This is the default brute-force-protection backend for mlcl-generated apps (single-instance). Multi-instance deployments should swap in @molecule/api-rate-limit-redis so the throttle is shared across replicas.

function setupRateLimitMemory(): Promise<void>

Constants

userRequestHandlerMap

Pre-wired request handler map for @molecule/api-resource-user.

const userRequestHandlerMap: UserRequestHandlerMap

deviceRequestHandlerMap

Pre-wired request handler map for @molecule/api-resource-device.

const deviceRequestHandlerMap: DeviceRequestHandlerMap

idParamSchema

Standard route-param schema for :id. Accepts any non-empty string. Pair with validateParams(idParamSchema).

const idParamSchema: z.ZodObject<{ id: z.ZodString }, z.core.$strip>

uuidParamSchema

Strict variant of idParamSchema that requires a UUID. Use when the underlying column is a uuid.

const uuidParamSchema: z.ZodObject<{ id: z.ZodString }, z.core.$strip>

deviceService

DeviceService implementation for the bond system.

Provides device CRUD operations that other resources can use through get('device') / require('device').

const deviceService: DeviceService

Namespaces

userAuthorization

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-ai-anthropic ^1.0.1
  • @molecule/api-ai-embeddings ^1.0.1
  • @molecule/api-ai-embeddings-openai ^1.0.1
  • @molecule/api-ai-openai ^1.0.1
  • @molecule/api-ai-speech ^1.0.1
  • @molecule/api-ai-speech-openai ^1.0.1
  • @molecule/api-ai-vector-store ^1.0.1
  • @molecule/api-ai-vector-store-pgvector ^1.0.1
  • @molecule/api-analytics ^1.0.1
  • @molecule/api-audit ^1.0.1
  • @molecule/api-audit-database ^1.0.1
  • @molecule/api-bond ^1.0.1
  • @molecule/api-cache ^1.0.1
  • @molecule/api-cache-memory ^1.0.1
  • @molecule/api-cache-redis ^1.0.1
  • @molecule/api-config ^1.0.1
  • @molecule/api-config-env ^1.0.1
  • @molecule/api-cron ^1.0.1
  • @molecule/api-cron-node-cron ^1.0.1
  • @molecule/api-database ^1.0.1
  • @molecule/api-database-pglite ^1.0.0
  • @molecule/api-database-postgresql ^1.0.1
  • @molecule/api-emails ^1.0.1
  • @molecule/api-emails-capture ^1.0.1
  • @molecule/api-emails-mailgun ^1.0.1
  • @molecule/api-encryption ^1.0.1
  • @molecule/api-encryption-aes ^1.0.1
  • @molecule/api-entitlements ^1.0.1
  • @molecule/api-error-tracking ^1.0.1
  • @molecule/api-error-tracking-console ^1.0.1
  • @molecule/api-error-tracking-sentry ^1.0.1
  • @molecule/api-geolocation ^1.0.1
  • @molecule/api-geolocation-google ^1.0.1
  • @molecule/api-geolocation-mapbox ^1.0.1
  • @molecule/api-geolocation-nominatim ^1.0.1
  • @molecule/api-http ^1.0.1
  • @molecule/api-http-fetch ^1.0.1
  • @molecule/api-i18n ^1.0.1
  • @molecule/api-image ^1.0.1
  • @molecule/api-image-sharp ^1.0.1
  • @molecule/api-import-export ^1.0.1
  • @molecule/api-import-export-csv ^1.0.1
  • @molecule/api-jwt ^1.0.1
  • @molecule/api-jwt-jsonwebtoken ^1.0.1
  • @molecule/api-logger ^1.0.1
  • @molecule/api-media-streaming ^1.0.1
  • @molecule/api-media-streaming-hls ^1.0.1
  • @molecule/api-middleware-body-parser ^1.0.1
  • @molecule/api-middleware-body-parser-express ^1.0.1
  • @molecule/api-middleware-cookie-parser ^1.0.1
  • @molecule/api-middleware-cookie-parser-express ^1.0.1
  • @molecule/api-middleware-cors ^1.0.1
  • @molecule/api-middleware-cors-express ^1.0.1
  • @molecule/api-middleware-validation ^1.0.1
  • @molecule/api-notifications-webhook ^1.0.1
  • @molecule/api-password ^1.0.1
  • @molecule/api-password-bcrypt ^1.0.1
  • @molecule/api-payments ^1.0.1
  • @molecule/api-payments-capture ^1.0.0
  • @molecule/api-payments-stripe ^1.0.1
  • @molecule/api-pdf ^1.0.1
  • @molecule/api-pdf-pdfkit ^1.0.1
  • @molecule/api-permissions ^1.0.1
  • @molecule/api-permissions-custom ^1.0.1
  • @molecule/api-push-capture ^1.0.1
  • @molecule/api-push-notifications ^1.0.1
  • @molecule/api-push-notifications-web-push ^1.0.1
  • @molecule/api-queue ^1.0.1
  • @molecule/api-queue-memory ^1.0.1
  • @molecule/api-queue-redis ^1.0.1
  • @molecule/api-rate-limit ^1.0.1
  • @molecule/api-rate-limit-memory ^1.0.1
  • @molecule/api-realtime ^1.0.1
  • @molecule/api-realtime-socketio ^1.0.1
  • @molecule/api-realtime-sse ^1.0.1
  • @molecule/api-realtime-ws ^1.0.1
  • @molecule/api-reporting ^1.0.1
  • @molecule/api-reporting-database ^1.0.1
  • @molecule/api-resource ^1.0.1
  • @molecule/api-resource-device ^1.0.1
  • @molecule/api-resource-payment ^1.0.1
  • @molecule/api-resource-user ^1.0.1
  • @molecule/api-search ^1.0.1
  • @molecule/api-search-meilisearch ^1.0.1
  • @molecule/api-search-postgres ^1.0.1
  • @molecule/api-secrets ^1.0.1
  • @molecule/api-secrets-env ^1.0.1
  • @molecule/api-server-default-express ^1.0.1
  • @molecule/api-two-factor ^1.0.1
  • @molecule/api-two-factor-otplib ^1.0.1
  • @molecule/api-uploads ^1.0.1
  • @molecule/api-uploads-filesystem ^1.0.1
  • @molecule/api-uploads-s3 ^1.0.1
  • @molecule/api-webhook ^1.0.1
  • @molecule/api-webhook-http ^1.0.1
  • @molecule/api-workflow ^1.0.1
  • @molecule/api-workflow-database ^1.0.1
  • express ^4.0.0 || ^5.0.0

Runtime Dependencies

  • @molecule/api-ai-anthropic

  • @molecule/api-ai-embeddings

  • @molecule/api-ai-embeddings-openai

  • @molecule/api-ai-openai

  • @molecule/api-ai-speech

  • @molecule/api-ai-speech-openai

  • @molecule/api-ai-vector-store

  • @molecule/api-ai-vector-store-pgvector

  • @molecule/api-analytics

  • @molecule/api-audit

  • @molecule/api-audit-database

  • @molecule/api-bond

  • @molecule/api-cache

  • @molecule/api-cache-memory

  • @molecule/api-cache-redis

  • @molecule/api-config

  • @molecule/api-config-env

  • @molecule/api-cron

  • @molecule/api-cron-node-cron

  • @molecule/api-database

  • @molecule/api-database-pglite

  • @molecule/api-database-postgresql

  • @molecule/api-emails

  • @molecule/api-emails-capture

  • @molecule/api-emails-mailgun

  • @molecule/api-encryption

  • @molecule/api-encryption-aes

  • @molecule/api-entitlements

  • @molecule/api-error-tracking

  • @molecule/api-error-tracking-console

  • @molecule/api-error-tracking-sentry

  • @molecule/api-geolocation

  • @molecule/api-geolocation-google

  • @molecule/api-geolocation-mapbox

  • @molecule/api-geolocation-nominatim

  • @molecule/api-http

  • @molecule/api-http-fetch

  • @molecule/api-i18n

  • @molecule/api-image

  • @molecule/api-image-sharp

  • @molecule/api-import-export

  • @molecule/api-import-export-csv

  • @molecule/api-jwt

  • @molecule/api-jwt-jsonwebtoken

  • @molecule/api-logger

  • @molecule/api-media-streaming

  • @molecule/api-media-streaming-hls

  • @molecule/api-middleware-body-parser

  • @molecule/api-middleware-body-parser-express

  • @molecule/api-middleware-cookie-parser

  • @molecule/api-middleware-cookie-parser-express

  • @molecule/api-middleware-cors

  • @molecule/api-middleware-cors-express

  • @molecule/api-middleware-validation

  • @molecule/api-notifications-webhook

  • @molecule/api-password

  • @molecule/api-password-bcrypt

  • @molecule/api-payments

  • @molecule/api-payments-capture

  • @molecule/api-payments-stripe

  • @molecule/api-pdf

  • @molecule/api-pdf-pdfkit

  • @molecule/api-permissions

  • @molecule/api-permissions-custom

  • @molecule/api-push-capture

  • @molecule/api-push-notifications

  • @molecule/api-push-notifications-web-push

  • @molecule/api-queue

  • @molecule/api-queue-memory

  • @molecule/api-queue-redis

  • @molecule/api-rate-limit

  • @molecule/api-rate-limit-memory

  • @molecule/api-realtime

  • @molecule/api-realtime-socketio

  • @molecule/api-realtime-sse

  • @molecule/api-realtime-ws

  • @molecule/api-reporting

  • @molecule/api-reporting-database

  • @molecule/api-resource

  • @molecule/api-resource-device

  • @molecule/api-resource-payment

  • @molecule/api-resource-user

  • @molecule/api-search

  • @molecule/api-search-meilisearch

  • @molecule/api-search-postgres

  • @molecule/api-secrets

  • @molecule/api-secrets-env

  • @molecule/api-server-default-express

  • @molecule/api-two-factor

  • @molecule/api-two-factor-otplib

  • @molecule/api-uploads

  • @molecule/api-uploads-filesystem

  • @molecule/api-uploads-s3

  • @molecule/api-webhook

  • @molecule/api-webhook-http

  • @molecule/api-workflow

  • @molecule/api-workflow-database

  • express

  • zod

  • Development falls back to zero-credential providers; production never does. When NODE_ENV !== 'production' and a provider's required env is missing, the setup wires the capture/local sibling instead and logs the swap: mailgun→emails-capture (MAILGUN_API_KEY/MAILGUN_DOMAIN), uploads-s3→uploads-filesystem (AWS_*), search-meilisearch→ search-postgres (MEILISEARCH_URL), web-push→push-capture (VAPID_*), geolocation-mapbox→nominatim (MAPBOX_ACCESS_TOKEN), cache-redis→cache-memory (REDIS_URL). In production the credentialed provider is wired regardless — missing env surfaces as loud, actionable 503s and boot-report entries, never a silent provider swap. So "emails don't arrive in dev" usually means they were CAPTURED (read them via the activity/capture tooling), not lost.

  • Realtime setups (setupRealtimeSocketio, setupRealtimeWs, setupRealtimeSse) all defer-attach. Each dynamic-imports its provider's createProvider({ deferAttach: true }), calls setProvider(), then registerServerCreatedHook((server) => provider.attachHttpServer?.(server)) from @molecule/api-server-default-express — so the realtime transport shares the API's HTTP server/port once it exists, instead of a standalone port a containerized sandbox / proxied deploy may not expose. Add new realtime bonds by mirroring this pattern exactly.

  • createBillingRouter registers the app's Stripe plan catalogue with @molecule/api-resource-payment at construction AND re-registers per checkout (price-id env vars may resolve after startup); webhook handling stays with @molecule/api-resource-user's handlePaymentNotification. A paid price whose planKeys entry is missing is skipped WITH a warning — that plan could never be granted.

  • Only wire the setups whose packages your app actually installed — each one imports its provider package (several lazily via dynamic import), so calling a setup for an uninstalled bond fails at that import.