@cosmicdrift/kumiko-server-runtime 0.211.0 → 0.213.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.
|
|
3
|
+
"version": "0.213.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.
|
|
84
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
83
|
+
"@cosmicdrift/kumiko-bundled-features": "0.213.0",
|
|
84
|
+
"@cosmicdrift/kumiko-framework": "0.213.0",
|
|
85
85
|
"temporal-polyfill": "^0.3.2"
|
|
86
86
|
},
|
|
87
87
|
"publishConfig": {
|
|
@@ -12,6 +12,7 @@ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import {
|
|
15
|
+
buildMissingTemplateError,
|
|
15
16
|
type ClientEntry,
|
|
16
17
|
computeBuildId,
|
|
17
18
|
discoverClientEntries,
|
|
@@ -333,4 +334,49 @@ describe("build-prod-bundle/discovery edges", () => {
|
|
|
333
334
|
await writeFile(join(workDir, "src/client_admin.tsx"), "// bad");
|
|
334
335
|
expect(discoverClientEntries(workDir)).toEqual([]);
|
|
335
336
|
});
|
|
337
|
+
|
|
338
|
+
// #2305: a module only imported by another client-*.tsx still matches
|
|
339
|
+
// the entry pattern and becomes a second bundle entry.
|
|
340
|
+
test("discoverClientEntries treats a plain imported module named client-<x>.tsx as its own entry", async () => {
|
|
341
|
+
await mkdir(join(workDir, "src"), { recursive: true });
|
|
342
|
+
await writeFile(join(workDir, "src/client-app.tsx"), "// real entry");
|
|
343
|
+
await writeFile(join(workDir, "src/client-features.tsx"), "export const clientFeatures = [];");
|
|
344
|
+
|
|
345
|
+
const entries = discoverClientEntries(workDir);
|
|
346
|
+
|
|
347
|
+
expect(entries.map((e) => e.name)).toEqual(["app", "features"]);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe("build-prod-bundle/buildMissingTemplateError", () => {
|
|
352
|
+
function multiEntry(): ClientEntry {
|
|
353
|
+
return {
|
|
354
|
+
name: "features",
|
|
355
|
+
sourceFile: "/Users/dev/offlot-app/src/client-features.tsx",
|
|
356
|
+
manifestKey: "client-features.js",
|
|
357
|
+
htmlPath: "features.html",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
test("names the discovered source file and the client-<suffix> convention", () => {
|
|
362
|
+
const message = buildMissingTemplateError(
|
|
363
|
+
{ "client-features.js": "/assets/client-features-abcd.js" },
|
|
364
|
+
multiEntry(),
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(message).toContain("src/client-features.tsx");
|
|
368
|
+
expect(message).toContain("client-<suffix>.tsx");
|
|
369
|
+
expect(message).toContain("umbenennen");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("single-mode entry gets no rename hint (nothing was auto-discovered by suffix)", () => {
|
|
373
|
+
const message = buildMissingTemplateError(
|
|
374
|
+
{ "client.js": "/assets/client-abcd.js" },
|
|
375
|
+
clientEntry(),
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
expect(message).toContain("src/client.tsx");
|
|
379
|
+
expect(message).not.toContain("umbenennen");
|
|
380
|
+
expect(message).not.toContain("client-<suffix>.tsx");
|
|
381
|
+
});
|
|
336
382
|
});
|
package/src/build-prod-bundle.ts
CHANGED
|
@@ -536,7 +536,9 @@ async function renderHtml(
|
|
|
536
536
|
return injectAssetTags(template, manifest, entry, buildInfo);
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
|
|
539
|
+
// @internal — exported for unit tests only. See #2305: the message must
|
|
540
|
+
// name the source file and the filename convention.
|
|
541
|
+
export function buildMissingTemplateError(manifest: BuildManifest, entry: ClientEntry): string {
|
|
540
542
|
const cssLine = manifest["styles.css"]
|
|
541
543
|
? ` <link rel="stylesheet" href="/styles.css" />\n`
|
|
542
544
|
: "";
|
|
@@ -544,8 +546,22 @@ function buildMissingTemplateError(manifest: BuildManifest, entry: ClientEntry):
|
|
|
544
546
|
? // html-ok: Error-Hilfetext (Tag-Snippet als Text), wird nie gerendert.
|
|
545
547
|
` <script type="module" src="/${entry.manifestKey}"></script>\n`
|
|
546
548
|
: "";
|
|
549
|
+
const sourceBasename = basenameOf(entry.sourceFile);
|
|
550
|
+
// Single-mode entries always carry manifestKey "client.js"; any other
|
|
551
|
+
// value came from discoverMultiClientEntries' filename match.
|
|
552
|
+
const isMultiEntry = entry.manifestKey !== "client.js";
|
|
553
|
+
const discoveryHint = isMultiEntry
|
|
554
|
+
? `"src/${sourceBasename}" wurde automatisch als eigener Bundle-Entry erkannt — ` +
|
|
555
|
+
`jede Datei nach dem Muster src/client-<suffix>.tsx zählt als Entry (hier: Suffix "${entry.name}"). ` +
|
|
556
|
+
`War das nicht beabsichtigt, z. B. weil die Datei nur ein von einem anderen client-*.tsx ` +
|
|
557
|
+
`importiertes Modul ist: Datei umbenennen (ohne "client-"-Präfix), dann verschwindet der Entry.\n` +
|
|
558
|
+
`\n` +
|
|
559
|
+
`War es beabsichtigt:\n`
|
|
560
|
+
: "";
|
|
547
561
|
return (
|
|
548
|
-
`[kumiko build] kein ${entry.htmlPath} gefunden
|
|
562
|
+
`[kumiko build] kein ${entry.htmlPath} gefunden für Entry "src/${sourceBasename}", ` +
|
|
563
|
+
`aber es gibt JS/CSS-Output.\n` +
|
|
564
|
+
discoveryHint +
|
|
549
565
|
`Leg ein public/${basenameOf(entry.htmlPath)} oder ${basenameOf(entry.htmlPath)} im App-Root an, z. B.:\n` +
|
|
550
566
|
`\n` +
|
|
551
567
|
`<!doctype html>\n` +
|
package/src/compose-features.ts
CHANGED
|
@@ -39,12 +39,12 @@ export type ComposeFeaturesOptions = {
|
|
|
39
39
|
* (+ auth-self-registration when authOptions.signup is set) before the
|
|
40
40
|
* app features. Mirror of "auth-mode" in run{Dev,Prod}App. */
|
|
41
41
|
readonly includeBundled: boolean;
|
|
42
|
-
/** Optional auth-feature
|
|
43
|
-
* createAuthEmailPasswordFeature.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* passwordReset
|
|
42
|
+
/** Optional auth-feature options passed through to
|
|
43
|
+
* createAuthEmailPasswordFeature. When passwordReset / emailVerification
|
|
44
|
+
* are set here, the feature registers the request/confirm handlers —
|
|
45
|
+
* otherwise it doesn't (500 if the routes are mounted via
|
|
46
|
+
* auth-routes.ts but no handler dispatches). Goes hand-in-hand with the
|
|
47
|
+
* passwordReset block in RunProdAppAuthOptions / RunDevAppAuthOptions. */
|
|
48
48
|
readonly authOptions?: AuthEmailPasswordOptions;
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -108,13 +108,12 @@ export function composeFeatures(
|
|
|
108
108
|
return [...bundled, ...filteredApp];
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
/** Shape
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* doppelt zu bauen. */
|
|
111
|
+
/** Shape of any run{Prod,Dev}App auth block that can carry a
|
|
112
|
+
* passwordReset/emailVerification config. The wrapper API
|
|
113
|
+
* (PasswordResetSetup) extends the feature API (PasswordResetOptions), so
|
|
114
|
+
* a structural-typed lookup on the auth-only subset is enough. Lets
|
|
115
|
+
* buildComposeAuthOptions be called with both RunProd- and
|
|
116
|
+
* RunDev-AuthOptions without building the helper twice. */
|
|
118
117
|
export type AuthOptionsCarrier = {
|
|
119
118
|
readonly passwordReset?: PasswordResetOptions;
|
|
120
119
|
readonly emailVerification?: EmailVerificationOptions;
|
|
@@ -124,24 +123,26 @@ export type AuthOptionsCarrier = {
|
|
|
124
123
|
readonly accountLockout?: AccountLockoutOptions;
|
|
125
124
|
};
|
|
126
125
|
|
|
127
|
-
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
126
|
+
/** Builds the authOptions block for composeFeatures from a wrapper auth
|
|
127
|
+
* block. Passes through ONLY the feature-side fields (hmacSecret,
|
|
128
|
+
* tokenTtlMinutes, mode) — the mail side (sendResetEmail/appResetUrl)
|
|
129
|
+
* belongs in the auth-routes config and is wired separately by the
|
|
130
|
+
* wrapper.
|
|
132
131
|
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
|
|
132
|
+
* Returns undefined when neither passwordReset nor emailVerification is
|
|
133
|
+
* set (composeFeatures default-deny: NO handler registered in the
|
|
134
|
+
* registry, /api/auth/request-password-reset etc. stay 401/404). */
|
|
135
|
+
// All five magic-link flows (reset/verify/signup/invite/unlock) accept the
|
|
136
|
+
// same appUrl shape — a plain string, or a `(locale) => string` function for
|
|
137
|
+
// apps with language-in-path routing (see SignupRequestOptions.appUrl).
|
|
137
138
|
type MailFlowFields = {
|
|
138
|
-
readonly appUrl: string;
|
|
139
|
+
readonly appUrl: string | ((locale: string) => string);
|
|
139
140
|
readonly tokenTtlMinutes?: number;
|
|
140
141
|
readonly appName?: string;
|
|
141
142
|
readonly locale?: AuthMailLocale;
|
|
142
143
|
};
|
|
143
144
|
|
|
144
|
-
// The magic-link mail fields shared by all
|
|
145
|
+
// The magic-link mail fields shared by all five flows. Conditional spreads omit
|
|
145
146
|
// undefined keys (exactOptionalPropertyTypes) and avoid the property-write that
|
|
146
147
|
// trips noPropertyAccessFromIndexSignature on the type-aliased option shapes.
|
|
147
148
|
// reset/verify layer hmacSecret (+ mode) on top.
|