@ykdz/template 0.0.21 → 0.0.23
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/node_modules/@ykdz/template-builtin-source/package.json +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +11 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/dependabot.yml +4 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/workflows/check.yml +2 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/drizzle/migrations/20260709120325_old_captain_flint/migration.sql +6 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/drizzle/migrations/20260709120325_old_captain_flint/snapshot.json +67 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/scripts/seed-example.ts +7 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/db.ts +2 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/index.ts +1 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/queries/todos.ts +17 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/readiness.ts +22 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/schema.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/seed/example.ts +23 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/test/todos.test.ts +2 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/+server.ts +2 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/Dockerfile +83 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/Dockerfile.dockerignore +14 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/pages/index/+Page.telefunc.ts +1 -2
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/pages/index/+Page.vue +6 -2
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/playwright.config.ts +50 -14
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/check-standalone-deployment.ts +449 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/container-entrypoint.sh +52 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/prepare-database.sh +6 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/run-playwright.ts +101 -12
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/server/app.ts +23 -12
- package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +13 -0
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +3 -2
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +99 -13
- package/node_modules/@ykdz/template-core/dist/module-graph.d.ts +12 -0
- package/node_modules/@ykdz/template-core/dist/module-graph.js +18 -0
- package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +7 -4
- package/node_modules/@ykdz/template-core/dist/project-github.d.ts +1 -0
- package/node_modules/@ykdz/template-core/dist/project-github.js +18 -5
- package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +57 -7
- package/node_modules/@ykdz/template-core/dist/renderer.js +4 -1
- package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +1 -1
- package/node_modules/@ykdz/template-core/package.json +2 -1
- package/node_modules/@ykdz/template-shared/dist/index.d.ts +6 -6
- package/node_modules/@ykdz/template-shared/package.json +1 -0
- package/package.json +5 -4
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
const templateInternalDependencyIdentities = new Set([
|
|
5
|
+
"@typescript/native",
|
|
6
|
+
"@typescript/typescript6",
|
|
7
|
+
]);
|
|
8
|
+
function assertGeneratedDependencyCatalogBoundary(dependencies) {
|
|
9
|
+
for (const dependency of dependencies) {
|
|
10
|
+
if (templateInternalDependencyIdentities.has(dependency)) {
|
|
11
|
+
throw new Error(`Generated Repository Dependency Catalog cannot include template-internal dependency: ${dependency}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
function templateRepositoryRoot() {
|
|
5
16
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
6
17
|
const candidates = [
|
|
@@ -151,6 +162,7 @@ function renderCatalogKey(key) {
|
|
|
151
162
|
return key.startsWith("@") ? JSON.stringify(key) : key;
|
|
152
163
|
}
|
|
153
164
|
export function pnpmWorkspaceYamlWithCatalogDependencies(workspaceYaml, dependencies, templateCatalog = loadTemplateDependencyCatalog()) {
|
|
165
|
+
assertGeneratedDependencyCatalogBoundary(dependencies);
|
|
154
166
|
const catalogStart = workspaceYaml
|
|
155
167
|
.split(/\r?\n/)
|
|
156
168
|
.findIndex((line) => line === "catalog:");
|
|
@@ -183,6 +195,7 @@ export function pnpmWorkspaceYamlWithCatalogDependencies(workspaceYaml, dependen
|
|
|
183
195
|
].join("\n");
|
|
184
196
|
}
|
|
185
197
|
export function renderGeneratedPnpmWorkspaceYaml(options) {
|
|
198
|
+
assertGeneratedDependencyCatalogBoundary(options.dependencies);
|
|
186
199
|
const catalog = selectTemplateDependencyCatalogEntries(options.dependencies);
|
|
187
200
|
const packages = options.packages ?? ["."];
|
|
188
201
|
const lines = [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CheckEnvironmentNeed } from "./module-graph.js";
|
|
1
|
+
import { type CheckEnvironmentNeed, type DeploymentCheckEnvironmentNeed } from "./module-graph.js";
|
|
2
2
|
import type { PresetSourceManifest } from "./preset-source.js";
|
|
3
3
|
import { type PresetProjectionSourceRoots } from "./projection-capabilities.js";
|
|
4
4
|
export type GeneratedScenarioSet = "init" | "package-addition-matrix" | "focused";
|
|
@@ -28,7 +28,8 @@ export type GeneratedScenarioCommandStep = {
|
|
|
28
28
|
readonly args: readonly string[];
|
|
29
29
|
readonly cwd: string;
|
|
30
30
|
readonly display: string;
|
|
31
|
-
readonly environmentNeedKind?: CheckEnvironmentNeed["kind"];
|
|
31
|
+
readonly environmentNeedKind?: CheckEnvironmentNeed["kind"] | DeploymentCheckEnvironmentNeed["kind"];
|
|
32
|
+
readonly phase?: "deployment-preparation" | "deployment";
|
|
32
33
|
};
|
|
33
34
|
export type GeneratedScenarioCommandRunner = (command: string, args: readonly string[], cwd: string, options?: {
|
|
34
35
|
readonly env?: Record<string, string> | undefined;
|
|
@@ -5,7 +5,7 @@ import { PackageAdditionSupport } from "@ykdz/template-shared";
|
|
|
5
5
|
import { execa } from "execa";
|
|
6
6
|
import * as v from "valibot";
|
|
7
7
|
import { assembleGenerationContext } from "./generation-context.js";
|
|
8
|
-
import { playwrightBrowserAssetsEnvironmentNeed, } from "./module-graph.js";
|
|
8
|
+
import { deploymentCheckEnvironmentNeeds, playwrightBrowserAssetsEnvironmentNeed, } from "./module-graph.js";
|
|
9
9
|
import { planNextStepInstructions } from "./next-step-instructions.js";
|
|
10
10
|
import { canPlanPackageLinkIntent, } from "./package-linking.js";
|
|
11
11
|
import { findPresetSourceManifestPreset } from "./preset-source.js";
|
|
@@ -14,7 +14,7 @@ const defaultDeterministicToolchainEnv = {
|
|
|
14
14
|
TEMPLATE_TOOLCHAIN_RESOLUTION: "bundled-fallback",
|
|
15
15
|
};
|
|
16
16
|
const defaultFixtureConcurrency = 2;
|
|
17
|
-
const scenarioFingerprintVersion =
|
|
17
|
+
const scenarioFingerprintVersion = 2;
|
|
18
18
|
const storedBlueprintSchema = v.object({
|
|
19
19
|
packages: v.optional(v.array(v.object({
|
|
20
20
|
name: v.string(),
|
|
@@ -235,6 +235,11 @@ async function writeScenarioReplayMarker(cache, fingerprint, scenario) {
|
|
|
235
235
|
await mkdir(cache.directory, { recursive: true });
|
|
236
236
|
await writeFile(path.join(cache.directory, `${fingerprint}.passed`), `${JSON.stringify({ scenario, fingerprint })}\n`, "utf8");
|
|
237
237
|
}
|
|
238
|
+
function deploymentReplayFingerprint(fingerprint) {
|
|
239
|
+
return createHash("sha256")
|
|
240
|
+
.update(`${fingerprint}\0docker-engine-available`)
|
|
241
|
+
.digest("hex");
|
|
242
|
+
}
|
|
238
243
|
export function packageLeafNameForAddedPreset(manifest, presetName) {
|
|
239
244
|
const preset = manifest.presets.find((entry) => entry.name === presetName);
|
|
240
245
|
if (!preset) {
|
|
@@ -392,6 +397,36 @@ function machineVerifiableNextStepsForPreset(presetName, projectDir, manifest, o
|
|
|
392
397
|
};
|
|
393
398
|
});
|
|
394
399
|
}
|
|
400
|
+
function deploymentStepsForPreset(presetName, scenario, projectDir, manifest, options) {
|
|
401
|
+
if (scenario.set === "init") {
|
|
402
|
+
return [];
|
|
403
|
+
}
|
|
404
|
+
const deploymentChecks = projectionPlanForPreset(presetName, projectDir, manifest, options).checkPlan
|
|
405
|
+
.deploymentChecks ?? [];
|
|
406
|
+
const needsDocker = deploymentChecks.some((check) => deploymentCheckEnvironmentNeeds(check).some((need) => need.kind === "docker-engine"));
|
|
407
|
+
if (!needsDocker) {
|
|
408
|
+
return [];
|
|
409
|
+
}
|
|
410
|
+
return [
|
|
411
|
+
{
|
|
412
|
+
id: "check-docker-engine",
|
|
413
|
+
command: "docker",
|
|
414
|
+
args: ["info", "--format", "{{.ServerVersion}}"],
|
|
415
|
+
cwd: projectDir,
|
|
416
|
+
display: "docker info --format {{.ServerVersion}}",
|
|
417
|
+
environmentNeedKind: "docker-engine",
|
|
418
|
+
phase: "deployment-preparation",
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
id: "run-deployment-check",
|
|
422
|
+
command: "pnpm",
|
|
423
|
+
args: ["run", "check:deployment"],
|
|
424
|
+
cwd: projectDir,
|
|
425
|
+
display: "pnpm run check:deployment",
|
|
426
|
+
phase: "deployment",
|
|
427
|
+
},
|
|
428
|
+
];
|
|
429
|
+
}
|
|
395
430
|
function addedPresetEnvironmentNeeds(manifest, scenario, projectDir, addedPackagePath, options) {
|
|
396
431
|
if (!scenario.addedPreset || !addedPackagePath) {
|
|
397
432
|
return [];
|
|
@@ -431,30 +466,37 @@ export function generatedScenarioQualityGateSteps(manifest, scenario, projectDir
|
|
|
431
466
|
const addedEnvironmentSteps = generatedScenarioEnvironmentNeedSteps(addedPresetEnvironmentNeeds(manifest, scenario, projectDir, addedPackagePath, normalizedOptions), projectDir);
|
|
432
467
|
const existingDisplays = new Set(steps.map((step) => step.display));
|
|
433
468
|
const extraEnvironmentSteps = addedEnvironmentSteps.filter((step) => !existingDisplays.has(step.display));
|
|
469
|
+
const deploymentSteps = deploymentStepsForPreset(scenario.basePreset, scenario, projectDir, manifest, normalizedOptions);
|
|
434
470
|
if (extraEnvironmentSteps.length === 0) {
|
|
435
|
-
return steps;
|
|
471
|
+
return [...steps, ...deploymentSteps];
|
|
436
472
|
}
|
|
437
473
|
const rootCheckIndex = steps.findIndex((step) => step.id === "run-root-check");
|
|
438
474
|
if (rootCheckIndex === -1) {
|
|
439
|
-
return [...steps, ...extraEnvironmentSteps];
|
|
475
|
+
return [...steps, ...extraEnvironmentSteps, ...deploymentSteps];
|
|
440
476
|
}
|
|
441
477
|
return [
|
|
442
478
|
...steps.slice(0, rootCheckIndex),
|
|
443
479
|
...extraEnvironmentSteps,
|
|
444
480
|
...steps.slice(rootCheckIndex),
|
|
481
|
+
...deploymentSteps,
|
|
445
482
|
];
|
|
446
483
|
}
|
|
447
484
|
async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, addedPackagePath, options) {
|
|
448
485
|
const steps = generatedScenarioQualityGateSteps(manifest, scenario, projectDir, addedPackagePath, options);
|
|
449
486
|
const requiresSerializedPlaywrightRootCheck = generatedScenarioRequiresSerializedRootCheck(steps);
|
|
450
487
|
let replayFingerprint;
|
|
488
|
+
let baseQualityGateReplayed = false;
|
|
489
|
+
let baseQualityGateMarkerWritten = false;
|
|
451
490
|
for (const step of steps) {
|
|
452
491
|
if (step.id === "install-dependencies") {
|
|
453
492
|
const installResult = await runGeneratedScenarioInstallStep(step, scenario, options);
|
|
454
493
|
replayFingerprint = installResult.fingerprint;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
494
|
+
baseQualityGateReplayed = installResult.baseQualityGateReplayed;
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (baseQualityGateReplayed &&
|
|
498
|
+
step.phase !== "deployment-preparation" &&
|
|
499
|
+
step.phase !== "deployment") {
|
|
458
500
|
continue;
|
|
459
501
|
}
|
|
460
502
|
const env = step.id === "run-root-check" ? { CI: "1" } : undefined;
|
|
@@ -464,13 +506,57 @@ async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, a
|
|
|
464
506
|
logPrefix: scenario.label,
|
|
465
507
|
});
|
|
466
508
|
};
|
|
509
|
+
if (step.environmentNeedKind === "docker-engine") {
|
|
510
|
+
try {
|
|
511
|
+
await runStep();
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
515
|
+
options.reporter.info?.(`-- Skipping deployment check for ${scenario.label}: Docker engine is unavailable (${reason})`);
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (step.phase === "deployment") {
|
|
521
|
+
const deploymentFingerprint = replayFingerprint === undefined
|
|
522
|
+
? undefined
|
|
523
|
+
: deploymentReplayFingerprint(replayFingerprint);
|
|
524
|
+
if (deploymentFingerprint !== undefined &&
|
|
525
|
+
options.replayCache?.read &&
|
|
526
|
+
(await scenarioReplayMarkerExists(options.replayCache, deploymentFingerprint))) {
|
|
527
|
+
options.reporter.info?.(`-- Replayed passed deployment fixture ${scenario.label}: ${deploymentFingerprint}`);
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
await runStep();
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
throw new Error(`Generated deployment command failed for ${scenario.label}; command: ${step.display}. See the cause for the deployment mode, phase, command output, and retained container logs.`, { cause: error });
|
|
535
|
+
}
|
|
536
|
+
if (deploymentFingerprint !== undefined && options.replayCache?.write) {
|
|
537
|
+
await writeScenarioReplayMarker(options.replayCache, deploymentFingerprint, scenario);
|
|
538
|
+
options.reporter.info?.(`-- Stored passed deployment fixture replay marker for ${scenario.label}: ${deploymentFingerprint}`);
|
|
539
|
+
}
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
467
542
|
if (step.id === "run-root-check" && requiresSerializedPlaywrightRootCheck) {
|
|
468
543
|
await options.rootCheckLock.run(runStep);
|
|
469
|
-
continue;
|
|
470
544
|
}
|
|
471
|
-
|
|
545
|
+
else {
|
|
546
|
+
await runStep();
|
|
547
|
+
}
|
|
548
|
+
if (step.id === "run-root-check" &&
|
|
549
|
+
options.replayCache?.write &&
|
|
550
|
+
replayFingerprint !== undefined) {
|
|
551
|
+
await writeScenarioReplayMarker(options.replayCache, replayFingerprint, scenario);
|
|
552
|
+
baseQualityGateMarkerWritten = true;
|
|
553
|
+
options.reporter.info?.(`-- Stored passed fixture replay marker for ${scenario.label}: ${replayFingerprint}`);
|
|
554
|
+
}
|
|
472
555
|
}
|
|
473
|
-
if (options.replayCache?.write &&
|
|
556
|
+
if (options.replayCache?.write &&
|
|
557
|
+
replayFingerprint !== undefined &&
|
|
558
|
+
!baseQualityGateMarkerWritten &&
|
|
559
|
+
!baseQualityGateReplayed) {
|
|
474
560
|
await writeScenarioReplayMarker(options.replayCache, replayFingerprint, scenario);
|
|
475
561
|
options.reporter.info?.(`-- Stored passed fixture replay marker for ${scenario.label}: ${replayFingerprint}`);
|
|
476
562
|
}
|
|
@@ -482,15 +568,15 @@ async function runGeneratedScenarioInstallStep(step, scenario, options) {
|
|
|
482
568
|
replayFingerprint = await hashGeneratedScenarioDirectory(scenario, step.cwd);
|
|
483
569
|
if (options.replayCache.read &&
|
|
484
570
|
(await scenarioReplayMarkerExists(options.replayCache, replayFingerprint))) {
|
|
485
|
-
options.reporter.info?.(`-- Replayed passed
|
|
486
|
-
return { fingerprint: replayFingerprint,
|
|
571
|
+
options.reporter.info?.(`-- Replayed passed base quality gate for ${scenario.label}: ${replayFingerprint}`);
|
|
572
|
+
return { fingerprint: replayFingerprint, baseQualityGateReplayed: true };
|
|
487
573
|
}
|
|
488
574
|
}
|
|
489
575
|
await options.runCommand(step.command, ["fetch"], step.cwd, {
|
|
490
576
|
logPrefix: scenario.label,
|
|
491
577
|
});
|
|
492
578
|
await options.runCommand(step.command, ["install", "--offline", "--frozen-lockfile"], step.cwd, { logPrefix: scenario.label });
|
|
493
|
-
return { fingerprint: replayFingerprint,
|
|
579
|
+
return { fingerprint: replayFingerprint, baseQualityGateReplayed: false };
|
|
494
580
|
}
|
|
495
581
|
async function checkGeneratedScenario(manifest, scenario, workspace, options) {
|
|
496
582
|
options.reporter.info?.(`\n== ${scenario.label} ==`);
|
|
@@ -26,6 +26,13 @@ export type CheckComponent = {
|
|
|
26
26
|
readonly kind: CheckComponentKind;
|
|
27
27
|
readonly owner: ComponentOwner;
|
|
28
28
|
};
|
|
29
|
+
export type DeploymentCheckComponent = {
|
|
30
|
+
readonly kind: "deployment-image";
|
|
31
|
+
readonly owner: PackageBoundaryOwner;
|
|
32
|
+
};
|
|
33
|
+
export type DeploymentCheckEnvironmentNeed = {
|
|
34
|
+
readonly kind: "docker-engine";
|
|
35
|
+
};
|
|
29
36
|
export type FixComponent = {
|
|
30
37
|
readonly kind: FixComponentKind;
|
|
31
38
|
readonly owner: ComponentOwner;
|
|
@@ -33,6 +40,7 @@ export type FixComponent = {
|
|
|
33
40
|
export type CheckPlan = {
|
|
34
41
|
readonly components: CheckComponent[];
|
|
35
42
|
readonly environmentNeeds: CheckEnvironmentNeed[];
|
|
43
|
+
readonly deploymentChecks?: DeploymentCheckComponent[] | undefined;
|
|
36
44
|
};
|
|
37
45
|
export type FixPlan = {
|
|
38
46
|
readonly components: FixComponent[];
|
|
@@ -43,6 +51,10 @@ export declare function fixComponentTaskName(component: FixComponent): string;
|
|
|
43
51
|
export declare function renderCheckLeafCommand(component: CheckComponent): string;
|
|
44
52
|
export declare function renderFixLeafCommand(component: FixComponent): string;
|
|
45
53
|
export declare function renderRootCheckCommand(plan: CheckPlan): string;
|
|
54
|
+
export declare function deploymentCheckEnvironmentNeeds(check: DeploymentCheckComponent): DeploymentCheckEnvironmentNeed[];
|
|
55
|
+
export declare function deploymentCheckTaskName(check: DeploymentCheckComponent): "check:deployment";
|
|
56
|
+
export declare function renderDeploymentCheckLeafCommand(check: DeploymentCheckComponent): string;
|
|
57
|
+
export declare function renderDeploymentCheckCommand(plan: Pick<CheckPlan, "deploymentChecks">): string;
|
|
46
58
|
export declare function renderFixCommand(plan: FixPlan): string;
|
|
47
59
|
export declare function renderPlaywrightBrowserInstallCommand(need: CheckEnvironmentNeed, options?: {
|
|
48
60
|
readonly withDeps?: boolean;
|
|
@@ -119,6 +119,24 @@ export function renderRootCheckCommand(plan) {
|
|
|
119
119
|
"check:run",
|
|
120
120
|
]));
|
|
121
121
|
}
|
|
122
|
+
export function deploymentCheckEnvironmentNeeds(check) {
|
|
123
|
+
switch (check.kind) {
|
|
124
|
+
case "deployment-image":
|
|
125
|
+
return [{ kind: "docker-engine" }];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function deploymentCheckTaskName(check) {
|
|
129
|
+
switch (check.kind) {
|
|
130
|
+
case "deployment-image":
|
|
131
|
+
return "check:deployment";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export function renderDeploymentCheckLeafCommand(check) {
|
|
135
|
+
return `pnpm --filter './${check.owner.path}' run ${deploymentCheckTaskName(check)}`;
|
|
136
|
+
}
|
|
137
|
+
export function renderDeploymentCheckCommand(plan) {
|
|
138
|
+
return uniqueTaskNames((plan.deploymentChecks ?? []).map(renderDeploymentCheckLeafCommand)).join(" && ");
|
|
139
|
+
}
|
|
122
140
|
export function renderFixCommand(plan) {
|
|
123
141
|
return renderTurboRunCommand(uniqueTaskNames([
|
|
124
142
|
...plan.components.flatMap(fixComponentTaskNames),
|
|
@@ -4,10 +4,12 @@ packages:
|
|
|
4
4
|
nodeLinker: hoisted
|
|
5
5
|
|
|
6
6
|
catalog:
|
|
7
|
+
"@typescript/native": npm:typescript@^7.0.2
|
|
8
|
+
"@typescript/typescript6": ^6.0.2
|
|
7
9
|
"@hono/node-server": ^2.0.6
|
|
8
10
|
"@playwright/test": ^1.61.1
|
|
9
11
|
"@tailwindcss/vite": ^4.3.2
|
|
10
|
-
"@types/node": ^24.
|
|
12
|
+
"@types/node": ^24.13.3
|
|
11
13
|
"@types/web-bluetooth": ^0.0.21
|
|
12
14
|
"@vitejs/plugin-vue": ^6.0.7
|
|
13
15
|
"@vikejs/hono": ^0.2.1
|
|
@@ -17,17 +19,18 @@ catalog:
|
|
|
17
19
|
execa: ^9.6.1
|
|
18
20
|
hono: ^4.12.27
|
|
19
21
|
oxfmt: ^0.58.0
|
|
20
|
-
oxlint: ^1.
|
|
22
|
+
oxlint: ^1.73.0
|
|
21
23
|
oxlint-tsgolint: ^0.24.0
|
|
22
24
|
pinia: ^3.0.4
|
|
25
|
+
srvx: ^0.11.21
|
|
23
26
|
tailwindcss: ^4.3.2
|
|
24
27
|
telefunc: ^0.2.22
|
|
25
28
|
tsc-alias: ^1.8.17
|
|
26
|
-
tsx: ^4.
|
|
29
|
+
tsx: ^4.23.0
|
|
27
30
|
turbo: 2.10.2
|
|
28
31
|
typescript: ^6.0.3
|
|
29
32
|
valibot: ^1.4.2
|
|
30
|
-
vite: ^8.1.
|
|
33
|
+
vite: ^8.1.4
|
|
31
34
|
vike: ^0.4.260
|
|
32
35
|
vike-vue: ^0.9.12
|
|
33
36
|
vitest: ^4.1.10
|
|
@@ -17,6 +17,7 @@ export type DependabotDirectory = `/${string}`;
|
|
|
17
17
|
export type DependencyMaintenancePolicy = {
|
|
18
18
|
readonly ecosystems: DependencyEcosystem[];
|
|
19
19
|
readonly directories?: Partial<Record<DependencyEcosystem, DependabotDirectory>>;
|
|
20
|
+
readonly extraDirectories?: Partial<Record<DependencyEcosystem, readonly DependabotDirectory[]>>;
|
|
20
21
|
readonly interval: "weekly";
|
|
21
22
|
};
|
|
22
23
|
type ProjectCheckWorkflowOptions = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderPlaywrightBrowserInstallCommand, } from "./module-graph.js";
|
|
1
|
+
import { deploymentCheckEnvironmentNeeds, deploymentCheckTaskName, renderPlaywrightBrowserInstallCommand, } from "./module-graph.js";
|
|
2
2
|
const defaultCiCapability = {
|
|
3
3
|
workflowName: "Check",
|
|
4
4
|
jobName: "check",
|
|
@@ -16,6 +16,8 @@ export function projectCheckWorkflow(options) {
|
|
|
16
16
|
...options.environmentPreparation,
|
|
17
17
|
};
|
|
18
18
|
const taskLayer = options.taskLayer ?? pnpmTaskLayer;
|
|
19
|
+
const deploymentChecks = options.checkPlan.deploymentChecks ?? [];
|
|
20
|
+
const needsDocker = deploymentChecks.some((check) => deploymentCheckEnvironmentNeeds(check).some((need) => need.kind === "docker-engine"));
|
|
19
21
|
const lines = [
|
|
20
22
|
`name: ${capability.workflowName}`,
|
|
21
23
|
"",
|
|
@@ -34,12 +36,20 @@ export function projectCheckWorkflow(options) {
|
|
|
34
36
|
if (environmentPreparation.nodeFromPackageMetadata) {
|
|
35
37
|
lines.push(" - uses: actions/setup-node@v6", " with:", " node-version-file: package.json", " - run: corepack enable");
|
|
36
38
|
}
|
|
39
|
+
if (needsDocker) {
|
|
40
|
+
lines.push(" - uses: docker/setup-buildx-action@v3");
|
|
41
|
+
}
|
|
37
42
|
if (environmentPreparation.rustToolchain) {
|
|
38
43
|
lines.push(" - uses: dtolnay/rust-toolchain@stable", " with:", " components: rustfmt, clippy", " - uses: Swatinem/rust-cache@v2");
|
|
39
44
|
}
|
|
40
45
|
lines.push(` - run: ${taskLayer.installCommand}`);
|
|
41
46
|
lines.push(...options.checkPlan.environmentNeeds.map((need) => ` - run: ${renderCiEnvironmentNeedCommand(need)}`));
|
|
42
|
-
lines.push(` - run: ${taskLayer.checkCommand}
|
|
47
|
+
lines.push(` - run: ${taskLayer.checkCommand}`);
|
|
48
|
+
const deploymentCheck = deploymentChecks[0];
|
|
49
|
+
if (deploymentCheck !== undefined) {
|
|
50
|
+
lines.push(` - run: pnpm run ${deploymentCheckTaskName(deploymentCheck)}`);
|
|
51
|
+
}
|
|
52
|
+
lines.push("");
|
|
43
53
|
return lines.join("\n");
|
|
44
54
|
}
|
|
45
55
|
export function projectDependabotConfig(policy) {
|
|
@@ -47,8 +57,11 @@ export function projectDependabotConfig(policy) {
|
|
|
47
57
|
"version: 2",
|
|
48
58
|
"",
|
|
49
59
|
"updates:",
|
|
50
|
-
...policy.ecosystems.flatMap((ecosystem) =>
|
|
51
|
-
|
|
60
|
+
...policy.ecosystems.flatMap((ecosystem) => [
|
|
61
|
+
policy.directories?.[ecosystem] ??
|
|
62
|
+
defaultDependabotDirectory(ecosystem),
|
|
63
|
+
...(policy.extraDirectories?.[ecosystem] ?? []),
|
|
64
|
+
].flatMap((directory) => renderDependabotUpdate(ecosystem, directory, policy.interval))),
|
|
52
65
|
"",
|
|
53
66
|
].join("\n");
|
|
54
67
|
}
|
|
@@ -62,7 +75,7 @@ function renderDependabotUpdate(ecosystem, directory, interval) {
|
|
|
62
75
|
if (ecosystem === "npm") {
|
|
63
76
|
lines.push(" groups:", " drizzle:", " patterns:", ' - "drizzle-*"', ' - "drizzle-orm"', " ignore:", ' - dependency-name: "@types/node"', " update-types:", " - version-update:semver-major");
|
|
64
77
|
}
|
|
65
|
-
if (ecosystem === "docker") {
|
|
78
|
+
if (ecosystem === "docker" && directory === "/.devcontainer") {
|
|
66
79
|
lines.push(" ignore:", " - dependency-name: mcr.microsoft.com/devcontainers/typescript-node", " update-types:", " - version-update:semver-major");
|
|
67
80
|
}
|
|
68
81
|
return lines;
|
|
@@ -4,7 +4,7 @@ import { normalizePresetProjectionDeclaration, projectionCapabilityIssues, valid
|
|
|
4
4
|
import { collectGeneratedManifestCatalogDependencies, collectGeneratedManifestCatalogReferences, renderCargoLockForPackage, renderGeneratedPnpmWorkspaceYaml, renderCargoDependencyTomlEntries, } from "./dependency-catalog.js";
|
|
5
5
|
import { browserTestToolLayer, checkedDockerfileFirstNodePnpmDevcontainer, dockerfileFirstRustPnpmDevcontainer, nodePnpmToolLayer, rustToolLayer, } from "./devcontainer.js";
|
|
6
6
|
import { editorCustomizationForCapabilities, loadEditorCustomizationDeclarations, } from "./editor-customization.js";
|
|
7
|
-
import { playwrightBrowserAssetsEnvironmentNeed, renderCheckLeafCommand, renderFixCommand, renderFixLeafCommand, renderRootCheckCommand, renderTurboRunCommand, } from "./module-graph.js";
|
|
7
|
+
import { playwrightBrowserAssetsEnvironmentNeed, renderDeploymentCheckCommand, renderCheckLeafCommand, renderFixCommand, renderFixLeafCommand, renderRootCheckCommand, renderTurboRunCommand, } from "./module-graph.js";
|
|
8
8
|
import { packageManifestExposureFields, packageTurboConfig, planPackageLinks, } from "./package-linking.js";
|
|
9
9
|
export { normalizePresetProjectionDeclaration, projectionCapabilityIssues, validateProjectionCapabilities, };
|
|
10
10
|
const strictTypescriptRootBoundary = {
|
|
@@ -77,6 +77,13 @@ const capabilityInterpreters = {
|
|
|
77
77
|
state.nodeWorkspace = capability;
|
|
78
78
|
state.sourceRoot = templateSourceRootForPreset(state, sourceRootPreset(capability));
|
|
79
79
|
state.operationFactories.push(workspaceNodePackagesOperations);
|
|
80
|
+
if (hasVikePackage(capability)) {
|
|
81
|
+
state.dependencyMaintenanceExtraDirectories.docker = ["/apps/web"];
|
|
82
|
+
state.deploymentCheckComponents.push({
|
|
83
|
+
kind: "deployment-image",
|
|
84
|
+
owner: { kind: "package-boundary", path: "apps/web" },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
80
87
|
if (capability.packages.length > 1) {
|
|
81
88
|
state.rootScriptFragments.dev = "turbo run dev --parallel";
|
|
82
89
|
}
|
|
@@ -277,6 +284,9 @@ export function interpretPresetProjectionDeclaration(options) {
|
|
|
277
284
|
const checkPlan = {
|
|
278
285
|
components: state.rootCheckComponents,
|
|
279
286
|
environmentNeeds: state.rootCheckEnvironmentNeeds,
|
|
287
|
+
...(state.deploymentCheckComponents.length === 0
|
|
288
|
+
? {}
|
|
289
|
+
: { deploymentChecks: state.deploymentCheckComponents }),
|
|
280
290
|
};
|
|
281
291
|
const fixPlan = {
|
|
282
292
|
components: state.rootFixComponents,
|
|
@@ -285,6 +295,7 @@ export function interpretPresetProjectionDeclaration(options) {
|
|
|
285
295
|
const packageScriptsByPath = packageScriptsByWorkspacePath(state);
|
|
286
296
|
const dependencyMaintenancePolicy = {
|
|
287
297
|
ecosystems: uniqueValues(state.dependencyMaintenanceEcosystems),
|
|
298
|
+
extraDirectories: state.dependencyMaintenanceExtraDirectories,
|
|
288
299
|
...(state.rustWorkspace === undefined
|
|
289
300
|
? {}
|
|
290
301
|
: {
|
|
@@ -383,6 +394,7 @@ function createProjectionCompositionState(sourceRoots) {
|
|
|
383
394
|
sourceRoots: {},
|
|
384
395
|
rootCheckComponents: [],
|
|
385
396
|
rootCheckEnvironmentNeeds: [],
|
|
397
|
+
deploymentCheckComponents: [],
|
|
386
398
|
packageCheckComponents: [],
|
|
387
399
|
rootFixComponents: [],
|
|
388
400
|
packageFixComponents: [],
|
|
@@ -392,6 +404,7 @@ function createProjectionCompositionState(sourceRoots) {
|
|
|
392
404
|
packageDependencies: new Set(),
|
|
393
405
|
packageDevDependencies: new Set(),
|
|
394
406
|
dependencyMaintenanceEcosystems: [],
|
|
407
|
+
dependencyMaintenanceExtraDirectories: {},
|
|
395
408
|
editorCustomizationCapabilities: [],
|
|
396
409
|
operationFactories: [],
|
|
397
410
|
flags: {},
|
|
@@ -752,6 +765,9 @@ function projectRootPackageScripts(checkPlan, fixPlan, fragments) {
|
|
|
752
765
|
const directFragments = directScriptFragments(fragments);
|
|
753
766
|
return {
|
|
754
767
|
check: `pnpm run check:boundaries && ${renderRootCheckCommand(checkPlan)}`,
|
|
768
|
+
...(checkPlan.deploymentChecks === undefined
|
|
769
|
+
? {}
|
|
770
|
+
: { "check:deployment": renderDeploymentCheckCommand(checkPlan) }),
|
|
755
771
|
fix: renderFixCommand(fixPlan),
|
|
756
772
|
...rootTaskEntrypoints(checkPlan, fixPlan),
|
|
757
773
|
...directFragments,
|
|
@@ -1057,7 +1073,9 @@ function vikePackageJson(context, packageName, scripts, packageLinkDependencies
|
|
|
1057
1073
|
dependencies: {
|
|
1058
1074
|
...packageLinkDependencies,
|
|
1059
1075
|
"@vikejs/hono": "catalog:",
|
|
1076
|
+
"drizzle-orm": "catalog:",
|
|
1060
1077
|
hono: "catalog:",
|
|
1078
|
+
srvx: "catalog:",
|
|
1061
1079
|
telefunc: "catalog:",
|
|
1062
1080
|
vike: "catalog:",
|
|
1063
1081
|
"vike-vue": "catalog:",
|
|
@@ -1110,6 +1128,10 @@ function vikeDbPackageJson(context) {
|
|
|
1110
1128
|
default: "./src/queries/todos.ts",
|
|
1111
1129
|
types: "./src/queries/todos.ts",
|
|
1112
1130
|
},
|
|
1131
|
+
"./readiness": {
|
|
1132
|
+
default: "./src/readiness.ts",
|
|
1133
|
+
types: "./src/readiness.ts",
|
|
1134
|
+
},
|
|
1113
1135
|
},
|
|
1114
1136
|
dependencies: {
|
|
1115
1137
|
"drizzle-orm": "catalog:",
|
|
@@ -1132,15 +1154,19 @@ function vikeDbPackageJson(context) {
|
|
|
1132
1154
|
function vikeDbPackageScripts() {
|
|
1133
1155
|
return {
|
|
1134
1156
|
"build:run": "tsc -p tsconfig.json --noEmit",
|
|
1157
|
+
"db:generate": "drizzle-kit generate",
|
|
1158
|
+
"db:migrate": "drizzle-kit migrate",
|
|
1159
|
+
"db:prepare:deploy": "pnpm run db:migrate",
|
|
1160
|
+
"db:prepare:dev": "pnpm run db:push && pnpm run db:seed:example",
|
|
1161
|
+
"db:prepare:test": 'rm -f "${DATABASE_FILE:-./node_modules/.tmp/test.sqlite}" && pnpm run db:push && pnpm run db:seed:example',
|
|
1135
1162
|
"db:push": "mkdir -p data node_modules/.tmp && drizzle-kit push",
|
|
1136
|
-
"
|
|
1137
|
-
"
|
|
1138
|
-
"drizzle:studio": "drizzle-kit studio",
|
|
1163
|
+
"db:seed:example": "node --experimental-strip-types scripts/seed-example.ts",
|
|
1164
|
+
"db:studio": "drizzle-kit studio",
|
|
1139
1165
|
"format:check:run": "oxfmt --list-different --config ../../oxfmt.config.ts .",
|
|
1140
1166
|
"format:write:run": "oxfmt --write --config ../../oxfmt.config.ts .",
|
|
1141
1167
|
"lint:run": "oxlint --quiet --format=unix --config ../../oxlint.config.ts .",
|
|
1142
1168
|
"lint:fix:run": "oxlint --format=unix --config ../../oxlint.config.ts . --fix",
|
|
1143
|
-
"test:run": "DATABASE_FILE=./node_modules/.tmp/test.sqlite pnpm run db:
|
|
1169
|
+
"test:run": "DATABASE_FILE=./node_modules/.tmp/test.sqlite pnpm run db:prepare:test && DATABASE_FILE=./node_modules/.tmp/test.sqlite vitest run --reporter=agent --silent=passed-only; status=$?; rm -f ./node_modules/.tmp/test.sqlite; exit $status",
|
|
1144
1170
|
"typecheck:run": "tsc -p tsconfig.json --noEmit --pretty false",
|
|
1145
1171
|
};
|
|
1146
1172
|
}
|
|
@@ -1565,9 +1591,10 @@ function nodePackageScripts(nodePackage, workspace) {
|
|
|
1565
1591
|
};
|
|
1566
1592
|
}
|
|
1567
1593
|
if (nodePackage.kind === "vike-app") {
|
|
1568
|
-
const dbCommand = "DATABASE_FILE=../../apps/web/data/app.sqlite pnpm --dir ../../packages/db run db:
|
|
1594
|
+
const dbCommand = "DATABASE_FILE=../../apps/web/data/app.sqlite pnpm --dir ../../packages/db run db:prepare:dev";
|
|
1569
1595
|
return {
|
|
1570
1596
|
"build:run": "vike build",
|
|
1597
|
+
"check:deployment": "node --experimental-strip-types scripts/check-standalone-deployment.ts",
|
|
1571
1598
|
dev: `${dbCommand} && vike dev`,
|
|
1572
1599
|
"format:check:run": "oxfmt --list-different --config ../../oxfmt.config.ts .",
|
|
1573
1600
|
"format:write:run": "oxfmt --write --config ../../oxfmt.config.ts .",
|
|
@@ -1836,6 +1863,21 @@ function vikeTemplateSourceOperation(options) {
|
|
|
1836
1863
|
from: options.sourceFile,
|
|
1837
1864
|
to,
|
|
1838
1865
|
};
|
|
1866
|
+
if (options.nodePackage.kind === "vike-app" &&
|
|
1867
|
+
options.sourceFile === "web/Dockerfile") {
|
|
1868
|
+
return [
|
|
1869
|
+
{
|
|
1870
|
+
kind: "writeTextTemplate",
|
|
1871
|
+
from: options.sourceFile,
|
|
1872
|
+
to,
|
|
1873
|
+
replacements: {
|
|
1874
|
+
NODE_VERSION: options.context.toolchain.nodeLtsMajor.value,
|
|
1875
|
+
PACKAGE_MANAGER_PIN: options.context.toolchain.packageManagerPin.value,
|
|
1876
|
+
WEB_PACKAGE_NAME: nodePackageName(options.context, options.nodePackage),
|
|
1877
|
+
},
|
|
1878
|
+
},
|
|
1879
|
+
];
|
|
1880
|
+
}
|
|
1839
1881
|
if (options.nodePackage.kind === "vike-app" &&
|
|
1840
1882
|
[
|
|
1841
1883
|
"web/pages/index/+Page.telefunc.ts",
|
|
@@ -1845,7 +1887,10 @@ function vikeTemplateSourceOperation(options) {
|
|
|
1845
1887
|
const dbPackageName = vikeDbPackageName(options.context);
|
|
1846
1888
|
const replacements = {
|
|
1847
1889
|
"web/pages/index/+Page.telefunc.ts": `import { createTodo, listTodos } from "${dbPackageName}/queries/todos";`,
|
|
1848
|
-
"web/server/app.ts":
|
|
1890
|
+
"web/server/app.ts": [
|
|
1891
|
+
`import { createDatabase } from "${dbPackageName}";`,
|
|
1892
|
+
`import { assertDatabaseReady } from "${dbPackageName}/readiness";`,
|
|
1893
|
+
].join("\n"),
|
|
1849
1894
|
"web/types/global.d.ts": `import type { Database } from "${dbPackageName}";`,
|
|
1850
1895
|
};
|
|
1851
1896
|
return [
|
|
@@ -1865,9 +1910,14 @@ function vikeTemplateSourceOperation(options) {
|
|
|
1865
1910
|
const vikeDbSourceFiles = [
|
|
1866
1911
|
"db/turbo.json",
|
|
1867
1912
|
"db/drizzle.config.ts",
|
|
1913
|
+
"db/drizzle/migrations/20260709120325_old_captain_flint/migration.sql",
|
|
1914
|
+
"db/drizzle/migrations/20260709120325_old_captain_flint/snapshot.json",
|
|
1915
|
+
"db/scripts/seed-example.ts",
|
|
1868
1916
|
"db/src/db.ts",
|
|
1869
1917
|
"db/src/index.ts",
|
|
1870
1918
|
"db/src/queries/todos.ts",
|
|
1919
|
+
"db/src/readiness.ts",
|
|
1920
|
+
"db/src/seed/example.ts",
|
|
1871
1921
|
"db/src/schema.ts",
|
|
1872
1922
|
"db/test/todos.test.ts",
|
|
1873
1923
|
];
|
|
@@ -216,6 +216,9 @@ function assertTextTemplatePath(relativePath) {
|
|
|
216
216
|
if (/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+\/(?:playwright|vite|vitest|oxfmt|oxlint)\.config\.ts$/.test(normalizedPath)) {
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
|
+
if (/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+\/Dockerfile$/.test(normalizedPath)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
219
222
|
assertFoundationTextPath(relativePath);
|
|
220
223
|
}
|
|
221
224
|
async function renderWriteText(operation, options) {
|
|
@@ -293,7 +296,7 @@ function parseAnchorComment(commentText) {
|
|
|
293
296
|
return multiline?.[1];
|
|
294
297
|
}
|
|
295
298
|
async function findTypeScriptAnchorRanges(sourceText) {
|
|
296
|
-
const ts = await import("typescript");
|
|
299
|
+
const ts = await import("@typescript/typescript6");
|
|
297
300
|
const sourceFile = ts.createSourceFile("template-anchor.ts", sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
298
301
|
const anchors = [];
|
|
299
302
|
const seenRanges = new Set();
|
|
@@ -25,12 +25,13 @@
|
|
|
25
25
|
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@typescript/typescript6": "catalog:",
|
|
28
29
|
"@ykdz/template-shared": "workspace:*",
|
|
29
|
-
"typescript": "catalog:",
|
|
30
30
|
"valibot": "catalog:"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "catalog:",
|
|
34
|
+
"@typescript/native": "catalog:",
|
|
34
35
|
"execa": "catalog:",
|
|
35
36
|
"oxfmt": "catalog:",
|
|
36
37
|
"oxlint": "catalog:",
|