@cosmicdrift/kumiko-dev-server 0.388.0 → 0.390.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/dist/build-server-bundle.js +4 -2
- package/dist/create-kumiko-server-stack.js +6 -4
- package/dist/create-kumiko-server-stylesheet.js +7 -9
- package/dist/create-kumiko-server.d.ts +4 -1
- package/dist/create-kumiko-server.js +2 -0
- package/dist/few-shot-corpus.d.ts +1 -1
- package/dist/few-shot-corpus.js +1 -1
- package/dist/framework-version.js +2 -1
- package/dist/managed-files/registry.js +5 -1
- package/dist/run-dev-app-auth.js +1 -0
- package/dist/run-dev-app-config.js +1 -1
- package/dist/run-dev-app-server-options.js +1 -0
- package/dist/run-dev-app.d.ts +12 -5
- package/dist/run-dev-app.js +5 -5
- package/dist/scaffold-app.d.ts +2 -1
- package/dist/scaffold-app.js +37 -9
- package/dist/scaffold-feature.js +1 -1
- package/dist/schema-apply.d.ts +3 -0
- package/dist/schema-apply.js +6 -2
- package/dist/setup-test-stack-from-features.d.ts +1 -0
- package/dist/setup-test-stack-from-features.js +6 -2
- package/package.json +16 -10
- package/src/changes.json +57 -0
- package/templates/deploy/Dockerfile.template +3 -2
- package/templates/managed/ci-public.yml.template +2 -2
- package/templates/managed/kumiko-schema.ts.template +4 -0
|
@@ -59,7 +59,8 @@ const hasBun = typeof Bun !== "undefined";
|
|
|
59
59
|
// reference the package at runtime (no native binding, plain HTTP client,
|
|
60
60
|
// but a real runtime import). A production crash in money-horse,
|
|
61
61
|
// "Cannot find package 'meilisearch'", occurred because it used to be in
|
|
62
|
-
// BUILD_ONLY_EXTERNALS instead.
|
|
62
|
+
// BUILD_ONLY_EXTERNALS instead. Its version comes from the framework's
|
|
63
|
+
// peerDependencies range.
|
|
63
64
|
const RUNTIME_EXTERNALS = [
|
|
64
65
|
"@node-rs/argon2",
|
|
65
66
|
"sharp",
|
|
@@ -296,7 +297,8 @@ async function resolveRuntimeDepsVersions(cwd, repoRoot, packages) {
|
|
|
296
297
|
continue;
|
|
297
298
|
const raw = await readFile(path, "utf-8");
|
|
298
299
|
const parsed = parseJsonOrThrow(raw, path);
|
|
299
|
-
|
|
300
|
+
// Peers first: a real dependency of the same source overrides a peer range.
|
|
301
|
+
Object.assign(allDeps, parsed.peerDependencies ?? {}, parsed.dependencies ?? {}, parsed.optionalDependencies ?? {});
|
|
300
302
|
}
|
|
301
303
|
// App package.json fills gaps only — pins extraRuntimeExternals without
|
|
302
304
|
// overriding framework-native pins the app may also list.
|
|
@@ -2,7 +2,7 @@ import { resolveAnonymousAccessFromRegistry } from "@cosmicdrift/kumiko-bundled-
|
|
|
2
2
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
3
3
|
import { createMetricsForFactory } from "@cosmicdrift/kumiko-framework/observability";
|
|
4
4
|
import { startDevJobRunners } from "@cosmicdrift/kumiko-server-runtime/boot/job-run-logger";
|
|
5
|
-
import { makeDispatchSystemQuery, makeDispatchSystemWrite, } from "@cosmicdrift/kumiko-server-runtime/extra-routes-deps";
|
|
5
|
+
import { makeDispatchSystemQuery, makeDispatchSystemWrite, makeFilesForTenant, } from "@cosmicdrift/kumiko-server-runtime/extra-routes-deps";
|
|
6
6
|
import { pushEntityProjectionTables, setupTestStack, } from "@cosmicdrift/kumiko-testing/stack";
|
|
7
7
|
import { logInfo } from "./dev-server-runtime.js";
|
|
8
8
|
import { isPersistentDevDb } from "./is-persistent-dev-db.js";
|
|
@@ -39,6 +39,7 @@ function buildDevStackOptions(options, dbMode) {
|
|
|
39
39
|
...(options.extraRoutes !== undefined && { extraRoutes: options.extraRoutes }),
|
|
40
40
|
...(options.trustedProxyHops !== undefined && { trustedProxyHops: options.trustedProxyHops }),
|
|
41
41
|
...(options.errorDocs && { errorDocs: options.errorDocs }),
|
|
42
|
+
...(options.rowLevelSecurity !== undefined && { rowLevelSecurity: options.rowLevelSecurity }),
|
|
42
43
|
// jobs.consumerLane unset = enqueuer-only; startDevJobRunners is the sole
|
|
43
44
|
// consumer/cron-scheduler per lane, so runOnBoot/cron jobs don't
|
|
44
45
|
// double-fire.
|
|
@@ -48,7 +49,7 @@ function buildDevStackOptions(options, dbMode) {
|
|
|
48
49
|
export async function bootDevStack(options, dbMode) {
|
|
49
50
|
logInfo(`[kumiko-server] booting Kumiko stack${dbMode.persistentDb ? ` — persistent DB "${dbMode.devDbName}"` : " — ephemeral test DB"}…`);
|
|
50
51
|
const stack = await setupTestStack(buildDevStackOptions(options, dbMode));
|
|
51
|
-
await createEventsTable(stack.
|
|
52
|
+
await createEventsTable(stack.unscopedDb);
|
|
52
53
|
await pushEntityProjectionTables(stack, stack.registry);
|
|
53
54
|
// `extraRoutes` is already mounted by setupTestStack's buildServer();
|
|
54
55
|
// `wire` is for co-running components that need the system-write
|
|
@@ -60,6 +61,7 @@ export async function bootDevStack(options, dbMode) {
|
|
|
60
61
|
// so application code sees the same interface in development and production.
|
|
61
62
|
redis: stack.redis.redis,
|
|
62
63
|
registry: stack.registry,
|
|
64
|
+
filesForTenant: makeFilesForTenant(stack.context),
|
|
63
65
|
metricsFor: createMetricsForFactory(stack.observability.meter),
|
|
64
66
|
dispatchSystemWrite: makeDispatchSystemWrite(stack.dispatcher),
|
|
65
67
|
dispatchSystemQuery: makeDispatchSystemQuery(stack.dispatcher),
|
|
@@ -85,13 +87,13 @@ export async function startDevBackgroundRunners(stack, jobQueueNamePrefix) {
|
|
|
85
87
|
registry: stack.registry,
|
|
86
88
|
db: stack.db,
|
|
87
89
|
// The stack's own AppContext, not a `{ db, registry }` literal: these
|
|
88
|
-
// runners consume the lanes, and a job reaching for ctx.files /
|
|
90
|
+
// runners consume the lanes, and a job reaching for ctx.services.files /
|
|
89
91
|
// ctx.notify / ctx.config would otherwise die here while the very same
|
|
90
92
|
// handler works on the request path.
|
|
91
93
|
context: stack.context,
|
|
92
94
|
redisUrl,
|
|
93
95
|
// Same dispatcher the request path writes through — without this,
|
|
94
|
-
// ctx.write/ctx.writeAs/ctx.queryAs inside a dev-run job throw on their
|
|
96
|
+
// ctx.dispatch.write/ctx.dispatch.writeAs/ctx.dispatch.queryAs inside a dev-run job throw on their
|
|
95
97
|
// first call.
|
|
96
98
|
dispatcher: stack.dispatcher,
|
|
97
99
|
// Must match setupTestStack's jobs.queueNamePrefix so enqueuer and
|
|
@@ -3,6 +3,7 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { existsSync, mkdtempSync } from "node:fs";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
|
+
import { resolveInstalledSync } from "@cosmicdrift/kumiko-server-runtime/resolve-installed-package";
|
|
6
7
|
import { canResolveTailwindStylesheet, resolveTailwindCli, } from "@cosmicdrift/kumiko-server-runtime/resolve-tailwind-cli";
|
|
7
8
|
import { hasBun, logError, logInfo } from "./dev-server-runtime.js";
|
|
8
9
|
// Duplicated in packages/testing/src/e2e/constants.ts: the Playwright config
|
|
@@ -44,18 +45,15 @@ export function resolveStylesheet(options) {
|
|
|
44
45
|
// silently rather than reporting an error.
|
|
45
46
|
return undefined;
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (!canResolveTailwindStylesheet(resolved, { bun: Bun, cwd: process.cwd() })) {
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
return resolved;
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
48
|
+
const resolved = resolveInstalledSync("@cosmicdrift/kumiko-renderer/web/styles.css", process.cwd());
|
|
49
|
+
if (resolved === undefined) {
|
|
55
50
|
logError("[kumiko-server] couldn't auto-resolve @cosmicdrift/kumiko-renderer/web/styles.css — " +
|
|
56
|
-
"pass `stylesheet: <path>` or `stylesheet: false` explicitly."
|
|
51
|
+
"pass `stylesheet: <path>` or `stylesheet: false` explicitly.");
|
|
57
52
|
return undefined;
|
|
58
53
|
}
|
|
54
|
+
return canResolveTailwindStylesheet(resolved, { bun: Bun, cwd: process.cwd() })
|
|
55
|
+
? resolved
|
|
56
|
+
: undefined;
|
|
59
57
|
}
|
|
60
58
|
// The E2E template can only reach an app's own server entry through its env,
|
|
61
59
|
// so the env has to count whenever the option is left undefined.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="bun-types" preserve="true" />
|
|
2
2
|
import type { AuthRoutesConfig, ExtraRouteDefinition } from "@cosmicdrift/kumiko-framework/api";
|
|
3
|
+
import { type RowLevelSecurityMode } from "@cosmicdrift/kumiko-framework/db";
|
|
3
4
|
import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
5
|
import type { ErrorDocsConfig } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
6
|
import type { PageHeadResolver, PageHeadSystemQuery } from "@cosmicdrift/kumiko-renderer/headless/apex";
|
|
@@ -64,6 +65,8 @@ export type DevHostDispatch = (req: Request, deps: {
|
|
|
64
65
|
readonly cspScriptHashes: readonly string[];
|
|
65
66
|
}) => DevHostDispatchResult | Promise<DevHostDispatchResult>;
|
|
66
67
|
export type CreateKumikoServerOptions = {
|
|
68
|
+
/** Row level security of the dev stack, as in prod. Default "on", so tenant-isolation bugs show up in development. */
|
|
69
|
+
readonly rowLevelSecurity?: RowLevelSecurityMode;
|
|
67
70
|
/** Features whose entities, handlers, and screens get wired into the
|
|
68
71
|
* dev stack. Pass every feature the app is supposed to run. */
|
|
69
72
|
readonly features: readonly FeatureDefinition[];
|
|
@@ -141,7 +144,7 @@ export type CreateKumikoServerOptions = {
|
|
|
141
144
|
readonly anonymousAccess?: TestStackOptions["anonymousAccess"];
|
|
142
145
|
/** File-storage provider forwarded to `setupTestStack`. When set, the
|
|
143
146
|
* stack mounts the upload routes (POST/GET/DELETE /api/files), exposes
|
|
144
|
-
* `ctx.files`, and creates the `file_refs` table. Example:
|
|
147
|
+
* `ctx.services.files`, and creates the `file_refs` table. Example:
|
|
145
148
|
* `{ storageProvider: createInMemoryFileProvider() }`. */
|
|
146
149
|
readonly files?: TestStackOptions["files"];
|
|
147
150
|
/** Feature-toggle resolver forwarded to `setupTestStack`. When set, the
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
//
|
|
15
15
|
// The companion prod entry will land at `@cosmicdrift/kumiko-framework/server`
|
|
16
16
|
// with a different options shape (clientDist, auth config, db url).
|
|
17
|
+
import { assertNoActiveRowLevelSecurityScope, } from "@cosmicdrift/kumiko-framework/db";
|
|
17
18
|
import { buildAppSchema } from "@cosmicdrift/kumiko-framework/engine";
|
|
18
19
|
import { buildBunServeOptions, resolveDerivedMaxRequestBodySize, } from "@cosmicdrift/kumiko-server-runtime/bun-serve-options";
|
|
19
20
|
import { stripNoRouteMatchHeader } from "@cosmicdrift/kumiko-server-runtime/try-hono-first";
|
|
@@ -33,6 +34,7 @@ import { hasBun, logInfo } from "./dev-server-runtime.js";
|
|
|
33
34
|
function startDevHttpServer(port, handleFetch, stack) {
|
|
34
35
|
if (!hasBun)
|
|
35
36
|
return undefined;
|
|
37
|
+
assertNoActiveRowLevelSecurityScope("dev server");
|
|
36
38
|
return Bun.serve(buildBunServeOptions(port, handleFetch, resolveDerivedMaxRequestBodySize(stack.registry), {
|
|
37
39
|
upgradeFetch: async (req, env) => stripNoRouteMatchHeader(await stack.app.fetch(req, env)),
|
|
38
40
|
}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FeaturePattern, type ParseError } from "@cosmicdrift/kumiko-
|
|
1
|
+
import { type FeaturePattern, type ParseError } from "@cosmicdrift/kumiko-feature-ast";
|
|
2
2
|
export type AuthoringStyle = "canonical" | "legacy";
|
|
3
3
|
export type CorpusWarning = {
|
|
4
4
|
/** Repo-relative path to the file that triggered the warning. */
|
package/dist/few-shot-corpus.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
// builder is permissive, and the Designer filters at read-time.
|
|
32
32
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
33
33
|
import { dirname, join, relative, resolve } from "node:path";
|
|
34
|
-
import { PATTERN_LIBRARY, parseFeatureFile, } from "@cosmicdrift/kumiko-
|
|
34
|
+
import { PATTERN_LIBRARY, parseFeatureFile, } from "@cosmicdrift/kumiko-feature-ast";
|
|
35
35
|
import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
36
36
|
// =============================================================================
|
|
37
37
|
// Builder
|
|
@@ -13,6 +13,7 @@ function isDevServerManifest(value) {
|
|
|
13
13
|
}
|
|
14
14
|
// All @cosmicdrift packages release in lockstep (changesets fixed-group), so
|
|
15
15
|
// the dev-server's own version is the framework version.
|
|
16
|
+
// Exact (no caret): `kumiko check managed` rejects ranges on @cosmicdrift pins.
|
|
16
17
|
export function resolveFrameworkVersion(startDir = import.meta.dir) {
|
|
17
18
|
let dir = startDir;
|
|
18
19
|
while (true) {
|
|
@@ -21,7 +22,7 @@ export function resolveFrameworkVersion(startDir = import.meta.dir) {
|
|
|
21
22
|
// A corrupt or foreign package.json on the way up must not abort the search.
|
|
22
23
|
const manifest = parseJsonSafe(readFileSync(candidate, "utf-8"), undefined);
|
|
23
24
|
if (isDevServerManifest(manifest))
|
|
24
|
-
return
|
|
25
|
+
return manifest.version;
|
|
25
26
|
}
|
|
26
27
|
const parent = dirname(dir);
|
|
27
28
|
if (parent === dir)
|
|
@@ -92,6 +92,7 @@ function renderReleaseWorkflow(facts) {
|
|
|
92
92
|
infraRef: infraRef ?? DEFAULT_INFRA_REF,
|
|
93
93
|
}, { privateDeploy: visibility === "private", publicRollout: visibility === "public" });
|
|
94
94
|
}
|
|
95
|
+
const COMPOSE_ONLY_DEPLOY_FILE = "migrate-step.sh";
|
|
95
96
|
export function renderManagedTemplates(facts) {
|
|
96
97
|
const deploy = renderDeployFiles({
|
|
97
98
|
appName: facts.appName,
|
|
@@ -99,7 +100,10 @@ export function renderManagedTemplates(facts) {
|
|
|
99
100
|
ensuredRegistryConfigFiles: [BUNFIG_FILES.unit],
|
|
100
101
|
});
|
|
101
102
|
return [
|
|
102
|
-
...deploy.files
|
|
103
|
+
...deploy.files
|
|
104
|
+
// Managed apps migrate through the migrate-db initContainer of the infra _app-deploy.yml; migrate-step.sh is compose-only.
|
|
105
|
+
.filter((file) => file.output !== COMPOSE_ONLY_DEPLOY_FILE)
|
|
106
|
+
.map((file) => marked(`deploy/${file.output}`, file.content, "#", file.output.endsWith(".sh"))),
|
|
103
107
|
marked(".husky/pre-push", readTemplate("husky-pre-push.template"), "#", true),
|
|
104
108
|
marked(".github/workflows/cache-cleanup.yml", readTemplate("cache-cleanup.yml.template"), "#"),
|
|
105
109
|
marked(".github/workflows/release.yml", renderReleaseWorkflow(facts), "#"),
|
package/dist/run-dev-app-auth.js
CHANGED
|
@@ -148,6 +148,7 @@ export async function runDevAfterSetup(stack, ctx) {
|
|
|
148
148
|
admin: effectiveAuth?.admin,
|
|
149
149
|
shortcutSeeds: wiring.shortcutSeeds,
|
|
150
150
|
cipher: bootCrypto.configCipher,
|
|
151
|
+
processName: "runDevApp",
|
|
151
152
|
});
|
|
152
153
|
for (const seed of config.stackSeeds) {
|
|
153
154
|
await seed(stack);
|
|
@@ -86,7 +86,7 @@ export async function resolveDevBootConfig(options, bootFailure) {
|
|
|
86
86
|
warn: (message) => createFallbackLogger("runDevApp").warn(message),
|
|
87
87
|
});
|
|
88
88
|
const extraRoutes = collectDevExtraRoutes(options, unsubscribeRoutes, wiring);
|
|
89
|
-
const features = composeAppFeatures(options.features, wiring.features, effectiveAuth);
|
|
89
|
+
const features = composeAppFeatures(options.features, wiring.features, effectiveAuth, options.bundledLists);
|
|
90
90
|
return { stackSeeds, wiring, envSource, effectiveAuth, unsubscribeLinks, extraRoutes, features };
|
|
91
91
|
}
|
|
92
92
|
// An explicitly wired file provider (options.files) satisfies the
|
|
@@ -3,6 +3,7 @@ function pickDevClientOptions(options) {
|
|
|
3
3
|
return {
|
|
4
4
|
...(options.clientEntry !== undefined && { clientEntry: options.clientEntry }),
|
|
5
5
|
...(options.errorDocs && { errorDocs: options.errorDocs }),
|
|
6
|
+
...(options.rowLevelSecurity !== undefined && { rowLevelSecurity: options.rowLevelSecurity }),
|
|
6
7
|
...(options.clientEntries !== undefined && { clientEntries: options.clientEntries }),
|
|
7
8
|
...(options.hostDispatch !== undefined && { hostDispatch: options.hostDispatch }),
|
|
8
9
|
...(options.resolvePageHead !== undefined && { resolvePageHead: options.resolvePageHead }),
|
package/dist/run-dev-app.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SeedAdminOptions } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/seeding";
|
|
2
2
|
import type { PostAuthLandingResolver } from "@cosmicdrift/kumiko-framework/api";
|
|
3
3
|
import type { KmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
|
|
4
|
-
import
|
|
4
|
+
import type { RowLevelSecurityMode } from "@cosmicdrift/kumiko-framework/db";
|
|
5
|
+
import { type BundledListsOptions, type FeatureDefinition, type Registry, type ValidateBootOptions } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
6
|
import type { ComposedEnvSchema } from "@cosmicdrift/kumiko-framework/env";
|
|
6
7
|
import type { ErrorDocsConfig } from "@cosmicdrift/kumiko-framework/errors";
|
|
7
8
|
import type { EnvelopeCipher, MasterKeyProvider } from "@cosmicdrift/kumiko-framework/secrets";
|
|
@@ -11,7 +12,7 @@ import type { TestStack } from "@cosmicdrift/kumiko-testing/stack";
|
|
|
11
12
|
import { type CreateKumikoServerOptions, type KumikoServerHandle } from "./create-kumiko-server.ts";
|
|
12
13
|
export type { AccountLockoutSetup, AccountUnlockSetup, AuthMailOptions, EmailVerificationSetup, InviteSetup, PasswordResetSetup, SignupSetup, } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
13
14
|
import type { AccountLockoutSetup, AccountUnlockSetup, AuthMailOptions, EmailVerificationSetup, InviteSetup, PasswordResetSetup, SignupSetup } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
14
|
-
import { type UnsubscribeOption } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
15
|
+
import { type ConfigOverridesInput, type UnsubscribeOption } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
15
16
|
export type RunDevAppAuthOptions = {
|
|
16
17
|
/** Admin user to seed at boot. Idempotent — re-runs in persistent-DB
|
|
17
18
|
* mode reuse the existing user. */
|
|
@@ -78,6 +79,8 @@ export type RunDevAppOptions = {
|
|
|
78
79
|
readonly features: readonly FeatureDefinition[];
|
|
79
80
|
/** Opt-in boot-validator warnings — see ValidateBootOptions. */
|
|
80
81
|
readonly validateBootOptions?: ValidateBootOptions;
|
|
82
|
+
/** One table block for every list of the bundled features, see ComposeFeaturesOptions.bundledLists. */
|
|
83
|
+
readonly bundledLists?: BundledListsOptions;
|
|
81
84
|
/** Browser entry module, bundled to /client.js. Mutually exclusive with
|
|
82
85
|
* `clientEntries`. */
|
|
83
86
|
readonly clientEntry?: string;
|
|
@@ -124,7 +127,9 @@ export type RunDevAppOptions = {
|
|
|
124
127
|
* no locale signal. Merged into AppContext before extraContext (app wins). */
|
|
125
128
|
readonly defaultLocale?: string;
|
|
126
129
|
readonly extraContext?: CreateKumikoServerOptions["extraContext"];
|
|
127
|
-
/**
|
|
130
|
+
/** App-level config values, same semantics and merge as RunProdAppOptions["appOverrides"]. */
|
|
131
|
+
readonly appOverrides?: ConfigOverridesInput;
|
|
132
|
+
/** MasterKeyProvider for the automatically wired `ctx.services.secrets`. Defaults to
|
|
128
133
|
* `createEnvMasterKeyProvider`; override it for KMS backends. Only relevant
|
|
129
134
|
* when the secrets feature is mounted. Symmetric with runProdApp. */
|
|
130
135
|
readonly masterKey?: MasterKeyProvider;
|
|
@@ -149,7 +154,7 @@ export type RunDevAppOptions = {
|
|
|
149
154
|
* role in `access.roles`. */
|
|
150
155
|
readonly anonymousAccess?: CreateKumikoServerOptions["anonymousAccess"];
|
|
151
156
|
/** File-Storage-Provider — aktiviert die Upload-Routes (/api/files) +
|
|
152
|
-
* `ctx.files`. Demos: `{ storageProvider: createInMemoryFileProvider() }`. */
|
|
157
|
+
* `ctx.services.files`. Demos: `{ storageProvider: createInMemoryFileProvider() }`. */
|
|
153
158
|
readonly files?: CreateKumikoServerOptions["files"];
|
|
154
159
|
/** App-defined HTTP routes, such as /feed.xml and /sitemap.xml. They are
|
|
155
160
|
* attached to the Hono app before the static-asset path. Symmetric with the
|
|
@@ -198,6 +203,8 @@ export type RunDevAppOptions = {
|
|
|
198
203
|
readonly trustedProxyHops?: number;
|
|
199
204
|
/** Links the app's own error reasons to its own docs (`docsUrl` in error responses); framework reasons keep the framework docs link. */
|
|
200
205
|
readonly errorDocs?: ErrorDocsConfig;
|
|
206
|
+
/** Row level security of the dev stack, as in prod. Default "on", so tenant-isolation bugs show up in development. */
|
|
207
|
+
readonly rowLevelSecurity?: RowLevelSecurityMode;
|
|
201
208
|
};
|
|
202
209
|
export declare function runDevApp(options: RunDevAppOptions): Promise<KumikoServerHandle>;
|
|
203
|
-
export declare function mergeConfigResolverDefault(ctx: CreateKumikoServerOptions["extraContext"], registry: Registry, envSource: Record<string, string | undefined>, cipher?: EnvelopeCipher): CreateKumikoServerOptions["extraContext"];
|
|
210
|
+
export declare function mergeConfigResolverDefault(ctx: CreateKumikoServerOptions["extraContext"], registry: Registry, envSource: Record<string, string | undefined>, cipher?: EnvelopeCipher, appOverrides?: ConfigOverridesInput): CreateKumikoServerOptions["extraContext"];
|
package/dist/run-dev-app.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// For maximum control, such as custom auth wiring, a different membership
|
|
12
12
|
// query, or a custom LoginRateLimiter, use `createKumikoServer` directly from
|
|
13
13
|
// @cosmicdrift/kumiko-dev-server.
|
|
14
|
-
import {
|
|
14
|
+
import { createConfigResolver } from "@cosmicdrift/kumiko-bundled-features/config";
|
|
15
15
|
import { parseTrustedProxyHopsEnv, TRUSTED_PROXY_HOPS_ENV, } from "@cosmicdrift/kumiko-framework/api";
|
|
16
16
|
import { findTierResolverUsage, } from "@cosmicdrift/kumiko-framework/engine";
|
|
17
17
|
import { createKumikoServer, } from "./create-kumiko-server.js";
|
|
@@ -19,7 +19,7 @@ import { createDevLateBindings, createLateBoundEffectiveFeatures, runDevAfterSet
|
|
|
19
19
|
import { configureDevBootCrypto, resolveDevAuthRegistry, resolveDevBootConfig, validateDevBoot, } from "./run-dev-app-config.js";
|
|
20
20
|
import { buildDevServerOptions } from "./run-dev-app-server-options.js";
|
|
21
21
|
import { renderWelcomeBanner } from "./welcome-banner.js";
|
|
22
|
-
import { addConfigAccessorFactory, buildBootExtraContext, loggerFromExtraContext, } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
22
|
+
import { addConfigAccessorFactory, buildBootExtraContext, buildConfigOverrides, loggerFromExtraContext, } from "@cosmicdrift/kumiko-server-runtime/run-prod-app";
|
|
23
23
|
export async function runDevApp(options) {
|
|
24
24
|
const bootFailure = { release: undefined };
|
|
25
25
|
try {
|
|
@@ -105,7 +105,7 @@ function renderDevWelcomeBanner(options, config, handle) {
|
|
|
105
105
|
function buildDevExtraContext(options, config, registry, bootCrypto) {
|
|
106
106
|
const { features, envSource, unsubscribeLinks } = config;
|
|
107
107
|
const cfgExtra = registry
|
|
108
|
-
? mergeConfigResolverDefault(options.extraContext, registry, envSource, bootCrypto.configCipher)
|
|
108
|
+
? mergeConfigResolverDefault(options.extraContext, registry, envSource, bootCrypto.configCipher, options.appOverrides)
|
|
109
109
|
: options.extraContext;
|
|
110
110
|
return (deps) => {
|
|
111
111
|
const base = typeof cfgExtra === "function" ? cfgExtra(deps) : (cfgExtra ?? {});
|
|
@@ -133,10 +133,10 @@ function buildDevExtraContext(options, config, registry, bootCrypto) {
|
|
|
133
133
|
// pins that the dev configResolver-default carries the ENV→app-override bridge
|
|
134
134
|
// and that a caller-supplied configResolver still overrides it. Not re-exported
|
|
135
135
|
// from the package barrel (index.ts lists only runDevApp).
|
|
136
|
-
export function mergeConfigResolverDefault(ctx, registry, envSource, cipher) {
|
|
136
|
+
export function mergeConfigResolverDefault(ctx, registry, envSource, cipher, appOverrides) {
|
|
137
137
|
const defaults = {
|
|
138
138
|
configResolver: createConfigResolver({
|
|
139
|
-
appOverrides:
|
|
139
|
+
appOverrides: buildConfigOverrides(registry, envSource, appOverrides),
|
|
140
140
|
...(cipher && { cipher }),
|
|
141
141
|
}),
|
|
142
142
|
};
|
package/dist/scaffold-app.d.ts
CHANGED
|
@@ -27,7 +27,8 @@ export type ScaffoldAppOptions = {
|
|
|
27
27
|
* (the CLI's ctx.cwd) MUST pass it so the scaffold lands where the
|
|
28
28
|
* command's output claims it does. */
|
|
29
29
|
readonly cwd?: string;
|
|
30
|
-
/**
|
|
30
|
+
/** Exact version pin for @cosmicdrift/* deps. Default: the running framework version
|
|
31
|
+
* (resolveFrameworkVersion); scaffoldApp throws when that cannot be resolved. */
|
|
31
32
|
readonly frameworkVersion?: string;
|
|
32
33
|
/** Bundled-features to mount in run-config.ts. Default: secrets + auth-foundation + sessions
|
|
33
34
|
* (the historical foundation). create-kumiko-app passes the picker output
|
package/dist/scaffold-app.js
CHANGED
|
@@ -21,7 +21,10 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
21
21
|
import { dirname, join, resolve } from "node:path";
|
|
22
22
|
import { APP_CONFIG_FILE } from "@cosmicdrift/kumiko-framework/config";
|
|
23
23
|
import { collectTableMetas, generateMigration, writeSnapshotJson, } from "@cosmicdrift/kumiko-framework/db";
|
|
24
|
+
import { DEFAULT_ROW_LEVEL_SECURITY_MODE } from "@cosmicdrift/kumiko-framework/internal/row-level-security";
|
|
25
|
+
import { escapeHtml } from "@cosmicdrift/kumiko-renderer/headless";
|
|
24
26
|
import { composeFeatures } from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
27
|
+
import { resolveFrameworkVersion } from "./framework-version.js";
|
|
25
28
|
import { isKebabSegment } from "./kebab.js";
|
|
26
29
|
import { CURRENT_INFRA_REF, PREPARE_SCRIPT, resolveManagedAppFacts, syncManagedFiles, } from "./managed-files/index.js";
|
|
27
30
|
import { renderAgentsMd, renderClaudeMd, renderMountedFeatureList } from "./scaffold-agent-docs.js";
|
|
@@ -45,7 +48,10 @@ export async function scaffoldApp(options) {
|
|
|
45
48
|
if (existsSync(destination)) {
|
|
46
49
|
throw new Error(`scaffoldApp: ${destination} already exists — refusing to overwrite`);
|
|
47
50
|
}
|
|
48
|
-
const version = options.frameworkVersion ??
|
|
51
|
+
const version = options.frameworkVersion ?? resolveFrameworkVersion();
|
|
52
|
+
if (version === undefined) {
|
|
53
|
+
throw new Error("scaffoldApp: cannot resolve the framework version; pass frameworkVersion explicitly");
|
|
54
|
+
}
|
|
49
55
|
const testSetup = options.testSetup?.({ appName: options.name, frameworkVersion: version });
|
|
50
56
|
mkdirSync(join(destination, "bin"), { recursive: true });
|
|
51
57
|
mkdirSync(join(destination, "src"), { recursive: true });
|
|
@@ -84,6 +90,9 @@ export async function scaffoldApp(options) {
|
|
|
84
90
|
files.push("src/client.tsx");
|
|
85
91
|
write(join(destination, "src", "styles.css"), renderStylesCss());
|
|
86
92
|
files.push("src/styles.css");
|
|
93
|
+
mkdirSync(join(destination, "public"), { recursive: true });
|
|
94
|
+
write(join(destination, "public", "index.html"), renderIndexHtml(options.name));
|
|
95
|
+
files.push("public/index.html");
|
|
87
96
|
write(join(destination, ".env.example"), renderEnvExample(options.name));
|
|
88
97
|
files.push(".env.example");
|
|
89
98
|
write(join(destination, "docker-compose.yml"), renderDockerCompose());
|
|
@@ -161,7 +170,7 @@ function renderPackageJson(name, version, testSetup, infraRef) {
|
|
|
161
170
|
"@tailwindcss/cli": "^4.3.0",
|
|
162
171
|
"@types/react": "^19.2.0",
|
|
163
172
|
"@types/react-dom": "^19.2.0",
|
|
164
|
-
"bun-types": "^1.4.
|
|
173
|
+
"bun-types": "^1.4.4",
|
|
165
174
|
tailwindcss: "^4.3.0",
|
|
166
175
|
typescript: "^6.0.3",
|
|
167
176
|
...testSetup?.devDependencies,
|
|
@@ -388,6 +397,7 @@ const kmsWiring =
|
|
|
388
397
|
await runProdApp({
|
|
389
398
|
features: APP_FEATURES,
|
|
390
399
|
...(appConfig.validateBootOptions && { validateBootOptions: appConfig.validateBootOptions }),
|
|
400
|
+
...(appConfig.rowLevelSecurity && { rowLevelSecurity: appConfig.rowLevelSecurity }),
|
|
391
401
|
envSchema,
|
|
392
402
|
staticDir: "./dist",
|
|
393
403
|
...kmsWiring,
|
|
@@ -404,12 +414,9 @@ function renderServer(appName) {
|
|
|
404
414
|
{ specifier: "../kumiko.config", names: [], defaultName: "appConfig" },
|
|
405
415
|
{ specifier: "../src/seed", names: ["seedDemoTasks"] },
|
|
406
416
|
]);
|
|
407
|
-
// Dev-only emailVerified skips the login verify gate for the seeded admin;
|
|
408
|
-
// prod's bin/main.ts leaves it unset because the verify flow must run there.
|
|
409
417
|
const authBlock = renderAdminAuthBlock(appName, [
|
|
410
418
|
'password: "changeme",',
|
|
411
419
|
'displayName: "Admin",',
|
|
412
|
-
"emailVerified: true,",
|
|
413
420
|
]);
|
|
414
421
|
return `// Dev bootstrap. \`bun --watch bin/server.ts\` (see package.json scripts.dev)
|
|
415
422
|
// starts a full-featured dev server with auto-reload on code changes.
|
|
@@ -552,6 +559,8 @@ services:
|
|
|
552
559
|
# Pinned to the project's own compose-file tag (663/1) — Alpine variant
|
|
553
560
|
# (~90MB vs ~400MB) and a reproducible patch version, bump on PG18 minors.
|
|
554
561
|
image: postgres:18.3-alpine
|
|
562
|
+
# Bun.SQL dials its whole pool eagerly; the default of 100 is too tight for app + tests.
|
|
563
|
+
command: postgres -c max_connections=300
|
|
555
564
|
environment:
|
|
556
565
|
POSTGRES_USER: postgres
|
|
557
566
|
POSTGRES_PASSWORD: postgres
|
|
@@ -660,6 +669,23 @@ Files whose first line reads \`kumiko-managed\` (deploy/, .github/workflows/,
|
|
|
660
669
|
For full docs see https://docs.kumiko.rocks.
|
|
661
670
|
`;
|
|
662
671
|
}
|
|
672
|
+
// No inline script: CSP is script-src 'self'.
|
|
673
|
+
function renderIndexHtml(appName) {
|
|
674
|
+
return `<!doctype html>
|
|
675
|
+
<html lang="en">
|
|
676
|
+
<head>
|
|
677
|
+
<meta charset="utf-8" />
|
|
678
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,interactive-widget=resizes-content" />
|
|
679
|
+
<title>${escapeHtml(appName)}</title>
|
|
680
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
681
|
+
</head>
|
|
682
|
+
<body>
|
|
683
|
+
<div id="root"></div>
|
|
684
|
+
<script type="module" src="/client.js"></script>
|
|
685
|
+
</body>
|
|
686
|
+
</html>
|
|
687
|
+
`;
|
|
688
|
+
}
|
|
663
689
|
function renderStylesCss() {
|
|
664
690
|
return [
|
|
665
691
|
'@import "@cosmicdrift/kumiko-renderer/web/styles.css";',
|
|
@@ -688,21 +714,22 @@ function renderBinKumiko() {
|
|
|
688
714
|
"// consumer status|restart <name>` to recover a dead event consumer without",
|
|
689
715
|
"// ad-hoc SQL. kumiko-build bundles this file to dist-server/kumiko.js.",
|
|
690
716
|
"",
|
|
691
|
-
'import { allAppFeatures } from "@cosmicdrift/kumiko-framework/config";',
|
|
692
717
|
'import { runConsumerCli } from "@cosmicdrift/kumiko-framework/consumer-cli";',
|
|
693
718
|
'import { kmsSlotsOf } from "@cosmicdrift/kumiko-framework/env";',
|
|
694
719
|
'import { runSchemaCli } from "@cosmicdrift/kumiko-framework/schema-cli";',
|
|
695
|
-
'import
|
|
720
|
+
'import { FEATURES } from "../kumiko/schema";',
|
|
696
721
|
'import { envSchema } from "./env-schema";',
|
|
697
722
|
"",
|
|
698
723
|
"const [, , cmd, ...rest] = Bun.argv;",
|
|
699
724
|
"const out = { log: (l: string) => console.log(l), err: (l: string) => console.error(l) };",
|
|
700
725
|
"",
|
|
701
726
|
'if (cmd === "schema") {',
|
|
702
|
-
" const features = allAppFeatures(appConfig);",
|
|
703
727
|
" const kmsSlots = kmsSlotsOf(envSchema.schema);",
|
|
704
728
|
" process.exit(",
|
|
705
|
-
" await runSchemaCli(rest, process.env.INIT_CWD ?? process.cwd(), out, {
|
|
729
|
+
" await runSchemaCli(rest, process.env.INIT_CWD ?? process.cwd(), out, {",
|
|
730
|
+
" features: FEATURES,",
|
|
731
|
+
" kmsSlots,",
|
|
732
|
+
" }),",
|
|
706
733
|
" );",
|
|
707
734
|
"}",
|
|
708
735
|
"",
|
|
@@ -747,6 +774,7 @@ async function writeInitMigration(destination, features) {
|
|
|
747
774
|
const metas = collectTableMetas(composed);
|
|
748
775
|
const result = generateMigration({
|
|
749
776
|
metas,
|
|
777
|
+
rowLevelSecurity: DEFAULT_ROW_LEVEL_SECURITY_MODE,
|
|
750
778
|
prevSnapshot: null,
|
|
751
779
|
name: "init",
|
|
752
780
|
sequenceNumber: 1,
|
package/dist/scaffold-feature.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// scaffolding).
|
|
13
13
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { join, resolve } from "node:path";
|
|
15
|
-
import { renderFeatureFile, } from "@cosmicdrift/kumiko-
|
|
15
|
+
import { renderFeatureFile, } from "@cosmicdrift/kumiko-feature-ast";
|
|
16
16
|
/**
|
|
17
17
|
* Generate a starter feature workspace at `destination`. Throws when
|
|
18
18
|
* the destination already exists — refuses to overwrite. The caller is
|
package/dist/schema-apply.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RowLevelSecurityMode } from "@cosmicdrift/kumiko-framework/db";
|
|
1
2
|
import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
3
|
import { type ComposeFeaturesOptions } from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
3
4
|
export type SchemaApplyOptions = ComposeFeaturesOptions & {
|
|
@@ -6,6 +7,8 @@ export type SchemaApplyOptions = ComposeFeaturesOptions & {
|
|
|
6
7
|
readonly features: readonly FeatureDefinition[];
|
|
7
8
|
/** Default INIT_CWD ?? process.cwd(); migrations live under <appCwd>/kumiko/migrations. */
|
|
8
9
|
readonly appCwd?: string;
|
|
10
|
+
/** Pass appConfig.rowLevelSecurity: on a role the policies bind, migrations and rebuilds only see rows through an "on" connection. Default "on". */
|
|
11
|
+
readonly rowLevelSecurity?: RowLevelSecurityMode;
|
|
9
12
|
};
|
|
10
13
|
export declare function runSchemaApply(opts: SchemaApplyOptions): Promise<number>;
|
|
11
14
|
export declare function runStandaloneSchemaCli(opts: SchemaApplyOptions): Promise<never>;
|
package/dist/schema-apply.js
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
// kumiko-build discovers the app bin via findRepoRoot() and bundles it.
|
|
8
8
|
import { existsSync } from "node:fs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
|
-
import { createDbConnection, runMigrationsFromDir } from "@cosmicdrift/kumiko-framework/db";
|
|
10
|
+
import { createDbConnection, runMigrationsFromDir, } from "@cosmicdrift/kumiko-framework/db";
|
|
11
11
|
import { createRegistry } from "@cosmicdrift/kumiko-framework/engine";
|
|
12
12
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
13
|
+
import { DEFAULT_ROW_LEVEL_SECURITY_MODE } from "@cosmicdrift/kumiko-framework/internal/row-level-security";
|
|
13
14
|
import { queueRebuildsFromMarkers, reportPendingRebuildRun, runPendingRebuilds, } from "@cosmicdrift/kumiko-framework/migrations";
|
|
14
15
|
import { createEventConsumerStateTable, createProjectionStateTable, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
15
16
|
import { composeFeatures, } from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
@@ -25,7 +26,10 @@ export async function runSchemaApply(opts) {
|
|
|
25
26
|
console.error(`\n ${migrationsDir} is missing — kumiko/migrations/ must be part of the image.\n`);
|
|
26
27
|
return 1;
|
|
27
28
|
}
|
|
28
|
-
const { db, close } = createDbConnection({
|
|
29
|
+
const { db, close } = createDbConnection({
|
|
30
|
+
url: dbUrl,
|
|
31
|
+
rowLevelSecurity: opts.rowLevelSecurity ?? DEFAULT_ROW_LEVEL_SECURITY_MODE,
|
|
32
|
+
});
|
|
29
33
|
try {
|
|
30
34
|
// Create infrastructure tables (event store + pipeline state) first; all are
|
|
31
35
|
// tableExists-gated and idempotent: on an existing DB this is a no-op, while
|
|
@@ -5,6 +5,7 @@ export type TestStackPreset = "config" | "template-resolver";
|
|
|
5
5
|
export type SetupTestStackFromFeaturesOptions = Omit<TestStackOptions, "features"> & {
|
|
6
6
|
readonly includeBundled?: boolean;
|
|
7
7
|
readonly authOptions?: ComposeFeaturesOptions["authOptions"];
|
|
8
|
+
readonly bundledLists?: ComposeFeaturesOptions["bundledLists"];
|
|
8
9
|
readonly presets?: readonly TestStackPreset[];
|
|
9
10
|
};
|
|
10
11
|
export declare function mergeExtraContext(base: TestStackOptions["extraContext"], presets: readonly TestStackPreset[]): TestStackOptions["extraContext"];
|
|
@@ -36,8 +36,12 @@ export function mergeExtraContext(base, presets) {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
export async function setupTestStackFromFeatures(appFeatures, options = {}) {
|
|
39
|
-
const { includeBundled = false, authOptions, presets = [], ...stackOptions } = options;
|
|
40
|
-
const features = composeFeatures(appFeatures, {
|
|
39
|
+
const { includeBundled = false, authOptions, bundledLists, presets = [], ...stackOptions } = options;
|
|
40
|
+
const features = composeFeatures(appFeatures, {
|
|
41
|
+
includeBundled,
|
|
42
|
+
authOptions,
|
|
43
|
+
...(bundledLists && { bundledLists }),
|
|
44
|
+
});
|
|
41
45
|
const extraContext = mergeExtraContext(stackOptions.extraContext, presets);
|
|
42
46
|
// Same run-logger wiring as prod, so jobs that declare tenantVisibleFailure
|
|
43
47
|
// write their failure rows in tests too.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.390.0",
|
|
4
4
|
"description": "Dev-tooling for Kumiko apps: local dev-server bootstrap (runDevApp), scaffolding. Its compose-stacks/env-schema subpaths are consumed at prod boot too — see @cosmicdrift/kumiko-server-runtime for the prod runner itself.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -77,18 +77,24 @@
|
|
|
77
77
|
"kumiko-upgrade": "./bin/kumiko-upgrade.ts"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
81
|
-
"@cosmicdrift/kumiko-
|
|
82
|
-
"@cosmicdrift/kumiko-
|
|
83
|
-
"@cosmicdrift/kumiko-renderer
|
|
84
|
-
"@cosmicdrift/kumiko-
|
|
85
|
-
"@cosmicdrift/kumiko-
|
|
86
|
-
"@cosmicdrift/kumiko-
|
|
87
|
-
"@cosmicdrift/kumiko-
|
|
88
|
-
"
|
|
80
|
+
"@cosmicdrift/kumiko-bundled-features": "0.390.0",
|
|
81
|
+
"@cosmicdrift/kumiko-feature-ast": "0.390.0",
|
|
82
|
+
"@cosmicdrift/kumiko-framework": "0.390.0",
|
|
83
|
+
"@cosmicdrift/kumiko-renderer": "0.390.0",
|
|
84
|
+
"@cosmicdrift/kumiko-renderer-mail-html": "0.390.0",
|
|
85
|
+
"@cosmicdrift/kumiko-guards": "0.390.0",
|
|
86
|
+
"@cosmicdrift/kumiko-server-runtime": "0.390.0",
|
|
87
|
+
"@cosmicdrift/kumiko-testing": "0.390.0",
|
|
88
|
+
"@cosmicdrift/kumiko-types": "0.390.0",
|
|
89
89
|
"ts-morph": "^28.0.0",
|
|
90
90
|
"zod": "^4.4.3"
|
|
91
91
|
},
|
|
92
|
+
"peerDependencies": {
|
|
93
|
+
"bun-types": "^1.4.4"
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"bun-types": "^1.4.4"
|
|
97
|
+
},
|
|
92
98
|
"publishConfig": {
|
|
93
99
|
"registry": "https://registry.npmjs.org",
|
|
94
100
|
"access": "public",
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.390.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "The managed Dockerfile names the real k3s migration step",
|
|
6
|
+
"detail": "The comment above the migrations COPY in the managed Dockerfile pointed at a release.yml InitContainer that does not exist. It now names the migrate-db initContainer of the infra _app-deploy.yml, and migrate-step.sh for compose hosts. Only the comment changes; the next kumiko-upgrade shows it as a managed-file diff."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.390.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "Scaffolded bin/kumiko.ts passes FEATURES from kumiko/schema",
|
|
12
|
+
"detail": "The scaffolded standalone CLI handed allAppFeatures(appConfig) to runSchemaCli, a raw list without the bundled foundation. It now imports FEATURES from kumiko/schema, which the Schema CLI Features guard requires. Existing apps are not touched."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.390.0",
|
|
16
|
+
"type": "breaking",
|
|
17
|
+
"title": "The dev server runs with row level security on",
|
|
18
|
+
"detail": "runDevApp and createKumikoServer default to rowLevelSecurity \"on\" and run the dev stack as kumiko_app. On boot against a persistent dev database, the stack creates the role and transfers ownership of the database and of the public schema's tables, views and sequences to kumiko_app. The database user in DATABASE_URL needs the right to create roles, which the superuser of a local Postgres has. Code that reads tenant tables through a raw connection without a scope sees no rows in development; the boot does not detect this. runSchemaApply takes rowLevelSecurity, and the managed kumiko/schema.ts exports ROW_LEVEL_SECURITY from appConfig; the managed file updates on the next sync.",
|
|
19
|
+
"migration": "Pass rowLevelSecurity: \"off\" to runDevApp while fixing code paths without tenant context; the dev database keeps kumiko_app as owner. A server entry written by an older scaffold passes appConfig.rowLevelSecurity to runProdApp by hand once the app turns row level security on. Manual migration, there is no codemod."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"version": "0.390.0",
|
|
23
|
+
"type": "improvement",
|
|
24
|
+
"title": "Scaffolded dev admin leaves emailVerified to the boot seed",
|
|
25
|
+
"detail": "The boot seed marks the operator-created admin and the seed shortcut accounts as email-verified, so the scaffolded `bin/server.ts` no longer sets `emailVerified: true` on its own. Self-registered users still go through the verify flow.",
|
|
26
|
+
"migration": "Optional. Existing apps can drop `emailVerified: true` from `auth.admin` in `bin/server.ts` and `bin/main.ts`; an explicit value still wins over the default."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"version": "0.389.0",
|
|
30
|
+
"type": "improvement",
|
|
31
|
+
"title": "Scaffolded apps pin Bun 1.4.4",
|
|
32
|
+
"detail": "The deploy Dockerfile template, the managed public CI workflow and the scaffolded bun-types range move from Bun 1.4.0 to 1.4.4, the minimum the Bun.SQL driver needs. The managed CI workflow updates on the next sync; the deploy Dockerfile is only written at scaffold time.",
|
|
33
|
+
"migration": "Raise BUN_VERSION in an existing deploy Dockerfile to 1.4.4 and bun-types to ^1.4.4 by hand."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"version": "0.389.0",
|
|
37
|
+
"type": "improvement",
|
|
38
|
+
"title": "Scaffolded docker-compose raises Postgres max_connections to 300",
|
|
39
|
+
"detail": "Bun.SQL dials its whole pool eagerly, so the default limit of 100 is too tight for an app plus its tests. Existing apps can add command postgres -c max_connections=300 to the postgres service."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"version": "0.389.0",
|
|
43
|
+
"type": "fix",
|
|
44
|
+
"title": "Fresh scaffolds build with bun run build",
|
|
45
|
+
"detail": "create-kumiko-app now writes public/index.html with the /styles.css and /client.js placeholders. Without it kumiko-build stopped with a missing-template error, so the scaffolded Dockerfile could not build either."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"version": "0.389.0",
|
|
49
|
+
"type": "fix",
|
|
50
|
+
"title": "Scaffolded apps get exact framework pins",
|
|
51
|
+
"detail": "resolveFrameworkVersion no longer prefixes ^ and scaffoldApp no longer falls back to \"*\", so a new app is green in kumiko check managed. Without a resolvable version and without an explicit frameworkVersion, scaffoldApp throws."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"version": "0.389.0",
|
|
55
|
+
"type": "improvement",
|
|
56
|
+
"title": "migrate-step.sh leaves the managed file set",
|
|
57
|
+
"detail": "Managed apps run migrations as the k3s InitContainer from release.yml, so deploy/migrate-step.sh is neither scaffolded nor synced for them. Delete it if present. kumiko-init-deploy keeps generating it for compose self-hosting."
|
|
58
|
+
},
|
|
2
59
|
{
|
|
3
60
|
"version": "0.388.0",
|
|
4
61
|
"type": "improvement",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
#
|
|
12
12
|
# Build context: repository root (the full source tree is only used in the build stage).
|
|
13
13
|
|
|
14
|
-
ARG BUN_VERSION=1.4.
|
|
14
|
+
ARG BUN_VERSION=1.4.4
|
|
15
15
|
{{#hasPrivateGhPackages}}
|
|
16
16
|
# Registry auth for @cosmicdriftgamestudio: CI passes the token as
|
|
17
17
|
# NPM_AUTH_TOKEN via --build-arg. Multi-stage ARG scoping needs the
|
|
@@ -69,7 +69,8 @@ RUN bun install --production --frozen-lockfile
|
|
|
69
69
|
# Client build (static assets) — served by runProdApp.staticDir.
|
|
70
70
|
COPY --from=build --chown=app:app /app/dist ./dist
|
|
71
71
|
|
|
72
|
-
# Checked-in SQL migrations for the pre-deploy `kumiko schema apply` step
|
|
72
|
+
# Checked-in SQL migrations for the pre-deploy `kumiko schema apply` step
|
|
73
|
+
# (migrate-db initContainer of the infra _app-deploy.yml on k3s, or migrate-step.sh on compose hosts).
|
|
73
74
|
# The shipped `kumiko-schema` bin reads `${INIT_CWD}/kumiko/migrations/*.sql`
|
|
74
75
|
# (see ENV INIT_CWD=/app below). kumiko/schema.ts is NOT needed at runtime
|
|
75
76
|
# (only generate reads it; apply is checksum-tracked SQL only).
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
fetch-depth: 0
|
|
32
32
|
- uses: oven-sh/setup-bun@v2
|
|
33
33
|
with:
|
|
34
|
-
bun-version: "1.4.
|
|
34
|
+
bun-version: "1.4.4"
|
|
35
35
|
- run: bun install --frozen-lockfile
|
|
36
36
|
- run: bun run typecheck
|
|
37
37
|
- run: bun run lint
|
|
@@ -81,7 +81,7 @@ jobs:
|
|
|
81
81
|
- uses: actions/checkout@v7
|
|
82
82
|
- uses: oven-sh/setup-bun@v2
|
|
83
83
|
with:
|
|
84
|
-
bun-version: "1.4.
|
|
84
|
+
bun-version: "1.4.4"
|
|
85
85
|
- run: bun install --frozen-lockfile
|
|
86
86
|
- name: Create test database
|
|
87
87
|
env:
|
|
@@ -22,9 +22,13 @@ const HAS_AUTH =
|
|
|
22
22
|
|
|
23
23
|
export const FEATURES: readonly FeatureDefinition[] = composeFeatures([...CONFIGURED_FEATURES], {
|
|
24
24
|
includeBundled: HAS_AUTH,
|
|
25
|
+
...(appConfig.bundledLists && { bundledLists: appConfig.bundledLists }),
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
// `kumiko check` validates the boot with the options kumiko.config.ts declares.
|
|
28
29
|
export const VALIDATE_BOOT_OPTIONS = appConfig.validateBootOptions;
|
|
29
30
|
|
|
31
|
+
// Decides whether `generate` emits row-level-security policies and `apply` runs as a policy-enforced connection.
|
|
32
|
+
export const ROW_LEVEL_SECURITY = appConfig.rowLevelSecurity;
|
|
33
|
+
|
|
30
34
|
export const ENTITY_METAS: readonly EntityTableMeta[] = collectTableMetas(FEATURES);
|