@cosmicdrift/kumiko-server-runtime 0.270.0 → 0.274.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-server-runtime",
3
- "version": "0.270.0",
3
+ "version": "0.274.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,8 +80,8 @@
80
80
  }
81
81
  },
82
82
  "dependencies": {
83
- "@cosmicdrift/kumiko-bundled-features": "0.270.0",
84
- "@cosmicdrift/kumiko-framework": "0.270.0",
83
+ "@cosmicdrift/kumiko-bundled-features": "0.274.0",
84
+ "@cosmicdrift/kumiko-framework": "0.274.0",
85
85
  "temporal-polyfill": "^0.3.2"
86
86
  },
87
87
  "publishConfig": {
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { createAuditFeature } from "@cosmicdrift/kumiko-bundled-features/audit";
2
3
  import { createDeliveryFeature } from "@cosmicdrift/kumiko-bundled-features/delivery";
3
4
  import { createSecretsFeature } from "@cosmicdrift/kumiko-bundled-features/secrets";
4
5
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
@@ -137,4 +138,26 @@ describe("buildBootExtraContext — framework-default provider autowire", () =>
137
138
  });
138
139
  expect(ctx["secrets"]).toBeDefined();
139
140
  });
141
+
142
+ test("audit feature mounted → _escapeHatchAuditSink wired", () => {
143
+ const ctx = buildBootExtraContext({
144
+ db: fakeDb,
145
+ features: [createAuditFeature()],
146
+ envSource: {},
147
+ registry,
148
+ hasAuth: false,
149
+ });
150
+ expect(typeof ctx["_escapeHatchAuditSink"]).toBe("function");
151
+ });
152
+
153
+ test("no audit feature → _escapeHatchAuditSink not wired", () => {
154
+ const ctx = buildBootExtraContext({
155
+ db: fakeDb,
156
+ features: [otherFeature],
157
+ envSource: {},
158
+ registry,
159
+ hasAuth: false,
160
+ });
161
+ expect(ctx["_escapeHatchAuditSink"]).toBeUndefined();
162
+ });
140
163
  });
@@ -1,3 +1,7 @@
1
+ import {
2
+ AUDIT_FEATURE,
3
+ createEscapeHatchAuditSink,
4
+ } from "@cosmicdrift/kumiko-bundled-features/audit";
1
5
  import { makeAuthPaths } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";
2
6
  import { resolveSessionStore } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
3
7
  import {
@@ -30,6 +34,7 @@ import type { KmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
30
34
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
31
35
  import type {
32
36
  ConfigResolver,
37
+ EscapeHatchAuditSink,
33
38
  FeatureDefinition,
34
39
  NotifyFactory,
35
40
  Registry,
@@ -85,17 +90,27 @@ function buildDeliveryNotifyFactory(opts: {
85
90
  readonly db: DbConnection;
86
91
  readonly registry: Registry;
87
92
  readonly sseBroker?: SseBroker;
93
+ readonly escapeHatchAuditSink?: EscapeHatchAuditSink;
88
94
  }): NotifyFactory {
89
95
  const deliveryService = createDeliveryService({
90
96
  db: opts.db,
91
97
  registry: opts.registry,
92
98
  channels: collectChannels(opts.registry),
93
99
  ...(opts.sseBroker && { sseBroker: opts.sseBroker }),
100
+ ...(opts.escapeHatchAuditSink && { escapeHatchAuditSink: opts.escapeHatchAuditSink }),
94
101
  });
95
102
  return (user, tenantId) => (notificationType, options) =>
96
103
  deliveryService.notify(notificationType, options, user, tenantId);
97
104
  }
98
105
 
106
+ function resolveEscapeHatchAuditSink(
107
+ features: readonly FeatureDefinition[],
108
+ db: DbConnection,
109
+ ): EscapeHatchAuditSink | undefined {
110
+ const hasAuditFeature = features.some((f) => f.name === AUDIT_FEATURE);
111
+ return hasAuditFeature ? createEscapeHatchAuditSink({ db }) : undefined;
112
+ }
113
+
99
114
  export function buildBootExtraContext(opts: {
100
115
  readonly db: DbConnection;
101
116
  readonly features: readonly FeatureDefinition[];
@@ -114,14 +129,17 @@ export function buildBootExtraContext(opts: {
114
129
  const hasSecretsFeature = opts.features.some((f) => f.name === SECRETS_FEATURE_NAME);
115
130
  const wireSecrets = hasSecretsFeature && crypto.masterKeyProvider !== undefined;
116
131
  const hasDeliveryFeature = opts.features.some((f) => f.name === DELIVERY_FEATURE);
132
+ const escapeHatchAuditSink = resolveEscapeHatchAuditSink(opts.features, opts.db);
117
133
  return {
118
134
  templateResolver: createTemplateResolverApi(opts.db),
119
135
  ...(opts.kms && { kms: opts.kms }),
136
+ ...(escapeHatchAuditSink && { _escapeHatchAuditSink: escapeHatchAuditSink }),
120
137
  ...(hasDeliveryFeature && {
121
138
  _notifyFactory: buildDeliveryNotifyFactory({
122
139
  db: opts.db,
123
140
  registry: opts.registry,
124
141
  ...(opts.sseBroker && { sseBroker: opts.sseBroker }),
142
+ ...(escapeHatchAuditSink && { escapeHatchAuditSink }),
125
143
  }),
126
144
  }),
127
145
  // Top-level provider so feature jobs (secrets rotate, config reencrypt)