@emmett-community/emmett-google-services-bootstrap 0.3.0 → 0.5.0
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.
- package/README.md +78 -1
- package/dist/ServiceBootstrap-BjFoQDd_.d.cts +338 -0
- package/dist/ServiceBootstrap-BjFoQDd_.d.ts +338 -0
- package/dist/chunk-AHOX5L65.js +922 -0
- package/dist/chunk-AHOX5L65.js.map +1 -0
- package/dist/chunk-UBZVIW2M.cjs +922 -0
- package/dist/chunk-UBZVIW2M.cjs.map +1 -0
- package/dist/index.cjs +52 -949
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -301
- package/dist/index.d.ts +19 -301
- package/dist/index.js +32 -892
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +49 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +31 -0
- package/dist/testing.d.ts +31 -0
- package/dist/testing.js +49 -0
- package/dist/testing.js.map +1 -0
- package/package.json +15 -5
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/bootstrap/ServiceBootstrap.ts","../src/firebase/FirebaseInitializer.ts","../src/pubsub/PubSubInitializer.ts","../src/eventstore/EventStoreFactory.ts","../src/lifecycle/DependencyChecker.ts","../src/lifecycle/GracefulShutdown.ts","../src/lifecycle/SignalHandlers.ts"],"sourcesContent":["export * from './bootstrap';\nexport * from './types';\nexport * from './firebase';\nexport * from './pubsub';\nexport * from './lifecycle';\nexport * from './eventstore';\nexport { realtimeDBInlineProjection } from '@emmett-community/emmett-google-realtime-db';\nexport {\n ApiE2ESpecification,\n ApiSpecification,\n createFirebaseAuthSecurityHandlers,\n existingStream,\n expectNewEvents,\n expectResponse,\n NoContent,\n OK,\n on,\n type ImportedHandlerModules,\n type TestRequest,\n} from '@emmett-community/emmett-expressjs-with-openapi';\n","import path from 'node:path';\nimport type { Application } from 'express';\nimport { createLogger } from '@emmett-community/emmett-observability';\nimport {\n createOpenApiValidatorOptions,\n getApplication,\n startAPI,\n type ApplicationOptions,\n type ImportedHandlerModules,\n type OpenApiValidatorOptions,\n} from '@emmett-community/emmett-expressjs-with-openapi';\nimport {\n getPubSubMessageBus,\n type Logger as PubSubLogger,\n} from '@emmett-community/emmett-google-pubsub';\nimport type { EventStore } from '@event-driven-io/emmett';\nimport type { Firestore } from '@google-cloud/firestore';\nimport type { PubSub } from '@google-cloud/pubsub';\nimport type { Auth } from 'firebase-admin/auth';\nimport type { app as FirebaseAppNamespace } from 'firebase-admin';\nimport type { Database } from 'firebase-admin/database';\nimport { FirebaseInitializer } from '../firebase/FirebaseInitializer';\nimport { PubSubInitializer } from '../pubsub/PubSubInitializer';\nimport { createEventStore } from '../eventstore/EventStoreFactory';\nimport {\n DependencyChecker,\n type DependencyCheckSummary,\n} from '../lifecycle/DependencyChecker';\nimport {\n GracefulShutdown,\n type GracefulShutdownResult,\n} from '../lifecycle/GracefulShutdown';\nimport { registerSignalHandlers } from '../lifecycle/SignalHandlers';\nimport type {\n DependencyCheck,\n Logger as BootstrapLogger,\n MessageBusWithLifecycle,\n ResolvedServiceBootstrapConfig,\n ServiceBootstrapConfig,\n} from '../types/config';\n\n/**\n * Runtime context produced by ServiceBootstrap.\n */\nexport type ServiceBootstrapContext = {\n serviceName: string;\n firebase: {\n app: FirebaseAppNamespace.App;\n firestore: Firestore;\n database: Database;\n auth: Auth;\n };\n firestore: Firestore;\n database: Database;\n auth: Auth;\n pubsub: PubSub;\n eventStore: EventStore;\n messageBus: MessageBusWithLifecycle;\n logger?: BootstrapLogger;\n getCurrentTime: () => Date;\n config: ResolvedServiceBootstrapConfig;\n};\n\n/**\n * Error thrown when required dependencies fail health checks.\n */\nexport class DependencyUnavailableError extends Error {\n readonly summary: DependencyCheckSummary;\n\n constructor(summary: DependencyCheckSummary) {\n const failed = summary.results\n .filter((result) => result.required && !result.ok)\n .map((result) => result.name)\n .join(', ');\n\n super(`Dependency check failed: ${failed}`);\n this.name = 'DependencyUnavailableError';\n this.summary = summary;\n }\n}\n\nexport type CreateAppOptions = {\n openApiPath: string;\n handlersPath: string;\n initializeHandlers: (handlers?: ImportedHandlerModules) => void | Promise<void>;\n openApiOptions?: Partial<\n Omit<\n OpenApiValidatorOptions,\n 'apiSpec' | 'operationHandlers' | 'initializeHandlers'\n >\n >;\n appOptions?: Omit<ApplicationOptions, 'openApiValidator' | 'observability'>;\n};\n\nexport type StartApiOptions = Omit<CreateAppOptions, 'initializeHandlers'> & {\n initializeHandlers: (\n handlers: ImportedHandlerModules | undefined,\n ctx: ServiceBootstrapContext,\n ) => void | Promise<void>;\n port?: number;\n registerSignalHandlers?: boolean;\n beforeStart?: (ctx: ServiceBootstrapContext) => void | Promise<void>;\n};\n\nconst normalizeContext = (data: unknown): Record<string, unknown> => {\n if (data === undefined || data === null) return {};\n if (typeof data === 'object' && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return { data };\n};\n\nconst normalizeErrorContext = (error: unknown): Record<string, unknown> => {\n if (error === undefined || error === null) return {};\n if (error instanceof Error) return { err: error };\n if (typeof error === 'object' && !Array.isArray(error)) {\n return { ...(error as Record<string, unknown>) };\n }\n return { err: error };\n};\n\nconst createPubSubLogger = (\n logger?: BootstrapLogger,\n): PubSubLogger | undefined => {\n if (!logger) return undefined;\n // Adapter: PubSub logger expects (msg, data), canonical logger uses (context, msg).\n const canonicalLogger = logger as any;\n return {\n debug: (msg, data) => canonicalLogger.debug(normalizeContext(data), msg),\n info: (msg, data) => canonicalLogger.info(normalizeContext(data), msg),\n warn: (msg, data) => canonicalLogger.warn(normalizeContext(data), msg),\n error: (msg, error) =>\n canonicalLogger.error(normalizeErrorContext(error), msg),\n };\n};\n\nconst resolvePath = (inputPath: string): string => {\n return path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(process.cwd(), inputPath);\n};\n\n/**\n * Orchestrates Firebase, PubSub, event store, and lifecycle utilities.\n */\nexport class ServiceBootstrap {\n private readonly config: ServiceBootstrapConfig;\n private resolvedConfig?: ResolvedServiceBootstrapConfig;\n private logger?: BootstrapLogger;\n private context?: ServiceBootstrapContext;\n private dependencyChecker?: DependencyChecker;\n private shutdownManager?: GracefulShutdown;\n\n constructor(config: ServiceBootstrapConfig) {\n this.config = config;\n }\n\n /**\n * Resolve configuration with defaults and environment variables.\n */\n getConfig(): ResolvedServiceBootstrapConfig {\n return this.resolveConfig();\n }\n\n /**\n * Return the initialized context if available.\n */\n getContext(): ServiceBootstrapContext | undefined {\n return this.context;\n }\n\n /**\n * Register process signal handlers that trigger shutdown.\n */\n registerSignalHandlers(options?: {\n signals?: NodeJS.Signals[];\n exitCode?: number;\n }): () => void {\n return registerSignalHandlers({\n shutdown: async (reason, exitCode) => {\n await this.shutdown(reason, exitCode);\n },\n signals: options?.signals,\n logger: this.getLogger(),\n exitCode: options?.exitCode,\n });\n }\n\n /**\n * Create an Express app using emmett-expressjs-with-openapi defaults.\n */\n async createApp(options: CreateAppOptions) {\n const logger = this.getLogger();\n const openApiValidator = createOpenApiValidatorOptions(\n resolvePath(options.openApiPath),\n {\n ...options.openApiOptions,\n operationHandlers: resolvePath(options.handlersPath),\n initializeHandlers: options.initializeHandlers,\n },\n );\n\n return getApplication({\n ...(options.appOptions ?? {}),\n openApiValidator,\n observability: logger ? { logger } : undefined,\n });\n }\n\n /**\n * Initialize, run dependency checks, create the app, and start the HTTP server.\n */\n async startApi(options: StartApiOptions): Promise<{\n app: Application;\n server: ReturnType<typeof startAPI>;\n context: ServiceBootstrapContext;\n }> {\n const {\n port,\n registerSignalHandlers,\n beforeStart,\n initializeHandlers,\n ...createAppOptions\n } = options;\n\n const logger = this.getLogger();\n\n try {\n const ctx = await this.initialize();\n\n if (beforeStart) {\n await beforeStart(ctx);\n }\n\n if (registerSignalHandlers !== false) {\n this.registerSignalHandlers();\n }\n\n await this.start();\n\n const app = await this.createApp({\n ...createAppOptions,\n initializeHandlers: (handlers) => initializeHandlers(handlers, ctx),\n });\n\n const server = startAPI(app, { port, logger });\n\n this.getShutdownManager().register({\n name: 'httpServer',\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n }),\n });\n\n logger?.info({ port: port ?? 3000 }, 'API server started');\n\n return { app, server, context: ctx };\n } catch (error) {\n logger?.error({ err: error }, 'Startup failed');\n await this.shutdown('Startup failed');\n throw error;\n }\n }\n\n /**\n * Initialize Firebase, PubSub, and event store wiring.\n * Does not execute dependency checks.\n */\n async initialize(): Promise<ServiceBootstrapContext> {\n if (this.context) {\n return this.context;\n }\n\n const resolvedConfig = this.resolveConfig();\n const logger = this.getLogger();\n\n const firebaseInitializer = new FirebaseInitializer({\n projectId: resolvedConfig.firebase.projectId,\n databaseURL: resolvedConfig.firebase.databaseURL,\n firestoreEmulatorHost: resolvedConfig.firebase.firestoreEmulatorHost,\n databaseEmulatorHost: resolvedConfig.firebase.databaseEmulatorHost,\n logger,\n _firebaseAdmin: resolvedConfig._testOverrides?.firebaseAdmin,\n });\n\n const firebase = await firebaseInitializer.initialize();\n\n const firestore = resolvedConfig._testOverrides?.firestore ?? firebase.firestore;\n const database = resolvedConfig._testOverrides?.database ?? firebase.database;\n const auth = resolvedConfig._testOverrides?.auth ?? firebase.auth;\n\n const pubsubInitializer = new PubSubInitializer({\n projectId: resolvedConfig.pubsub.projectId,\n emulatorHost: resolvedConfig.pubsub.emulatorHost,\n logger,\n _pubsub: resolvedConfig._testOverrides?.pubsub,\n });\n\n const pubsub = await pubsubInitializer.initialize();\n\n const eventStore =\n resolvedConfig._testOverrides?.eventStore ??\n createEventStore({\n firestore,\n database,\n projections: resolvedConfig.projections,\n collections: resolvedConfig.eventStore.collections,\n logger,\n });\n\n const messageBus =\n resolvedConfig._testOverrides?.messageBus ??\n getPubSubMessageBus({\n pubsub,\n useEmulator: pubsubInitializer.isEmulatorMode(),\n topicPrefix: resolvedConfig.pubsub.topicPrefix,\n subscriptionOptions: resolvedConfig.pubsub.subscriptionOptions,\n autoCreateResources: resolvedConfig.pubsub.autoCreateResources,\n cleanupOnClose: resolvedConfig.pubsub.cleanupOnClose,\n closePubSubClient: resolvedConfig.pubsub.closePubSubClient,\n observability: { logger: createPubSubLogger(logger) },\n });\n\n this.shutdownManager = new GracefulShutdown({\n ...resolvedConfig.shutdown,\n logger,\n });\n\n this.registerDefaultShutdownTasks({\n messageBus,\n firestore,\n firebaseApp: firebase.app,\n });\n\n this.dependencyChecker = new DependencyChecker({ logger });\n\n this.context = {\n serviceName: resolvedConfig.serviceName,\n firebase: {\n app: firebase.app,\n firestore,\n database,\n auth,\n },\n firestore,\n database,\n auth,\n pubsub,\n eventStore,\n messageBus,\n logger,\n getCurrentTime: resolvedConfig.getCurrentTime,\n config: resolvedConfig,\n };\n\n return this.context;\n }\n\n /**\n * Initialize and run dependency checks before returning context.\n */\n async start(): Promise<ServiceBootstrapContext> {\n const ctx = await this.initialize();\n const resolvedConfig = this.resolveConfig();\n\n const checks: DependencyCheck[] = [];\n\n if (resolvedConfig.includeDefaultDependencyChecks) {\n checks.push(...this.buildDefaultDependencyChecks(ctx));\n }\n\n if (resolvedConfig.dependencies.length > 0) {\n checks.push(...resolvedConfig.dependencies);\n }\n\n if (checks.length > 0) {\n const summary = await this.getDependencyChecker().checkAll(checks);\n\n if (!summary.ok) {\n const error = new DependencyUnavailableError(summary);\n\n this.logger?.error(\n {\n err: error,\n results: summary.results,\n },\n 'Dependency checks failed',\n );\n\n if (resolvedConfig.shutdownOnDependencyFailure) {\n await this.shutdown('Dependency check failed');\n }\n\n throw error;\n }\n }\n\n this.logger?.info(\n { serviceName: resolvedConfig.serviceName },\n 'Service is running',\n );\n\n return ctx;\n }\n\n /**\n * Execute graceful shutdown tasks and return the shutdown result.\n */\n async shutdown(reason: string, exitCode = 1): Promise<GracefulShutdownResult> {\n return this.getShutdownManager().shutdown(reason, exitCode);\n }\n\n private getLogger(): BootstrapLogger | undefined {\n if (this.logger !== undefined) {\n return this.logger;\n }\n\n const resolvedConfig = this.resolveConfig();\n const observability = resolvedConfig.observability;\n\n if (observability.logger) {\n this.logger = observability.logger;\n return this.logger;\n }\n\n if (observability.createLogger === false) {\n this.logger = undefined;\n return this.logger;\n }\n\n this.logger = createLogger({\n serviceName: resolvedConfig.serviceName,\n environment: observability.environment,\n logLevel: observability.logLevel,\n });\n\n return this.logger;\n }\n\n private resolveConfig(): ResolvedServiceBootstrapConfig {\n if (this.resolvedConfig) {\n return this.resolvedConfig;\n }\n\n const missing: string[] = [];\n\n const serviceName = this.config.serviceName?.trim();\n if (!serviceName) {\n missing.push('serviceName');\n }\n\n const firestoreEmulatorHost =\n this.config.firebase?.firestoreEmulatorHost ??\n process.env.FIRESTORE_EMULATOR_HOST;\n\n const databaseEmulatorHost =\n this.config.firebase?.databaseEmulatorHost ??\n process.env.FIREBASE_DATABASE_EMULATOR_HOST;\n\n const pubsubEmulatorHost =\n this.config.pubsub?.emulatorHost ?? process.env.PUBSUB_EMULATOR_HOST;\n\n const hasEmulator =\n Boolean(firestoreEmulatorHost) ||\n Boolean(databaseEmulatorHost) ||\n Boolean(pubsubEmulatorHost);\n\n const firebaseProjectId =\n this.config.firebase?.projectId ??\n process.env.FIRESTORE_PROJECT_ID ??\n process.env.GCLOUD_PROJECT ??\n process.env.GOOGLE_CLOUD_PROJECT ??\n (hasEmulator ? 'demo-project' : undefined);\n\n if (!firebaseProjectId) {\n missing.push('firebase.projectId (or FIRESTORE_PROJECT_ID)');\n }\n\n const pubsubProjectId =\n this.config.pubsub?.projectId ??\n process.env.PUBSUB_PROJECT_ID ??\n firebaseProjectId ??\n (hasEmulator ? 'demo-project' : undefined);\n\n if (!pubsubProjectId) {\n missing.push('pubsub.projectId (or PUBSUB_PROJECT_ID)');\n }\n\n if (missing.length > 0) {\n throw new Error(`Missing required configuration: ${missing.join(', ')}`);\n }\n\n const resolvedServiceName = serviceName as string;\n const resolvedFirebaseProjectId = firebaseProjectId as string;\n const resolvedPubsubProjectId = pubsubProjectId as string;\n\n const databaseURL =\n this.config.firebase?.databaseURL ??\n this.getDatabaseURL(resolvedFirebaseProjectId, databaseEmulatorHost);\n\n const observability = {\n ...this.config.observability,\n environment:\n this.config.observability?.environment ?? process.env.NODE_ENV,\n logLevel:\n this.config.observability?.logLevel ??\n (process.env.LOG_LEVEL as\n | 'fatal'\n | 'error'\n | 'warn'\n | 'info'\n | 'debug'\n | 'trace'\n | 'silent'\n | undefined),\n createLogger: this.config.observability?.createLogger ?? true,\n };\n\n const getCurrentTime = this.config.getCurrentTime ?? (() => new Date());\n\n this.resolvedConfig = {\n serviceName: resolvedServiceName,\n firebase: {\n projectId: resolvedFirebaseProjectId,\n databaseURL,\n firestoreEmulatorHost,\n databaseEmulatorHost,\n },\n pubsub: {\n projectId: resolvedPubsubProjectId,\n emulatorHost: pubsubEmulatorHost,\n topicPrefix: this.config.pubsub?.topicPrefix ?? resolvedServiceName,\n subscriptionOptions: this.config.pubsub?.subscriptionOptions,\n autoCreateResources: this.config.pubsub?.autoCreateResources ?? true,\n cleanupOnClose: this.config.pubsub?.cleanupOnClose ?? false,\n closePubSubClient: this.config.pubsub?.closePubSubClient ?? true,\n },\n observability,\n projections: this.config.projections ?? [],\n getCurrentTime,\n dependencies: this.config.dependencies ?? [],\n includeDefaultDependencyChecks:\n this.config.includeDefaultDependencyChecks ?? true,\n autoStartMessageBus: this.config.autoStartMessageBus ?? true,\n shutdownOnDependencyFailure:\n this.config.shutdownOnDependencyFailure ?? true,\n shutdown: {\n timeoutMs: this.config.shutdown?.timeoutMs ?? 30000,\n exitOnComplete: this.config.shutdown?.exitOnComplete ?? false,\n exitFn: this.config.shutdown?.exitFn,\n },\n eventStore: {\n collections: this.config.eventStore?.collections,\n },\n _testOverrides: this.config._testOverrides,\n };\n\n return this.resolvedConfig;\n }\n\n private getDatabaseURL(projectId: string, emulatorHost?: string): string {\n if (emulatorHost) {\n return `http://${emulatorHost}?ns=${projectId}`;\n }\n return `https://${projectId}-default-rtdb.firebaseio.com`;\n }\n\n private getDependencyChecker(): DependencyChecker {\n if (!this.dependencyChecker) {\n this.dependencyChecker = new DependencyChecker({ logger: this.getLogger() });\n }\n return this.dependencyChecker;\n }\n\n private getShutdownManager(): GracefulShutdown {\n if (!this.shutdownManager) {\n this.shutdownManager = new GracefulShutdown({\n ...this.resolveConfig().shutdown,\n logger: this.getLogger(),\n });\n }\n return this.shutdownManager;\n }\n\n private registerDefaultShutdownTasks(options: {\n messageBus: MessageBusWithLifecycle;\n firestore: Firestore;\n firebaseApp: FirebaseAppNamespace.App;\n }): void {\n const shutdownManager = this.getShutdownManager();\n\n if (options.messageBus?.close) {\n shutdownManager.register({\n name: 'messageBus',\n close: () => options.messageBus.close(),\n });\n }\n\n if (typeof options.firestore.terminate === 'function') {\n shutdownManager.register({\n name: 'firestore',\n close: () => options.firestore.terminate(),\n });\n }\n\n if (typeof options.firebaseApp.delete === 'function') {\n shutdownManager.register({\n name: 'firebaseApp',\n close: () => options.firebaseApp.delete(),\n });\n }\n }\n\n private buildDefaultDependencyChecks(\n ctx: ServiceBootstrapContext,\n ): DependencyCheck[] {\n const checks: DependencyCheck[] = [];\n\n if (this.resolveConfig().autoStartMessageBus) {\n checks.push({\n name: 'PubSub',\n check: () => ctx.messageBus.start(),\n successMessage: 'Message bus started',\n });\n }\n\n checks.push({\n name: 'Firestore',\n check: async () => {\n await ctx.firestore.doc('_healthcheck/connection').get();\n },\n });\n\n checks.push({\n name: 'Realtime Database',\n check: async () => {\n await ctx.database.ref('_healthcheck/connection').once('value');\n },\n });\n\n return checks;\n }\n}\n","import admin from 'firebase-admin';\nimport type { Firestore } from '@google-cloud/firestore';\nimport type { Auth } from 'firebase-admin/auth';\nimport type { app as FirebaseAppNamespace } from 'firebase-admin';\nimport type { Database } from 'firebase-admin/database';\nimport type { FirebaseAdminLike, Logger } from '../types/config';\n\nexport type FirebaseInitializationOptions = {\n projectId: string;\n databaseURL?: string;\n firestoreEmulatorHost?: string;\n databaseEmulatorHost?: string;\n logger?: Logger;\n _firebaseAdmin?: FirebaseAdminLike;\n};\n\nexport type FirebaseInitResult = {\n app: FirebaseAppNamespace.App;\n firestore: Firestore;\n database: Database;\n auth: Auth;\n};\n\nconst normalizeContext = (data: unknown): Record<string, unknown> => {\n if (data === undefined || data === null) return {};\n if (typeof data === 'object' && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return { data };\n};\n\nconst normalizeErrorContext = (error: unknown): Record<string, unknown> => {\n if (error === undefined || error === null) return {};\n if (error instanceof Error) return { err: error };\n if (typeof error === 'object' && !Array.isArray(error)) {\n return { ...(error as Record<string, unknown>) };\n }\n return { err: error };\n};\n\nconst safeLog = {\n debug: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.debug(normalizeContext(data), msg);\n },\n info: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.info(normalizeContext(data), msg);\n },\n warn: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.warn(normalizeContext(data), msg);\n },\n error: (logger: Logger | undefined, msg: string, error?: unknown): void => {\n if (!logger) return;\n logger.error(normalizeErrorContext(error), msg);\n },\n};\n\n/**\n * Initializes Firebase Admin SDK with emulator support.\n */\nexport class FirebaseInitializer {\n private readonly options: FirebaseInitializationOptions;\n\n constructor(options: FirebaseInitializationOptions) {\n this.options = options;\n }\n\n /**\n * Returns true if emulator hosts are configured.\n */\n isEmulatorMode(): boolean {\n return Boolean(\n this.options.firestoreEmulatorHost ||\n this.options.databaseEmulatorHost ||\n process.env.FIRESTORE_EMULATOR_HOST ||\n process.env.FIREBASE_DATABASE_EMULATOR_HOST,\n );\n }\n\n /**\n * Initialize Firebase Admin and return service handles.\n */\n async initialize(): Promise<FirebaseInitResult> {\n const {\n projectId,\n databaseURL,\n firestoreEmulatorHost,\n databaseEmulatorHost,\n logger,\n } = this.options;\n\n if (firestoreEmulatorHost && !process.env.FIRESTORE_EMULATOR_HOST) {\n process.env.FIRESTORE_EMULATOR_HOST = firestoreEmulatorHost;\n }\n\n if (databaseEmulatorHost && !process.env.FIREBASE_DATABASE_EMULATOR_HOST) {\n process.env.FIREBASE_DATABASE_EMULATOR_HOST = databaseEmulatorHost;\n }\n\n const resolvedDatabaseURL =\n databaseURL ?? this.getDatabaseURL(projectId, databaseEmulatorHost);\n\n const firebaseAdmin = this.options._firebaseAdmin ?? admin;\n const app = this.getOrCreateApp(firebaseAdmin, projectId, resolvedDatabaseURL);\n\n safeLog.info(logger, 'Firebase initialized', {\n projectId,\n databaseURL: resolvedDatabaseURL,\n emulatorMode: this.isEmulatorMode(),\n });\n\n const firestore = app.firestore();\n const database = app.database();\n const auth = app.auth();\n\n if (firestoreEmulatorHost) {\n firestore.settings({\n host: firestoreEmulatorHost,\n ssl: false,\n });\n safeLog.info(logger, 'Firestore emulator configured', {\n host: firestoreEmulatorHost,\n });\n }\n\n return { app, firestore, database, auth };\n }\n\n private getOrCreateApp(\n firebaseAdmin: FirebaseAdminLike,\n projectId: string,\n databaseURL: string,\n ): FirebaseAppNamespace.App {\n const apps = (firebaseAdmin.apps ?? []).filter(\n (app): app is FirebaseAppNamespace.App => app !== null,\n );\n\n if (apps.length > 0 && firebaseAdmin.app) {\n safeLog.debug(this.options.logger, 'Reusing existing Firebase app');\n return firebaseAdmin.app();\n }\n\n safeLog.debug(this.options.logger, 'Creating Firebase app');\n return firebaseAdmin.initializeApp(\n {\n projectId,\n databaseURL,\n },\n );\n }\n\n private getDatabaseURL(projectId: string, emulatorHost?: string): string {\n if (emulatorHost) {\n return `http://${emulatorHost}?ns=${projectId}`;\n }\n return `https://${projectId}-default-rtdb.firebaseio.com`;\n }\n}\n","import { PubSub } from '@google-cloud/pubsub';\nimport type { Logger } from '../types/config';\n\nexport type PubSubInitializationOptions = {\n projectId: string;\n emulatorHost?: string;\n logger?: Logger;\n _pubsub?: PubSub;\n};\n\nconst normalizeContext = (data: unknown): Record<string, unknown> => {\n if (data === undefined || data === null) return {};\n if (typeof data === 'object' && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return { data };\n};\n\nconst normalizeErrorContext = (error: unknown): Record<string, unknown> => {\n if (error === undefined || error === null) return {};\n if (error instanceof Error) return { err: error };\n if (typeof error === 'object' && !Array.isArray(error)) {\n return { ...(error as Record<string, unknown>) };\n }\n return { err: error };\n};\n\nconst safeLog = {\n debug: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.debug(normalizeContext(data), msg);\n },\n info: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.info(normalizeContext(data), msg);\n },\n warn: (logger: Logger | undefined, msg: string, data?: unknown): void => {\n if (!logger) return;\n logger.warn(normalizeContext(data), msg);\n },\n error: (logger: Logger | undefined, msg: string, error?: unknown): void => {\n if (!logger) return;\n logger.error(normalizeErrorContext(error), msg);\n },\n};\n\n/**\n * Initializes PubSub client with optional emulator support.\n */\nexport class PubSubInitializer {\n private readonly options: PubSubInitializationOptions;\n\n constructor(options: PubSubInitializationOptions) {\n this.options = options;\n }\n\n /**\n * Returns true if emulator host is configured.\n */\n isEmulatorMode(): boolean {\n return Boolean(\n this.options.emulatorHost || process.env.PUBSUB_EMULATOR_HOST,\n );\n }\n\n /**\n * Initialize PubSub client or return injected instance.\n */\n async initialize(): Promise<PubSub> {\n const { projectId, emulatorHost, logger } = this.options;\n\n if (emulatorHost && !process.env.PUBSUB_EMULATOR_HOST) {\n process.env.PUBSUB_EMULATOR_HOST = emulatorHost;\n }\n\n if (this.options._pubsub) {\n safeLog.info(logger, 'Using provided PubSub client', {\n projectId,\n emulatorHost: emulatorHost ?? process.env.PUBSUB_EMULATOR_HOST,\n });\n return this.options._pubsub;\n }\n\n const pubsub = new PubSub({ projectId });\n\n safeLog.info(logger, 'PubSub initialized', {\n projectId,\n emulatorHost: emulatorHost ?? process.env.PUBSUB_EMULATOR_HOST,\n emulatorMode: this.isEmulatorMode(),\n });\n\n return pubsub;\n }\n}\n","import {\n getFirestoreEventStore,\n type FirestoreEventStoreOptions,\n} from '@emmett-community/emmett-google-firestore';\nimport {\n wireRealtimeDBProjections,\n type RealtimeDBInlineProjectionDefinition,\n} from '@emmett-community/emmett-google-realtime-db';\nimport type { EventStore } from '@event-driven-io/emmett';\nimport type { Firestore } from '@google-cloud/firestore';\nimport type { Database } from 'firebase-admin/database';\nimport type { Logger } from '../types/config';\n\nexport type EventStoreFactoryOptions = {\n firestore: Firestore;\n database: Database;\n projections?: RealtimeDBInlineProjectionDefinition[];\n logger?: Logger;\n collections?: FirestoreEventStoreOptions['collections'];\n};\n\n/**\n * Create a Firestore-backed event store and wire RealtimeDB projections if provided.\n */\nexport const createEventStore = <T extends EventStore = EventStore>(\n options: EventStoreFactoryOptions,\n): T => {\n const { firestore, database, projections, logger, collections } = options;\n const observability = logger ? { logger } : undefined;\n\n const baseEventStore = getFirestoreEventStore(firestore, {\n observability,\n collections,\n });\n\n if (projections && projections.length > 0) {\n return wireRealtimeDBProjections({\n eventStore: baseEventStore as unknown as T,\n database,\n projections,\n observability,\n }) as T;\n }\n\n return baseEventStore as unknown as T;\n};\n","import type { DependencyCheck, Logger } from '../types/config';\n\nexport class DependencyTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Dependency check timed out after ${timeoutMs}ms`);\n this.name = 'DependencyTimeoutError';\n }\n}\n\nexport type DependencyCheckResult = {\n name: string;\n ok: boolean;\n required: boolean;\n durationMs: number;\n timedOut: boolean;\n error?: unknown;\n};\n\nexport type DependencyCheckSummary = {\n ok: boolean;\n results: DependencyCheckResult[];\n};\n\nconst normalizeErrorContext = (error: unknown): Record<string, unknown> => {\n if (error === undefined || error === null) return {};\n if (error instanceof Error) return { err: error };\n if (typeof error === 'object' && !Array.isArray(error)) {\n return { ...(error as Record<string, unknown>) };\n }\n return { err: error };\n};\n\nconst withTimeout = async <T>(promise: Promise<T>, timeoutMs?: number): Promise<T> => {\n if (!timeoutMs || timeoutMs <= 0) return promise;\n\n let timeoutId: NodeJS.Timeout | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new DependencyTimeoutError(timeoutMs));\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n};\n\n/**\n * Helper for one-off dependency checks with optional logging.\n */\nexport const startDependency = async (\n dependency: string,\n startFn: () => Promise<void>,\n options?: {\n logger?: Logger;\n successMessage?: string;\n timeoutMs?: number;\n },\n): Promise<boolean> => {\n const { logger, successMessage, timeoutMs } = options ?? {};\n const startTime = Date.now();\n\n try {\n await withTimeout(startFn(), timeoutMs);\n logger?.info({ dependency, durationMs: Date.now() - startTime }, successMessage);\n return true;\n } catch (error) {\n logger?.warn(\n { dependency, durationMs: Date.now() - startTime, ...normalizeErrorContext(error) },\n 'Unable to reach dependency',\n );\n return false;\n }\n};\n\n/**\n * Executes dependency checks with optional timeouts.\n */\nexport class DependencyChecker {\n private readonly logger?: Logger;\n private readonly defaultTimeoutMs?: number;\n\n constructor(options?: { logger?: Logger; defaultTimeoutMs?: number }) {\n this.logger = options?.logger;\n this.defaultTimeoutMs = options?.defaultTimeoutMs;\n }\n\n async check(dependency: DependencyCheck): Promise<DependencyCheckResult> {\n const start = Date.now();\n const timeoutMs = dependency.timeoutMs ?? this.defaultTimeoutMs;\n\n try {\n await withTimeout(dependency.check(), timeoutMs);\n\n if (dependency.successMessage) {\n this.logger?.info(\n { dependency: dependency.name, durationMs: Date.now() - start },\n dependency.successMessage,\n );\n }\n\n return {\n name: dependency.name,\n ok: true,\n required: dependency.required ?? true,\n durationMs: Date.now() - start,\n timedOut: false,\n };\n } catch (error) {\n const timedOut = error instanceof DependencyTimeoutError;\n\n this.logger?.warn(\n {\n dependency: dependency.name,\n durationMs: Date.now() - start,\n timedOut,\n ...normalizeErrorContext(error),\n },\n 'Dependency check failed',\n );\n\n return {\n name: dependency.name,\n ok: false,\n required: dependency.required ?? true,\n durationMs: Date.now() - start,\n timedOut,\n error,\n };\n }\n }\n\n async checkAll(dependencies: DependencyCheck[]): Promise<DependencyCheckSummary> {\n const results: DependencyCheckResult[] = [];\n\n for (const dependency of dependencies) {\n results.push(await this.check(dependency));\n }\n\n const ok = results.every((result) => result.ok || !result.required);\n\n return { ok, results };\n }\n}\n","import type { GracefulShutdownConfig, Logger } from '../types/config';\n\nexport class ShutdownTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Shutdown task timed out after ${timeoutMs}ms`);\n this.name = 'ShutdownTimeoutError';\n }\n}\n\nexport type ShutdownTask = {\n name: string;\n close: () => Promise<void>;\n timeoutMs?: number;\n};\n\nexport type ShutdownTaskResult = {\n name: string;\n ok: boolean;\n timedOut: boolean;\n durationMs: number;\n error?: unknown;\n};\n\nexport type GracefulShutdownResult = {\n reason: string;\n exitCode: number;\n tasks: ShutdownTaskResult[];\n};\n\nconst normalizeContext = (data: unknown): Record<string, unknown> => {\n if (data === undefined || data === null) return {};\n if (typeof data === 'object' && !Array.isArray(data)) {\n return { ...(data as Record<string, unknown>) };\n }\n return { data };\n};\n\nconst normalizeErrorContext = (error: unknown): Record<string, unknown> => {\n if (error === undefined || error === null) return {};\n if (error instanceof Error) return { err: error };\n if (typeof error === 'object' && !Array.isArray(error)) {\n return { ...(error as Record<string, unknown>) };\n }\n return { err: error };\n};\n\nconst withTimeout = async <T>(promise: Promise<T>, timeoutMs?: number): Promise<T> => {\n if (!timeoutMs || timeoutMs <= 0) return promise;\n\n let timeoutId: NodeJS.Timeout | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new ShutdownTimeoutError(timeoutMs));\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n};\n\n/**\n * Runs shutdown tasks with timeout handling and optional exit.\n */\nexport class GracefulShutdown {\n private readonly logger?: Logger;\n private readonly timeoutMs?: number;\n private readonly exitOnComplete: boolean;\n private readonly exitFn: (code: number) => void;\n private readonly tasks: ShutdownTask[] = [];\n private shuttingDown = false;\n private lastResult?: GracefulShutdownResult;\n\n constructor(options?: GracefulShutdownConfig & { logger?: Logger }) {\n this.logger = options?.logger;\n this.timeoutMs = options?.timeoutMs;\n this.exitOnComplete = options?.exitOnComplete ?? false;\n this.exitFn = options?.exitFn ?? process.exit;\n }\n\n /**\n * Register a shutdown task.\n */\n register(task: ShutdownTask): void {\n this.tasks.push(task);\n }\n\n /**\n * Execute all shutdown tasks and return the aggregated result.\n */\n async shutdown(reason: string, exitCode = 1): Promise<GracefulShutdownResult> {\n if (this.shuttingDown && this.lastResult) {\n return this.lastResult;\n }\n\n this.shuttingDown = true;\n this.logger?.info({ reason }, 'Shutting down gracefully');\n\n const results: ShutdownTaskResult[] = [];\n\n for (const task of this.tasks) {\n const start = Date.now();\n const timeoutMs = task.timeoutMs ?? this.timeoutMs;\n\n try {\n await withTimeout(task.close(), timeoutMs);\n results.push({\n name: task.name,\n ok: true,\n timedOut: false,\n durationMs: Date.now() - start,\n });\n this.logger?.info(\n { task: task.name, durationMs: Date.now() - start },\n 'Shutdown task completed',\n );\n } catch (error) {\n const timedOut = error instanceof ShutdownTimeoutError;\n results.push({\n name: task.name,\n ok: false,\n timedOut,\n durationMs: Date.now() - start,\n error,\n });\n this.logger?.warn(\n {\n task: task.name,\n timedOut,\n durationMs: Date.now() - start,\n ...normalizeErrorContext(error),\n },\n 'Shutdown task failed',\n );\n }\n }\n\n const failed = results.some((result) => !result.ok || result.timedOut);\n const finalExitCode = failed ? exitCode : 0;\n\n if (failed) {\n const failedTasks = results\n .filter((result) => !result.ok || result.timedOut)\n .map((result) => result.name);\n this.logger?.error(\n normalizeContext({ failedTasks }),\n 'Shutdown completed with failures',\n );\n } else {\n this.logger?.info({}, 'Shutdown completed');\n }\n\n const result = { reason, exitCode: finalExitCode, tasks: results };\n this.lastResult = result;\n\n if (this.exitOnComplete) {\n this.exitFn(finalExitCode);\n }\n\n return result;\n }\n}\n","import type { Logger } from '../types/config';\n\nexport type SignalHandlerOptions = {\n shutdown: (reason: string, exitCode?: number) => void | Promise<void>;\n signals?: NodeJS.Signals[];\n logger?: Logger;\n exitCode?: number;\n};\n\n/**\n * Register process signal handlers and return an unregister function.\n */\nexport const registerSignalHandlers = (\n options: SignalHandlerOptions,\n): (() => void) => {\n const signals = options.signals ?? ['SIGINT', 'SIGTERM'];\n const handlers = new Map<NodeJS.Signals, () => void>();\n\n for (const signal of signals) {\n const handler = () => {\n options.logger?.info({ signal }, 'Shutdown signal received');\n void options.shutdown(`Signal ${signal} received`, options.exitCode ?? 0);\n };\n\n handlers.set(signal, handler);\n process.on(signal, handler);\n }\n\n return () => {\n for (const [signal, handler] of handlers.entries()) {\n process.off(signal, handler);\n }\n };\n};\n"],"mappings":"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","names":["admin","normalizeContext","normalizeErrorContext","safeLog","normalizeErrorContext","normalizeContext","normalizeErrorContext","withTimeout","result","normalizeContext","normalizeErrorContext","path","registerSignalHandlers","import_emmett_google_realtime_db","import_emmett_expressjs_with_openapi"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/emmett-google-services-bootstrap/emmett-google-services-bootstrap/dist/index.cjs","../src/bootstrap/probes.ts","../src/index.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;ACdA,6FAAqC;AAO9B,IAAM,UAAA,EAAY,4CAAA,MAAG,CAAA,EAAA,GAAY,4CAAA,EAAK,IAAA,EAAM,EAAE,MAAA,EAAQ,KAAK,EAAE,CAAC,CAAC,CAAA;AAO/D,IAAM,SAAA,EAAW,CAAC,GAAA,EAAA,GACvB,4CAAA,MAAG,CAAA,EAAA,GAAY;AACb,EAAA,MAAM,QAAA,EAAU,MAAM,GAAA,CAAI,cAAA,CAAe,CAAA;AACzC,EAAA,MAAM,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,EAAA,GAAA,CAAY;AAAA,IAC9C,IAAA,EAAM,MAAA,CAAO,IAAA;AAAA,IACb,EAAA,EAAI,MAAA,CAAO;AAAA,EACb,CAAA,CAAE,CAAA;AAEF,EAAA,OAAO,OAAA,CAAQ,GAAA,EACX,4CAAA,EAAK,IAAA,EAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,OAAO,EAAE,CAAC,EAAA,EACxC,sDAAA,GAAa,EAAK,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,aAAA,EAAe,OAAO,EAAE,CAAC,CAAA;AACnE,CAAC,CAAA;ADAH;AACA;AEpBA,qFAA2C;AAC3C;AACE;AACA;AACA;AACA;AACA;AAAA;AFuBF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,8sCAAC","file":"/home/runner/work/emmett-google-services-bootstrap/emmett-google-services-bootstrap/dist/index.cjs","sourcesContent":[null,"import { HttpResponse, OK, on } from '@emmett-community/emmett-expressjs-with-openapi';\nimport type { ServiceBootstrapContext } from './ServiceBootstrap';\n\n/**\n * Handler for `GET /health` (liveness): the process is up and serving requests.\n * Wire it to the `getHealth` operation of the service contract.\n */\nexport const getHealth = on(async () => OK({ body: { status: 'ok' } }));\n\n/**\n * Handler for `GET /ready` (readiness): answers 200 when the stores, the message bus and the\n * configured dependencies answer, and 503 with the failed checks otherwise.\n * Wire it to the `getReady` operation of the service contract.\n */\nexport const getReady = (ctx: Pick<ServiceBootstrapContext, 'checkReadiness'>) =>\n on(async () => {\n const summary = await ctx.checkReadiness();\n const checks = summary.results.map((result) => ({\n name: result.name,\n ok: result.ok,\n }));\n\n return summary.ok\n ? OK({ body: { status: 'ready', checks } })\n : HttpResponse(503, { body: { status: 'unavailable', checks } });\n });\n","export * from './bootstrap';\nexport * from './types';\nexport * from './firebase';\nexport * from './pubsub';\nexport * from './lifecycle';\nexport * from './eventstore';\nexport { realtimeDBInlineProjection } from '@emmett-community/emmett-google-realtime-db';\nexport {\n createFirebaseAuthSecurityHandlers,\n lazyApplication,\n NoContent,\n OK,\n on,\n type ImportedHandlerModules,\n} from '@emmett-community/emmett-expressjs-with-openapi';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,314 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
1
|
+
import { S as ServiceBootstrapContext, L as Logger, F as FirebaseAdminLike } from './ServiceBootstrap-BjFoQDd_.cjs';
|
|
2
|
+
export { C as CreateAppOptions, e as DependencyCheck, k as DependencyCheckResult, l as DependencyCheckSummary, m as DependencyChecker, j as DependencyTimeoutError, D as DependencyUnavailableError, d as FirebaseConfig, r as GracefulShutdown, G as GracefulShutdownConfig, q as GracefulShutdownResult, c as LogLevel, M as MessageBusWithLifecycle, O as ObservabilityConfig, P as PubSubConfig, R as ResolvedFirebaseConfig, h as ResolvedPubSubConfig, i as ResolvedServiceBootstrapConfig, b as ServiceBootstrap, g as ServiceBootstrapConfig, f as ServiceBootstrapOverrides, o as ShutdownTask, p as ShutdownTaskResult, n as ShutdownTimeoutError, a as StartApiOptions, s as startDependency } from './ServiceBootstrap-BjFoQDd_.cjs';
|
|
3
|
+
import * as express from 'express';
|
|
4
|
+
import * as qs from 'qs';
|
|
5
|
+
import * as express_serve_static_core from 'express-serve-static-core';
|
|
5
6
|
import { Firestore } from '@google-cloud/firestore';
|
|
6
|
-
import { PubSub } from '@google-cloud/pubsub';
|
|
7
7
|
import { Auth } from 'firebase-admin/auth';
|
|
8
8
|
import { app } from 'firebase-admin';
|
|
9
9
|
import { Database } from 'firebase-admin/database';
|
|
10
|
-
import {
|
|
10
|
+
import { PubSub } from '@google-cloud/pubsub';
|
|
11
|
+
import { FirestoreEventStoreOptions } from '@emmett-community/emmett-google-firestore';
|
|
11
12
|
import { RealtimeDBInlineProjectionDefinition } from '@emmett-community/emmett-google-realtime-db';
|
|
12
13
|
export { realtimeDBInlineProjection } from '@emmett-community/emmett-google-realtime-db';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Canonical logger contract used across Emmett packages.
|
|
18
|
-
* Matches Pino style (context, message).
|
|
19
|
-
*/
|
|
20
|
-
interface Logger {
|
|
21
|
-
debug(context: Record<string, unknown>, message?: string): void;
|
|
22
|
-
info(context: Record<string, unknown>, message?: string): void;
|
|
23
|
-
warn(context: Record<string, unknown>, message?: string): void;
|
|
24
|
-
error(context: Record<string, unknown>, message?: string): void;
|
|
25
|
-
}
|
|
26
|
-
type ObservabilityConfig = {
|
|
27
|
-
logger?: Logger;
|
|
28
|
-
logLevel?: LogLevel;
|
|
29
|
-
environment?: string;
|
|
30
|
-
createLogger?: boolean;
|
|
31
|
-
};
|
|
32
|
-
type FirebaseConfig = {
|
|
33
|
-
projectId?: string;
|
|
34
|
-
databaseURL?: string;
|
|
35
|
-
firestoreEmulatorHost?: string;
|
|
36
|
-
databaseEmulatorHost?: string;
|
|
37
|
-
};
|
|
38
|
-
type PubSubConfig = {
|
|
39
|
-
projectId?: string;
|
|
40
|
-
emulatorHost?: string;
|
|
41
|
-
topicPrefix?: string;
|
|
42
|
-
subscriptionOptions?: SubscriptionOptions;
|
|
43
|
-
autoCreateResources?: boolean;
|
|
44
|
-
cleanupOnClose?: boolean;
|
|
45
|
-
closePubSubClient?: boolean;
|
|
46
|
-
};
|
|
47
|
-
type DependencyCheck = {
|
|
48
|
-
name: string;
|
|
49
|
-
check: () => Promise<void>;
|
|
50
|
-
successMessage?: string;
|
|
51
|
-
timeoutMs?: number;
|
|
52
|
-
required?: boolean;
|
|
53
|
-
};
|
|
54
|
-
type GracefulShutdownConfig = {
|
|
55
|
-
timeoutMs?: number;
|
|
56
|
-
exitOnComplete?: boolean;
|
|
57
|
-
exitFn?: (code: number) => void;
|
|
58
|
-
};
|
|
59
|
-
type MessageBusWithLifecycle = MessageBus & EventSubscription & CommandProcessor & ScheduledMessageProcessor & PubSubMessageBusLifecycle;
|
|
60
|
-
interface FirebaseAdminLike {
|
|
61
|
-
initializeApp(options: {
|
|
62
|
-
projectId: string;
|
|
63
|
-
databaseURL?: string;
|
|
64
|
-
}, name?: string): app.App;
|
|
65
|
-
app?: () => app.App;
|
|
66
|
-
apps?: Array<app.App | null>;
|
|
67
|
-
}
|
|
68
|
-
type ServiceBootstrapOverrides = {
|
|
69
|
-
firebaseAdmin?: FirebaseAdminLike;
|
|
70
|
-
firestore?: Firestore;
|
|
71
|
-
database?: Database;
|
|
72
|
-
auth?: Auth;
|
|
73
|
-
pubsub?: PubSub;
|
|
74
|
-
eventStore?: EventStore;
|
|
75
|
-
messageBus?: MessageBusWithLifecycle;
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Main configuration for ServiceBootstrap.
|
|
79
|
-
* Values can be provided explicitly or via environment variables.
|
|
80
|
-
*/
|
|
81
|
-
type ServiceBootstrapConfig = {
|
|
82
|
-
serviceName: string;
|
|
83
|
-
firebase?: FirebaseConfig;
|
|
84
|
-
pubsub?: PubSubConfig;
|
|
85
|
-
eventStore?: {
|
|
86
|
-
collections?: FirestoreEventStoreOptions['collections'];
|
|
87
|
-
};
|
|
88
|
-
observability?: ObservabilityConfig;
|
|
89
|
-
projections?: RealtimeDBInlineProjectionDefinition[];
|
|
90
|
-
getCurrentTime?: () => Date;
|
|
91
|
-
dependencies?: DependencyCheck[];
|
|
92
|
-
includeDefaultDependencyChecks?: boolean;
|
|
93
|
-
autoStartMessageBus?: boolean;
|
|
94
|
-
shutdownOnDependencyFailure?: boolean;
|
|
95
|
-
shutdown?: GracefulShutdownConfig;
|
|
96
|
-
_testOverrides?: ServiceBootstrapOverrides;
|
|
97
|
-
};
|
|
98
|
-
type ResolvedFirebaseConfig = {
|
|
99
|
-
projectId: string;
|
|
100
|
-
databaseURL: string;
|
|
101
|
-
firestoreEmulatorHost?: string;
|
|
102
|
-
databaseEmulatorHost?: string;
|
|
103
|
-
};
|
|
104
|
-
type ResolvedPubSubConfig = {
|
|
105
|
-
projectId: string;
|
|
106
|
-
emulatorHost?: string;
|
|
107
|
-
topicPrefix: string;
|
|
108
|
-
subscriptionOptions?: SubscriptionOptions;
|
|
109
|
-
autoCreateResources: boolean;
|
|
110
|
-
cleanupOnClose: boolean;
|
|
111
|
-
closePubSubClient: boolean;
|
|
112
|
-
};
|
|
113
|
-
type ResolvedServiceBootstrapConfig = {
|
|
114
|
-
serviceName: string;
|
|
115
|
-
firebase: ResolvedFirebaseConfig;
|
|
116
|
-
pubsub: ResolvedPubSubConfig;
|
|
117
|
-
eventStore: {
|
|
118
|
-
collections?: FirestoreEventStoreOptions['collections'];
|
|
119
|
-
};
|
|
120
|
-
observability: ObservabilityConfig;
|
|
121
|
-
projections: RealtimeDBInlineProjectionDefinition[];
|
|
122
|
-
getCurrentTime: () => Date;
|
|
123
|
-
dependencies: DependencyCheck[];
|
|
124
|
-
includeDefaultDependencyChecks: boolean;
|
|
125
|
-
autoStartMessageBus: boolean;
|
|
126
|
-
shutdownOnDependencyFailure: boolean;
|
|
127
|
-
shutdown: GracefulShutdownConfig;
|
|
128
|
-
_testOverrides?: ServiceBootstrapOverrides;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
declare class DependencyTimeoutError extends Error {
|
|
132
|
-
constructor(timeoutMs: number);
|
|
133
|
-
}
|
|
134
|
-
type DependencyCheckResult = {
|
|
135
|
-
name: string;
|
|
136
|
-
ok: boolean;
|
|
137
|
-
required: boolean;
|
|
138
|
-
durationMs: number;
|
|
139
|
-
timedOut: boolean;
|
|
140
|
-
error?: unknown;
|
|
141
|
-
};
|
|
142
|
-
type DependencyCheckSummary = {
|
|
143
|
-
ok: boolean;
|
|
144
|
-
results: DependencyCheckResult[];
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
* Helper for one-off dependency checks with optional logging.
|
|
148
|
-
*/
|
|
149
|
-
declare const startDependency: (dependency: string, startFn: () => Promise<void>, options?: {
|
|
150
|
-
logger?: Logger;
|
|
151
|
-
successMessage?: string;
|
|
152
|
-
timeoutMs?: number;
|
|
153
|
-
}) => Promise<boolean>;
|
|
154
|
-
/**
|
|
155
|
-
* Executes dependency checks with optional timeouts.
|
|
156
|
-
*/
|
|
157
|
-
declare class DependencyChecker {
|
|
158
|
-
private readonly logger?;
|
|
159
|
-
private readonly defaultTimeoutMs?;
|
|
160
|
-
constructor(options?: {
|
|
161
|
-
logger?: Logger;
|
|
162
|
-
defaultTimeoutMs?: number;
|
|
163
|
-
});
|
|
164
|
-
check(dependency: DependencyCheck): Promise<DependencyCheckResult>;
|
|
165
|
-
checkAll(dependencies: DependencyCheck[]): Promise<DependencyCheckSummary>;
|
|
166
|
-
}
|
|
14
|
+
import { EventStore } from '@event-driven-io/emmett';
|
|
15
|
+
export { ImportedHandlerModules, NoContent, OK, createFirebaseAuthSecurityHandlers, lazyApplication, on } from '@emmett-community/emmett-expressjs-with-openapi';
|
|
16
|
+
import '@emmett-community/emmett-google-pubsub';
|
|
167
17
|
|
|
168
|
-
declare class ShutdownTimeoutError extends Error {
|
|
169
|
-
constructor(timeoutMs: number);
|
|
170
|
-
}
|
|
171
|
-
type ShutdownTask = {
|
|
172
|
-
name: string;
|
|
173
|
-
close: () => Promise<void>;
|
|
174
|
-
timeoutMs?: number;
|
|
175
|
-
};
|
|
176
|
-
type ShutdownTaskResult = {
|
|
177
|
-
name: string;
|
|
178
|
-
ok: boolean;
|
|
179
|
-
timedOut: boolean;
|
|
180
|
-
durationMs: number;
|
|
181
|
-
error?: unknown;
|
|
182
|
-
};
|
|
183
|
-
type GracefulShutdownResult = {
|
|
184
|
-
reason: string;
|
|
185
|
-
exitCode: number;
|
|
186
|
-
tasks: ShutdownTaskResult[];
|
|
187
|
-
};
|
|
188
18
|
/**
|
|
189
|
-
*
|
|
19
|
+
* Handler for `GET /health` (liveness): the process is up and serving requests.
|
|
20
|
+
* Wire it to the `getHealth` operation of the service contract.
|
|
190
21
|
*/
|
|
191
|
-
declare
|
|
192
|
-
private readonly logger?;
|
|
193
|
-
private readonly timeoutMs?;
|
|
194
|
-
private readonly exitOnComplete;
|
|
195
|
-
private readonly exitFn;
|
|
196
|
-
private readonly tasks;
|
|
197
|
-
private shuttingDown;
|
|
198
|
-
private lastResult?;
|
|
199
|
-
constructor(options?: GracefulShutdownConfig & {
|
|
200
|
-
logger?: Logger;
|
|
201
|
-
});
|
|
202
|
-
/**
|
|
203
|
-
* Register a shutdown task.
|
|
204
|
-
*/
|
|
205
|
-
register(task: ShutdownTask): void;
|
|
206
|
-
/**
|
|
207
|
-
* Execute all shutdown tasks and return the aggregated result.
|
|
208
|
-
*/
|
|
209
|
-
shutdown(reason: string, exitCode?: number): Promise<GracefulShutdownResult>;
|
|
210
|
-
}
|
|
211
|
-
|
|
22
|
+
declare const getHealth: (request: express.Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, response: express.Response, _next: express.NextFunction) => Promise<void>;
|
|
212
23
|
/**
|
|
213
|
-
*
|
|
24
|
+
* Handler for `GET /ready` (readiness): answers 200 when the stores, the message bus and the
|
|
25
|
+
* configured dependencies answer, and 503 with the failed checks otherwise.
|
|
26
|
+
* Wire it to the `getReady` operation of the service contract.
|
|
214
27
|
*/
|
|
215
|
-
|
|
216
|
-
serviceName: string;
|
|
217
|
-
firebase: {
|
|
218
|
-
app: app.App;
|
|
219
|
-
firestore: Firestore;
|
|
220
|
-
database: Database;
|
|
221
|
-
auth: Auth;
|
|
222
|
-
};
|
|
223
|
-
firestore: Firestore;
|
|
224
|
-
database: Database;
|
|
225
|
-
auth: Auth;
|
|
226
|
-
pubsub: PubSub;
|
|
227
|
-
eventStore: EventStore;
|
|
228
|
-
messageBus: MessageBusWithLifecycle;
|
|
229
|
-
logger?: Logger;
|
|
230
|
-
getCurrentTime: () => Date;
|
|
231
|
-
config: ResolvedServiceBootstrapConfig;
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Error thrown when required dependencies fail health checks.
|
|
235
|
-
*/
|
|
236
|
-
declare class DependencyUnavailableError extends Error {
|
|
237
|
-
readonly summary: DependencyCheckSummary;
|
|
238
|
-
constructor(summary: DependencyCheckSummary);
|
|
239
|
-
}
|
|
240
|
-
type CreateAppOptions = {
|
|
241
|
-
openApiPath: string;
|
|
242
|
-
handlersPath: string;
|
|
243
|
-
initializeHandlers: (handlers?: ImportedHandlerModules) => void | Promise<void>;
|
|
244
|
-
openApiOptions?: Partial<Omit<OpenApiValidatorOptions, 'apiSpec' | 'operationHandlers' | 'initializeHandlers'>>;
|
|
245
|
-
appOptions?: Omit<ApplicationOptions, 'openApiValidator' | 'observability'>;
|
|
246
|
-
};
|
|
247
|
-
type StartApiOptions = Omit<CreateAppOptions, 'initializeHandlers'> & {
|
|
248
|
-
initializeHandlers: (handlers: ImportedHandlerModules | undefined, ctx: ServiceBootstrapContext) => void | Promise<void>;
|
|
249
|
-
port?: number;
|
|
250
|
-
registerSignalHandlers?: boolean;
|
|
251
|
-
beforeStart?: (ctx: ServiceBootstrapContext) => void | Promise<void>;
|
|
252
|
-
};
|
|
253
|
-
/**
|
|
254
|
-
* Orchestrates Firebase, PubSub, event store, and lifecycle utilities.
|
|
255
|
-
*/
|
|
256
|
-
declare class ServiceBootstrap {
|
|
257
|
-
private readonly config;
|
|
258
|
-
private resolvedConfig?;
|
|
259
|
-
private logger?;
|
|
260
|
-
private context?;
|
|
261
|
-
private dependencyChecker?;
|
|
262
|
-
private shutdownManager?;
|
|
263
|
-
constructor(config: ServiceBootstrapConfig);
|
|
264
|
-
/**
|
|
265
|
-
* Resolve configuration with defaults and environment variables.
|
|
266
|
-
*/
|
|
267
|
-
getConfig(): ResolvedServiceBootstrapConfig;
|
|
268
|
-
/**
|
|
269
|
-
* Return the initialized context if available.
|
|
270
|
-
*/
|
|
271
|
-
getContext(): ServiceBootstrapContext | undefined;
|
|
272
|
-
/**
|
|
273
|
-
* Register process signal handlers that trigger shutdown.
|
|
274
|
-
*/
|
|
275
|
-
registerSignalHandlers(options?: {
|
|
276
|
-
signals?: NodeJS.Signals[];
|
|
277
|
-
exitCode?: number;
|
|
278
|
-
}): () => void;
|
|
279
|
-
/**
|
|
280
|
-
* Create an Express app using emmett-expressjs-with-openapi defaults.
|
|
281
|
-
*/
|
|
282
|
-
createApp(options: CreateAppOptions): Promise<Application>;
|
|
283
|
-
/**
|
|
284
|
-
* Initialize, run dependency checks, create the app, and start the HTTP server.
|
|
285
|
-
*/
|
|
286
|
-
startApi(options: StartApiOptions): Promise<{
|
|
287
|
-
app: Application;
|
|
288
|
-
server: ReturnType<typeof startAPI>;
|
|
289
|
-
context: ServiceBootstrapContext;
|
|
290
|
-
}>;
|
|
291
|
-
/**
|
|
292
|
-
* Initialize Firebase, PubSub, and event store wiring.
|
|
293
|
-
* Does not execute dependency checks.
|
|
294
|
-
*/
|
|
295
|
-
initialize(): Promise<ServiceBootstrapContext>;
|
|
296
|
-
/**
|
|
297
|
-
* Initialize and run dependency checks before returning context.
|
|
298
|
-
*/
|
|
299
|
-
start(): Promise<ServiceBootstrapContext>;
|
|
300
|
-
/**
|
|
301
|
-
* Execute graceful shutdown tasks and return the shutdown result.
|
|
302
|
-
*/
|
|
303
|
-
shutdown(reason: string, exitCode?: number): Promise<GracefulShutdownResult>;
|
|
304
|
-
private getLogger;
|
|
305
|
-
private resolveConfig;
|
|
306
|
-
private getDatabaseURL;
|
|
307
|
-
private getDependencyChecker;
|
|
308
|
-
private getShutdownManager;
|
|
309
|
-
private registerDefaultShutdownTasks;
|
|
310
|
-
private buildDefaultDependencyChecks;
|
|
311
|
-
}
|
|
28
|
+
declare const getReady: (ctx: Pick<ServiceBootstrapContext, "checkReadiness">) => (request: express.Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, response: express.Response, _next: express.NextFunction) => Promise<void>;
|
|
312
29
|
|
|
313
30
|
type FirebaseInitializationOptions = {
|
|
314
31
|
projectId: string;
|
|
@@ -381,10 +98,11 @@ type EventStoreFactoryOptions = {
|
|
|
381
98
|
projections?: RealtimeDBInlineProjectionDefinition[];
|
|
382
99
|
logger?: Logger;
|
|
383
100
|
collections?: FirestoreEventStoreOptions['collections'];
|
|
101
|
+
hooks?: FirestoreEventStoreOptions['hooks'];
|
|
384
102
|
};
|
|
385
103
|
/**
|
|
386
104
|
* Create a Firestore-backed event store and wire RealtimeDB projections if provided.
|
|
387
105
|
*/
|
|
388
106
|
declare const createEventStore: <T extends EventStore = EventStore>(options: EventStoreFactoryOptions) => T;
|
|
389
107
|
|
|
390
|
-
export { type
|
|
108
|
+
export { type EventStoreFactoryOptions, FirebaseAdminLike, type FirebaseInitResult, type FirebaseInitializationOptions, FirebaseInitializer, Logger, type PubSubInitializationOptions, PubSubInitializer, ServiceBootstrapContext, type SignalHandlerOptions, createEventStore, getHealth, getReady, registerSignalHandlers };
|