@shipfox/api-server 7.0.1 → 7.1.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +47 -0
- package/README.md +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.js +5 -1
- package/dist/instrumentation.js.map +1 -1
- package/dist/modules.d.ts +5 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +22 -2
- package/dist/modules.js.map +1 -1
- package/dist/routes/login-methods.d.ts +5 -0
- package/dist/routes/login-methods.d.ts.map +1 -0
- package/dist/routes/login-methods.js +22 -0
- package/dist/routes/login-methods.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +68 -11
- package/dist/server.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +23 -32
- package/src/index.ts +6 -1
- package/src/instrumentation.ts +5 -1
- package/src/modules.test.ts +34 -0
- package/src/modules.ts +23 -3
- package/src/routes/login-methods.test.ts +56 -0
- package/src/routes/login-methods.ts +21 -0
- package/src/server.test.ts +26 -6
- package/src/server.ts +52 -14
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 7 files with swc (415.93ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# @shipfox/api-server
|
|
2
2
|
|
|
3
|
+
## 7.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 769d919: Adds an anonymous login-method catalog with a published bounded DTO contract.
|
|
8
|
+
- 2e05e0e: Adds a host factory for replacing only the default Runners module with the composed Auth client.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- ac42c96: Adds boundary-owned reporting for unexpected API runtime failures while preserving expected client and provider outcomes.
|
|
13
|
+
- 6ce08c0: Adds provider-neutral OpenTelemetry traces and Prometheus metrics across the API, Fastify, module workers, and Temporal workers.
|
|
14
|
+
- Updated dependencies [ac42c96]
|
|
15
|
+
- Updated dependencies [769d919]
|
|
16
|
+
- Updated dependencies [2a7d951]
|
|
17
|
+
- Updated dependencies [6ce08c0]
|
|
18
|
+
- Updated dependencies [8bb32b2]
|
|
19
|
+
- @shipfox/node-error-monitoring@0.2.0
|
|
20
|
+
- @shipfox/node-fastify@0.3.0
|
|
21
|
+
- @shipfox/node-module@0.5.0
|
|
22
|
+
- @shipfox/api-dispatcher@7.1.0
|
|
23
|
+
- @shipfox/api-logs@7.1.0
|
|
24
|
+
- @shipfox/api-triggers@7.1.0
|
|
25
|
+
- @shipfox/api-runners@7.1.0
|
|
26
|
+
- @shipfox/api-agent@7.1.0
|
|
27
|
+
- @shipfox/api-integration-core@7.1.0
|
|
28
|
+
- @shipfox/api-auth-dto@7.1.0
|
|
29
|
+
- @shipfox/api-auth@7.1.0
|
|
30
|
+
- @shipfox/node-opentelemetry@0.6.0
|
|
31
|
+
- @shipfox/api-email-challenges@0.3.0
|
|
32
|
+
- @shipfox/api-definitions@7.1.0
|
|
33
|
+
- @shipfox/api-workflows@7.1.0
|
|
34
|
+
- @shipfox/annotations@7.1.0
|
|
35
|
+
- @shipfox/api-projects@7.1.0
|
|
36
|
+
- @shipfox/api-secrets@7.1.0
|
|
37
|
+
- @shipfox/api-workspaces@7.1.0
|
|
38
|
+
|
|
39
|
+
## 7.0.2
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- @shipfox/annotations@6.0.0
|
|
44
|
+
- @shipfox/api-auth@7.0.2
|
|
45
|
+
- @shipfox/api-email-challenges@0.2.3
|
|
46
|
+
- @shipfox/api-logs@6.0.0
|
|
47
|
+
- @shipfox/api-runners@7.0.2
|
|
48
|
+
- @shipfox/api-workflows@7.0.2
|
|
49
|
+
|
|
3
50
|
## 7.0.1
|
|
4
51
|
|
|
5
52
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Runs a Shipfox API server.
|
|
|
7
7
|
- **`defaultModules()`**: Returns the standard module list.
|
|
8
8
|
- **`createServer()`**: Builds an API server. The caller owns process signals.
|
|
9
9
|
- **`runServer()`**: Starts the server. It listens for SIGTERM and SIGINT.
|
|
10
|
+
- **`createLoginMethodsRoute()`**: Builds the public login-method catalog route. `createServer` mounts it automatically.
|
|
10
11
|
- **Instrumentation preload**: Starts metrics early. Load it before feature modules.
|
|
11
12
|
|
|
12
13
|
## Installation
|
|
@@ -41,6 +42,7 @@ node --import @shipfox/api-server/instrumentation ./dist/index.js
|
|
|
41
42
|
## Behavior Notes
|
|
42
43
|
|
|
43
44
|
- **Custom composition**: Pass a module list to make a custom server. A module must declare a unique `loginMethods` entry. `createServer` throws before startup side effects when no login method is available.
|
|
45
|
+
- **Login-method catalog**: Every server composition exposes a public, unauthenticated `GET /auth/login-methods`, listing the bounded IDs of every module-contributed login method.
|
|
44
46
|
- **Signal handling**: `createServer` does not install signal handlers.
|
|
45
47
|
- **Lifecycle**: `start` starts workers and module services before the HTTP listener. `stop` is safe to call again. It stops services before workers and shared clients.
|
|
46
48
|
- **Process scope**: Run one server at a time.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { type DefaultModulesOptions, defaultModules } from './modules.js';
|
|
1
|
+
export { type DefaultModulesOptions, type DefaultRunnersModuleFactory, defaultModules, } from './modules.js';
|
|
2
|
+
export { createLoginMethodsRoute } from './routes/login-methods.js';
|
|
2
3
|
export type { CreateServerOptions, RunServerOptions, ServerHandle } from './server.js';
|
|
3
4
|
export { createServer, runServer } from './server.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,uBAAuB,EAAC,MAAM,2BAA2B,CAAC;AAClE,YAAY,EAAC,mBAAmB,EAAE,gBAAgB,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AACrF,OAAO,EAAC,YAAY,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {type DefaultModulesOptions
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n type DefaultModulesOptions,\n type DefaultRunnersModuleFactory,\n defaultModules,\n} from './modules.js';\nexport {createLoginMethodsRoute} from './routes/login-methods.js';\nexport type {CreateServerOptions, RunServerOptions, ServerHandle} from './server.js';\nexport {createServer, runServer} from './server.js';\n"],"names":["defaultModules","createLoginMethodsRoute","createServer","runServer"],"mappings":"AAAA,SAGEA,cAAc,QACT,eAAe;AACtB,SAAQC,uBAAuB,QAAO,4BAA4B;AAElE,SAAQC,YAAY,EAAEC,SAAS,QAAO,cAAc"}
|
package/dist/instrumentation.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
1
2
|
import { startInstanceInstrumentation } from '@shipfox/node-opentelemetry';
|
|
3
|
+
const { version } = createRequire(import.meta.url)('../package.json');
|
|
2
4
|
// The metrics API has no proxy meter: instruments created before this preload
|
|
3
5
|
// completes bind to a no-op provider for the process lifetime.
|
|
4
6
|
await startInstanceInstrumentation({
|
|
5
7
|
serviceName: 'api',
|
|
8
|
+
serviceVersion: version,
|
|
6
9
|
instrumentations: {
|
|
7
10
|
fastify: true,
|
|
8
11
|
http: true,
|
|
9
|
-
pg: true
|
|
12
|
+
pg: true,
|
|
13
|
+
awsSdk: true
|
|
10
14
|
}
|
|
11
15
|
});
|
|
12
16
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/instrumentation.ts"],"sourcesContent":["import {startInstanceInstrumentation} from '@shipfox/node-opentelemetry';\n\n// The metrics API has no proxy meter: instruments created before this preload\n// completes bind to a no-op provider for the process lifetime.\nawait startInstanceInstrumentation({\n serviceName: 'api',\n instrumentations: {fastify: true, http: true, pg: true},\n});\n"],"names":["startInstanceInstrumentation","serviceName","instrumentations","fastify","http","pg"],"mappings":"AAAA,SAAQA,4BAA4B,QAAO,8BAA8B;AAEzE,8EAA8E;AAC9E,+DAA+D;AAC/D,
|
|
1
|
+
{"version":3,"sources":["../src/instrumentation.ts"],"sourcesContent":["import {createRequire} from 'node:module';\nimport {startInstanceInstrumentation} from '@shipfox/node-opentelemetry';\n\nconst {version} = createRequire(import.meta.url)('../package.json') as {version: string};\n\n// The metrics API has no proxy meter: instruments created before this preload\n// completes bind to a no-op provider for the process lifetime.\nawait startInstanceInstrumentation({\n serviceName: 'api',\n serviceVersion: version,\n instrumentations: {fastify: true, http: true, pg: true, awsSdk: true},\n});\n"],"names":["createRequire","startInstanceInstrumentation","version","url","serviceName","serviceVersion","instrumentations","fastify","http","pg","awsSdk"],"mappings":"AAAA,SAAQA,aAAa,QAAO,cAAc;AAC1C,SAAQC,4BAA4B,QAAO,8BAA8B;AAEzE,MAAM,EAACC,OAAO,EAAC,GAAGF,cAAc,YAAYG,GAAG,EAAE;AAEjD,8EAA8E;AAC9E,+DAA+D;AAC/D,MAAMF,6BAA6B;IACjCG,aAAa;IACbC,gBAAgBH;IAChBI,kBAAkB;QAACC,SAAS;QAAMC,MAAM;QAAMC,IAAI;QAAMC,QAAQ;IAAI;AACtE"}
|
package/dist/modules.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { type AuthInterModuleClient } from '@shipfox/api-auth-dto/inter-module';
|
|
1
2
|
import { type WebhookDeliverySource } from '@shipfox/api-integration-core';
|
|
2
3
|
import type { ShipfoxModule } from '@shipfox/node-module';
|
|
3
4
|
export interface DefaultModulesOptions {
|
|
4
5
|
webhookDeliverySource?: WebhookDeliverySource | undefined;
|
|
6
|
+
runnersModule?: DefaultRunnersModuleFactory | undefined;
|
|
5
7
|
}
|
|
8
|
+
export type DefaultRunnersModuleFactory = (options: {
|
|
9
|
+
auth: AuthInterModuleClient;
|
|
10
|
+
}) => ShipfoxModule;
|
|
6
11
|
export declare function defaultModules(options?: DefaultModulesOptions): Promise<ShipfoxModule[]>;
|
|
7
12
|
//# sourceMappingURL=modules.d.ts.map
|
package/dist/modules.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,oCAAoC,CAAC;AAK5C,OAAO,EAA4B,KAAK,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;AAgBpG,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAOxD,MAAM,WAAW,qBAAqB;IACpC,qBAAqB,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC1D,aAAa,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,EAAE;IAAC,IAAI,EAAE,qBAAqB,CAAA;CAAC,KAAK,aAAa,CAAC;AAEpG,wBAAsB,cAAc,CAClC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,aAAa,EAAE,CAAC,CA6I1B"}
|
package/dist/modules.js
CHANGED
|
@@ -23,10 +23,30 @@ import { createWorkflowsModule } from '@shipfox/api-workflows';
|
|
|
23
23
|
import { workflowsInterModuleContract } from '@shipfox/api-workflows-dto/inter-module';
|
|
24
24
|
import { workspacesModule } from '@shipfox/api-workspaces';
|
|
25
25
|
import { workspacesInterModuleContract } from '@shipfox/api-workspaces-dto/inter-module';
|
|
26
|
+
import { reportError } from '@shipfox/node-error-monitoring';
|
|
26
27
|
import { durationToSeconds } from '@shipfox/node-jwt';
|
|
27
28
|
import { createInMemoryInterModuleTransport, registerInterModulePresentations } from '@shipfox/node-module/inter-module';
|
|
29
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
28
30
|
export async function defaultModules(options = {}) {
|
|
29
|
-
const interModuleTransport = createInMemoryInterModuleTransport(
|
|
31
|
+
const interModuleTransport = createInMemoryInterModuleTransport({
|
|
32
|
+
reportInternalError: (error, context)=>{
|
|
33
|
+
logger().error({
|
|
34
|
+
err: error,
|
|
35
|
+
module: context.module,
|
|
36
|
+
method: context.method,
|
|
37
|
+
phase: context.phase
|
|
38
|
+
}, 'Inter-module call failed unexpectedly');
|
|
39
|
+
reportError(error, {
|
|
40
|
+
boundary: 'inter-module',
|
|
41
|
+
operation: `${context.module}.${context.method}`,
|
|
42
|
+
tags: {
|
|
43
|
+
module: context.module,
|
|
44
|
+
method: context.method,
|
|
45
|
+
phase: context.phase
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
30
50
|
const workflowsClient = interModuleTransport.createClient(workflowsInterModuleContract);
|
|
31
51
|
const authClient = interModuleTransport.createClient(authInterModuleContract);
|
|
32
52
|
const agentClient = interModuleTransport.createClient(agentInterModuleContract);
|
|
@@ -138,7 +158,7 @@ export async function defaultModules(options = {}) {
|
|
|
138
158
|
integrations: integrationsClient
|
|
139
159
|
}),
|
|
140
160
|
annotationsModule,
|
|
141
|
-
createRunnersModule({
|
|
161
|
+
(options.runnersModule ?? createRunnersModule)({
|
|
142
162
|
auth: authClient
|
|
143
163
|
}),
|
|
144
164
|
createLogsModule({
|
package/dist/modules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/modules.ts"],"sourcesContent":["import {annotationsModule} from '@shipfox/annotations';\nimport {annotationsInterModuleContract} from '@shipfox/annotations-dto/inter-module';\nimport {createAgentModule} from '@shipfox/api-agent';\nimport {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';\nimport {createAuthModule} from '@shipfox/api-auth';\nimport {config as authConfig} from '@shipfox/api-auth/config';\nimport {authInterModuleContract} from '@shipfox/api-auth-dto/inter-module';\nimport {createDefinitionsModule} from '@shipfox/api-definitions';\nimport {definitionsInterModuleContract} from '@shipfox/api-definitions-dto/inter-module';\nimport {dispatcherModule} from '@shipfox/api-dispatcher';\nimport {emailChallengesModule} from '@shipfox/api-email-challenges';\nimport {createIntegrationsContext, type WebhookDeliverySource} from '@shipfox/api-integration-core';\nimport {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto';\nimport {createLogsModule} from '@shipfox/api-logs';\nimport {createProjectsModule} from '@shipfox/api-projects';\nimport {projectsInterModuleContract} from '@shipfox/api-projects-dto';\nimport {createRunnersModule} from '@shipfox/api-runners';\nimport {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';\nimport {createSecretsModule} from '@shipfox/api-secrets';\nimport {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';\nimport {createTriggersModule} from '@shipfox/api-triggers';\nimport {createWorkflowsModule} from '@shipfox/api-workflows';\nimport {workflowsInterModuleContract} from '@shipfox/api-workflows-dto/inter-module';\nimport {workspacesModule} from '@shipfox/api-workspaces';\nimport {workspacesInterModuleContract} from '@shipfox/api-workspaces-dto/inter-module';\nimport {durationToSeconds} from '@shipfox/node-jwt';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {\n createInMemoryInterModuleTransport,\n registerInterModulePresentations,\n} from '@shipfox/node-module/inter-module';\n\nexport interface DefaultModulesOptions {\n webhookDeliverySource?: WebhookDeliverySource | undefined;\n}\n\nexport async function defaultModules(\n options: DefaultModulesOptions = {},\n): Promise<ShipfoxModule[]> {\n const interModuleTransport = createInMemoryInterModuleTransport();\n const workflowsClient = interModuleTransport.createClient(workflowsInterModuleContract);\n const authClient = interModuleTransport.createClient(authInterModuleContract);\n const agentClient = interModuleTransport.createClient(agentInterModuleContract);\n const runnersClient = interModuleTransport.createClient(runnersInterModuleContract);\n const projectsClient = interModuleTransport.createClient(projectsInterModuleContract);\n const definitionsClient = interModuleTransport.createClient(definitionsInterModuleContract);\n const annotationsClient = interModuleTransport.createClient(annotationsInterModuleContract);\n const secretsClient = interModuleTransport.createClient(secretsInterModuleContract);\n const workspacesClient = interModuleTransport.createClient(workspacesInterModuleContract);\n const integrationsClient = interModuleTransport.createClient(integrationsInterModuleContract);\n const integrations = await createIntegrationsContext({\n workspaces: workspacesClient,\n secrets: {\n deleteSecrets: async (params) => (await secretsClient.deleteSecrets(params)).deleted,\n linear: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/linear/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/linear/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/linear/${params.namespace}`,\n })\n ).deleted,\n },\n jira: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/jira/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/jira/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/jira/${params.namespace}`,\n })\n ).deleted,\n },\n slack: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/slack/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/slack/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/slack/${params.namespace}`,\n })\n ).deleted,\n },\n },\n agentTools: {workflows: workflowsClient},\n webhookDeliverySource: options.webhookDeliverySource,\n });\n const projectsModule = createProjectsModule({integrations: integrationsClient});\n const definitionsModule = createDefinitionsModule({\n projects: projectsClient,\n integrations: integrationsClient,\n });\n\n const modules = [\n emailChallengesModule,\n createAuthModule({workspaces: workspacesClient}),\n workspacesModule,\n createSecretsModule(projectsClient),\n createAgentModule({secrets: secretsClient}),\n integrations.module,\n projectsModule,\n definitionsModule,\n createWorkflowsModule({\n annotations: annotationsClient,\n agent: agentClient,\n definitions: definitionsClient,\n auth: authClient,\n projects: projectsClient,\n runners: runnersClient,\n secrets: secretsClient,\n integrations: integrationsClient,\n }),\n annotationsModule,\n createRunnersModule({auth: authClient}),\n createLogsModule({\n workflows: workflowsClient,\n jobLeaseTokenTtlSeconds: durationToSeconds(authConfig.AUTH_JOB_LEASE_TOKEN_EXPIRES_IN),\n }),\n createTriggersModule({workflows: workflowsClient}),\n dispatcherModule,\n ];\n registerInterModulePresentations({transport: interModuleTransport, modules});\n interModuleTransport.seal();\n return modules;\n}\n"],"names":["annotationsModule","annotationsInterModuleContract","createAgentModule","agentInterModuleContract","createAuthModule","config","authConfig","authInterModuleContract","createDefinitionsModule","definitionsInterModuleContract","dispatcherModule","emailChallengesModule","createIntegrationsContext","integrationsInterModuleContract","createLogsModule","createProjectsModule","projectsInterModuleContract","createRunnersModule","runnersInterModuleContract","createSecretsModule","secretsInterModuleContract","createTriggersModule","createWorkflowsModule","workflowsInterModuleContract","workspacesModule","workspacesInterModuleContract","durationToSeconds","createInMemoryInterModuleTransport","registerInterModulePresentations","defaultModules","options","interModuleTransport","workflowsClient","createClient","authClient","agentClient","runnersClient","projectsClient","definitionsClient","annotationsClient","secretsClient","workspacesClient","integrationsClient","integrations","workspaces","secrets","deleteSecrets","params","deleted","linear","getSecret","namespace","value","setSecrets","editedBy","secretParams","undefined","jira","slack","agentTools","workflows","webhookDeliverySource","projectsModule","definitionsModule","projects","modules","module","annotations","agent","definitions","auth","runners","jobLeaseTokenTtlSeconds","AUTH_JOB_LEASE_TOKEN_EXPIRES_IN","transport","seal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/modules.ts"],"sourcesContent":["import {annotationsModule} from '@shipfox/annotations';\nimport {annotationsInterModuleContract} from '@shipfox/annotations-dto/inter-module';\nimport {createAgentModule} from '@shipfox/api-agent';\nimport {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';\nimport {createAuthModule} from '@shipfox/api-auth';\nimport {config as authConfig} from '@shipfox/api-auth/config';\nimport {\n type AuthInterModuleClient,\n authInterModuleContract,\n} from '@shipfox/api-auth-dto/inter-module';\nimport {createDefinitionsModule} from '@shipfox/api-definitions';\nimport {definitionsInterModuleContract} from '@shipfox/api-definitions-dto/inter-module';\nimport {dispatcherModule} from '@shipfox/api-dispatcher';\nimport {emailChallengesModule} from '@shipfox/api-email-challenges';\nimport {createIntegrationsContext, type WebhookDeliverySource} from '@shipfox/api-integration-core';\nimport {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto';\nimport {createLogsModule} from '@shipfox/api-logs';\nimport {createProjectsModule} from '@shipfox/api-projects';\nimport {projectsInterModuleContract} from '@shipfox/api-projects-dto';\nimport {createRunnersModule} from '@shipfox/api-runners';\nimport {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';\nimport {createSecretsModule} from '@shipfox/api-secrets';\nimport {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';\nimport {createTriggersModule} from '@shipfox/api-triggers';\nimport {createWorkflowsModule} from '@shipfox/api-workflows';\nimport {workflowsInterModuleContract} from '@shipfox/api-workflows-dto/inter-module';\nimport {workspacesModule} from '@shipfox/api-workspaces';\nimport {workspacesInterModuleContract} from '@shipfox/api-workspaces-dto/inter-module';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {durationToSeconds} from '@shipfox/node-jwt';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {\n createInMemoryInterModuleTransport,\n registerInterModulePresentations,\n} from '@shipfox/node-module/inter-module';\nimport {logger} from '@shipfox/node-opentelemetry';\n\nexport interface DefaultModulesOptions {\n webhookDeliverySource?: WebhookDeliverySource | undefined;\n runnersModule?: DefaultRunnersModuleFactory | undefined;\n}\n\nexport type DefaultRunnersModuleFactory = (options: {auth: AuthInterModuleClient}) => ShipfoxModule;\n\nexport async function defaultModules(\n options: DefaultModulesOptions = {},\n): Promise<ShipfoxModule[]> {\n const interModuleTransport = createInMemoryInterModuleTransport({\n reportInternalError: (error, context) => {\n logger().error(\n {err: error, module: context.module, method: context.method, phase: context.phase},\n 'Inter-module call failed unexpectedly',\n );\n reportError(error, {\n boundary: 'inter-module',\n operation: `${context.module}.${context.method}`,\n tags: {module: context.module, method: context.method, phase: context.phase},\n });\n },\n });\n const workflowsClient = interModuleTransport.createClient(workflowsInterModuleContract);\n const authClient = interModuleTransport.createClient(authInterModuleContract);\n const agentClient = interModuleTransport.createClient(agentInterModuleContract);\n const runnersClient = interModuleTransport.createClient(runnersInterModuleContract);\n const projectsClient = interModuleTransport.createClient(projectsInterModuleContract);\n const definitionsClient = interModuleTransport.createClient(definitionsInterModuleContract);\n const annotationsClient = interModuleTransport.createClient(annotationsInterModuleContract);\n const secretsClient = interModuleTransport.createClient(secretsInterModuleContract);\n const workspacesClient = interModuleTransport.createClient(workspacesInterModuleContract);\n const integrationsClient = interModuleTransport.createClient(integrationsInterModuleContract);\n const integrations = await createIntegrationsContext({\n workspaces: workspacesClient,\n secrets: {\n deleteSecrets: async (params) => (await secretsClient.deleteSecrets(params)).deleted,\n linear: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/linear/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/linear/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/linear/${params.namespace}`,\n })\n ).deleted,\n },\n jira: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/jira/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/jira/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/jira/${params.namespace}`,\n })\n ).deleted,\n },\n slack: {\n getSecret: async (params) =>\n (\n await secretsClient.getSecret({\n ...params,\n namespace: `system/integrations/slack/${params.namespace}`,\n })\n ).value,\n setSecrets: async (params) => {\n const {editedBy, ...secretParams} = params;\n await secretsClient.setSecrets({\n ...secretParams,\n namespace: `system/integrations/slack/${secretParams.namespace}`,\n ...(editedBy === undefined ? {} : {editedBy}),\n });\n },\n deleteSecrets: async (params) =>\n (\n await secretsClient.deleteSecrets({\n ...params,\n namespace: `system/integrations/slack/${params.namespace}`,\n })\n ).deleted,\n },\n },\n agentTools: {workflows: workflowsClient},\n webhookDeliverySource: options.webhookDeliverySource,\n });\n const projectsModule = createProjectsModule({integrations: integrationsClient});\n const definitionsModule = createDefinitionsModule({\n projects: projectsClient,\n integrations: integrationsClient,\n });\n\n const modules = [\n emailChallengesModule,\n createAuthModule({workspaces: workspacesClient}),\n workspacesModule,\n createSecretsModule(projectsClient),\n createAgentModule({secrets: secretsClient}),\n integrations.module,\n projectsModule,\n definitionsModule,\n createWorkflowsModule({\n annotations: annotationsClient,\n agent: agentClient,\n definitions: definitionsClient,\n auth: authClient,\n projects: projectsClient,\n runners: runnersClient,\n secrets: secretsClient,\n integrations: integrationsClient,\n }),\n annotationsModule,\n (options.runnersModule ?? createRunnersModule)({auth: authClient}),\n createLogsModule({\n workflows: workflowsClient,\n jobLeaseTokenTtlSeconds: durationToSeconds(authConfig.AUTH_JOB_LEASE_TOKEN_EXPIRES_IN),\n }),\n createTriggersModule({workflows: workflowsClient}),\n dispatcherModule,\n ];\n registerInterModulePresentations({transport: interModuleTransport, modules});\n interModuleTransport.seal();\n return modules;\n}\n"],"names":["annotationsModule","annotationsInterModuleContract","createAgentModule","agentInterModuleContract","createAuthModule","config","authConfig","authInterModuleContract","createDefinitionsModule","definitionsInterModuleContract","dispatcherModule","emailChallengesModule","createIntegrationsContext","integrationsInterModuleContract","createLogsModule","createProjectsModule","projectsInterModuleContract","createRunnersModule","runnersInterModuleContract","createSecretsModule","secretsInterModuleContract","createTriggersModule","createWorkflowsModule","workflowsInterModuleContract","workspacesModule","workspacesInterModuleContract","reportError","durationToSeconds","createInMemoryInterModuleTransport","registerInterModulePresentations","logger","defaultModules","options","interModuleTransport","reportInternalError","error","context","err","module","method","phase","boundary","operation","tags","workflowsClient","createClient","authClient","agentClient","runnersClient","projectsClient","definitionsClient","annotationsClient","secretsClient","workspacesClient","integrationsClient","integrations","workspaces","secrets","deleteSecrets","params","deleted","linear","getSecret","namespace","value","setSecrets","editedBy","secretParams","undefined","jira","slack","agentTools","workflows","webhookDeliverySource","projectsModule","definitionsModule","projects","modules","annotations","agent","definitions","auth","runners","runnersModule","jobLeaseTokenTtlSeconds","AUTH_JOB_LEASE_TOKEN_EXPIRES_IN","transport","seal"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-methods.d.ts","sourceRoot":"","sources":["../../src/routes/login-methods.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAEtD,wBAAgB,uBAAuB,CAAC,EAAC,YAAY,EAAC,EAAE;IAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAA;CAAC,mDAgB7F"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { loginMethodsResponseSchema } from '@shipfox/api-auth-dto';
|
|
2
|
+
import { defineRoute } from '@shipfox/node-fastify';
|
|
3
|
+
export function createLoginMethodsRoute({ loginMethods }) {
|
|
4
|
+
const response = loginMethodsResponseSchema.parse({
|
|
5
|
+
login_methods: loginMethods.map(({ id })=>({
|
|
6
|
+
id
|
|
7
|
+
}))
|
|
8
|
+
});
|
|
9
|
+
return defineRoute({
|
|
10
|
+
method: 'GET',
|
|
11
|
+
path: '/auth/login-methods',
|
|
12
|
+
description: 'List the login methods available in this server composition.',
|
|
13
|
+
schema: {
|
|
14
|
+
response: {
|
|
15
|
+
200: loginMethodsResponseSchema
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
handler: ()=>response
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=login-methods.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/routes/login-methods.ts"],"sourcesContent":["import {loginMethodsResponseSchema} from '@shipfox/api-auth-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {LoginMethod} from '@shipfox/node-module';\n\nexport function createLoginMethodsRoute({loginMethods}: {loginMethods: readonly LoginMethod[]}) {\n const response = loginMethodsResponseSchema.parse({\n login_methods: loginMethods.map(({id}) => ({id})),\n });\n\n return defineRoute({\n method: 'GET',\n path: '/auth/login-methods',\n description: 'List the login methods available in this server composition.',\n schema: {\n response: {\n 200: loginMethodsResponseSchema,\n },\n },\n handler: () => response,\n });\n}\n"],"names":["loginMethodsResponseSchema","defineRoute","createLoginMethodsRoute","loginMethods","response","parse","login_methods","map","id","method","path","description","schema","handler"],"mappings":"AAAA,SAAQA,0BAA0B,QAAO,wBAAwB;AACjE,SAAQC,WAAW,QAAO,wBAAwB;AAGlD,OAAO,SAASC,wBAAwB,EAACC,YAAY,EAAyC;IAC5F,MAAMC,WAAWJ,2BAA2BK,KAAK,CAAC;QAChDC,eAAeH,aAAaI,GAAG,CAAC,CAAC,EAACC,EAAE,EAAC,GAAM,CAAA;gBAACA;YAAE,CAAA;IAChD;IAEA,OAAOP,YAAY;QACjBQ,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNR,UAAU;gBACR,KAAKJ;YACP;QACF;QACAa,SAAS,IAAMT;IACjB;AACF"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,aAAa,EAElB,KAAK,YAAY,EAIjB,KAAK,aAAa,EAGnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,aAAa,EAElB,KAAK,YAAY,EAIjB,KAAK,aAAa,EAGnB,MAAM,sBAAsB,CAAC;AAY9B,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrF;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsHtF;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CA6ChF"}
|
package/dist/server.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closeErrorMonitoring, markErrorReported, reportError } from '@shipfox/node-error-monitoring';
|
|
2
2
|
import { closeApp, createApp, listen } from '@shipfox/node-fastify';
|
|
3
3
|
import { aggregateLoginMethods, initializeModules, registerModuleMetrics, runModuleStartupTasks, startModuleServices, startModuleWorkers } from '@shipfox/node-module';
|
|
4
4
|
import { logger, shutdownServiceMetrics, startServiceMetrics } from '@shipfox/node-opentelemetry';
|
|
5
5
|
import { closePostgresClient, createPostgresClient } from '@shipfox/node-postgres';
|
|
6
6
|
import { config, parseApiTrustProxy } from './config.js';
|
|
7
7
|
import { createE2eAdminAuthMethod, createE2eRouteGroup } from './e2e.js';
|
|
8
|
+
import { createLoginMethodsRoute } from './routes/login-methods.js';
|
|
8
9
|
const RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
9
10
|
const ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS = 2_000;
|
|
10
11
|
let hasActiveServer = false;
|
|
@@ -14,7 +15,7 @@ export async function createServer(options) {
|
|
|
14
15
|
}
|
|
15
16
|
hasActiveServer = true;
|
|
16
17
|
try {
|
|
17
|
-
aggregateLoginMethods({
|
|
18
|
+
const loginMethods = aggregateLoginMethods({
|
|
18
19
|
modules: options.modules
|
|
19
20
|
});
|
|
20
21
|
startServiceMetrics({
|
|
@@ -47,6 +48,9 @@ export async function createServer(options) {
|
|
|
47
48
|
...e2eAuth
|
|
48
49
|
],
|
|
49
50
|
routes: [
|
|
51
|
+
createLoginMethodsRoute({
|
|
52
|
+
loginMethods
|
|
53
|
+
}),
|
|
50
54
|
...routes,
|
|
51
55
|
...mountedE2eRoutes
|
|
52
56
|
],
|
|
@@ -100,11 +104,26 @@ export async function createServer(options) {
|
|
|
100
104
|
()=>servicesHandle?.stop(),
|
|
101
105
|
()=>workersHandle?.stop(),
|
|
102
106
|
()=>shutdownServiceMetrics(),
|
|
103
|
-
()=>closePostgresClient()
|
|
104
|
-
async ()=>{
|
|
105
|
-
await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
106
|
-
}
|
|
107
|
+
()=>closePostgresClient()
|
|
107
108
|
]);
|
|
109
|
+
for (const cleanupError of cleanupErrors){
|
|
110
|
+
logger().error({
|
|
111
|
+
err: cleanupError
|
|
112
|
+
}, 'Failed to clean up API server during shutdown');
|
|
113
|
+
reportError(cleanupError, {
|
|
114
|
+
boundary: 'api.shutdown',
|
|
115
|
+
operation: 'cleanup'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const errorMonitoringClosed = await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
120
|
+
if (!errorMonitoringClosed) {
|
|
121
|
+
logger().error('Timed out closing error monitoring during API shutdown');
|
|
122
|
+
cleanupErrors.push(new Error('Timed out closing error monitoring during API shutdown'));
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
cleanupErrors.push(error);
|
|
126
|
+
}
|
|
108
127
|
throwCleanupErrors(cleanupErrors, 'Failed to stop API server');
|
|
109
128
|
stopped = true;
|
|
110
129
|
hasActiveServer = false;
|
|
@@ -128,6 +147,10 @@ export async function createServer(options) {
|
|
|
128
147
|
err: cleanupError,
|
|
129
148
|
bootError: error
|
|
130
149
|
}, 'Failed to clean up API server boot');
|
|
150
|
+
reportError(cleanupError, {
|
|
151
|
+
boundary: 'api.startup',
|
|
152
|
+
operation: 'cleanup'
|
|
153
|
+
});
|
|
131
154
|
}
|
|
132
155
|
hasActiveServer = false;
|
|
133
156
|
throw error;
|
|
@@ -156,10 +179,23 @@ export async function runServer(options) {
|
|
|
156
179
|
err: cleanupError,
|
|
157
180
|
startError: error
|
|
158
181
|
}, 'Failed to clean up API server startup');
|
|
182
|
+
reportError(cleanupError, {
|
|
183
|
+
boundary: 'api.startup',
|
|
184
|
+
operation: 'cleanup-after-failed-start'
|
|
185
|
+
});
|
|
159
186
|
}
|
|
160
187
|
throw error;
|
|
161
188
|
}
|
|
162
|
-
const stopAndExit = ()=>void handle.stop().
|
|
189
|
+
const stopAndExit = ()=>void handle.stop().then(()=>process.exit(0), (error)=>{
|
|
190
|
+
logger().error({
|
|
191
|
+
err: error
|
|
192
|
+
}, 'Failed to stop API server after shutdown signal');
|
|
193
|
+
reportError(error, {
|
|
194
|
+
boundary: 'api.shutdown',
|
|
195
|
+
operation: 'signal-stop'
|
|
196
|
+
});
|
|
197
|
+
process.exit(1);
|
|
198
|
+
});
|
|
163
199
|
process.once('SIGTERM', stopAndExit);
|
|
164
200
|
process.once('SIGINT', stopAndExit);
|
|
165
201
|
return handle;
|
|
@@ -188,7 +224,9 @@ async function runCleanupSteps(steps) {
|
|
|
188
224
|
function throwCleanupErrors(cleanupErrors, message) {
|
|
189
225
|
if (cleanupErrors.length === 0) return;
|
|
190
226
|
if (cleanupErrors.length === 1) throw cleanupErrors[0];
|
|
191
|
-
|
|
227
|
+
const aggregate = new AggregateError(cleanupErrors, message);
|
|
228
|
+
markErrorReported(aggregate);
|
|
229
|
+
throw aggregate;
|
|
192
230
|
}
|
|
193
231
|
async function handleModuleWorkerFailure(error, worker, onWorkerFailure) {
|
|
194
232
|
await handleModuleRuntimeFailure({
|
|
@@ -215,10 +253,20 @@ async function handleModuleRuntimeFailure(options) {
|
|
|
215
253
|
err: options.error,
|
|
216
254
|
...options.fields
|
|
217
255
|
}, options.message);
|
|
218
|
-
|
|
256
|
+
reportError(options.error, {
|
|
257
|
+
boundary: 'api.runtime',
|
|
258
|
+
tags: options.fields
|
|
259
|
+
});
|
|
219
260
|
try {
|
|
220
261
|
await closeHttpServerAfterRuntimeFailure();
|
|
221
|
-
await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
262
|
+
const errorMonitoringClosed = await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
263
|
+
if (!errorMonitoringClosed) {
|
|
264
|
+
logger().error('Timed out closing error monitoring after module runtime failure');
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
logger().error({
|
|
268
|
+
err: error
|
|
269
|
+
}, 'Failed to close error monitoring after module runtime failure');
|
|
222
270
|
} finally{
|
|
223
271
|
await options.onFailure();
|
|
224
272
|
}
|
|
@@ -238,14 +286,23 @@ async function closeHttpServerAfterRuntimeFailure() {
|
|
|
238
286
|
}
|
|
239
287
|
});
|
|
240
288
|
if (result === 'timeout') {
|
|
289
|
+
const error = new Error('Timed out closing HTTP server after module runtime failure');
|
|
241
290
|
logger().error({
|
|
242
291
|
timeoutMs: RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS
|
|
243
|
-
},
|
|
292
|
+
}, error.message);
|
|
293
|
+
reportError(error, {
|
|
294
|
+
boundary: 'api.runtime',
|
|
295
|
+
operation: 'close-http-timeout'
|
|
296
|
+
});
|
|
244
297
|
}
|
|
245
298
|
} catch (error) {
|
|
246
299
|
logger().error({
|
|
247
300
|
err: error
|
|
248
301
|
}, 'Failed to close HTTP server after module runtime failure');
|
|
302
|
+
reportError(error, {
|
|
303
|
+
boundary: 'api.runtime',
|
|
304
|
+
operation: 'close-http'
|
|
305
|
+
});
|
|
249
306
|
} finally{
|
|
250
307
|
if (timeoutId) {
|
|
251
308
|
clearTimeout(timeoutId);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import {captureException, closeErrorMonitoring} from '@shipfox/node-error-monitoring';\nimport {closeApp, createApp, listen} from '@shipfox/node-fastify';\nimport {\n aggregateLoginMethods,\n initializeModules,\n type ModuleService,\n type ModuleServicesHandle,\n type ModuleWorker,\n type ModuleWorkersHandle,\n registerModuleMetrics,\n runModuleStartupTasks,\n type ShipfoxModule,\n startModuleServices,\n startModuleWorkers,\n} from '@shipfox/node-module';\nimport {logger, shutdownServiceMetrics, startServiceMetrics} from '@shipfox/node-opentelemetry';\nimport {closePostgresClient, createPostgresClient} from '@shipfox/node-postgres';\nimport {config, parseApiTrustProxy} from './config.js';\nimport {createE2eAdminAuthMethod, createE2eRouteGroup} from './e2e.js';\n\nconst RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS = 10_000;\nconst ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS = 2_000;\n\nlet hasActiveServer = false;\n\nexport interface CreateServerOptions {\n modules: ShipfoxModule[];\n onWorkerFailure?: (error: unknown, worker: ModuleWorker) => void | Promise<void>;\n onServiceFailure?: (error: unknown, service: ModuleService) => void | Promise<void>;\n}\n\nexport interface ServerHandle {\n start(): Promise<string>;\n stop(): Promise<void>;\n}\n\nexport interface RunServerOptions {\n modules: ShipfoxModule[];\n onStartupFailure?: (error: unknown) => void | Promise<void>;\n}\n\nexport async function createServer(options: CreateServerOptions): Promise<ServerHandle> {\n if (hasActiveServer) {\n throw new Error('Cannot create a second API server before the existing server stops');\n }\n hasActiveServer = true;\n\n try {\n aggregateLoginMethods({modules: options.modules});\n startServiceMetrics({serviceName: 'api'});\n createPostgresClient();\n\n const {auth, routes, e2eRoutes, workers, services, outboxRegistry} = await initializeModules({\n modules: options.modules,\n });\n registerModuleMetrics({modules: options.modules, context: {outboxRegistry}});\n await runModuleStartupTasks({modules: options.modules, context: {outboxRegistry}});\n\n const e2eAuth = config.E2E_ENABLED ? [createE2eAdminAuthMethod(config)] : [];\n const mountedE2eRoutes = createE2eRouteGroup(e2eRoutes, config);\n\n logger().info('Creating HTTP server');\n await createApp({\n auth: [...auth, ...e2eAuth],\n routes: [...routes, ...mountedE2eRoutes],\n fastifyOptions: {trustProxy: parseApiTrustProxy(config.API_TRUST_PROXY)},\n });\n\n let workersHandle: ModuleWorkersHandle | undefined;\n let servicesHandle: ModuleServicesHandle | undefined;\n let startPromise: Promise<string> | undefined;\n let stopPromise: Promise<void> | undefined;\n let stopped = false;\n\n const start = (): Promise<string> => {\n if (stopPromise || stopped)\n return Promise.reject(new Error('Cannot start a stopped API server'));\n\n startPromise ??= (async () => {\n logger().info('Starting module workers');\n workersHandle = await startModuleWorkers({\n workers,\n context: {outboxRegistry},\n onWorkerFailure: (error, worker) =>\n handleModuleWorkerFailure(error, worker, options.onWorkerFailure),\n });\n\n logger().info('Starting module services');\n servicesHandle = await startModuleServices({\n services,\n context: {outboxRegistry},\n onServiceFailure: (error, service) =>\n handleModuleServiceFailure(error, service, options.onServiceFailure),\n });\n\n if (stopPromise) throw new Error('API server stopped during startup');\n\n logger().info('Starting HTTP server');\n const address =\n config.API_PORT === undefined ? await listen() : await listen({port: config.API_PORT});\n logger().info({address}, 'HTTP server listening');\n return address;\n })();\n return startPromise;\n };\n\n const stop = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n\n stopPromise ??= (async () => {\n try {\n await startPromise?.catch(() => undefined);\n const cleanupErrors = await runCleanupSteps([\n () => closeApp(),\n () => servicesHandle?.stop(),\n () => workersHandle?.stop(),\n () => shutdownServiceMetrics(),\n () => closePostgresClient(),\n async () => {\n await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);\n },\n ]);\n throwCleanupErrors(cleanupErrors, 'Failed to stop API server');\n stopped = true;\n hasActiveServer = false;\n } finally {\n stopPromise = undefined;\n }\n })();\n return stopPromise;\n };\n\n return {start, stop};\n } catch (error) {\n const cleanupErrors = await runCleanupSteps([\n () => shutdownServiceMetrics(),\n () => closePostgresClient(),\n ]);\n for (const cleanupError of cleanupErrors) {\n logger().error({err: cleanupError, bootError: error}, 'Failed to clean up API server boot');\n }\n hasActiveServer = false;\n throw error;\n }\n}\n\nexport async function runServer(options: RunServerOptions): Promise<ServerHandle> {\n let handle: ServerHandle;\n try {\n handle = await createServer({\n modules: options.modules,\n onWorkerFailure: () => process.exit(1),\n onServiceFailure: () => process.exit(1),\n });\n } catch (error) {\n await reportStartupFailure(error, options.onStartupFailure);\n throw error;\n }\n\n try {\n await handle.start();\n } catch (error) {\n await reportStartupFailure(error, options.onStartupFailure);\n try {\n await handle.stop();\n } catch (cleanupError) {\n logger().error(\n {err: cleanupError, startError: error},\n 'Failed to clean up API server startup',\n );\n }\n throw error;\n }\n\n const stopAndExit = () => void handle.stop().finally(() => process.exit(0));\n process.once('SIGTERM', stopAndExit);\n process.once('SIGINT', stopAndExit);\n\n return handle;\n}\n\nasync function reportStartupFailure(\n error: unknown,\n onStartupFailure: RunServerOptions['onStartupFailure'],\n): Promise<void> {\n try {\n await onStartupFailure?.(error);\n } catch (reportingError) {\n logger().error(\n {err: reportingError, startError: error},\n 'Failed to report API server startup error',\n );\n }\n}\n\ntype CleanupStep = () => void | Promise<void>;\n\nasync function runCleanupSteps(steps: CleanupStep[]): Promise<unknown[]> {\n const cleanupErrors: unknown[] = [];\n for (const step of steps) {\n try {\n await step();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n return cleanupErrors;\n}\n\nfunction throwCleanupErrors(cleanupErrors: unknown[], message: string): void {\n if (cleanupErrors.length === 0) return;\n if (cleanupErrors.length === 1) throw cleanupErrors[0];\n throw new AggregateError(cleanupErrors, message);\n}\n\nasync function handleModuleWorkerFailure(\n error: unknown,\n worker: ModuleWorker,\n onWorkerFailure: CreateServerOptions['onWorkerFailure'],\n): Promise<void> {\n await handleModuleRuntimeFailure({\n error,\n fields: {taskQueue: worker.taskQueue},\n message: 'Module worker stopped unexpectedly',\n onFailure: () => onWorkerFailure?.(error, worker),\n });\n}\n\nasync function handleModuleServiceFailure(\n error: unknown,\n service: ModuleService,\n onServiceFailure: CreateServerOptions['onServiceFailure'],\n): Promise<void> {\n await handleModuleRuntimeFailure({\n error,\n fields: {service: service.name},\n message: 'Module service stopped unexpectedly',\n onFailure: () => onServiceFailure?.(error, service),\n });\n}\n\nasync function handleModuleRuntimeFailure(options: {\n error: unknown;\n fields: Record<string, string>;\n message: string;\n onFailure(): void | Promise<void>;\n}): Promise<void> {\n logger().error({err: options.error, ...options.fields}, options.message);\n captureException(options.error);\n\n try {\n await closeHttpServerAfterRuntimeFailure();\n await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);\n } finally {\n await options.onFailure();\n }\n}\n\nasync function closeHttpServerAfterRuntimeFailure(): Promise<void> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<'timeout'>((resolve) => {\n timeoutId = setTimeout(() => resolve('timeout'), RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS);\n });\n try {\n const result = await Promise.race([closeApp().then(() => 'closed' as const), timeout]).finally(\n () => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n },\n );\n if (result === 'timeout') {\n logger().error(\n {timeoutMs: RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS},\n 'Timed out closing HTTP server after module runtime failure',\n );\n }\n } catch (error) {\n logger().error({err: error}, 'Failed to close HTTP server after module runtime failure');\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n}\n"],"names":["captureException","closeErrorMonitoring","closeApp","createApp","listen","aggregateLoginMethods","initializeModules","registerModuleMetrics","runModuleStartupTasks","startModuleServices","startModuleWorkers","logger","shutdownServiceMetrics","startServiceMetrics","closePostgresClient","createPostgresClient","config","parseApiTrustProxy","createE2eAdminAuthMethod","createE2eRouteGroup","RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS","ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS","hasActiveServer","createServer","options","Error","modules","serviceName","auth","routes","e2eRoutes","workers","services","outboxRegistry","context","e2eAuth","E2E_ENABLED","mountedE2eRoutes","info","fastifyOptions","trustProxy","API_TRUST_PROXY","workersHandle","servicesHandle","startPromise","stopPromise","stopped","start","Promise","reject","onWorkerFailure","error","worker","handleModuleWorkerFailure","onServiceFailure","service","handleModuleServiceFailure","address","API_PORT","undefined","port","stop","resolve","catch","cleanupErrors","runCleanupSteps","throwCleanupErrors","cleanupError","err","bootError","runServer","handle","process","exit","reportStartupFailure","onStartupFailure","startError","stopAndExit","finally","once","reportingError","steps","step","push","message","length","AggregateError","handleModuleRuntimeFailure","fields","taskQueue","onFailure","name","closeHttpServerAfterRuntimeFailure","timeoutId","timeout","setTimeout","result","race","then","clearTimeout","timeoutMs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import {closeErrorMonitoring, markErrorReported, reportError} from '@shipfox/node-error-monitoring';\nimport {closeApp, createApp, listen} from '@shipfox/node-fastify';\nimport {\n aggregateLoginMethods,\n initializeModules,\n type ModuleService,\n type ModuleServicesHandle,\n type ModuleWorker,\n type ModuleWorkersHandle,\n registerModuleMetrics,\n runModuleStartupTasks,\n type ShipfoxModule,\n startModuleServices,\n startModuleWorkers,\n} from '@shipfox/node-module';\nimport {logger, shutdownServiceMetrics, startServiceMetrics} from '@shipfox/node-opentelemetry';\nimport {closePostgresClient, createPostgresClient} from '@shipfox/node-postgres';\nimport {config, parseApiTrustProxy} from './config.js';\nimport {createE2eAdminAuthMethod, createE2eRouteGroup} from './e2e.js';\nimport {createLoginMethodsRoute} from './routes/login-methods.js';\n\nconst RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS = 10_000;\nconst ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS = 2_000;\n\nlet hasActiveServer = false;\n\nexport interface CreateServerOptions {\n modules: ShipfoxModule[];\n onWorkerFailure?: (error: unknown, worker: ModuleWorker) => void | Promise<void>;\n onServiceFailure?: (error: unknown, service: ModuleService) => void | Promise<void>;\n}\n\nexport interface ServerHandle {\n start(): Promise<string>;\n stop(): Promise<void>;\n}\n\nexport interface RunServerOptions {\n modules: ShipfoxModule[];\n onStartupFailure?: (error: unknown) => void | Promise<void>;\n}\n\nexport async function createServer(options: CreateServerOptions): Promise<ServerHandle> {\n if (hasActiveServer) {\n throw new Error('Cannot create a second API server before the existing server stops');\n }\n hasActiveServer = true;\n\n try {\n const loginMethods = aggregateLoginMethods({modules: options.modules});\n startServiceMetrics({serviceName: 'api'});\n createPostgresClient();\n\n const {auth, routes, e2eRoutes, workers, services, outboxRegistry} = await initializeModules({\n modules: options.modules,\n });\n registerModuleMetrics({modules: options.modules, context: {outboxRegistry}});\n await runModuleStartupTasks({modules: options.modules, context: {outboxRegistry}});\n\n const e2eAuth = config.E2E_ENABLED ? [createE2eAdminAuthMethod(config)] : [];\n const mountedE2eRoutes = createE2eRouteGroup(e2eRoutes, config);\n\n logger().info('Creating HTTP server');\n await createApp({\n auth: [...auth, ...e2eAuth],\n routes: [createLoginMethodsRoute({loginMethods}), ...routes, ...mountedE2eRoutes],\n fastifyOptions: {trustProxy: parseApiTrustProxy(config.API_TRUST_PROXY)},\n });\n\n let workersHandle: ModuleWorkersHandle | undefined;\n let servicesHandle: ModuleServicesHandle | undefined;\n let startPromise: Promise<string> | undefined;\n let stopPromise: Promise<void> | undefined;\n let stopped = false;\n\n const start = (): Promise<string> => {\n if (stopPromise || stopped)\n return Promise.reject(new Error('Cannot start a stopped API server'));\n\n startPromise ??= (async () => {\n logger().info('Starting module workers');\n workersHandle = await startModuleWorkers({\n workers,\n context: {outboxRegistry},\n onWorkerFailure: (error, worker) =>\n handleModuleWorkerFailure(error, worker, options.onWorkerFailure),\n });\n\n logger().info('Starting module services');\n servicesHandle = await startModuleServices({\n services,\n context: {outboxRegistry},\n onServiceFailure: (error, service) =>\n handleModuleServiceFailure(error, service, options.onServiceFailure),\n });\n\n if (stopPromise) throw new Error('API server stopped during startup');\n\n logger().info('Starting HTTP server');\n const address =\n config.API_PORT === undefined ? await listen() : await listen({port: config.API_PORT});\n logger().info({address}, 'HTTP server listening');\n return address;\n })();\n return startPromise;\n };\n\n const stop = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n\n stopPromise ??= (async () => {\n try {\n await startPromise?.catch(() => undefined);\n const cleanupErrors = await runCleanupSteps([\n () => closeApp(),\n () => servicesHandle?.stop(),\n () => workersHandle?.stop(),\n () => shutdownServiceMetrics(),\n () => closePostgresClient(),\n ]);\n for (const cleanupError of cleanupErrors) {\n logger().error({err: cleanupError}, 'Failed to clean up API server during shutdown');\n reportError(cleanupError, {boundary: 'api.shutdown', operation: 'cleanup'});\n }\n try {\n const errorMonitoringClosed = await closeErrorMonitoring(\n ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS,\n );\n if (!errorMonitoringClosed) {\n logger().error('Timed out closing error monitoring during API shutdown');\n cleanupErrors.push(\n new Error('Timed out closing error monitoring during API shutdown'),\n );\n }\n } catch (error) {\n cleanupErrors.push(error);\n }\n throwCleanupErrors(cleanupErrors, 'Failed to stop API server');\n stopped = true;\n hasActiveServer = false;\n } finally {\n stopPromise = undefined;\n }\n })();\n return stopPromise;\n };\n\n return {start, stop};\n } catch (error) {\n const cleanupErrors = await runCleanupSteps([\n () => shutdownServiceMetrics(),\n () => closePostgresClient(),\n ]);\n for (const cleanupError of cleanupErrors) {\n logger().error({err: cleanupError, bootError: error}, 'Failed to clean up API server boot');\n reportError(cleanupError, {boundary: 'api.startup', operation: 'cleanup'});\n }\n hasActiveServer = false;\n throw error;\n }\n}\n\nexport async function runServer(options: RunServerOptions): Promise<ServerHandle> {\n let handle: ServerHandle;\n try {\n handle = await createServer({\n modules: options.modules,\n onWorkerFailure: () => process.exit(1),\n onServiceFailure: () => process.exit(1),\n });\n } catch (error) {\n await reportStartupFailure(error, options.onStartupFailure);\n throw error;\n }\n\n try {\n await handle.start();\n } catch (error) {\n await reportStartupFailure(error, options.onStartupFailure);\n try {\n await handle.stop();\n } catch (cleanupError) {\n logger().error(\n {err: cleanupError, startError: error},\n 'Failed to clean up API server startup',\n );\n reportError(cleanupError, {\n boundary: 'api.startup',\n operation: 'cleanup-after-failed-start',\n });\n }\n throw error;\n }\n\n const stopAndExit = () =>\n void handle.stop().then(\n () => process.exit(0),\n (error) => {\n logger().error({err: error}, 'Failed to stop API server after shutdown signal');\n reportError(error, {boundary: 'api.shutdown', operation: 'signal-stop'});\n process.exit(1);\n },\n );\n process.once('SIGTERM', stopAndExit);\n process.once('SIGINT', stopAndExit);\n\n return handle;\n}\n\nasync function reportStartupFailure(\n error: unknown,\n onStartupFailure: RunServerOptions['onStartupFailure'],\n): Promise<void> {\n try {\n await onStartupFailure?.(error);\n } catch (reportingError) {\n logger().error(\n {err: reportingError, startError: error},\n 'Failed to report API server startup error',\n );\n }\n}\n\ntype CleanupStep = () => void | Promise<void>;\n\nasync function runCleanupSteps(steps: CleanupStep[]): Promise<unknown[]> {\n const cleanupErrors: unknown[] = [];\n for (const step of steps) {\n try {\n await step();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n return cleanupErrors;\n}\n\nfunction throwCleanupErrors(cleanupErrors: unknown[], message: string): void {\n if (cleanupErrors.length === 0) return;\n if (cleanupErrors.length === 1) throw cleanupErrors[0];\n const aggregate = new AggregateError(cleanupErrors, message);\n markErrorReported(aggregate);\n throw aggregate;\n}\n\nasync function handleModuleWorkerFailure(\n error: unknown,\n worker: ModuleWorker,\n onWorkerFailure: CreateServerOptions['onWorkerFailure'],\n): Promise<void> {\n await handleModuleRuntimeFailure({\n error,\n fields: {taskQueue: worker.taskQueue},\n message: 'Module worker stopped unexpectedly',\n onFailure: () => onWorkerFailure?.(error, worker),\n });\n}\n\nasync function handleModuleServiceFailure(\n error: unknown,\n service: ModuleService,\n onServiceFailure: CreateServerOptions['onServiceFailure'],\n): Promise<void> {\n await handleModuleRuntimeFailure({\n error,\n fields: {service: service.name},\n message: 'Module service stopped unexpectedly',\n onFailure: () => onServiceFailure?.(error, service),\n });\n}\n\nasync function handleModuleRuntimeFailure(options: {\n error: unknown;\n fields: Record<string, string>;\n message: string;\n onFailure(): void | Promise<void>;\n}): Promise<void> {\n logger().error({err: options.error, ...options.fields}, options.message);\n reportError(options.error, {\n boundary: 'api.runtime',\n tags: options.fields,\n });\n\n try {\n await closeHttpServerAfterRuntimeFailure();\n const errorMonitoringClosed = await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);\n if (!errorMonitoringClosed) {\n logger().error('Timed out closing error monitoring after module runtime failure');\n }\n } catch (error) {\n logger().error({err: error}, 'Failed to close error monitoring after module runtime failure');\n } finally {\n await options.onFailure();\n }\n}\n\nasync function closeHttpServerAfterRuntimeFailure(): Promise<void> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<'timeout'>((resolve) => {\n timeoutId = setTimeout(() => resolve('timeout'), RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS);\n });\n try {\n const result = await Promise.race([closeApp().then(() => 'closed' as const), timeout]).finally(\n () => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n },\n );\n if (result === 'timeout') {\n const error = new Error('Timed out closing HTTP server after module runtime failure');\n logger().error({timeoutMs: RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS}, error.message);\n reportError(error, {boundary: 'api.runtime', operation: 'close-http-timeout'});\n }\n } catch (error) {\n logger().error({err: error}, 'Failed to close HTTP server after module runtime failure');\n reportError(error, {boundary: 'api.runtime', operation: 'close-http'});\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n}\n"],"names":["closeErrorMonitoring","markErrorReported","reportError","closeApp","createApp","listen","aggregateLoginMethods","initializeModules","registerModuleMetrics","runModuleStartupTasks","startModuleServices","startModuleWorkers","logger","shutdownServiceMetrics","startServiceMetrics","closePostgresClient","createPostgresClient","config","parseApiTrustProxy","createE2eAdminAuthMethod","createE2eRouteGroup","createLoginMethodsRoute","RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS","ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS","hasActiveServer","createServer","options","Error","loginMethods","modules","serviceName","auth","routes","e2eRoutes","workers","services","outboxRegistry","context","e2eAuth","E2E_ENABLED","mountedE2eRoutes","info","fastifyOptions","trustProxy","API_TRUST_PROXY","workersHandle","servicesHandle","startPromise","stopPromise","stopped","start","Promise","reject","onWorkerFailure","error","worker","handleModuleWorkerFailure","onServiceFailure","service","handleModuleServiceFailure","address","API_PORT","undefined","port","stop","resolve","catch","cleanupErrors","runCleanupSteps","cleanupError","err","boundary","operation","errorMonitoringClosed","push","throwCleanupErrors","bootError","runServer","handle","process","exit","reportStartupFailure","onStartupFailure","startError","stopAndExit","then","once","reportingError","steps","step","message","length","aggregate","AggregateError","handleModuleRuntimeFailure","fields","taskQueue","onFailure","name","tags","closeHttpServerAfterRuntimeFailure","timeoutId","timeout","setTimeout","result","race","finally","clearTimeout","timeoutMs"],"mappings":"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"}
|