@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/README.md
CHANGED
|
@@ -87,6 +87,7 @@ await bootstrap.startApi({
|
|
|
87
87
|
- `FIREBASE_DATABASE_EMULATOR_HOST`: Realtime DB emulator host
|
|
88
88
|
- `PUBSUB_PROJECT_ID`: PubSub project id
|
|
89
89
|
- `PUBSUB_EMULATOR_HOST`: PubSub emulator host
|
|
90
|
+
- `PUBSUB_TOPIC_PREFIX`: prefix of topics and subscriptions (used when `pubsub.topicPrefix` is not set; defaults to the service name)
|
|
90
91
|
- `LOG_LEVEL`: default log level for built-in logger
|
|
91
92
|
- `NODE_ENV`: forwarded to logging helpers
|
|
92
93
|
|
|
@@ -104,6 +105,7 @@ const config: ServiceBootstrapConfig = {
|
|
|
104
105
|
pubsub: {
|
|
105
106
|
projectId: 'demo-project',
|
|
106
107
|
topicPrefix: 'user-service',
|
|
108
|
+
subscriptionId: 'user-service',
|
|
107
109
|
autoCreateResources: true,
|
|
108
110
|
},
|
|
109
111
|
eventStore: {
|
|
@@ -118,16 +120,30 @@ const config: ServiceBootstrapConfig = {
|
|
|
118
120
|
logLevel: 'info',
|
|
119
121
|
},
|
|
120
122
|
includeDefaultDependencyChecks: true,
|
|
123
|
+
includeRealtimeDatabaseCheck: true,
|
|
121
124
|
autoStartMessageBus: true,
|
|
122
125
|
shutdownOnDependencyFailure: true,
|
|
123
126
|
};
|
|
124
127
|
```
|
|
125
128
|
|
|
129
|
+
### Subscriptions
|
|
130
|
+
|
|
131
|
+
Event and command subscriptions are named after the service, so they survive restarts and the replicas of a service share them:
|
|
132
|
+
|
|
133
|
+
- Events: `<topicPrefix>-evt-<EventType>-<subscriptionId>`. An event normally reaches one replica, but it can be delivered again, so handlers must be idempotent.
|
|
134
|
+
- Commands: `<topicPrefix>-cmd-<CommandType>-<subscriptionId>`, so a command has one handler.
|
|
135
|
+
|
|
136
|
+
`pubsub.subscriptionId` defaults to the service name. `includeRealtimeDatabaseCheck: false` leaves the Realtime Database out of the default dependency checks, for services that do not use it.
|
|
137
|
+
|
|
126
138
|
### Event store collection names
|
|
127
139
|
|
|
128
140
|
- `eventStore.collections.streams`: Firestore collection that stores stream metadata (defaults to `"streams"`).
|
|
129
141
|
- `eventStore.collections.counters`: Firestore collection for shared counters (defaults to `"_counters"`).
|
|
130
142
|
|
|
143
|
+
### Event store hooks
|
|
144
|
+
|
|
145
|
+
`eventStore.hooks` is passed as is to the Firestore event store. `hooks.beforeCommit(transaction, events)` runs inside the transaction of every append, so what it writes on the transaction commits atomically with the events. See the readme of `@emmett-community/emmett-google-firestore` for the rules of the hook. `ctx.eventStore.appendToStream` returns `messageIds`, the `messageId` stored on each event.
|
|
146
|
+
|
|
131
147
|
## API
|
|
132
148
|
|
|
133
149
|
### ServiceBootstrap
|
|
@@ -138,13 +154,45 @@ const config: ServiceBootstrapConfig = {
|
|
|
138
154
|
- `shutdown(reason, exitCode?)` runs graceful shutdown tasks.
|
|
139
155
|
- `registerSignalHandlers()` installs SIGINT/SIGTERM handlers.
|
|
140
156
|
- `startApi()` initializes, runs checks, creates the app, and starts the HTTP server.
|
|
157
|
+
- `checkReadiness()` runs the readiness checks (also available as `ctx.checkReadiness`).
|
|
158
|
+
|
|
159
|
+
`ctx.eventStore` follows Emmett's `EventStore` contract: `readStream` returns `{ events, currentStreamVersion, streamExists }`.
|
|
160
|
+
|
|
161
|
+
### Health and readiness
|
|
162
|
+
|
|
163
|
+
The probes are routes of the service contract. Declare `GET /health` and `GET /ready` in the OpenAPI document and wire them to the handlers of the package:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// handlers/health.ts: the module of x-eov-operation-handler: health
|
|
167
|
+
import type { NextFunction, Request, Response } from 'express';
|
|
168
|
+
import {
|
|
169
|
+
getHealth as health,
|
|
170
|
+
getReady as ready,
|
|
171
|
+
type ServiceBootstrapContext,
|
|
172
|
+
} from '@emmett-community/emmett-google-services-bootstrap';
|
|
173
|
+
|
|
174
|
+
let readyHandler: ReturnType<typeof ready>;
|
|
175
|
+
|
|
176
|
+
// Called from the initializeHandlers option of startApi()/createApp()
|
|
177
|
+
export const initializeHandlers = (ctx: ServiceBootstrapContext) => {
|
|
178
|
+
readyHandler = ready(ctx);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const getHealth = health;
|
|
182
|
+
export const getReady = (req: Request, res: Response, next: NextFunction) =>
|
|
183
|
+
readyHandler(req, res, next);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`/health` answers `200 { "status": "ok" }`. `/ready` answers `200 { "status": "ready", "checks": [...] }` when Firestore, the Realtime Database (unless `includeRealtimeDatabaseCheck` is `false`), the message bus and the configured `dependencies` answer, and `503 { "status": "unavailable", "checks": [...] }` otherwise. Each check has a 3 s timeout.
|
|
141
187
|
|
|
142
188
|
### Lifecycle utilities
|
|
143
189
|
|
|
144
190
|
- `DependencyChecker` and `startDependency()` for health checks.
|
|
145
|
-
- `GracefulShutdown` for ordered shutdown tasks.
|
|
191
|
+
- `GracefulShutdown` for ordered shutdown tasks (`registerFirst()` adds a task that runs before the others).
|
|
146
192
|
- `registerSignalHandlers()` to attach process signals.
|
|
147
193
|
|
|
194
|
+
`startApi()` closes the HTTP server first, then the message bus, Firestore and the Firebase app.
|
|
195
|
+
|
|
148
196
|
## What this package intentionally does NOT do
|
|
149
197
|
|
|
150
198
|
- Hide application infrastructure choices behind magic defaults
|
|
@@ -154,6 +202,35 @@ const config: ServiceBootstrapConfig = {
|
|
|
154
202
|
|
|
155
203
|
## Testing
|
|
156
204
|
|
|
205
|
+
`@emmett-community/emmett-google-services-bootstrap/testing` builds a service bootstrap on the in-memory Firestore, Realtime Database and Pub/Sub of the `/testing` entries of the platform libraries, with no emulator and no network. The event store, the projections and the message bus are the real ones:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { createTestServiceBootstrap } from '@emmett-community/emmett-google-services-bootstrap/testing';
|
|
209
|
+
|
|
210
|
+
const { bootstrap, firestore, database, messageBus } = createTestServiceBootstrap({
|
|
211
|
+
serviceName: 'user-service',
|
|
212
|
+
projections: [userDetailsProjection],
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const ctx = await bootstrap.start();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Use `overrides` to replace any piece, for example to share one `pubsub` between two services.
|
|
219
|
+
|
|
220
|
+
For API tests, use `ApiSpecification` and `ApiE2ESpecification` from `@event-driven-io/emmett-expressjs` (install it in `devDependencies`, with the same version as `@event-driven-io/emmett`). They take the application right away, so wrap the one built by `createApp()` with `lazyApplication`, which this package re-exports:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { ApiSpecification, expectResponse } from '@event-driven-io/emmett-expressjs';
|
|
224
|
+
import { lazyApplication } from '@emmett-community/emmett-google-services-bootstrap';
|
|
225
|
+
|
|
226
|
+
const given = ApiSpecification.for(
|
|
227
|
+
() => getInMemoryEventStore(),
|
|
228
|
+
(eventStore) => lazyApplication(createTestApp(eventStore)),
|
|
229
|
+
);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
To test this package:
|
|
233
|
+
|
|
157
234
|
```bash
|
|
158
235
|
npm run test:unit
|
|
159
236
|
npm run test:int
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { Application } from 'express';
|
|
2
|
+
import { ImportedHandlerModules, OpenApiValidatorOptions, ApplicationOptions, startAPI } from '@emmett-community/emmett-expressjs-with-openapi';
|
|
3
|
+
import { MessageBus, EventSubscription, CommandProcessor, ScheduledMessageProcessor, EventStore } from '@event-driven-io/emmett';
|
|
4
|
+
import { Firestore } from '@google-cloud/firestore';
|
|
5
|
+
import { PubSub } from '@google-cloud/pubsub';
|
|
6
|
+
import { Auth } from 'firebase-admin/auth';
|
|
7
|
+
import { app } from 'firebase-admin';
|
|
8
|
+
import { Database } from 'firebase-admin/database';
|
|
9
|
+
import { PubSubMessageBusLifecycle, SubscriptionOptions } from '@emmett-community/emmett-google-pubsub';
|
|
10
|
+
import { RealtimeDBInlineProjectionDefinition } from '@emmett-community/emmett-google-realtime-db';
|
|
11
|
+
import { FirestoreEventStoreOptions } from '@emmett-community/emmett-google-firestore';
|
|
12
|
+
|
|
13
|
+
type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'silent';
|
|
14
|
+
/**
|
|
15
|
+
* Canonical logger contract used across Emmett packages.
|
|
16
|
+
* Matches Pino style (context, message).
|
|
17
|
+
*/
|
|
18
|
+
interface Logger {
|
|
19
|
+
debug(context: Record<string, unknown>, message?: string): void;
|
|
20
|
+
info(context: Record<string, unknown>, message?: string): void;
|
|
21
|
+
warn(context: Record<string, unknown>, message?: string): void;
|
|
22
|
+
error(context: Record<string, unknown>, message?: string): void;
|
|
23
|
+
}
|
|
24
|
+
type ObservabilityConfig = {
|
|
25
|
+
logger?: Logger;
|
|
26
|
+
logLevel?: LogLevel;
|
|
27
|
+
environment?: string;
|
|
28
|
+
createLogger?: boolean;
|
|
29
|
+
};
|
|
30
|
+
type FirebaseConfig = {
|
|
31
|
+
projectId?: string;
|
|
32
|
+
databaseURL?: string;
|
|
33
|
+
firestoreEmulatorHost?: string;
|
|
34
|
+
databaseEmulatorHost?: string;
|
|
35
|
+
};
|
|
36
|
+
type PubSubConfig = {
|
|
37
|
+
projectId?: string;
|
|
38
|
+
emulatorHost?: string;
|
|
39
|
+
/** Prefix of topics and subscriptions. Defaults to `PUBSUB_TOPIC_PREFIX`, then the service name. */
|
|
40
|
+
topicPrefix?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Stable id of this service's subscriptions, shared by its replicas and kept across restarts.
|
|
43
|
+
* Defaults to the service name.
|
|
44
|
+
*/
|
|
45
|
+
subscriptionId?: string;
|
|
46
|
+
subscriptionOptions?: SubscriptionOptions;
|
|
47
|
+
autoCreateResources?: boolean;
|
|
48
|
+
cleanupOnClose?: boolean;
|
|
49
|
+
closePubSubClient?: boolean;
|
|
50
|
+
};
|
|
51
|
+
type DependencyCheck = {
|
|
52
|
+
name: string;
|
|
53
|
+
check: () => Promise<void>;
|
|
54
|
+
successMessage?: string;
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
required?: boolean;
|
|
57
|
+
};
|
|
58
|
+
type GracefulShutdownConfig = {
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
exitOnComplete?: boolean;
|
|
61
|
+
exitFn?: (code: number) => void;
|
|
62
|
+
};
|
|
63
|
+
type MessageBusWithLifecycle = MessageBus & EventSubscription & CommandProcessor & ScheduledMessageProcessor & PubSubMessageBusLifecycle;
|
|
64
|
+
interface FirebaseAdminLike {
|
|
65
|
+
initializeApp(options: {
|
|
66
|
+
projectId: string;
|
|
67
|
+
databaseURL?: string;
|
|
68
|
+
}, name?: string): app.App;
|
|
69
|
+
app?: () => app.App;
|
|
70
|
+
apps?: Array<app.App | null>;
|
|
71
|
+
}
|
|
72
|
+
type ServiceBootstrapOverrides = {
|
|
73
|
+
firebaseAdmin?: FirebaseAdminLike;
|
|
74
|
+
firestore?: Firestore;
|
|
75
|
+
database?: Database;
|
|
76
|
+
auth?: Auth;
|
|
77
|
+
pubsub?: PubSub;
|
|
78
|
+
eventStore?: EventStore;
|
|
79
|
+
messageBus?: MessageBusWithLifecycle;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Main configuration for ServiceBootstrap.
|
|
83
|
+
* Values can be provided explicitly or via environment variables.
|
|
84
|
+
*/
|
|
85
|
+
type ServiceBootstrapConfig = {
|
|
86
|
+
serviceName: string;
|
|
87
|
+
firebase?: FirebaseConfig;
|
|
88
|
+
pubsub?: PubSubConfig;
|
|
89
|
+
eventStore?: {
|
|
90
|
+
collections?: FirestoreEventStoreOptions['collections'];
|
|
91
|
+
hooks?: FirestoreEventStoreOptions['hooks'];
|
|
92
|
+
};
|
|
93
|
+
observability?: ObservabilityConfig;
|
|
94
|
+
projections?: RealtimeDBInlineProjectionDefinition[];
|
|
95
|
+
getCurrentTime?: () => Date;
|
|
96
|
+
dependencies?: DependencyCheck[];
|
|
97
|
+
includeDefaultDependencyChecks?: boolean;
|
|
98
|
+
/** Check the Realtime Database with the default checks. Set to `false` for services that do not use it. */
|
|
99
|
+
includeRealtimeDatabaseCheck?: boolean;
|
|
100
|
+
autoStartMessageBus?: boolean;
|
|
101
|
+
shutdownOnDependencyFailure?: boolean;
|
|
102
|
+
shutdown?: GracefulShutdownConfig;
|
|
103
|
+
_testOverrides?: ServiceBootstrapOverrides;
|
|
104
|
+
};
|
|
105
|
+
type ResolvedFirebaseConfig = {
|
|
106
|
+
projectId: string;
|
|
107
|
+
databaseURL: string;
|
|
108
|
+
firestoreEmulatorHost?: string;
|
|
109
|
+
databaseEmulatorHost?: string;
|
|
110
|
+
};
|
|
111
|
+
type ResolvedPubSubConfig = {
|
|
112
|
+
projectId: string;
|
|
113
|
+
emulatorHost?: string;
|
|
114
|
+
topicPrefix: string;
|
|
115
|
+
subscriptionId: string;
|
|
116
|
+
subscriptionOptions?: SubscriptionOptions;
|
|
117
|
+
autoCreateResources: boolean;
|
|
118
|
+
cleanupOnClose: boolean;
|
|
119
|
+
closePubSubClient: boolean;
|
|
120
|
+
};
|
|
121
|
+
type ResolvedServiceBootstrapConfig = {
|
|
122
|
+
serviceName: string;
|
|
123
|
+
firebase: ResolvedFirebaseConfig;
|
|
124
|
+
pubsub: ResolvedPubSubConfig;
|
|
125
|
+
eventStore: {
|
|
126
|
+
collections?: FirestoreEventStoreOptions['collections'];
|
|
127
|
+
hooks?: FirestoreEventStoreOptions['hooks'];
|
|
128
|
+
};
|
|
129
|
+
observability: ObservabilityConfig;
|
|
130
|
+
projections: RealtimeDBInlineProjectionDefinition[];
|
|
131
|
+
getCurrentTime: () => Date;
|
|
132
|
+
dependencies: DependencyCheck[];
|
|
133
|
+
includeDefaultDependencyChecks: boolean;
|
|
134
|
+
includeRealtimeDatabaseCheck: boolean;
|
|
135
|
+
autoStartMessageBus: boolean;
|
|
136
|
+
shutdownOnDependencyFailure: boolean;
|
|
137
|
+
shutdown: GracefulShutdownConfig;
|
|
138
|
+
_testOverrides?: ServiceBootstrapOverrides;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
declare class DependencyTimeoutError extends Error {
|
|
142
|
+
constructor(timeoutMs: number);
|
|
143
|
+
}
|
|
144
|
+
type DependencyCheckResult = {
|
|
145
|
+
name: string;
|
|
146
|
+
ok: boolean;
|
|
147
|
+
required: boolean;
|
|
148
|
+
durationMs: number;
|
|
149
|
+
timedOut: boolean;
|
|
150
|
+
error?: unknown;
|
|
151
|
+
};
|
|
152
|
+
type DependencyCheckSummary = {
|
|
153
|
+
ok: boolean;
|
|
154
|
+
results: DependencyCheckResult[];
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Helper for one-off dependency checks with optional logging.
|
|
158
|
+
*/
|
|
159
|
+
declare const startDependency: (dependency: string, startFn: () => Promise<void>, options?: {
|
|
160
|
+
logger?: Logger;
|
|
161
|
+
successMessage?: string;
|
|
162
|
+
timeoutMs?: number;
|
|
163
|
+
}) => Promise<boolean>;
|
|
164
|
+
/**
|
|
165
|
+
* Executes dependency checks with optional timeouts.
|
|
166
|
+
*/
|
|
167
|
+
declare class DependencyChecker {
|
|
168
|
+
private readonly logger?;
|
|
169
|
+
private readonly defaultTimeoutMs?;
|
|
170
|
+
constructor(options?: {
|
|
171
|
+
logger?: Logger;
|
|
172
|
+
defaultTimeoutMs?: number;
|
|
173
|
+
});
|
|
174
|
+
check(dependency: DependencyCheck): Promise<DependencyCheckResult>;
|
|
175
|
+
checkAll(dependencies: DependencyCheck[]): Promise<DependencyCheckSummary>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
declare class ShutdownTimeoutError extends Error {
|
|
179
|
+
constructor(timeoutMs: number);
|
|
180
|
+
}
|
|
181
|
+
type ShutdownTask = {
|
|
182
|
+
name: string;
|
|
183
|
+
close: () => Promise<void>;
|
|
184
|
+
timeoutMs?: number;
|
|
185
|
+
};
|
|
186
|
+
type ShutdownTaskResult = {
|
|
187
|
+
name: string;
|
|
188
|
+
ok: boolean;
|
|
189
|
+
timedOut: boolean;
|
|
190
|
+
durationMs: number;
|
|
191
|
+
error?: unknown;
|
|
192
|
+
};
|
|
193
|
+
type GracefulShutdownResult = {
|
|
194
|
+
reason: string;
|
|
195
|
+
exitCode: number;
|
|
196
|
+
tasks: ShutdownTaskResult[];
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Runs shutdown tasks with timeout handling and optional exit.
|
|
200
|
+
*/
|
|
201
|
+
declare class GracefulShutdown {
|
|
202
|
+
private readonly logger?;
|
|
203
|
+
private readonly timeoutMs?;
|
|
204
|
+
private readonly exitOnComplete;
|
|
205
|
+
private readonly exitFn;
|
|
206
|
+
private readonly tasks;
|
|
207
|
+
private shuttingDown;
|
|
208
|
+
private lastResult?;
|
|
209
|
+
constructor(options?: GracefulShutdownConfig & {
|
|
210
|
+
logger?: Logger;
|
|
211
|
+
});
|
|
212
|
+
/**
|
|
213
|
+
* Register a shutdown task.
|
|
214
|
+
*/
|
|
215
|
+
register(task: ShutdownTask): void;
|
|
216
|
+
/**
|
|
217
|
+
* Register a shutdown task that runs before the ones already registered.
|
|
218
|
+
*/
|
|
219
|
+
registerFirst(task: ShutdownTask): void;
|
|
220
|
+
/**
|
|
221
|
+
* Execute all shutdown tasks and return the aggregated result.
|
|
222
|
+
*/
|
|
223
|
+
shutdown(reason: string, exitCode?: number): Promise<GracefulShutdownResult>;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Runtime context produced by ServiceBootstrap.
|
|
228
|
+
*/
|
|
229
|
+
type ServiceBootstrapContext = {
|
|
230
|
+
serviceName: string;
|
|
231
|
+
firebase: {
|
|
232
|
+
app: app.App;
|
|
233
|
+
firestore: Firestore;
|
|
234
|
+
database: Database;
|
|
235
|
+
auth: Auth;
|
|
236
|
+
};
|
|
237
|
+
firestore: Firestore;
|
|
238
|
+
database: Database;
|
|
239
|
+
auth: Auth;
|
|
240
|
+
pubsub: PubSub;
|
|
241
|
+
eventStore: EventStore;
|
|
242
|
+
messageBus: MessageBusWithLifecycle;
|
|
243
|
+
logger?: Logger;
|
|
244
|
+
getCurrentTime: () => Date;
|
|
245
|
+
config: ResolvedServiceBootstrapConfig;
|
|
246
|
+
/**
|
|
247
|
+
* Runs the readiness checks (the same dependencies the startup checks, without starting the
|
|
248
|
+
* message bus again). Used by the `/ready` handler.
|
|
249
|
+
*/
|
|
250
|
+
checkReadiness: () => Promise<DependencyCheckSummary>;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Error thrown when required dependencies fail health checks.
|
|
254
|
+
*/
|
|
255
|
+
declare class DependencyUnavailableError extends Error {
|
|
256
|
+
readonly summary: DependencyCheckSummary;
|
|
257
|
+
constructor(summary: DependencyCheckSummary);
|
|
258
|
+
}
|
|
259
|
+
type CreateAppOptions = {
|
|
260
|
+
openApiPath: string;
|
|
261
|
+
handlersPath: string;
|
|
262
|
+
initializeHandlers: (handlers?: ImportedHandlerModules) => void | Promise<void>;
|
|
263
|
+
openApiOptions?: Partial<Omit<OpenApiValidatorOptions, 'apiSpec' | 'operationHandlers' | 'initializeHandlers'>>;
|
|
264
|
+
appOptions?: Omit<ApplicationOptions, 'openApiValidator' | 'observability'>;
|
|
265
|
+
};
|
|
266
|
+
type StartApiOptions = Omit<CreateAppOptions, 'initializeHandlers'> & {
|
|
267
|
+
initializeHandlers: (handlers: ImportedHandlerModules | undefined, ctx: ServiceBootstrapContext) => void | Promise<void>;
|
|
268
|
+
port?: number;
|
|
269
|
+
registerSignalHandlers?: boolean;
|
|
270
|
+
beforeStart?: (ctx: ServiceBootstrapContext) => void | Promise<void>;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Orchestrates Firebase, PubSub, event store, and lifecycle utilities.
|
|
274
|
+
*/
|
|
275
|
+
declare class ServiceBootstrap {
|
|
276
|
+
private readonly config;
|
|
277
|
+
private resolvedConfig?;
|
|
278
|
+
private logger?;
|
|
279
|
+
private context?;
|
|
280
|
+
private dependencyChecker?;
|
|
281
|
+
private shutdownManager?;
|
|
282
|
+
constructor(config: ServiceBootstrapConfig);
|
|
283
|
+
/**
|
|
284
|
+
* Resolve configuration with defaults and environment variables.
|
|
285
|
+
*/
|
|
286
|
+
getConfig(): ResolvedServiceBootstrapConfig;
|
|
287
|
+
/**
|
|
288
|
+
* Return the initialized context if available.
|
|
289
|
+
*/
|
|
290
|
+
getContext(): ServiceBootstrapContext | undefined;
|
|
291
|
+
/**
|
|
292
|
+
* Register process signal handlers that trigger shutdown.
|
|
293
|
+
*/
|
|
294
|
+
registerSignalHandlers(options?: {
|
|
295
|
+
signals?: NodeJS.Signals[];
|
|
296
|
+
exitCode?: number;
|
|
297
|
+
}): () => void;
|
|
298
|
+
/**
|
|
299
|
+
* Create an Express app using emmett-expressjs-with-openapi defaults.
|
|
300
|
+
*/
|
|
301
|
+
createApp(options: CreateAppOptions): Promise<Application>;
|
|
302
|
+
/**
|
|
303
|
+
* Initialize, run dependency checks, create the app, and start the HTTP server.
|
|
304
|
+
*/
|
|
305
|
+
startApi(options: StartApiOptions): Promise<{
|
|
306
|
+
app: Application;
|
|
307
|
+
server: ReturnType<typeof startAPI>;
|
|
308
|
+
context: ServiceBootstrapContext;
|
|
309
|
+
}>;
|
|
310
|
+
/**
|
|
311
|
+
* Initialize Firebase, PubSub, and event store wiring.
|
|
312
|
+
* Does not execute dependency checks.
|
|
313
|
+
*/
|
|
314
|
+
initialize(): Promise<ServiceBootstrapContext>;
|
|
315
|
+
/**
|
|
316
|
+
* Initialize and run dependency checks before returning context.
|
|
317
|
+
*/
|
|
318
|
+
start(): Promise<ServiceBootstrapContext>;
|
|
319
|
+
/**
|
|
320
|
+
* Run the readiness checks: the stores and the message bus must answer, plus the configured
|
|
321
|
+
* dependencies. A hung dependency fails the check instead of hanging the probe.
|
|
322
|
+
*/
|
|
323
|
+
checkReadiness(): Promise<DependencyCheckSummary>;
|
|
324
|
+
/**
|
|
325
|
+
* Execute graceful shutdown tasks and return the shutdown result.
|
|
326
|
+
*/
|
|
327
|
+
shutdown(reason: string, exitCode?: number): Promise<GracefulShutdownResult>;
|
|
328
|
+
private getLogger;
|
|
329
|
+
private resolveConfig;
|
|
330
|
+
private getDatabaseURL;
|
|
331
|
+
private getDependencyChecker;
|
|
332
|
+
private getShutdownManager;
|
|
333
|
+
private registerDefaultShutdownTasks;
|
|
334
|
+
private buildDefaultDependencyChecks;
|
|
335
|
+
private buildStoreDependencyChecks;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export { type CreateAppOptions as C, DependencyUnavailableError as D, type FirebaseAdminLike as F, type GracefulShutdownConfig as G, type Logger as L, type MessageBusWithLifecycle as M, type ObservabilityConfig as O, type PubSubConfig as P, type ResolvedFirebaseConfig as R, type ServiceBootstrapContext as S, type StartApiOptions as a, ServiceBootstrap as b, type LogLevel as c, type FirebaseConfig as d, type DependencyCheck as e, type ServiceBootstrapOverrides as f, type ServiceBootstrapConfig as g, type ResolvedPubSubConfig as h, type ResolvedServiceBootstrapConfig as i, DependencyTimeoutError as j, type DependencyCheckResult as k, type DependencyCheckSummary as l, DependencyChecker as m, ShutdownTimeoutError as n, type ShutdownTask as o, type ShutdownTaskResult as p, type GracefulShutdownResult as q, GracefulShutdown as r, startDependency as s };
|