@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.
Files changed (40) hide show
  1. package/node_modules/@ykdz/template-builtin-source/package.json +1 -1
  2. package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +11 -0
  3. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/dependabot.yml +4 -0
  4. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/workflows/check.yml +2 -0
  5. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/drizzle/migrations/20260709120325_old_captain_flint/migration.sql +6 -0
  6. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/drizzle/migrations/20260709120325_old_captain_flint/snapshot.json +67 -0
  7. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/scripts/seed-example.ts +7 -0
  8. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/db.ts +2 -1
  9. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/index.ts +1 -0
  10. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/queries/todos.ts +17 -1
  11. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/readiness.ts +22 -0
  12. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/schema.ts +1 -1
  13. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/seed/example.ts +23 -0
  14. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/test/todos.test.ts +2 -0
  15. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/+server.ts +2 -1
  16. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/Dockerfile +83 -0
  17. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/Dockerfile.dockerignore +14 -0
  18. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/pages/index/+Page.telefunc.ts +1 -2
  19. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/pages/index/+Page.vue +6 -2
  20. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/playwright.config.ts +50 -14
  21. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/check-standalone-deployment.ts +449 -0
  22. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/container-entrypoint.sh +52 -0
  23. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/prepare-database.sh +6 -0
  24. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/run-playwright.ts +101 -12
  25. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/server/app.ts +23 -12
  26. package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +13 -0
  27. package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +3 -2
  28. package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +99 -13
  29. package/node_modules/@ykdz/template-core/dist/module-graph.d.ts +12 -0
  30. package/node_modules/@ykdz/template-core/dist/module-graph.js +18 -0
  31. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +7 -4
  32. package/node_modules/@ykdz/template-core/dist/project-github.d.ts +1 -0
  33. package/node_modules/@ykdz/template-core/dist/project-github.js +18 -5
  34. package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +57 -7
  35. package/node_modules/@ykdz/template-core/dist/renderer.js +4 -1
  36. package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +1 -1
  37. package/node_modules/@ykdz/template-core/package.json +2 -1
  38. package/node_modules/@ykdz/template-shared/dist/index.d.ts +6 -6
  39. package/node_modules/@ykdz/template-shared/package.json +1 -0
  40. package/package.json +5 -4
@@ -65,7 +65,6 @@
65
65
  "dependencies": {
66
66
  "@ykdz/template-core": "workspace:*",
67
67
  "@ykdz/template-shared": "workspace:*",
68
- "typescript": "catalog:",
69
68
  "valibot": "catalog:"
70
69
  },
71
70
  "devDependencies": {
@@ -73,6 +72,7 @@
73
72
  "@playwright/test": "catalog:",
74
73
  "@tailwindcss/vite": "catalog:",
75
74
  "@types/node": "catalog:",
75
+ "@typescript/native": "catalog:",
76
76
  "@vikejs/hono": "catalog:",
77
77
  "@vitejs/plugin-vue": "catalog:",
78
78
  "drizzle-kit": "catalog:",
@@ -223,6 +223,7 @@
223
223
  "oxfmt",
224
224
  "oxlint",
225
225
  "oxlint-tsgolint",
226
+ "srvx",
226
227
  "tailwindcss",
227
228
  "telefunc",
228
229
  "typescript",
@@ -251,6 +252,8 @@
251
252
  "sourceFiles": [
252
253
  "web/+server.ts",
253
254
  "web/.env.example",
255
+ "web/Dockerfile",
256
+ "web/Dockerfile.dockerignore",
254
257
  "web/assets/logo.svg",
255
258
  "web/components/CounterButton.vue",
256
259
  "web/components/PageShell.vue",
@@ -261,6 +264,9 @@
261
264
  "web/pages/index/+Page.telefunc.ts",
262
265
  "web/pages/tailwind.css",
263
266
  "web/playwright.config.ts",
267
+ "web/scripts/check-standalone-deployment.ts",
268
+ "web/scripts/container-entrypoint.sh",
269
+ "web/scripts/prepare-database.sh",
264
270
  "web/scripts/run-playwright.ts",
265
271
  "web/turbo.json",
266
272
  "web/server/api.ts",
@@ -306,7 +312,12 @@
306
312
  "vike-app/db/turbo.json",
307
313
  "vike-app/web/+server.ts",
308
314
  "vike-app/web/.env.example",
315
+ "vike-app/web/Dockerfile",
316
+ "vike-app/web/Dockerfile.dockerignore",
309
317
  "vike-app/web/playwright.config.ts",
318
+ "vike-app/web/scripts/check-standalone-deployment.ts",
319
+ "vike-app/web/scripts/container-entrypoint.sh",
320
+ "vike-app/web/scripts/prepare-database.sh",
310
321
  "vike-app/web/vite.config.ts",
311
322
  "vike-app/web/turbo.json",
312
323
  "vike-app/web/vitest.config.ts"
@@ -26,3 +26,7 @@ updates:
26
26
  - dependency-name: mcr.microsoft.com/devcontainers/typescript-node
27
27
  update-types:
28
28
  - version-update:semver-major
29
+ - package-ecosystem: docker
30
+ directory: /apps/web
31
+ schedule:
32
+ interval: weekly
@@ -15,6 +15,8 @@ jobs:
15
15
  with:
16
16
  node-version-file: package.json
17
17
  - run: corepack enable
18
+ - uses: docker/setup-buildx-action@v3
18
19
  - run: pnpm install
19
20
  - run: pnpm --filter ./apps/web exec playwright install --with-deps chromium
20
21
  - run: pnpm run check
22
+ - run: pnpm run check:deployment
@@ -0,0 +1,6 @@
1
+ CREATE TABLE `todos` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT,
3
+ `title` text NOT NULL UNIQUE,
4
+ `completed` integer DEFAULT false NOT NULL,
5
+ `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
6
+ );
@@ -0,0 +1,67 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "sqlite",
4
+ "id": "0a8f7496-a1ed-412a-a634-7989609bcbe0",
5
+ "prevIds": ["00000000-0000-0000-0000-000000000000"],
6
+ "ddl": [
7
+ {
8
+ "name": "todos",
9
+ "entityType": "tables"
10
+ },
11
+ {
12
+ "type": "integer",
13
+ "notNull": false,
14
+ "autoincrement": true,
15
+ "default": null,
16
+ "generated": null,
17
+ "name": "id",
18
+ "entityType": "columns",
19
+ "table": "todos"
20
+ },
21
+ {
22
+ "type": "text",
23
+ "notNull": true,
24
+ "autoincrement": false,
25
+ "default": null,
26
+ "generated": null,
27
+ "name": "title",
28
+ "entityType": "columns",
29
+ "table": "todos"
30
+ },
31
+ {
32
+ "type": "integer",
33
+ "notNull": true,
34
+ "autoincrement": false,
35
+ "default": "false",
36
+ "generated": null,
37
+ "name": "completed",
38
+ "entityType": "columns",
39
+ "table": "todos"
40
+ },
41
+ {
42
+ "type": "text",
43
+ "notNull": true,
44
+ "autoincrement": false,
45
+ "default": "(CURRENT_TIMESTAMP)",
46
+ "generated": null,
47
+ "name": "created_at",
48
+ "entityType": "columns",
49
+ "table": "todos"
50
+ },
51
+ {
52
+ "columns": ["id"],
53
+ "nameExplicit": false,
54
+ "name": "todos_pk",
55
+ "table": "todos",
56
+ "entityType": "pks"
57
+ },
58
+ {
59
+ "columns": ["title"],
60
+ "nameExplicit": false,
61
+ "name": "todos_title_unique",
62
+ "entityType": "uniques",
63
+ "table": "todos"
64
+ }
65
+ ],
66
+ "renames": []
67
+ }
@@ -0,0 +1,7 @@
1
+ import { createDatabase } from "#db/db";
2
+ import { assertDatabaseReady } from "#db/readiness";
3
+ import { seedExampleData } from "#db/seed/example";
4
+
5
+ const db = createDatabase();
6
+ assertDatabaseReady(db);
7
+ await seedExampleData(db);
@@ -7,11 +7,12 @@ import { defineRelations } from "drizzle-orm/relations";
7
7
  import * as schema from "#db/schema";
8
8
 
9
9
  const relations = defineRelations(schema);
10
+ const defaultDatabaseFile = "./data/app.sqlite";
10
11
 
11
12
  export type Database = ReturnType<typeof createDatabase>;
12
13
 
13
14
  export function createDatabase(databaseFile = process.env.DATABASE_FILE) {
14
- const file = databaseFile ?? "./data/app.sqlite";
15
+ const file = databaseFile ?? defaultDatabaseFile;
15
16
  mkdirSync(path.dirname(file), { recursive: true });
16
17
  return drizzle(file, { relations });
17
18
  }
@@ -1 +1,2 @@
1
1
  export { createDatabase, type Database } from "#db/db";
2
+ export { assertDatabaseReady } from "#db/readiness";
@@ -3,8 +3,20 @@ import { desc, eq } from "drizzle-orm";
3
3
  import type { Database } from "#db/db";
4
4
  import { todos, type NewTodo } from "#db/schema";
5
5
 
6
+ const listTodosStatements = new WeakMap<
7
+ Database,
8
+ ReturnType<typeof prepareListTodos>
9
+ >();
10
+
6
11
  export async function listTodos(db: Database) {
7
- return db.select().from(todos).orderBy(desc(todos.createdAt));
12
+ let statement = listTodosStatements.get(db);
13
+
14
+ if (!statement) {
15
+ statement = prepareListTodos(db);
16
+ listTodosStatements.set(db, statement);
17
+ }
18
+
19
+ return statement.all();
8
20
  }
9
21
 
10
22
  export async function createTodo(db: Database, values: NewTodo) {
@@ -26,3 +38,7 @@ export async function completeTodo(db: Database, id: number) {
26
38
 
27
39
  return todo;
28
40
  }
41
+
42
+ function prepareListTodos(db: Database) {
43
+ return db.select().from(todos).orderBy(desc(todos.createdAt)).prepare();
44
+ }
@@ -0,0 +1,22 @@
1
+ import { sql } from "drizzle-orm";
2
+
3
+ import type { Database } from "#db/db";
4
+ import { todos } from "#db/schema";
5
+
6
+ export function assertDatabaseReady(db: Database) {
7
+ try {
8
+ db.select({ ready: sql`1` })
9
+ .from(todos)
10
+ .limit(1)
11
+ .all();
12
+ } catch (cause) {
13
+ throw new Error(
14
+ [
15
+ "Database is not ready.",
16
+ "For local development, run `pnpm --dir packages/db run db:prepare:dev`.",
17
+ "For deployment, run `pnpm --dir packages/db run db:prepare:deploy` before starting the app.",
18
+ ].join(" "),
19
+ { cause },
20
+ );
21
+ }
22
+ }
@@ -3,7 +3,7 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
3
3
 
4
4
  export const todos = sqliteTable("todos", {
5
5
  id: integer({ mode: "number" }).primaryKey({ autoIncrement: true }),
6
- title: text().notNull(),
6
+ title: text().notNull().unique(),
7
7
  completed: integer({ mode: "boolean" }).default(false).notNull(),
8
8
  createdAt: text("created_at")
9
9
  .default(sql`(CURRENT_TIMESTAMP)`)
@@ -0,0 +1,23 @@
1
+ import { eq } from "drizzle-orm";
2
+
3
+ import type { Database } from "#db/db";
4
+ import { todos } from "#db/schema";
5
+
6
+ const exampleTodos = [
7
+ "Read the generated TODO.md",
8
+ "Try the Telefunc todo flow",
9
+ ] as const;
10
+
11
+ export async function seedExampleData(db: Database) {
12
+ for (const title of exampleTodos) {
13
+ const existing = await db
14
+ .select({ id: todos.id })
15
+ .from(todos)
16
+ .where(eq(todos.title, title))
17
+ .limit(1);
18
+
19
+ if (existing.length === 0) {
20
+ await db.insert(todos).values({ title });
21
+ }
22
+ }
23
+ }
@@ -2,10 +2,12 @@ import { describe, expect, it } from "vitest";
2
2
 
3
3
  import { createDatabase } from "#db/db";
4
4
  import { createTodo, listTodos } from "#db/queries/todos";
5
+ import { assertDatabaseReady } from "#db/readiness";
5
6
 
6
7
  describe("todo queries", () => {
7
8
  it("creates and lists todos through Drizzle SQLite", async () => {
8
9
  const db = createDatabase();
10
+ assertDatabaseReady(db);
9
11
  const title = `发布模板 ${Date.now()}`;
10
12
 
11
13
  await expect(createTodo(db, { title })).resolves.toMatchObject({
@@ -1,8 +1,9 @@
1
1
  import type { Server } from "vike/types";
2
2
 
3
- import { app } from "#/server/app";
3
+ import { createApp } from "#/server/app";
4
4
 
5
5
  const port = Number.parseInt(process.env.PORT ?? "3000", 10);
6
+ const app = createApp();
6
7
 
7
8
  export default {
8
9
  fetch: app.fetch,
@@ -0,0 +1,83 @@
1
+ # syntax=docker/dockerfile:1.7
2
+
3
+ ARG DEPLOYMENT_BUILD_ID="local"
4
+
5
+ FROM node:{{NODE_VERSION}}-bookworm-slim AS base
6
+ ARG PACKAGE_MANAGER_PIN="{{PACKAGE_MANAGER_PIN}}"
7
+ ENV COREPACK_HOME="/corepack"
8
+ ENV PNPM_HOME="/pnpm"
9
+ ENV PATH="$PNPM_HOME:$PATH"
10
+ WORKDIR /repo
11
+ RUN corepack enable && corepack prepare "$PACKAGE_MANAGER_PIN" --activate
12
+
13
+ FROM base AS pruner
14
+ COPY pnpm-lock.yaml pnpm-workspace.yaml ./
15
+ RUN pnpm fetch
16
+ COPY package.json turbo.json ./
17
+ COPY apps/web/package.json apps/web/package.json
18
+ COPY packages/db/package.json packages/db/package.json
19
+ RUN pnpm install --offline --frozen-lockfile
20
+ COPY . .
21
+ RUN pnpm exec turbo prune {{WEB_PACKAGE_NAME}} --docker
22
+
23
+ FROM base AS build
24
+ COPY --from=pruner /repo/out/json/pnpm-lock.yaml ./pnpm-lock.yaml
25
+ COPY --from=pruner /repo/out/json/pnpm-workspace.yaml ./pnpm-workspace.yaml
26
+ RUN pnpm fetch
27
+ COPY --from=pruner /repo/out/json/ ./
28
+ RUN pnpm install --offline --frozen-lockfile
29
+ COPY --from=pruner /repo/out/full/ ./
30
+ RUN pnpm --filter ./apps/web run build:run
31
+ RUN pnpm --filter ./apps/web deploy --prod --legacy /runtime-deploy \
32
+ && rm -rf /runtime-deploy/node_modules/@*/db \
33
+ && find /runtime-deploy/node_modules/.pnpm -mindepth 1 -maxdepth 1 -type d -name '*@file+packages+db' -exec rm -rf '{}' +
34
+
35
+ FROM node:{{NODE_VERSION}}-bookworm-slim AS application-runtime
36
+ ENV NODE_ENV="production"
37
+ WORKDIR /app
38
+ RUN groupadd --system --gid 1001 nodejs \
39
+ && useradd --system --uid 1001 --gid nodejs --home-dir /app --shell /usr/sbin/nologin app \
40
+ && install -d -o app -g nodejs /app /data
41
+ COPY --from=build --chown=app:nodejs /runtime-deploy/node_modules ./node_modules
42
+ COPY --from=build --chown=app:nodejs /repo/apps/web/dist ./dist
43
+ COPY --chmod=755 --from=build /repo/apps/web/scripts/container-entrypoint.sh /usr/local/bin/container-entrypoint
44
+ ENV DATABASE_FILE="/data/app.sqlite"
45
+ USER app
46
+
47
+ FROM base AS database-preparation
48
+ ENV NODE_ENV="production"
49
+ COPY --from=pruner /repo/out/json/pnpm-lock.yaml ./pnpm-lock.yaml
50
+ COPY --from=pruner /repo/out/json/pnpm-workspace.yaml ./pnpm-workspace.yaml
51
+ RUN pnpm fetch
52
+ COPY --from=pruner /repo/out/json/ ./
53
+ RUN pnpm install --offline --frozen-lockfile --prod=false
54
+ COPY --from=pruner /repo/out/full/ ./
55
+ RUN groupadd --system --gid 1001 nodejs \
56
+ && useradd --system --uid 1001 --gid nodejs --home-dir /app --shell /usr/sbin/nologin app \
57
+ && install -d -o app -g nodejs /app /data
58
+ COPY --chmod=755 --from=pruner /repo/out/full/apps/web/scripts/container-entrypoint.sh /usr/local/bin/container-entrypoint
59
+ COPY --chmod=755 --from=pruner /repo/out/full/apps/web/scripts/prepare-database.sh /usr/local/bin/prepare-database
60
+ ENV DATABASE_FILE="/data/app.sqlite"
61
+ USER app
62
+
63
+ # Final deployment target: standalone
64
+ # One-container deployments prepare the database before startup.
65
+ FROM database-preparation AS standalone
66
+ ARG DEPLOYMENT_BUILD_ID
67
+ LABEL org.opencontainers.image.version="$DEPLOYMENT_BUILD_ID"
68
+ WORKDIR /app
69
+ COPY --from=application-runtime --chown=app:nodejs /app/node_modules ./node_modules
70
+ COPY --from=application-runtime --chown=app:nodejs /app/dist ./dist
71
+ EXPOSE 3000
72
+ ENTRYPOINT ["/usr/local/bin/container-entrypoint"]
73
+ CMD ["prepare-and-start"]
74
+
75
+ # Final deployment target: runtime
76
+ # Start-only image for databases prepared by a matching standalone image.
77
+ FROM application-runtime AS runtime
78
+ ARG DEPLOYMENT_BUILD_ID
79
+ LABEL org.opencontainers.image.version="$DEPLOYMENT_BUILD_ID"
80
+ ENV CONTAINER_CAPABILITY="start-only"
81
+ EXPOSE 3000
82
+ ENTRYPOINT ["/usr/local/bin/container-entrypoint"]
83
+ CMD ["start-only"]
@@ -0,0 +1,14 @@
1
+ .git
2
+ .template
3
+ node_modules
4
+ **/node_modules
5
+ **/.turbo
6
+ **/dist
7
+ **/playwright-report
8
+ **/test-results
9
+ apps/web/data
10
+ apps/web/node_modules/.tmp
11
+ packages/db/data
12
+ packages/db/node_modules/.tmp
13
+ *.sqlite
14
+ *.sqlite-*
@@ -1,6 +1,5 @@
1
- import { getContext } from "telefunc";
2
-
3
1
  // @template-anchor db-package-import
2
+ import { getContext } from "telefunc";
4
3
 
5
4
  export type Todo = Awaited<ReturnType<typeof onLoadTodos>>[number];
6
5
 
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { ref } from "vue";
2
+ import { onMounted, ref } from "vue";
3
3
 
4
4
  import CounterButton from "#/components/CounterButton.vue";
5
5
 
@@ -32,6 +32,10 @@ async function submitTodo() {
32
32
  title.value = "";
33
33
  await refreshTodos();
34
34
  }
35
+
36
+ onMounted(() => {
37
+ void refreshTodos();
38
+ });
35
39
  </script>
36
40
 
37
41
  <template>
@@ -65,7 +69,7 @@ async function submitTodo() {
65
69
  type="button"
66
70
  @click="refreshTodos"
67
71
  >
68
- 加载待办事项
72
+ 刷新待办事项
69
73
  </button>
70
74
 
71
75
  <p
@@ -1,22 +1,53 @@
1
- import { fileURLToPath } from "node:url";
2
-
3
1
  import { defineConfig, devices } from "@playwright/test";
4
2
 
3
+ const externalBaseUrlName = "PLAYWRIGHT_EXTERNAL_BASE_URL";
4
+
5
+ function externalBaseUrl(): string | undefined {
6
+ if (!Object.hasOwn(process.env, externalBaseUrlName)) {
7
+ return undefined;
8
+ }
9
+
10
+ const value = process.env[externalBaseUrlName]?.trim();
11
+ if (!value) {
12
+ throw new Error(`${externalBaseUrlName} must be a non-empty HTTP(S) URL`);
13
+ }
14
+
15
+ let url: URL;
16
+ try {
17
+ url = new URL(value);
18
+ } catch {
19
+ throw new Error(`${externalBaseUrlName} must be a valid HTTP(S) URL`);
20
+ }
21
+
22
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
23
+ throw new Error(`${externalBaseUrlName} must use HTTP or HTTPS`);
24
+ }
25
+
26
+ return url.toString();
27
+ }
28
+
5
29
  function requiredPort(name: string): number {
30
+ return Number(requiredEnv(name));
31
+ }
32
+
33
+ function requiredEnv(name: string): string {
6
34
  const value = process.env[name];
7
35
 
8
36
  if (!value) {
9
37
  throw new Error(`${name} must be set by scripts/run-playwright.ts`);
10
38
  }
11
39
 
12
- return Number(value);
40
+ return value;
13
41
  }
14
42
 
15
- const previewPort = requiredPort("PLAYWRIGHT_WEB_PORT");
16
- const previewUrl = `http://127.0.0.1:${previewPort}`;
17
- const databaseFile = fileURLToPath(
18
- new URL("./node_modules/.tmp/e2e.sqlite", import.meta.url),
19
- );
43
+ const externalServiceUrl = externalBaseUrl();
44
+ const previewPort = externalServiceUrl
45
+ ? undefined
46
+ : requiredPort("PLAYWRIGHT_WEB_PORT");
47
+ const previewUrl = externalServiceUrl ?? `http://127.0.0.1:${previewPort}`;
48
+ const databaseFile = externalServiceUrl
49
+ ? undefined
50
+ : requiredEnv("DATABASE_FILE");
20
51
 
21
52
  function shellValue(value: string): string {
22
53
  return `'${value.replaceAll("'", "'\\''")}'`;
@@ -27,13 +58,18 @@ export default defineConfig({
27
58
  timeout: 60_000,
28
59
  use: {
29
60
  baseURL: previewUrl,
30
- trace: "on-first-retry",
31
- },
32
- webServer: {
33
- command: `DATABASE_FILE=${shellValue(databaseFile)} pnpm --dir ../../packages/db run db:push && DATABASE_FILE=${shellValue(databaseFile)} PORT=${previewPort} node dist/server/index.mjs`,
34
- reuseExistingServer: !process.env.CI,
35
- url: previewUrl,
61
+ trace: "retain-on-failure",
36
62
  },
63
+ ...(externalServiceUrl
64
+ ? {}
65
+ : {
66
+ webServer: {
67
+ command: `DATABASE_FILE=${shellValue(databaseFile!)} pnpm --dir ../../packages/db run db:prepare:test && PORT=${previewPort} node dist/server/index.mjs`,
68
+ reuseExistingServer: !process.env.CI,
69
+ timeout: 60_000,
70
+ url: previewUrl,
71
+ },
72
+ }),
37
73
  projects: [
38
74
  {
39
75
  name: "chromium",