@cosmicdrift/kumiko-dev-server 0.363.0 → 0.365.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 +12 -9
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -1
- package/dist/compose-stacks.d.ts +8 -1
- package/dist/compose-stacks.js +6 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/resolve-dev-pii-kms.d.ts +2 -0
- package/dist/resolve-dev-pii-kms.js +16 -3
- package/dist/run-dev-app.js +16 -8
- package/dist/scaffold-agent-docs.d.ts +3 -0
- package/dist/scaffold-agent-docs.js +17 -0
- package/dist/scaffold-app-feature.js +1 -2
- package/dist/scaffold-app.d.ts +1 -0
- package/dist/scaffold-app.js +275 -295
- package/dist/scaffold-demo-tasks.js +2 -1
- package/package.json +8 -9
- package/src/changes.json +43 -0
- package/bin/kumiko-schema-check.ts +0 -175
- package/dist/schema-check-core.d.ts +0 -2
- package/dist/schema-check-core.js +0 -24
|
@@ -110,9 +110,9 @@ export async function buildServerBundle(options = {}) {
|
|
|
110
110
|
await mkdir(outDir, { recursive: true });
|
|
111
111
|
// Ein Bun.build-Call mit allen Entries + splitting → das Framework wird
|
|
112
112
|
// einmal als shared chunk abgelegt statt pro Entry inlined.
|
|
113
|
-
const optionalSiblingEntries = ["worker
|
|
114
|
-
.map((
|
|
115
|
-
.filter((path) =>
|
|
113
|
+
const optionalSiblingEntries = ["worker", "bootstrap"]
|
|
114
|
+
.map((baseName) => discoverSiblingEntry(dirname(serverEntry), baseName))
|
|
115
|
+
.filter((path) => path !== undefined);
|
|
116
116
|
const entrypoints = [serverEntry, ...(kumikoCli ? [kumikoCli] : []), ...optionalSiblingEntries];
|
|
117
117
|
const result = await Bun.build({
|
|
118
118
|
entrypoints,
|
|
@@ -162,12 +162,15 @@ export async function buildServerBundle(options = {}) {
|
|
|
162
162
|
return { outDir, entries, chunks, totalBytes, runtimeDeps };
|
|
163
163
|
}
|
|
164
164
|
export function discoverServerEntry(cwd) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
return discoverSiblingEntry(join(cwd, "bin"), "main");
|
|
166
|
+
}
|
|
167
|
+
// `.ts` wins over `.js`, same precedence for the server entry and its siblings.
|
|
168
|
+
function discoverSiblingEntry(dir, baseName) {
|
|
169
|
+
for (const extension of [".ts", ".js"]) {
|
|
170
|
+
const candidate = join(dir, `${baseName}${extension}`);
|
|
171
|
+
if (existsSync(candidate))
|
|
172
|
+
return candidate;
|
|
173
|
+
}
|
|
171
174
|
return undefined;
|
|
172
175
|
}
|
|
173
176
|
// Walking up vom App-cwd bis ein Verzeichnis mit `bin/kumiko.ts` gefunden wird.
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,4 +2,3 @@ export { buildProdBundle, buildServerBundle, discoverServerEntry, formatBuildRes
|
|
|
2
2
|
export { formatScanWarning, runCodegen } from "./codegen/index.js";
|
|
3
3
|
export { createCrashTracker } from "./crash-tracker.js";
|
|
4
4
|
export { runInitDeployCli } from "./init-deploy-cli.js";
|
|
5
|
-
export { implicitAuthModeFeatureNames, resolveGeneratePath } from "./schema-check-core.js";
|
package/dist/cli.js
CHANGED
|
@@ -6,4 +6,3 @@ export { buildProdBundle, buildServerBundle, discoverServerEntry, formatBuildRes
|
|
|
6
6
|
export { formatScanWarning, runCodegen } from "./codegen/index.js";
|
|
7
7
|
export { createCrashTracker } from "./crash-tracker.js";
|
|
8
8
|
export { runInitDeployCli } from "./init-deploy-cli.js";
|
|
9
|
-
export { implicitAuthModeFeatureNames, resolveGeneratePath } from "./schema-check-core.js";
|
package/dist/compose-stacks.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type AuthMfaFeatureOptions } from "@cosmicdrift/kumiko-bundled-features
|
|
|
2
2
|
import { type LegalPagesOptions } from "@cosmicdrift/kumiko-bundled-features/legal-pages";
|
|
3
3
|
import { type UserDataRightsOptions } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
4
4
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
|
+
import { type MailBrandSuffixResolver, type MailFooterResolver } from "@cosmicdrift/kumiko-renderer-mail-html";
|
|
5
6
|
export type FileProviderKind = "inmemory" | "s3" | "s3-env";
|
|
6
7
|
export type MailTransportKind = "inmemory" | "smtp";
|
|
7
8
|
export type GdprStackOrder = "retention-first" | "compliance-first";
|
|
@@ -48,7 +49,13 @@ export type IdentityStackOptions = {
|
|
|
48
49
|
};
|
|
49
50
|
export declare function stackFeatureNames(features: readonly FeatureDefinition[]): string[];
|
|
50
51
|
export declare function composePagesStack(options?: PagesStackOptions): FeatureDefinition[];
|
|
51
|
-
export
|
|
52
|
+
export type RendererStackOptions = {
|
|
53
|
+
/** Platform imprint, privacy link and footer text under every mail; see createRendererMailHtmlFeature. */
|
|
54
|
+
readonly mailFooter?: MailFooterResolver;
|
|
55
|
+
/** Word after the tenant name in the mail's brand row, e.g. "Status". */
|
|
56
|
+
readonly mailBrandSuffix?: MailBrandSuffixResolver;
|
|
57
|
+
};
|
|
58
|
+
export declare function composeRendererStack(options?: RendererStackOptions): FeatureDefinition[];
|
|
52
59
|
export declare function composeMailStack(options: MailStackOptions): FeatureDefinition[];
|
|
53
60
|
export declare function composeFileStack(options: FileStackOptions): FeatureDefinition[];
|
|
54
61
|
/** Retention + compliance (+ optional lifecycle/sessions). UDR/files mount separately — order varies per app. */
|
package/dist/compose-stacks.js
CHANGED
|
@@ -30,7 +30,7 @@ import { createTemplateResolverFeature } from "@cosmicdrift/kumiko-bundled-featu
|
|
|
30
30
|
import { createTenantLifecycleFeature } from "@cosmicdrift/kumiko-bundled-features/tenant-lifecycle";
|
|
31
31
|
import { createUserDataRightsFeature, } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
32
32
|
import { createUserDataRightsDefaultsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights-defaults";
|
|
33
|
-
import { createRendererMailHtmlFeature } from "@cosmicdrift/kumiko-renderer-mail-html";
|
|
33
|
+
import { createRendererMailHtmlFeature, } from "@cosmicdrift/kumiko-renderer-mail-html";
|
|
34
34
|
export function stackFeatureNames(features) {
|
|
35
35
|
return features.map((f) => f.name);
|
|
36
36
|
}
|
|
@@ -44,11 +44,14 @@ export function composePagesStack(options = {}) {
|
|
|
44
44
|
createLegalPagesFeature(options.wrapLayout !== undefined ? { wrapLayout: options.wrapLayout } : {}),
|
|
45
45
|
];
|
|
46
46
|
}
|
|
47
|
-
export function composeRendererStack() {
|
|
47
|
+
export function composeRendererStack(options = {}) {
|
|
48
48
|
return [
|
|
49
49
|
createTemplateResolverFeature(),
|
|
50
50
|
createRendererFoundationFeature(),
|
|
51
|
-
createRendererMailHtmlFeature(
|
|
51
|
+
createRendererMailHtmlFeature({
|
|
52
|
+
...(options.mailFooter !== undefined && { footer: options.mailFooter }),
|
|
53
|
+
...(options.mailBrandSuffix !== undefined && { brandSuffix: options.mailBrandSuffix }),
|
|
54
|
+
}),
|
|
52
55
|
];
|
|
53
56
|
}
|
|
54
57
|
export function composeMailStack(options) {
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { runInitDeployCli } from "./init-deploy-cli.js";
|
|
|
11
11
|
export type { RunDevAppAuthOptions, RunDevAppOptions, SeedFn } from "./run-dev-app.js";
|
|
12
12
|
export { runDevApp } from "./run-dev-app.js";
|
|
13
13
|
export type { ScaffoldAppOptions, ScaffoldAppResult, ScaffoldFeatureEntry, } from "./scaffold-app.js";
|
|
14
|
-
export { scaffoldApp } from "./scaffold-app.js";
|
|
14
|
+
export { SCAFFOLD_BIOME_VERSION, scaffoldApp } from "./scaffold-app.js";
|
|
15
15
|
export type { ScaffoldAppFeatureOptions, ScaffoldAppFeatureResult, } from "./scaffold-app-feature.js";
|
|
16
16
|
export { runConfigPathForApp, scaffoldAppFeature } from "./scaffold-app-feature.js";
|
|
17
17
|
export type { CheckDeployDriftResult, DeployDriftEntry, RenderDeployFilesOptions, RenderDeployFilesResult, RenderedDeployFile, ScaffoldDeployDetected, ScaffoldDeployOptions, ScaffoldDeployResult, ScaffoldedFile, } from "./scaffold-deploy.js";
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export { buildFewShotCorpus, pathToId } from "./few-shot-corpus.js";
|
|
|
25
25
|
export { resolveFrameworkVersion } from "./framework-version.js";
|
|
26
26
|
export { runInitDeployCli } from "./init-deploy-cli.js";
|
|
27
27
|
export { runDevApp } from "./run-dev-app.js";
|
|
28
|
-
export { scaffoldApp } from "./scaffold-app.js";
|
|
28
|
+
export { SCAFFOLD_BIOME_VERSION, scaffoldApp } from "./scaffold-app.js";
|
|
29
29
|
export { runConfigPathForApp, scaffoldAppFeature } from "./scaffold-app-feature.js";
|
|
30
30
|
export { checkDeployDrift, renderDeployFiles, scaffoldDeploy } from "./scaffold-deploy.js";
|
|
31
31
|
export { scaffoldFeature } from "./scaffold-feature.js";
|
|
@@ -2,6 +2,8 @@ import { type KmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
|
|
|
2
2
|
export type DevPiiKmsResolution = {
|
|
3
3
|
readonly kms: KmsAdapter | undefined;
|
|
4
4
|
readonly blindIndexKey: string | undefined;
|
|
5
|
+
/** True only when the ephemeral default minted the key, not when the app passed one. */
|
|
6
|
+
readonly generatedBlindIndexKey: boolean;
|
|
5
7
|
readonly mode: "app-kms" | "ephemeral-default" | "plaintext";
|
|
6
8
|
};
|
|
7
9
|
type DevPiiKmsOptions = {
|
|
@@ -8,7 +8,9 @@ export function captureEphemeralDevPiiKms(resolution) {
|
|
|
8
8
|
if (resolution.mode !== "ephemeral-default")
|
|
9
9
|
return () => { };
|
|
10
10
|
const ownKms = configuredPiiSubjectKms();
|
|
11
|
-
const ownBlindIndexKey =
|
|
11
|
+
const ownBlindIndexKey = resolution.generatedBlindIndexKey
|
|
12
|
+
? configuredBlindIndexKey()
|
|
13
|
+
: undefined;
|
|
12
14
|
return () => {
|
|
13
15
|
if (ownKms !== undefined && configuredPiiSubjectKms() === ownKms) {
|
|
14
16
|
configurePiiSubjectKms(undefined);
|
|
@@ -20,14 +22,25 @@ export function captureEphemeralDevPiiKms(resolution) {
|
|
|
20
22
|
}
|
|
21
23
|
export function resolveDevPiiKms(options, env = process.env) {
|
|
22
24
|
if (options.kms !== undefined && options.kms !== false) {
|
|
23
|
-
return {
|
|
25
|
+
return {
|
|
26
|
+
kms: options.kms,
|
|
27
|
+
blindIndexKey: options.blindIndexKey,
|
|
28
|
+
generatedBlindIndexKey: false,
|
|
29
|
+
mode: "app-kms",
|
|
30
|
+
};
|
|
24
31
|
}
|
|
25
32
|
if (options.kms === false || isPersistentDevDb(env)) {
|
|
26
|
-
return {
|
|
33
|
+
return {
|
|
34
|
+
kms: undefined,
|
|
35
|
+
blindIndexKey: options.blindIndexKey,
|
|
36
|
+
generatedBlindIndexKey: false,
|
|
37
|
+
mode: "plaintext",
|
|
38
|
+
};
|
|
27
39
|
}
|
|
28
40
|
return {
|
|
29
41
|
kms: new InMemoryKmsAdapter(),
|
|
30
42
|
blindIndexKey: options.blindIndexKey ?? randomBytes(32).toString("base64"),
|
|
43
|
+
generatedBlindIndexKey: options.blindIndexKey === undefined,
|
|
31
44
|
mode: "ephemeral-default",
|
|
32
45
|
};
|
|
33
46
|
}
|
package/dist/run-dev-app.js
CHANGED
|
@@ -22,7 +22,7 @@ import { TenantQueries } from "@cosmicdrift/kumiko-bundled-features/tenant";
|
|
|
22
22
|
import { createInMemoryLoginRateLimiter, parseTrustedProxyHopsEnv, TRUSTED_PROXY_HOPS_ENV, } from "@cosmicdrift/kumiko-framework/api";
|
|
23
23
|
import { configureBlindIndexKey, configurePiiSubjectKms, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
24
24
|
import { configureEntityFieldEncryption } from "@cosmicdrift/kumiko-framework/db";
|
|
25
|
-
import { collectWriteHandlerQns, createRegistry, FILE_STORAGE_PROVIDER_BOOT_SENTINEL, FILE_STORAGE_PROVIDER_ENV, findTierResolverUsage,
|
|
25
|
+
import { collectWriteHandlerQns, createRegistry, FILE_STORAGE_PROVIDER_BOOT_SENTINEL, FILE_STORAGE_PROVIDER_ENV, findTierResolverUsage, requireTierResolverPlugin, validateAppCustomScreenWriteQns, validateBoot, } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
26
|
import { warnIfNonUtcServerTimeZone } from "@cosmicdrift/kumiko-framework/time";
|
|
27
27
|
import { applyBootSeeds } from "@cosmicdrift/kumiko-server-runtime/boot/apply-boot-seeds";
|
|
28
28
|
import { resolveBootCrypto } from "@cosmicdrift/kumiko-server-runtime/boot/boot-crypto";
|
|
@@ -67,7 +67,13 @@ export async function runDevApp(options) {
|
|
|
67
67
|
// die früher nur runProdApp fing und sonst erst den Prod-Pod im
|
|
68
68
|
// CrashLoopBackOff sterben ließ (#359). Wirft synchron, bevor ein
|
|
69
69
|
// Socket oder Watcher (codegen-Write) aufgeht.
|
|
70
|
-
validateBoot
|
|
70
|
+
// Resolved before validateBoot: an app-supplied masterKey provider must satisfy the
|
|
71
|
+
// encrypted-field gate here exactly as it does in runProdApp.
|
|
72
|
+
const bootCrypto = resolveBootCrypto(envSource, options.masterKey);
|
|
73
|
+
validateBoot(features, {
|
|
74
|
+
...(bootCrypto.entityFieldCipher && { entityFieldCipher: bootCrypto.entityFieldCipher }),
|
|
75
|
+
...bootOptions,
|
|
76
|
+
});
|
|
71
77
|
warnIfNonUtcServerTimeZone();
|
|
72
78
|
validateAppCustomScreenWriteQns(process.cwd(), collectWriteHandlerQns(features));
|
|
73
79
|
// Codegen + File-Watcher — schreibt `<appRoot>/.kumiko/types.generated.d.ts`
|
|
@@ -122,7 +128,6 @@ export async function runDevApp(options) {
|
|
|
122
128
|
// throwaway-Registry hier extrahiert nur die config-Keys, weil der
|
|
123
129
|
// configResolver vor dem Server-Boot konstruiert wird (stack.registry
|
|
124
130
|
// gibt's erst onAfterSetup) — createKumikoServer baut intern seine eigene.
|
|
125
|
-
const bootCrypto = resolveBootCrypto(envSource, options.masterKey);
|
|
126
131
|
// App-wide cipher for `encrypted: true` entity fields (symmetrisch zu
|
|
127
132
|
// runProdApp) — executors resolve it lazily.
|
|
128
133
|
configureEntityFieldEncryption(bootCrypto.entityFieldCipher);
|
|
@@ -197,6 +202,13 @@ export async function runDevApp(options) {
|
|
|
197
202
|
let tokenVerifier;
|
|
198
203
|
const patFeature = features.find((f) => f.name === PAT_FEATURE);
|
|
199
204
|
const mfaFeature = features.find((f) => f.name === AUTH_MFA_FEATURE);
|
|
205
|
+
if (effectiveAuth &&
|
|
206
|
+
mfaFeature &&
|
|
207
|
+
registry?.getWriteHandler(AuthHandlers.switchTenantMfaGate) === undefined) {
|
|
208
|
+
throw new Error(`[runDevApp] auth-mfa is mounted but ${AuthHandlers.switchTenantMfaGate} is not registered: ` +
|
|
209
|
+
"createAuthEmailPasswordFeature registers it only when mfaStatusChecker is set, and without it " +
|
|
210
|
+
"POST /auth/switch-tenant would mint sessions without the second factor");
|
|
211
|
+
}
|
|
200
212
|
const patAuthFragment = patFeature
|
|
201
213
|
? {
|
|
202
214
|
tokenVerifier: (rawToken) => {
|
|
@@ -322,11 +334,7 @@ export async function runDevApp(options) {
|
|
|
322
334
|
// on the resolver being live (e.g. seed that writes a SystemAdmin's
|
|
323
335
|
// tier-assignment can immediately read tier-cuts).
|
|
324
336
|
if (tierResolverUsage) {
|
|
325
|
-
|
|
326
|
-
if (!isTierResolverPlugin(plugin)) {
|
|
327
|
-
throw new Error("tier-resolver registration options must provide a build() factory");
|
|
328
|
-
}
|
|
329
|
-
tierResolverHolder.resolver = await plugin.build({
|
|
337
|
+
tierResolverHolder.resolver = await requireTierResolverPlugin(tierResolverUsage).build({
|
|
330
338
|
db: stack.db,
|
|
331
339
|
registry: stack.registry,
|
|
332
340
|
cacheSync: stack.cacheSync,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const FRAMEWORK_AGENTS_IMPORT = "@node_modules/@cosmicdrift/kumiko-framework/AGENTS.md";
|
|
2
|
+
const FRAMEWORK_AGENTS_PATH = "node_modules/@cosmicdrift/kumiko-framework/AGENTS.md";
|
|
3
|
+
const FRAMEWORK_AGENTS_DIR = "node_modules/@cosmicdrift/kumiko-framework/agents/";
|
|
4
|
+
export function renderAgentsMd() {
|
|
5
|
+
return `# Agent instructions
|
|
6
|
+
|
|
7
|
+
This app is built on Kumiko. The framework guide for coding agents ships with the installed package and matches its version:
|
|
8
|
+
|
|
9
|
+
- \`${FRAMEWORK_AGENTS_PATH}\`: start here.
|
|
10
|
+
- \`${FRAMEWORK_AGENTS_DIR}\`: generated indexes of bundled features, widgets and tested examples.
|
|
11
|
+
|
|
12
|
+
Read the framework guide before you add or change a feature. App-specific rules go below.
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
export function renderClaudeMd() {
|
|
16
|
+
return `${FRAMEWORK_AGENTS_IMPORT}\n@AGENTS.md\n`;
|
|
17
|
+
}
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
// Auto-mount via ts-morph: opens src/run-config.ts, finds
|
|
9
9
|
// `export const APP_FEATURES = [...]`, prepends import + appends entry.
|
|
10
10
|
// User's promise "defineFeature → nichts woanders eintragen" is met
|
|
11
|
-
// for the run-config side
|
|
12
|
-
// touched here — DX-4 auto-discovery resolves that.
|
|
11
|
+
// for the run-config side; the schema is derived from the mounted features.
|
|
13
12
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
14
13
|
import { join, resolve } from "node:path";
|
|
15
14
|
import { Project, SyntaxKind } from "ts-morph";
|
package/dist/scaffold-app.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type ScaffoldTestSetupFactory = (input: {
|
|
|
16
16
|
readonly appName: string;
|
|
17
17
|
readonly frameworkVersion: string;
|
|
18
18
|
}) => ScaffoldTestSetup;
|
|
19
|
+
export declare const SCAFFOLD_BIOME_VERSION = "2.5.7";
|
|
19
20
|
export type ScaffoldAppOptions = {
|
|
20
21
|
/** kebab-case app name (e.g. "my-shop"). Becomes package-name + folder. */
|
|
21
22
|
readonly name: string;
|