@cosmicdrift/kumiko-server-runtime 0.353.0 → 0.354.1

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.
@@ -139,6 +139,7 @@ export async function bootWorkerProcess(options, envSource, profile) {
139
139
  envSource,
140
140
  registry,
141
141
  hasAuth: includeBundled,
142
+ redis,
142
143
  crypto: bootCrypto,
143
144
  ...(options.kms && { kms: options.kms }),
144
145
  ...(profile.deliverQueuedInline === true && { deliverQueuedInline: true }),
@@ -43,6 +43,7 @@ export type BuildInfo = {
43
43
  /** ISO-Zeitstempel des Builds, lesbare Anzeige-Version (ersetzt den rohen sha). */
44
44
  readonly builtAt: string;
45
45
  };
46
+ export declare const DEFAULT_HTML = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,interactive-widget=resizes-content\" />\n <title>Kumiko</title>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>\n";
46
47
  /** Folder name relative to dist/ for hashed assets (JS, CSS, file-loader
47
48
  * outputs). Exported damit runProdApp dieselbe Konvention für Cache-
48
49
  * Header nutzt — Drift verhindern. */
@@ -67,7 +67,7 @@ const hasBun = typeof globalThis.Bun !== "undefined";
67
67
  // index.html mit den richtigen Placeholder-Tags.
68
68
  // interactive-widget=resizes-content (fw#1918): keeps `position: fixed`
69
69
  // bottom bars anchored above a mobile keyboard instead of behind it.
70
- const DEFAULT_HTML = `<!doctype html>
70
+ export const DEFAULT_HTML = `<!doctype html>
71
71
  <html lang="en">
72
72
  <head>
73
73
  <meta charset="utf-8" />
@@ -1,9 +1,15 @@
1
- import { buildRequestContextDataFromRequest, requestContext, } from "@cosmicdrift/kumiko-framework/api";
1
+ import { buildRequestContextDataFromRequest, } from "@cosmicdrift/kumiko-framework/api";
2
2
  import { createAnonymousUser } from "@cosmicdrift/kumiko-framework/engine";
3
+ import { requestContext } from "@cosmicdrift/kumiko-framework/internal/request-context";
3
4
  // Single wiring for the anonymous-role systemQuery that page-head and
4
5
  // hostDispatch resolvers receive, shared by runProdApp and the dev server so
5
6
  // the anonymous role / request-context / client-IP resolution can't drift.
6
7
  export function buildRequestBoundSystemQuery(params) {
7
8
  const { req, dispatcher, resolver, socketAddress } = params;
8
- return (type, payload, tenantId) => requestContext.run(requestContext.get() ?? buildRequestContextDataFromRequest(req, { resolver, socketAddress }), () => dispatcher.query(type, payload, createAnonymousUser(tenantId)));
9
+ return (type, payload, tenantId, options) => {
10
+ const base = requestContext.get() ?? buildRequestContextDataFromRequest(req, { resolver, socketAddress });
11
+ // The caller's signal replaces the request's: it already folds the request signal in.
12
+ const data = options?.signal ? { ...base, signal: options.signal } : base;
13
+ return requestContext.run(data, () => dispatcher.query(type, payload, createAnonymousUser(tenantId)));
14
+ };
9
15
  }
@@ -6,6 +6,7 @@ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
6
6
  import type { ConfigResolver, FeatureDefinition, Registry } from "@cosmicdrift/kumiko-framework/engine";
7
7
  import type { Logger } from "@cosmicdrift/kumiko-framework/logging";
8
8
  import type { MasterKeyProvider } from "@cosmicdrift/kumiko-framework/secrets";
9
+ import type { Redis } from "ioredis";
9
10
  import { type BootCrypto } from "./boot/boot-crypto.js";
10
11
  import type { AuthMailOptions, EmailVerificationSetup, InviteSetup, PasswordResetSetup, SignupSetup } from "./run-prod-app.js";
11
12
  export declare function addConfigAccessorFactory<T extends {
@@ -21,6 +22,8 @@ export declare function buildBootExtraContext(opts: {
21
22
  readonly crypto?: BootCrypto;
22
23
  readonly masterKey?: MasterKeyProvider;
23
24
  readonly sseBroker?: SseBroker;
25
+ /** Backs notify's idempotencyKey dedup; without it such a notify throws. */
26
+ readonly redis?: Redis;
24
27
  readonly kms?: KmsAdapter;
25
28
  /** One-shot process (runBootstrap): nothing drains its job queue once it
26
29
  * exits, so queued channels must send inline instead of enqueueing. */
@@ -49,6 +49,7 @@ function buildDeliveryNotifyFactory(opts) {
49
49
  db: opts.db,
50
50
  registry: opts.registry,
51
51
  channels: collectChannels(opts.registry),
52
+ ...(opts.redis && { idempotencyRedis: opts.redis }),
52
53
  ...(opts.secrets && { secrets: opts.secrets }),
53
54
  ...(opts.sseBroker && { sseBroker: opts.sseBroker }),
54
55
  ...(opts.escapeHatchAuditSink && { escapeHatchAuditSink: opts.escapeHatchAuditSink }),
@@ -83,6 +84,15 @@ function resolveBootSecrets(db, features, crypto, registry) {
83
84
  dekCache: crypto.dekCache,
84
85
  });
85
86
  }
87
+ function bootCryptoContext(crypto) {
88
+ return {
89
+ ...(crypto.masterKeyProvider && { masterKeyProvider: crypto.masterKeyProvider }),
90
+ // Encrypt/decrypt partner for `encrypted: true` config keys. Wired
91
+ // whenever a master key exists — NOT gated on the secrets feature,
92
+ // config encryption must work without mounting ctx.secrets.
93
+ ...(crypto.configCipher && { configEncryption: crypto.configCipher }),
94
+ };
95
+ }
86
96
  export function buildBootExtraContext(opts) {
87
97
  const crypto = opts.crypto ?? resolveBootCrypto(opts.envSource, opts.masterKey);
88
98
  const hasDeliveryFeature = opts.features.some((f) => f.name === DELIVERY_FEATURE);
@@ -98,6 +108,7 @@ export function buildBootExtraContext(opts) {
98
108
  registry: opts.registry,
99
109
  ...(secrets && { secrets }),
100
110
  ...(opts.sseBroker && { sseBroker: opts.sseBroker }),
111
+ ...(opts.redis && { redis: opts.redis }),
101
112
  ...(escapeHatchAuditSink && { escapeHatchAuditSink }),
102
113
  ...(opts.log && { log: opts.log }),
103
114
  deliverQueuedInline: opts.deliverQueuedInline,
@@ -105,11 +116,7 @@ export function buildBootExtraContext(opts) {
105
116
  }),
106
117
  // Top-level provider so feature jobs (secrets rotate, config reencrypt)
107
118
  // reach it via ctx — previously only test-stack wired it.
108
- ...(crypto.masterKeyProvider && { masterKeyProvider: crypto.masterKeyProvider }),
109
- // Encrypt/decrypt partner for `encrypted: true` config keys. Wired
110
- // whenever a master key exists — NOT gated on the secrets feature,
111
- // config encryption must work without mounting ctx.secrets.
112
- ...(crypto.configCipher && { configEncryption: crypto.configCipher }),
119
+ ...bootCryptoContext(crypto),
113
120
  ...(secrets && { secrets }),
114
121
  ...(opts.hasAuth && {
115
122
  configResolver: createConfigResolver({
@@ -173,6 +173,7 @@ trustedProxyHops = 0) {
173
173
  path: url.pathname,
174
174
  host,
175
175
  systemQuery,
176
+ requestSignal: req.signal,
176
177
  });
177
178
  if (injected === text)
178
179
  return html;
@@ -431,6 +431,7 @@ export async function runProdApp(options) {
431
431
  registry,
432
432
  hasAuth: !!effectiveAuth,
433
433
  sseBroker,
434
+ redis,
434
435
  crypto: bootCrypto,
435
436
  ...(options.kms && { kms: options.kms }),
436
437
  ...(bootLogger && { log: bootLogger }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-server-runtime",
3
- "version": "0.353.0",
3
+ "version": "0.354.1",
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>",
@@ -84,11 +84,11 @@
84
84
  }
85
85
  },
86
86
  "dependencies": {
87
- "@cosmicdrift/kumiko-bundled-features": "0.353.0",
88
- "@cosmicdrift/kumiko-framework": "0.353.0",
89
- "@cosmicdrift/kumiko-headless": "0.353.0",
90
- "@cosmicdrift/kumiko-renderer-web": "0.353.0",
91
- "@cosmicdrift/kumiko-types": "0.353.0",
87
+ "@cosmicdrift/kumiko-bundled-features": "0.354.1",
88
+ "@cosmicdrift/kumiko-framework": "0.354.1",
89
+ "@cosmicdrift/kumiko-headless": "0.354.1",
90
+ "@cosmicdrift/kumiko-renderer-web": "0.354.1",
91
+ "@cosmicdrift/kumiko-types": "0.354.1",
92
92
  "bun-types": "^1.3.13",
93
93
  "ioredis": "^5.10.1",
94
94
  "temporal-polyfill": "^0.3.2"
package/src/changes.json CHANGED
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "version": "0.354.0",
4
+ "type": "fix",
5
+ "title": "Boot context passes Redis to the delivery service",
6
+ "detail": "notify with an idempotencyKey used to throw because the delivery service had no idempotencyRedis. Production boot, dev boot and the worker boot now hand over the existing Redis.",
7
+ "migration": "No action needed."
8
+ },
2
9
  {
3
10
  "version": "0.353.0",
4
11
  "type": "fix",