@cosmicdrift/kumiko-server-runtime 0.370.0 → 0.371.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.
@@ -1,3 +1,4 @@
1
+ import { type TierSyncResult } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
1
2
  import { type SubscriptionStripeOptions } from "@cosmicdrift/kumiko-bundled-features/subscription-stripe";
2
3
  import type { ExtraRouteDefinition } from "@cosmicdrift/kumiko-framework/api";
3
4
  import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
@@ -27,6 +28,8 @@ export type BillingBootOption = {
27
28
  readonly tierNames?: readonly string[];
28
29
  /** Default `"fail-webhook"`: Stripe retries, so a failed tier sync gets another attempt. */
29
30
  readonly onTierSyncError?: "log" | "fail-webhook";
31
+ /** Runs after every webhook whose tier sync succeeded, also when the tier stayed the same (`changed: false`). */
32
+ readonly afterSync?: (result: TierSyncResult<string>) => Promise<void>;
30
33
  };
31
34
  export declare function resolveBillingOption(billing: BillingBootOption, envSource: Record<string, string | undefined>): {
32
35
  readonly feature: FeatureDefinition;
@@ -30,6 +30,7 @@ export function resolveBillingOption(billing, envSource) {
30
30
  isTierName: (value) => tierNames.has(value),
31
31
  defaultTier: billing.defaultTier,
32
32
  onSyncError: billing.onTierSyncError ?? "fail-webhook",
33
+ ...(billing.afterSync && { afterSync: billing.afterSync }),
33
34
  });
34
35
  return { feature, route: tierSync.createWebhookRoute({ path: webhookPath }) };
35
36
  }
@@ -14,12 +14,13 @@ export type MailBootOption = {
14
14
  readonly transport: "smtp-env" | "inmemory" | EmailTransport;
15
15
  /** Sender when `SMTP_FROM` is unset (`"smtp-env"` only). Default `auth.mail.from`, then `noreply@localhost`. */
16
16
  readonly from?: string;
17
- /** Maps a user id to the stored email. Default: the `user` row of that tenant. */
17
+ /** Maps a user id to the stored email. Default: the `user` row with that id (any tenant). */
18
18
  readonly resolveEmail?: EmailChannelOptions["resolveEmail"];
19
19
  /** Per-tenant transport, see `createChannelEmailFeature`. */
20
20
  readonly tenantTransport?: TenantTransportResolver;
21
21
  };
22
22
  export declare const CHANNEL_EMAIL_FEATURE = "channel-email";
23
+ export declare function resolveStoredUserEmail(userId: string, ctx: Parameters<EmailChannelOptions["resolveEmail"]>[1]): Promise<string | null>;
23
24
  export declare function resolveMailOption(mail: MailBootOption, deps: {
24
25
  readonly envSource: Record<string, string | undefined>;
25
26
  readonly isProduction: boolean;
@@ -4,10 +4,9 @@ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
4
4
  export const CHANNEL_EMAIL_FEATURE = "channel-email";
5
5
  // channel-email decrypts the returned value itself, so the raw stored column
6
6
  // (ciphertext under an active KMS) is the right thing to hand back.
7
- async function resolveStoredUserEmail(userId, ctx) {
7
+ export async function resolveStoredUserEmail(userId, ctx) {
8
8
  const rows = await selectMany(ctx.db, userTable, {
9
9
  id: userId,
10
- tenantId: ctx.tenantId,
11
10
  });
12
11
  return rows[0]?.email ?? null;
13
12
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export type { BillingBootOption } from "./boot-options/billing-option.ts";
1
+ export { type BillingBootOption, resolveBillingOption } from "./boot-options/billing-option.ts";
2
2
  export type { DemoAccountRole, DemoModeNotice, DemoModeOption, } from "./boot-options/demo-mode.ts";
3
+ export { buildDemoModeRoute, withDemoReadOnlyFetch, } from "./boot-options/demo-mode.ts";
3
4
  export type { FileStorageBootOption, FileStorageProviderName, } from "./boot-options/file-storage-option.ts";
4
5
  export type { KmsMode } from "./boot-options/kms-mode.ts";
5
6
  export type { MailBootOption } from "./boot-options/mail-option.ts";
@@ -10,8 +11,8 @@ export { type ComposeFeaturesOptions, composeFeatures } from "./compose-features
10
11
  export type { RateLimitOption } from "./rate-limit-defaults.ts";
11
12
  export type { RunBootstrapOptions } from "./run-bootstrap.ts";
12
13
  export { runBootstrap } from "./run-bootstrap.ts";
13
- export type { AccountUnlockSetup, EmailVerificationSetup, InviteSetup, PageHeadMeta, PageHeadResolver, PageHeadSystemQuery, PasswordResetSetup, ProdAppHandle, ProdSeedFn, RunProdAppAuthOptions, RunProdAppOptions, SignupSetup, } from "./run-prod-app.ts";
14
- export { requireEnv, runProdApp } from "./run-prod-app.ts";
14
+ export type { AccountUnlockSetup, EmailVerificationSetup, HostDispatchFn, InviteSetup, PageHeadMeta, PageHeadResolver, PageHeadSystemQuery, PasswordResetSetup, ProdAppHandle, ProdSeedFn, RunProdAppAuthOptions, RunProdAppOptions, SignupSetup, } from "./run-prod-app.ts";
15
+ export { parseRunMode, requireEnv, runProdApp } from "./run-prod-app.ts";
15
16
  export type { RunWorkerAppOptions, WorkerAppHandle, WorkerWireDeps, } from "./run-worker-app.ts";
16
17
  export { runWorkerApp } from "./run-worker-app.ts";
17
18
  export type { CspExtension, CspOption, SecurityHeadersOption } from "./security-headers.ts";
package/dist/index.js CHANGED
@@ -2,9 +2,11 @@
2
2
  // runDevApp (kumiko-dev-server), aber ohne Dev-/Scaffold-/Codegen-
3
3
  // Tooling (ts-morph) als Dependency — Prod-Apps ziehen so kein
4
4
  // Dev-Tooling mehr in ihre node_modules.
5
+ export { resolveBillingOption } from "./boot-options/billing-option.js";
6
+ export { buildDemoModeRoute, withDemoReadOnlyFetch, } from "./boot-options/demo-mode.js";
5
7
  export { readBundledAsset, resolveBundledAsset, } from "./bundled-assets.js";
6
8
  export { composeFeatures } from "./compose-features.js";
7
9
  export { runBootstrap } from "./run-bootstrap.js";
8
- export { requireEnv, runProdApp } from "./run-prod-app.js";
10
+ export { parseRunMode, requireEnv, runProdApp } from "./run-prod-app.js";
9
11
  export { runWorkerApp } from "./run-worker-app.js";
10
12
  export { makeSeedCreateFileRef } from "./seed-dispatcher.js";
@@ -6,6 +6,7 @@ import { type KmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
6
6
  import { type EffectiveFeaturesResolver, type FeatureDefinition, type ValidateBootOptions } from "@cosmicdrift/kumiko-framework/engine";
7
7
  import { type AllInOneEntrypoint, type ApiEntrypoint } from "@cosmicdrift/kumiko-framework/entrypoint";
8
8
  import { type ComposedEnvSchema, KumikoBootError } from "@cosmicdrift/kumiko-framework/env";
9
+ import { type DryRunEnvMode } from "@cosmicdrift/kumiko-framework/env/dry-run";
9
10
  import type { ErrorDocsConfig } from "@cosmicdrift/kumiko-framework/errors";
10
11
  import type { JobRunnerOptions } from "@cosmicdrift/kumiko-framework/jobs";
11
12
  import { type ObservabilityOptions, type ObservabilityProvider } from "@cosmicdrift/kumiko-framework/observability";
@@ -29,6 +30,8 @@ export { resolveUnsubscribeWiring, type UnsubscribeOption, } from "./resolve-uns
29
30
  export { addConfigAccessorFactory, buildBootExtraContext, loggerFromExtraContext, resolveAuthMail, } from "./run-prod-app-boot-context.ts";
30
31
  export { staticCachePolicy } from "./run-prod-app-static-files.ts";
31
32
  export declare function requireEnv(name: string, src?: Record<string, string | undefined>, context?: string): string;
33
+ type RunMode = DryRunEnvMode;
34
+ export declare function parseRunMode(raw: string | undefined): RunMode | null;
32
35
  /** Wrapper API for the password-reset flow.
33
36
  *
34
37
  * Since the delivery migration PasswordResetOptions carries `appUrl`
@@ -201,6 +204,8 @@ export type RunProdAppDeps = {
201
204
  readonly redis: Redis;
202
205
  readonly registry: import("@cosmicdrift/kumiko-framework/engine").Registry;
203
206
  readonly sseBroker: SseBroker;
207
+ /** The env the boot runs on: process env or `envSource`, with the boot-option defaults (e.g. `fileStorage`) underneath. */
208
+ readonly env: Readonly<Record<string, string | undefined>>;
204
209
  };
205
210
  export type AnonymousAccessOption = import("@cosmicdrift/kumiko-framework/api").AnonymousAccessConfig | ((deps: RunProdAppDeps) => import("@cosmicdrift/kumiko-framework/api").AnonymousAccessConfig);
206
211
  export type ExtraContextOption = Record<string, unknown> | ((deps: RunProdAppDeps) => Record<string, unknown>);
@@ -124,7 +124,7 @@ function readEnv(name, src = process.env) {
124
124
  const value = src[name];
125
125
  return value === undefined || value === "" ? undefined : value;
126
126
  }
127
- function parseRunMode(raw) {
127
+ export function parseRunMode(raw) {
128
128
  const mode = parseDryRunEnvMode(raw);
129
129
  if (mode !== undefined)
130
130
  return mode;
@@ -502,7 +502,7 @@ export async function runProdApp(options) {
502
502
  // wins), which is exactly how fw#2630's cross-replica fanout fix shipped
503
503
  // without ever taking effect in production.
504
504
  const { sseBroker, ownedRedisSseBroker } = createDefaultSseBroker(envSource);
505
- const deps = { db, redis, registry, sseBroker };
505
+ const deps = { db, redis, registry, sseBroker, env: envSource };
506
506
  const resolvedExtraContext = typeof options.extraContext === "function"
507
507
  ? options.extraContext(deps)
508
508
  : (options.extraContext ?? {});
@@ -546,6 +546,7 @@ export async function runProdApp(options) {
546
546
  const resolvedAnonymousAccess = await resolveAnonymousAccessFromRegistry(baseAnonymousAccess, {
547
547
  db,
548
548
  registry,
549
+ warn: (message) => createFallbackLogger("runProdApp").warn(message),
549
550
  });
550
551
  // Sessions opt-in: db ist hier schon konkret (createDbConnection oben),
551
552
  // also direkt verdrahten — kein late-bound nötig wie bei runDevApp.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-server-runtime",
3
- "version": "0.370.0",
3
+ "version": "0.371.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 tooling.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -88,19 +88,19 @@
88
88
  }
89
89
  },
90
90
  "dependencies": {
91
- "@cosmicdrift/kumiko-bundled-features": "0.370.0",
92
- "@cosmicdrift/kumiko-framework": "0.370.0",
93
- "@cosmicdrift/kumiko-headless": "0.370.0",
94
- "@cosmicdrift/kumiko-renderer-mail-html": "0.370.0",
95
- "@cosmicdrift/kumiko-renderer-web": "0.370.0",
96
- "@cosmicdrift/kumiko-types": "0.370.0",
91
+ "@cosmicdrift/kumiko-bundled-features": "0.371.1",
92
+ "@cosmicdrift/kumiko-framework": "0.371.1",
93
+ "@cosmicdrift/kumiko-headless": "0.371.1",
94
+ "@cosmicdrift/kumiko-renderer-mail-html": "0.371.1",
95
+ "@cosmicdrift/kumiko-renderer-web": "0.371.1",
96
+ "@cosmicdrift/kumiko-types": "0.371.1",
97
97
  "bun-types": "^1.3.13",
98
98
  "ioredis": "^5.10.1",
99
99
  "temporal-polyfill": "^0.3.2",
100
100
  "zod": "^4.4.3"
101
101
  },
102
102
  "devDependencies": {
103
- "@cosmicdrift/kumiko-testing": "0.370.0"
103
+ "@cosmicdrift/kumiko-testing": "0.371.1"
104
104
  },
105
105
  "publishConfig": {
106
106
  "registry": "https://registry.npmjs.org",
package/src/changes.json CHANGED
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.371.0",
4
+ "type": "improvement",
5
+ "title": "Default mail resolveEmail finds users of any tenant",
6
+ "detail": "The default resolveEmail of the mail boot option loads the user by id only. Rows in read_users carry the system tenant, so the former tenantId filter returned null for every real tenant."
7
+ },
8
+ {
9
+ "version": "0.371.0",
10
+ "type": "improvement",
11
+ "title": "extraContext factories see the boot env, billing hook and new exports",
12
+ "detail": "The merged env, including the defaults of declarative boot options such as FILE_STORAGE_PROVIDER from fileStorage, is passed to extraContext factories as env. resolveBillingOption, parseRunMode, HostDispatchFn, buildDemoModeRoute and withDemoReadOnlyFetch are exported from the package index. The billing boot option accepts afterSync."
13
+ },
2
14
  {
3
15
  "version": "0.370.0",
4
16
  "type": "breaking",