@cosmicdrift/kumiko-server-runtime 0.343.0 → 0.345.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.
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
|
+
export declare const APP_VERSION_ENV = "KUMIKO_APP_VERSION";
|
|
3
|
+
export declare const GIT_COMMIT_ENV = "KUMIKO_GIT_COMMIT";
|
|
4
|
+
export declare const INSTANCE_ID_ENV = "HOSTNAME";
|
|
5
|
+
export declare const UNKNOWN_APP_VERSION = "unknown";
|
|
6
|
+
type EnvSource = Readonly<Record<string, string | undefined>>;
|
|
7
|
+
export type AppStartedPayload = {
|
|
8
|
+
readonly version: string;
|
|
9
|
+
readonly commit?: string;
|
|
10
|
+
readonly instanceId: string;
|
|
11
|
+
readonly startedAt: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function resolveAppStartedPayload(envSource: EnvSource, fallbackHostname: string, startedAt: string): AppStartedPayload;
|
|
14
|
+
export declare function recordAppStartedOnBoot(opts: {
|
|
15
|
+
readonly db: DbConnection;
|
|
16
|
+
readonly envSource: EnvSource;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { hostname } from "node:os";
|
|
2
|
+
import { APP_INSTANCE_STREAM_TYPE, APP_STARTED_EVENT_TYPE, append, } from "@cosmicdrift/kumiko-framework/event-store";
|
|
3
|
+
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
4
|
+
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
+
import { SYSTEM_TENANT_ID, SYSTEM_USER_ID } from "@cosmicdrift/kumiko-types/identifiers";
|
|
6
|
+
export const APP_VERSION_ENV = "KUMIKO_APP_VERSION";
|
|
7
|
+
export const GIT_COMMIT_ENV = "KUMIKO_GIT_COMMIT";
|
|
8
|
+
export const INSTANCE_ID_ENV = "HOSTNAME";
|
|
9
|
+
export const UNKNOWN_APP_VERSION = "unknown";
|
|
10
|
+
function nonEmpty(value) {
|
|
11
|
+
return value === undefined || value === "" ? undefined : value;
|
|
12
|
+
}
|
|
13
|
+
export function resolveAppStartedPayload(envSource, fallbackHostname, startedAt) {
|
|
14
|
+
const commit = nonEmpty(envSource[GIT_COMMIT_ENV]);
|
|
15
|
+
return {
|
|
16
|
+
version: nonEmpty(envSource[APP_VERSION_ENV]) ?? UNKNOWN_APP_VERSION,
|
|
17
|
+
...(commit !== undefined ? { commit } : {}),
|
|
18
|
+
instanceId: nonEmpty(envSource[INSTANCE_ID_ENV]) ?? fallbackHostname,
|
|
19
|
+
startedAt,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Audit trail only: a failed append must never keep the app from booting.
|
|
23
|
+
export async function recordAppStartedOnBoot(opts) {
|
|
24
|
+
const payload = resolveAppStartedPayload(opts.envSource, hostname(), Temporal.Now.instant().toString());
|
|
25
|
+
try {
|
|
26
|
+
await append(opts.db, {
|
|
27
|
+
aggregateId: generateId(),
|
|
28
|
+
aggregateType: APP_INSTANCE_STREAM_TYPE,
|
|
29
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
30
|
+
expectedVersion: 0,
|
|
31
|
+
type: APP_STARTED_EVENT_TYPE,
|
|
32
|
+
payload,
|
|
33
|
+
metadata: { userId: SYSTEM_USER_ID },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
createFallbackLogger("app-started").warn("Could not record app.started event; continuing boot", {
|
|
38
|
+
version: payload.version,
|
|
39
|
+
error: e instanceof Error ? e.message : String(e),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
package/dist/run-prod-app.js
CHANGED
|
@@ -65,6 +65,7 @@ import { applyBootSeeds } from "./boot/apply-boot-seeds.js";
|
|
|
65
65
|
import { resolveBootCrypto } from "./boot/boot-crypto.js";
|
|
66
66
|
import { jobRunLoggerCallbacks } from "./boot/job-run-logger.js";
|
|
67
67
|
import { startPiiEventBackfillOnBoot } from "./boot/pii-event-backfill-on-boot.js";
|
|
68
|
+
import { recordAppStartedOnBoot } from "./boot/record-app-started-on-boot.js";
|
|
68
69
|
import { buildBunServeOptions, resolveDerivedMaxRequestBodySize } from "./bun-serve-options.js";
|
|
69
70
|
import { buildComposeAuthOptions, composeFeatures } from "./compose-features.js";
|
|
70
71
|
import { makeDispatchSystemWrite } from "./extra-routes-deps.js";
|
|
@@ -527,6 +528,7 @@ export async function runProdApp(options) {
|
|
|
527
528
|
...patAuthFragment,
|
|
528
529
|
...(mfaFeature && {
|
|
529
530
|
mfaVerifyHandler: AuthMfaHandlers.verify,
|
|
531
|
+
switchTenantMfaGateHandler: AuthHandlers.switchTenantMfaGate,
|
|
530
532
|
mfaPreauthEnableStartHandler: AuthMfaHandlers.enableStartPreauth,
|
|
531
533
|
mfaPreauthConfirmHandler: AuthMfaHandlers.enableConfirmPreauth,
|
|
532
534
|
mfaVerifyRateLimit: createRedisLoginRateLimiter(redis, undefined, undefined, "mfa-verify"),
|
|
@@ -679,6 +681,7 @@ export async function runProdApp(options) {
|
|
|
679
681
|
});
|
|
680
682
|
}
|
|
681
683
|
await entrypoint.start();
|
|
684
|
+
await recordAppStartedOnBoot({ db, envSource });
|
|
682
685
|
startPiiEventBackfillOnBoot({
|
|
683
686
|
db,
|
|
684
687
|
registry,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-server-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.345.0",
|
|
4
4
|
"description": "Production server-boot runtime for Kumiko apps: connections, schema-drift-gate, seeds, lifecycle, graceful shutdown. Symmetric to kumiko-dev-server's runDevApp, without dev/scaffold/codegen tooling.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
84
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
85
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
86
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
83
|
+
"@cosmicdrift/kumiko-bundled-features": "0.345.0",
|
|
84
|
+
"@cosmicdrift/kumiko-framework": "0.345.0",
|
|
85
|
+
"@cosmicdrift/kumiko-headless": "0.345.0",
|
|
86
|
+
"@cosmicdrift/kumiko-renderer-web": "0.345.0",
|
|
87
87
|
"bun-types": "^1.3.13",
|
|
88
88
|
"ioredis": "^5.10.1",
|
|
89
89
|
"temporal-polyfill": "^0.3.2"
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.345.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "runProdApp records an app.started system event with version and instance on every boot",
|
|
6
|
+
"detail": "runProdApp records a `kumiko:system:app.started` event on every boot\nEach start appends one event under the system tenant (stream type `app-instance`) with the app version, the instance id (`HOSTNAME`, else the OS hostname) and the start time. Set `KUMIKO_APP_VERSION` and optionally `KUMIKO_GIT_COMMIT` in the deployment; without a version the event records `\"unknown\"`. A failed write is logged and does not stop the boot. The framework exports `APP_STARTED_EVENT_TYPE` and `APP_INSTANCE_STREAM_TYPE` from `event-store`."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.343.0",
|
|
4
10
|
"type": "fix",
|