@gadmin2n/schematics 0.0.135 → 0.0.137

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 (95) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.server +2 -2
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/compose-ctl.sh +1 -1
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/canvas.prisma +1 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +14 -3
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/User.ts +4 -4
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.md +2 -2
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.yml +13 -92
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/readme.md +105 -7
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/ensure-database.js +1 -1
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +7 -6
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/prisma.config.ts +9 -1
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/gen-jwt.ts +85 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/notify-dev-servers.js +9 -8
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/wait-for-nest-ready.js +5 -5
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +43 -2
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +9 -1
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflows.ts +24 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas-export.dto.ts +27 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas-export.service.spec.ts +430 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas-export.service.ts +203 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.ts +36 -3
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.module.ts +2 -1
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.spec.ts +54 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.ts +245 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.module.ts +10 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.service.spec.ts +366 -0
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.service.ts +110 -0
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +19 -1
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +15 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +79 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +41 -19
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/start-prod.sh +5 -5
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +37 -573
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/web/ecosystem.dev.config.cjs +12 -1
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +1 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +3 -2
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +39 -26
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/i18n.ts +3 -1
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +3 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +3 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +23 -5
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +66 -10
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +16 -7
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +21 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasApi.ts +30 -0
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/ExportModal.tsx +84 -0
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/ImportModal.tsx +166 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/hooks/useCanvasHistory.ts +52 -13
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +6 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +6 -1
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +17 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +18 -6
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +225 -0
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/utilities/lazy-with-reload.ts +31 -0
  55. package/package.json +1 -1
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-dsl-validate.spec.ts +0 -220
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-dsl-validate.ts +0 -132
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/TODO.md +0 -152
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/config/development-sql.yaml +0 -5
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/docker-compose.yml +0 -25
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/package.json +0 -13
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.dockerignore +0 -12
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.env +0 -7
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/Dockerfile +0 -79
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/GRACEFUL-DEPLOYMENT.md +0 -270
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/SANDBOX.md +0 -122
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/package-lock.json +0 -4285
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/package.json +0 -28
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/code-execute.ts +0 -51
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/db-execute.ts +0 -85
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/db-query.ts +0 -35
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/http-request.ts +0 -54
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/index.ts +0 -6
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/reporting.ts +0 -85
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/send-notification.ts +0 -47
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/config.ts +0 -13
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/condition.ts +0 -101
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/context.ts +0 -58
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/graph.ts +0 -184
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/helpers.ts +0 -133
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/node-types.ts +0 -96
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/types.ts +0 -77
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/validate.ts +0 -109
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/index.ts +0 -101
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/outbox-poller.ts +0 -382
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/activities/code-execute.test.ts +0 -44
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/activities/http-request.test.ts +0 -87
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/cron-trigger-workflow.test.ts +0 -20
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/helpers.test.ts +0 -225
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/node-type-consistency.test.ts +0 -101
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/validate.test.ts +0 -205
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/workflows/dsl-workflow.ts +0 -499
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/tsconfig.json +0 -19
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/vitest.config.ts +0 -8
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/yarn.lock +0 -1905
@@ -46,7 +46,7 @@ COPY --from=builder --chown=node:node /app/server/package.json /app/server/yarn.
46
46
 
47
47
  # 注意:这里不能用 `yarn install --production`。
48
48
  # start-prod.sh 启动时需要:
49
- # - prisma CLI(运行 `yarn push:db`)
49
+ # - prisma CLI(运行 `yarn migrate:deploy`)
50
50
  # - ts-node + dotenv-cli(运行 `yarn seed`)
51
51
  # 这三者在 package.json 中位于 devDependencies,--production 会跳过它们。
52
52
  # 故安装全量依赖;产物体积增加约 80MB,换来启动脚本统一可用。
@@ -74,7 +74,7 @@ RUN chmod +x start-prod.sh
74
74
  # 复制环境变量配置(作为默认值,K8s 注入的同名变量优先级更高)
75
75
  COPY --from=builder --chown=node:node /app/server/.env ./.env
76
76
 
77
- # package.json 的 push:db / seed 都走 `dotenv -e .env.local -e .env -- ...`,
77
+ # package.json 的 migrate:deploy / seed 都走 `dotenv -e .env.local -e .env -- ...`,
78
78
  # dotenv-cli v7 在指定文件不存在时会报错;镜像里没有 .env.local,touch 空文件兜底。
79
79
  RUN touch .env.local && chown node:node .env.local
80
80
 
@@ -190,7 +190,7 @@ print_post_up_guide() {
190
190
 
191
191
  提示:
192
192
  · 前端开发请用 cd web && yarn dev (本 compose 的 web 是 nginx 静态镜像,无热更新)
193
- · server-init 是一次性容器,跑完 push:db + seed 后退出 (Exited 0) 是正常的
193
+ · server-init 是一次性容器,跑完 migrate:deploy + seed 后退出 (Exited 0) 是正常的
194
194
  EOF
195
195
  }
196
196
 
@@ -3,6 +3,7 @@
3
3
  /// @IgnoreAutoField
4
4
  model Canvas {
5
5
  id String @id @default(cuid())
6
+ code String @unique @default(nanoid()) @db.VarChar(21) @map("code")
6
7
  name String @db.VarChar(255)
7
8
  userId String @db.VarChar(255) @map("user_id")
8
9
  items Json @default("[]")
@@ -99,9 +99,9 @@ model WorkflowInstance {
99
99
  model WorkflowNodeExecution {
100
100
  id BigInt @id @default(autoincrement())
101
101
  instanceId BigInt @map("instance_id")
102
- nodeId String @db.VarChar(64) // DSL node.id
103
- nodeType String @db.VarChar(64) // e.g. "http_request"
104
- nodeLabel String? @db.VarChar(128) // human-readable label
102
+ nodeId String @db.VarChar(64) @map("node_id") // DSL node.id
103
+ nodeType String @db.VarChar(64) @map("node_type") // e.g. "http_request"
104
+ nodeLabel String? @db.VarChar(128) @map("node_label") // human-readable label
105
105
  status WorkflowInstanceStatus @default(PENDING)
106
106
  input Json?
107
107
  output Json?
@@ -177,3 +177,14 @@ model WorkflowEventOutbox {
177
177
  // (Prisma schema 不支持 WHERE 子句的 partial index)
178
178
  @@map("t_workflow_event_outbox")
179
179
  }
180
+
181
+ /// @IgnoreReactCode
182
+ model TemporalTenantConfig {
183
+ adminUrl String @db.VarChar(256) @map("admin_url") // shared temporal admin API URL,e.g. http://localhost:8081
184
+ adminToken String @db.VarChar(128) @map("admin_token") // X-Admin-Token
185
+ namespace String @db.VarChar(64) @map("namespace") // 租户 namespace,需与 TEMPORAL_NAMESPACE 一致
186
+ dbUrl String @db.Text @map("db_url") // shared worker 视角的本项目 DB URL
187
+ displayName String @db.VarChar(128) @map("display_name") // 租户展示名
188
+
189
+ @@map("t_temporal_tenant_config")
190
+ }
@@ -18,7 +18,7 @@ export const User: ModelConfig = {
18
18
  {
19
19
  action: "EXPORT",
20
20
  desc: "export",
21
- fields: ["*", "!createdAt"],
21
+ fields: ["*", "!createdAt", "!groupMemberships.*", "!groupMemberships"],
22
22
  },
23
23
  { action: "INSERT", desc: "Insert" },
24
24
  ],
@@ -27,7 +27,7 @@ export const User: ModelConfig = {
27
27
  filter: ["roles"],
28
28
  sorter: ["id", "roles"],
29
29
  },
30
- fields: ["*", "!createdAt"],
30
+ fields: ["*", "!createdAt", "!groupMemberships.*", "!groupMemberships"],
31
31
  rowSelection: {
32
32
  actions: [
33
33
  { action: "DELETE", desc: "Delete" },
@@ -50,7 +50,7 @@ export const User: ModelConfig = {
50
50
  },
51
51
  },
52
52
  form: {
53
- fields: ["*", "!creator", "!createdAt", "!updatedAt"],
53
+ fields: ["*", "!creator", "!createdAt", "!updatedAt", "!groupMemberships.*", "!groupMemberships"],
54
54
  reaction: {
55
55
  id: {
56
56
  toggle: [],
@@ -61,6 +61,6 @@ export const User: ModelConfig = {
61
61
  },
62
62
  },
63
63
  show: {
64
- fields: ["*", "!createdAt"],
64
+ fields: ["*", "!createdAt", "!groupMemberships.*", "!groupMemberships"],
65
65
  },
66
66
  };
@@ -135,7 +135,7 @@ lsof -iTCP:8080 -sTCP:LISTEN
135
135
  docker compose logs server-init
136
136
  ```
137
137
 
138
- 如果状态是 `Exited (1)` 或更高,说明 push:db 或 seed 失败了,server / worker 不会启动。看日志排错后用 `docker compose up -d server-init` 重跑(幂等)。
138
+ 如果状态是 `Exited (1)` 或更高,说明 migrate:deploy 或 seed 失败了,server / worker 不会启动。看日志排错后用 `docker compose up -d server-init` 重跑(幂等)。
139
139
 
140
140
  ### Temporal schema 初始化失败
141
141
 
@@ -154,7 +154,7 @@ server 镜像里 `TAIHU_*` 用的是 `server/.env` 默认值,对应太湖测
154
154
  ```bash
155
155
  ./compose-ctl.sh --reset
156
156
  # 等 temporal-server 重新做 schema setup(看日志 `temporal-server` 里出现 "Temporal server started")
157
- # server-init 会自动重跑 push:db + seed,业务库回到种子数据状态
157
+ # server-init 会自动重跑 migrate:deploy + seed,业务库回到种子数据状态
158
158
  ```
159
159
 
160
160
  ## 用到的镜像
@@ -16,10 +16,10 @@
16
16
  #
17
17
  # 端口分配(已避免冲突):
18
18
  # 5432 -> PostgreSQL
19
- # 7233 -> Temporal gRPC(Server)
20
19
  # 8000 -> NestJS Server(API)
21
- # 8080 -> Temporal Web UI
22
20
  # 3000 -> Web 前端(nginx,容器内 80)
21
+ # Phase 3 起 gadmin-test 不再内嵌 temporal — TEMPORAL_ADDRESS 指向共享 temporal-shared
22
+ # 部署,见 docs/superpowers/specs/2026-07-14-shared-temporal-phase3-design.md
23
23
  #
24
24
  # 镜像构建依赖(与 Jenkinsfile 保持一致的方案 C):
25
25
  # server / web 通过 ARG CODEGEN_IMAGE + FROM ${CODEGEN_IMAGE} 引用本地 codegen 镜像,
@@ -28,12 +28,14 @@
28
28
  #
29
29
  # 首次启动顺序(depends_on + healthcheck 自动编排):
30
30
  # 1. postgres 起来 → healthy(pg_isready)
31
- # 2. temporal-server auto-setup 跑 schema 初始化(约 30~60s)→ healthy
32
- # 3. server / temporal-worker / temporal-ui 起来
31
+ # 2. server-init 跑 migrate:deploy + seed → 退出
32
+ # 3. server 起来
33
33
  # 4. web 起来
34
34
  #
35
+ # 前置:Phase 3 起 server 需要能连到共享 temporal(TEMPORAL_ADDRESS 必填);
36
+ # 首次使用先跑 `bash dev/register-tenant.sh` 注册本项目为租户。
37
+ #
35
38
  # 提示:
36
- # - 仅起 Temporal(不起 web/server/worker)请用 ./temporal/docker-compose.yml
37
39
  # - web 是生产 nginx 镜像,不支持热更新;前端开发请直接 `cd web && yarn dev`
38
40
  # =============================================================================
39
41
 
@@ -81,68 +83,14 @@ services:
81
83
  retries: 10
82
84
 
83
85
  # ---------------------------------------------------------------------------
84
- # Temporal Server (auto-setup):自动建 schema、起 frontend/history/matching/worker
85
- # 不开 ENABLE_ES,visibility 走 PG(与本地联调最小依赖一致)
86
- # ---------------------------------------------------------------------------
87
- temporal-server:
88
- # 生产 Helm chart 1.2.0 捆绑的 Temporal Server 是 1.31.0(见 docs/temporal-server-argocd.md),
89
- # 但 Docker Hub 上 temporalio/auto-setup 镜像目前最新只到 1.29.6.1(auto-setup tag 通常滞后于 server)。
90
- # 本地联调用最接近的 1.29.6.1 即可,schema 与 1.31.0 兼容。
91
- image: temporalio/auto-setup:1.29.6.1
92
- container_name: temporal-server
93
- restart: unless-stopped
94
- depends_on:
95
- postgres:
96
- condition: service_healthy
97
- environment:
98
- DB: postgres12
99
- DB_PORT: 5432
100
- POSTGRES_SEEDS: postgres
101
- POSTGRES_USER: ${POSTGRES_USER:-kavenma}
102
- POSTGRES_PWD: ${POSTGRES_PASSWORD:-kavenma}
103
- DBNAME: temporal
104
- VISIBILITY_DBNAME: temporal_visibility
105
- DYNAMIC_CONFIG_FILE_PATH: config/dynamicconfig/development-sql.yaml
106
- # 显式绑 0.0.0.0:podman rootless CNI 下 server 默认只绑容器主网卡 IP(如 10.89.x.x),
107
- # 容器内 127.0.0.1:7233 连不通 → healthcheck 永远 unhealthy → worker 不启动。
108
- # 设成 0.0.0.0 后 docker / podman 都可达。
109
- BIND_ON_IP: 0.0.0.0
110
- volumes:
111
- - ./temporal/config:/etc/temporal/config/dynamicconfig
112
- ports:
113
- - "7233:7233"
114
- healthcheck:
115
- # auto-setup 镜像自带 temporal CLI;healthcheck 在容器内执行,地址用 127.0.0.1
116
- test: ["CMD-SHELL", "temporal operator cluster health --address 127.0.0.1:7233 || exit 1"]
117
- interval: 10s
118
- timeout: 5s
119
- retries: 12
120
- start_period: 30s
121
-
122
- # ---------------------------------------------------------------------------
123
- # Temporal Web UI
124
- # ---------------------------------------------------------------------------
125
- temporal-ui:
126
- image: temporalio/ui:latest
127
- container_name: temporal-ui
128
- restart: unless-stopped
129
- depends_on:
130
- temporal-server:
131
- condition: service_started
132
- environment:
133
- TEMPORAL_ADDRESS: temporal-server:7233
134
- ports:
135
- - "8080:8080"
136
-
137
- # ---------------------------------------------------------------------------
138
- # Server 一次性初始化:prisma db push + seed
86
+ # Server 一次性初始化:migrate:deploy + seed
139
87
  # ---------------------------------------------------------------------------
140
88
  # 直接复用 codegen 镜像(它已含 server 全量依赖:ts-node / prisma CLI / seed/ 源码)。
141
89
  # 业务 server 镜像走 `--production` 安装、且不复制 seed/,因此 seed 不能在 server
142
90
  # 容器里跑;这里独立成 init 容器,跑完即退出。
143
91
  #
144
92
  # 幂等:
145
- # - prisma db push 多次执行无害(只补 schema 差异)
93
+ # - migrate:deploy 多次执行无害(只补 schema 差异)
146
94
  # - seed 全部用 createMany skipDuplicates / upsert 风格,重复跑不会重复插
147
95
  #
148
96
  # 依赖:
@@ -167,8 +115,8 @@ services:
167
115
  - -c
168
116
  - |
169
117
  set -e
170
- echo "[server-init] prisma db push ..."
171
- yarn push:db
118
+ echo "[server-init] migrate deploy ..."
119
+ yarn migrate:deploy
172
120
  echo "[server-init] seed ..."
173
121
  yarn seed
174
122
  echo "[server-init] done."
@@ -193,42 +141,15 @@ services:
193
141
  condition: service_healthy
194
142
  server-init:
195
143
  condition: service_completed_successfully
196
- # 不等 temporal-server healthy:server 启动不强依赖 Temporal
197
- temporal-server:
198
- condition: service_started
199
144
  environment:
200
145
  DATABASE_URL: postgresql://${POSTGRES_USER:-kavenma}:${POSTGRES_PASSWORD:-kavenma}@postgres:5432/gadmin_demo?schema=public
201
- TEMPORAL_ADDRESS: temporal-server:7233
202
- TEMPORAL_NAMESPACE: ${TEMPORAL_NAMESPACE:-default}
146
+ TEMPORAL_ADDRESS: ${TEMPORAL_ADDRESS:?TEMPORAL_ADDRESS not set — see server/.env}
147
+ TEMPORAL_NAMESPACE: ${TEMPORAL_NAMESPACE:-gadmin-test}
203
148
  TEMPORAL_TASK_QUEUE: ${TEMPORAL_TASK_QUEUE:-workflow-execution}
204
149
  NODE_ENV: ${NODE_ENV:-development}
205
150
  ports:
206
151
  - "8000:8000"
207
152
 
208
- # ---------------------------------------------------------------------------
209
- # Temporal Worker(Node.js 长驻进程)
210
- # ---------------------------------------------------------------------------
211
- temporal-worker:
212
- image: ${COMPOSE_PROJECT_NAME}-temporal-worker:local
213
- build:
214
- context: ./temporal/worker
215
- dockerfile: Dockerfile
216
- container_name: gadmin2-temporal-worker
217
- restart: on-failure
218
- depends_on:
219
- postgres:
220
- condition: service_healthy
221
- server-init:
222
- condition: service_completed_successfully
223
- temporal-server:
224
- condition: service_healthy
225
- environment:
226
- TEMPORAL_ADDRESS: temporal-server:7233
227
- TEMPORAL_NAMESPACE: ${TEMPORAL_NAMESPACE:-default}
228
- TEMPORAL_TASK_QUEUE: ${TEMPORAL_TASK_QUEUE:-workflow-execution}
229
- DATABASE_URL: postgresql://${POSTGRES_USER:-kavenma}:${POSTGRES_PASSWORD:-kavenma}@postgres:5432/gadmin_demo?schema=public
230
- # 无对外端口、无 health endpoint
231
-
232
153
  # ---------------------------------------------------------------------------
233
154
  # Web 前端(生产 nginx 镜像;本地仅用于完整集成验证)
234
155
  # 镜像构建依赖 codegen:先 `docker compose --profile codegen build codegen`
@@ -27,7 +27,7 @@ $ vi config/ui/{ModelName}.ts
27
27
 
28
28
  ### Generate code after edit config/schema.prisma or config/ui.config.ts
29
29
  ```
30
- $ gadmin2 g prisma:dev #Run prisma push db first. Command "gadmin2 g prisma" without run "prisma push db"
30
+ $ gadmin2 g prisma:dev # 生成 CRUD 代码 + 创建并应用迁移(内部调 migrate:dev);gadmin2 g prisma 只生成代码、不碰数据库
31
31
  ```
32
32
 
33
33
  ### Start web DevServer
@@ -45,6 +45,104 @@ $ yarn start:dev
45
45
  ```
46
46
  About nestjs server [read more](https://ptc.coding.intlgame.com/p/gadmin2/d/schematics/git/tree/master/src/lib/application/files/server/nest/README.md)
47
47
 
48
+ ## 数据库迁移(Prisma Migrations)
49
+
50
+ > Schema 的唯一手写真源是 `config/prisma/*.prisma`。`gadmin2 g prisma:dev` 会据此聚合出 `server/prisma/schema.prisma`、生成后端 CRUD 代码,并调用 `migrate:dev` 创建并应用迁移。
51
+
52
+ ### Git 追踪边界
53
+
54
+ | 类别 | 路径 | 是否入库 | 谁生成 |
55
+ |------|------|:---:|------|
56
+ | Schema 真源(手改) | `config/prisma/*.prisma` | ✅ | 人 |
57
+ | 迁移文件 | `server/prisma/migrations/` | ✅ | `prisma migrate` |
58
+ | 前端页面 | `web/src/routes/` | ✅ | react 生成器 |
59
+ | 聚合 schema | `server/prisma/schema.prisma` | ❌ | gadmin 聚合 |
60
+ | 后端 CRUD | `server/src/generated/` | ❌ | nestjs 生成器 |
61
+
62
+ 因为 `schema.prisma` 与 `generated/` 不入库,**每次拉取到 schema/迁移变更后都要本地重新生成**(见下方 git hook)。
63
+
64
+ ### 环境规则(重要)
65
+
66
+ `gadmin2 g prisma:dev` 在检测到漂移时会提示重置数据库,**只能在各自本地库运行**;共享库(测试/生产)一律用 `migrate deploy`(只回放迁移、从不删数据)。
67
+
68
+ | 环境 | 允许的迁移命令 |
69
+ |------|------|
70
+ | 本地开发(各自本地库) | `gadmin2 g prisma:dev` |
71
+ | 共享测试 / 生产库 | 仅 `yarn migrate:deploy` |
72
+
73
+ ### 命令详解:`gadmin2 g prisma:dev` vs `yarn migrate:deploy`
74
+
75
+ **`gadmin2 g prisma:dev`(内部调 `migrate:dev` = `prisma migrate dev --name auto`)**
76
+
77
+ 一条命令做四件事,按顺序:
78
+
79
+ 1. 据 `config/prisma/*.prisma` 聚合出 `server/prisma/schema.prisma`,并生成后端 CRUD 代码
80
+ 2. 对比迁移目录与数据库 `_prisma_migrations` 表,**按顺序应用所有 pending 迁移**(含刚拉下来的别人的迁移)
81
+ 3. 再对比 `schema.prisma` 与迁移历史,**若本地还有未捕获的 schema 改动,则生成一个新迁移并应用**(`--name auto` 自动命名)
82
+ 4. 重新生成 Prisma Client
83
+
84
+ 要点:
85
+ - **会生成迁移、会应用、会重新生成代码**——本地开发的主命令。
86
+ - 检测到**漂移(drift)**(本地库和迁移历史对不上,如曾手动 `db push` 改过表)时,会**交互式提示重置数据库(drop 重建)**。纯拉取+应用别人迁移通常不触发;本地库被改脏才会。遇到时看清提示再决定,别盲目回车。
87
+ - 因为会改本地库且交互,**绝不能对共享/生产库运行**。
88
+
89
+ **`yarn migrate:deploy`(= `prisma migrate deploy`)**
90
+
91
+ - **只回放 pending 迁移,从不生成迁移、从不删数据、无交互**,也不会因 drift 提示 reset。
92
+ - **不重新生成后端 CRUD 代码**——若拉下来的变更带了新表/新字段需要 module 代码,还得再跑 `gadmin2 g prisma`(只生成代码、不碰库)。
93
+ - 共享测试库、生产库、CI/部署链路(`start-prod.sh`)专用。
94
+
95
+ **如何选(拉取到别人的新迁移后)**
96
+
97
+ | 我的情况 | 用哪条 |
98
+ |------|------|
99
+ | 本地开发,且/或自己也改了 schema,要生成代码 | `gadmin2 g prisma:dev` |
100
+ | 本地开发,确定自己没改 schema,只想安全应用别人迁移 | `yarn migrate:deploy`(如需代码再 `gadmin2 g prisma`) |
101
+ | 共享测试 / 生产库 | 只能 `yarn migrate:deploy` |
102
+
103
+ ### 日常开发流
104
+
105
+ ```
106
+ 1. 改 config/prisma/{module}.prisma # 唯一手写处
107
+ 2. yarn migrate:create # 只生成迁移文件,不应用
108
+ 3. 审查 server/prisma/migrations/xxx/migration.sql # 重点看 DROP / 改列类型 / NOT NULL
109
+ 4. gadmin2 g prisma:dev # 生成 CRUD 代码 + 应用迁移到本地库
110
+ 5. 提交 config/prisma/* + server/prisma/migrations/* + web/src/routes/*
111
+ ```
112
+
113
+ > 建议第 2、3 步分开:先 `--create-only` 生成、人工审 SQL,再应用,避免误改把线上表 DROP。急活也可跳过直接跑第 4 步(`migrate:dev` 会交互式要迁移名并一步生成+应用)。
114
+
115
+ ### 拉取他人改动后
116
+
117
+ `.husky/post-merge` 与 `.husky/post-rewrite` 会在 `git pull`(merge)/ `git pull --rebase` 后,检测本次是否含 schema/迁移变更并提示:
118
+
119
+ - 含 `config/prisma/*` 或新迁移 → 运行 `gadmin2 g prisma:dev`(应用新迁移 + 重新生成后端代码)
120
+ - 仅含 `config/ui/*` → 运行 `gadmin2 g prisma`(只重新生成前端代码)
121
+
122
+ hook 只提示、不自动执行(`migrate:dev` 会改本地库且交互,不宜静默跑);需先在项目根跑过一次 `yarn`(触发 `husky install`)hook 才生效。
123
+
124
+ ### 首次接入迁移(baseline)
125
+
126
+ 如果现存库最初由 `db push` 建立、无迁移历史,切换到迁移前需 baseline。`0_init` 为全量基线,已入库。是否要标记「已应用」取决于**本库是否已有表**(这条记录写在数据库 `_prisma_migrations` 表,不随 git 同步,每个库独立):
127
+
128
+ | 场景 | 生成 0_init | `migrate resolve --applied 0_init` | 之后 |
129
+ |------|:---:|:---:|------|
130
+ | 已有本地库(db push 建的) | ❌ 文件已入库 | ✅ 必须一次 | 正常 `gadmin2 g prisma:dev` |
131
+ | 新环境 / 空库 | ❌ | ❌ 不需要 | 直接 `gadmin2 g prisma:dev` 建全表 |
132
+ | 共享测试/生产库(现存非空) | ❌ | ✅ 首次一次 | 之后 `yarn migrate:deploy` |
133
+
134
+ resolve 命令(在 `server/` 下执行,注意用本地 `dotenv-cli` 以避免命中全局 python-dotenv):
135
+
136
+ ```bash
137
+ $ cd server
138
+ $ ./node_modules/.bin/dotenv -e .env.local -e .env -- npx prisma migrate resolve --applied 0_init
139
+ $ ./node_modules/.bin/dotenv -e .env.local -e .env -- npx prisma migrate status # 验证:应显示 up to date、无 pending
140
+ ```
141
+
142
+ ### 迁移冲突约定
143
+
144
+ 两人各自基于同一父迁移生成迁移,合并后顺序会乱。约定:schema 改动**小步快合**;合并遇到迁移冲突时,**后合并者删掉自己的迁移文件、rebase 后重新 `yarn migrate:create`**,不要手改文件名时间戳。
145
+
48
146
  ## 构建与部署
49
147
 
50
148
  ### 模块划分
@@ -144,7 +242,7 @@ post.always: 清理本地 codegen 中间镜像
144
242
  │ • CREATE DATABASE temporal_visibility
145
243
  │
146
244
  ├── server-init(一次性容器,depends_on postgres healthy)
147
- │ • yarn push:db (prisma 把 schema 推到 gadmin_demo)
245
+ │ • yarn migrate:deploy (prisma 把 schema 推到 gadmin_demo)
148
246
  │ • yarn seed (播种 RBAC 等基础数据,跑完即退出 Exited 0)
149
247
  │
150
248
  └── server / web / temporal-* (正常服务)
@@ -157,7 +255,7 @@ post.always: 清理本地 codegen 中间镜像
157
255
 
158
256
  #### 2. 生产 / 临时环境(K8s + `server/start-prod.sh`)
159
257
 
160
- server 镜像的入口是 `start-prod.sh`,比本地 compose 多了「按需 push:db」「per-branch schema 隔离」逻辑:
258
+ server 镜像的入口是 `start-prod.sh`,比本地 compose 多了「按需 migrate:deploy」「per-branch schema 隔离」逻辑:
161
259
 
162
260
  ```
163
261
  container start
@@ -173,13 +271,13 @@ container start
173
271
  │ │
174
272
  │ ├─ A. 临时环境(feature*/bugfix*/hotfix*):每次启动都重建分支 schema
175
273
  │ │ • 改写 DATABASE_URL:schema=<DEPLOY_NAME>(- 与 / 替换为 _)
176
- │ │ • yarn push:db
274
+ │ │ • yarn migrate:deploy
177
275
  │ │ • node migrate-between-pg-schemas.js (从 public schema 拷数据到分支 schema)
178
276
  │ │ • yarn seed (幂等,每次启动都跑)
179
277
  │ │
180
278
  │ └─ B. 非临时环境(默认 / production):按需初始化
181
279
  │ • DATABASE_URL 兜底 schema=public
182
- │ • 探测 t_role:不存在或 count=0 → yarn push:db + yarn seed;否则跳过
280
+ │ • 探测 t_role:不存在或 count=0 → yarn migrate:deploy + yarn seed;否则跳过
183
281
  │ • 连接失败等异常 → 保守走初始化路径
184
282
  │
185
283
  └── exec node dist/src/main ← 启动 NestJS
@@ -188,7 +286,7 @@ container start
188
286
  要点:
189
287
  - `ensure-database.js` 与本地 compose 的 `init.sql` 是**互补关系**:compose 路径走 init.sql,K8s / 外部托管 PG 走 ensure-database.js。重复执行无副作用。
190
288
  - 临时环境「每次启动都 seed」依赖所有 seed 实现都是 upsert / skipDuplicates 风格,重复跑不插重。
191
- - 非临时环境用 `t_role` 行数判断是否需要初始化(首次部署或被清库),避免每次重启都跑 push:db + seed。
289
+ - 非临时环境用 `t_role` 行数判断是否需要初始化(首次部署或被清库),避免每次重启都跑 migrate:deploy + seed。
192
290
  - 如果部署环境已通过 DBA / 运维流程保证库存在,可设 `SKIP_ENSURE_DATABASE=1` 跳过 ensure-database.js(预留开关,当前实现未消费该变量,按需扩展)。
193
291
 
194
292
  #### 3. 谁在何时建什么 — 总览
@@ -196,7 +294,7 @@ container start
196
294
  | 对象 | 本地 compose | 生产 / 临时环境 |
197
295
  |---|---|---|
198
296
  | 数据库(`gadmin_demo`) | `dev/postgres/init.sql`(pgdata 卷为空时) | `ensure-database.js`(每次启动幂等) |
199
- | Schema + 表结构 | `server-init` 里 `yarn push:db` | `start-prod.sh` 按分支策略 `yarn push:db` |
297
+ | Schema + 表结构 | `server-init` 里 `yarn migrate:deploy` | `start-prod.sh` 按分支策略 `yarn migrate:deploy` |
200
298
  | 基础数据(seed) | `server-init` 里 `yarn seed` | `start-prod.sh` 按分支策略 `yarn seed` |
201
299
  | 临时环境 schema 隔离 | — | `start-prod.sh` 改写 DATABASE_URL + `migrate-between-pg-schemas.js` |
202
300
 
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * 失败语义:
15
15
  * - 任何步骤异常(连接失败 / 权限不足 / SQL 报错)都直接 exit 1,让 start-prod.sh 终止。
16
- * 下游 push:db / 应用启动反正都会失败,越早暴露越好。
16
+ * 下游 migrate:deploy / 应用启动反正都会失败,越早暴露越好。
17
17
  *
18
18
  * 关闭开关:
19
19
  * - 若部署侧确认 DB 由外部流程保证存在、不希望本步执行,
@@ -22,22 +22,23 @@
22
22
  "test:cov": "jest --coverage",
23
23
  "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
24
24
  "test:e2e": "jest --config ./test/jest-e2e.json",
25
- "migrate:dev": "npm run push:db && dotenv -e .env.local -e .env -- prisma migrate",
26
- "migrate:dev:create": "dotenv -e .env.local -e .env -- prisma migrate dev --create-only",
25
+ "migrate:dev": "dotenv -e .env.local -e .env -- prisma migrate dev --name auto",
26
+ "migrate:create": "dotenv -e .env.local -e .env -- prisma migrate dev --create-only",
27
27
  "migrate:deploy": "dotenv -e .env.local -e .env -- prisma migrate deploy",
28
28
  "migrate:status": "dotenv -e .env.local -e .env -- prisma migrate status",
29
29
  "generate": "dotenv -e .env.local -e .env -- npx prisma generate",
30
- "generate:dev": "npm run migrate:dev && dotenv -e .env.local -e .env -- npx prisma generate",
30
+ "generate:dev": "npm run migrate:dev",
31
31
  "postgenerate:dev": "dotenv -e .env.local -e .env -- ts-node seed/data-mngt.seed.ts",
32
32
  "postgadminGenerate": "node scripts/notify-dev-servers.js",
33
33
  "push:db": "dotenv -e .env.local -e .env -- prisma db push --skip-generate",
34
34
  "seed": "dotenv -e .env.local -e .env -- ts-node seed/index.ts",
35
- "prisma:studio": "dotenv -e .env.local -e .env -- prisma studio"
35
+ "prisma:studio": "dotenv -e .env.local -e .env -- prisma studio",
36
+ "gen:jwt": "dotenv -e .env.local -e .env -- ts-node scripts/gen-jwt.ts"
36
37
  },
37
38
  "dependencies": {
38
39
  "@agendajs/postgres-backend": "^3.0.5",
39
40
  "@azure/identity": "^4.13.0",
40
- "@gadmin2n/nest-common": "^0.0.51",
41
+ "@gadmin2n/nest-common": "^0.1.3",
41
42
  "@nestjs/cache-manager": "^3.0.1",
42
43
  "@nestjs/common": "^10.4.15",
43
44
  "@nestjs/config": "^3.2.0",
@@ -90,7 +91,7 @@
90
91
  "devDependencies": {
91
92
  "@faker-js/faker": "^10.4.0",
92
93
  "@gadmin2n/prisma-nest-generator": "^0.0.49",
93
- "@gadmin2n/prisma-react-generator": "^0.0.65",
94
+ "@gadmin2n/prisma-react-generator": "^0.0.69",
94
95
  "@nestjs/cli": "^11.0.21",
95
96
  "@nestjs/testing": "^10.4.15",
96
97
  "@swc/cli": "^0.8.1",
@@ -6,6 +6,11 @@ import { defineConfig } from 'prisma/config';
6
6
  dotenv.config({ path: path.resolve(__dirname, '.env.local') });
7
7
  dotenv.config({ path: path.resolve(__dirname, '.env') });
8
8
 
9
+ // 从连接串的 ?schema= 读取外部表所在 schema,缺省 public
10
+ const schema =
11
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
12
+ new URL(process.env.DATABASE_URL!).searchParams.get('schema') ?? 'public';
13
+
9
14
  export default defineConfig({
10
15
  engine: 'classic',
11
16
  datasource: {
@@ -18,6 +23,9 @@ export default defineConfig({
18
23
  tables: {
19
24
  // 将要被 Prisma 标记为“外部管理”的表名列表
20
25
  // 可以使用 "schema.table" 或仅 "table"(依你 DB/项目设置)
21
- external: ['public.users'],
26
+ // agenda_jobs / agenda_logs 均由 @agendajs/postgres-backend 在服务启动时
27
+ // 通过 CREATE TABLE IF NOT EXISTS 自动创建并维护(含部分索引、唯一索引、触发器),
28
+ // Prisma schema 无法完整表达,故整体交给库管理,迁移不碰。
29
+ external: [`${schema}.agenda_jobs`, `${schema}.agenda_logs`],
22
30
  },
23
31
  });
@@ -0,0 +1,85 @@
1
+ /**
2
+ * gen-jwt.ts — 使用 TaiHuId.sign() 为 seed 用户生成 JWT token
3
+ *
4
+ * Usage:
5
+ * yarn gen:jwt --userid kavenma
6
+ * yarn gen:jwt --userid kavenma --expiresIn 3600
7
+ *
8
+ * userid 必须在 seed/users.ts 中存在。
9
+ */
10
+
11
+ import seedUsers from '../seed/users';
12
+ import TaiHuId from '../src/lib/taihu';
13
+
14
+ function parseArgs(): Record<string, string> {
15
+ const argv = process.argv.slice(2);
16
+ const flags: Record<string, string> = {};
17
+ for (let i = 0; i < argv.length; i++) {
18
+ if (argv[i].startsWith('--')) {
19
+ const key = argv[i].slice(2);
20
+ const next = argv[i + 1];
21
+ flags[key] = next && !next.startsWith('--') ? argv[++i] : 'true';
22
+ }
23
+ }
24
+ return flags;
25
+ }
26
+
27
+ async function main() {
28
+ const flags = parseArgs();
29
+ const { userid, expiresIn } = flags;
30
+
31
+ if (!userid) {
32
+ console.error('[gen-jwt] --userid is required.');
33
+ console.error(
34
+ `[gen-jwt] Available userids: ${seedUsers
35
+ .map((u) => u.userid)
36
+ .join(', ')}`,
37
+ );
38
+ process.exit(1);
39
+ }
40
+
41
+ const user = seedUsers.find((u) => u.userid === userid);
42
+ if (!user) {
43
+ console.error(`[gen-jwt] userid "${userid}" not found in seed/users.ts.`);
44
+ console.error(
45
+ `[gen-jwt] Available userids: ${seedUsers
46
+ .map((u) => u.userid)
47
+ .join(', ')}`,
48
+ );
49
+ process.exit(1);
50
+ }
51
+
52
+ const ttl = expiresIn ? parseInt(expiresIn, 10) : 7 * 24 * 60 * 60; // 默认 7 天
53
+
54
+ const token = await TaiHuId.sign(
55
+ {
56
+ user_id: user.userid,
57
+ sub: user.userid,
58
+ name: user.username,
59
+ email: `${user.userid}@tencent.com`,
60
+ },
61
+ ttl,
62
+ );
63
+
64
+ console.log(
65
+ `[gen-jwt] ✅ Generated JWT for userid=${user.userid} (expiresIn=${ttl}s):\n`,
66
+ );
67
+ console.log(token);
68
+
69
+ console.log('\n[gen-jwt] 🍪 如何在浏览器中种入 cookie:');
70
+ console.log(' 1) 打开目标站点(例如 http://localhost:3000),进入 DevTools');
71
+ console.log(' 2) Application → Cookies → 选择当前域名');
72
+ console.log(
73
+ ' 新增一条 cookie:Name=gadmin-token Value=<上面的 token> Path=/',
74
+ );
75
+ console.log(' 3) 刷新页面即可以该 userid 身份登录\n');
76
+ console.log(' 或在 DevTools Console 中执行(同域下即时生效):');
77
+ console.log(
78
+ ` document.cookie = "gadmin-token=${token}; path=/; max-age=${ttl}"`,
79
+ );
80
+ }
81
+
82
+ main().catch((e) => {
83
+ console.error('[gen-jwt] Fatal error:', e);
84
+ process.exit(1);
85
+ });
@@ -44,7 +44,7 @@ const HEALTH_URL = `http://127.0.0.1:${NEST_PORT}/api/health/live`;
44
44
  const WEB_SENTINEL = path.resolve(process.cwd(), '..', 'web', '.vite-restart');
45
45
 
46
46
  function log(msg) {
47
- process.stdout.write(`[postgadminGenerate] ${msg}\n`);
47
+ process.stdout.write(`\x1b[90m[postgadminGenerate] ${msg}\x1b[0m\n`);
48
48
  }
49
49
 
50
50
  function pingOnce(url) {
@@ -81,18 +81,19 @@ function touchViteSentinel() {
81
81
  }
82
82
 
83
83
  (async () => {
84
+ const rawOpts = {
85
+ pollMs: envInt('POSTGEN_POLL_MS'),
86
+ initialStableMs: envInt('POSTGEN_INITIAL_STABLE_MS'),
87
+ maxStableMs: envInt('POSTGEN_MAX_STABLE_MS'),
88
+ observeDownTimeoutMs: envInt('POSTGEN_OBSERVE_DOWN_TIMEOUT_MS'),
89
+ totalTimeoutMs: envInt('POSTGEN_TOTAL_TIMEOUT_MS'),
90
+ };
84
91
  await waitForNestReady({
85
92
  ping: () => pingOnce(HEALTH_URL),
86
93
  sleep,
87
94
  now: () => Date.now(),
88
95
  log,
89
- opts: {
90
- pollMs: envInt('POSTGEN_POLL_MS'),
91
- initialStableMs: envInt('POSTGEN_INITIAL_STABLE_MS'),
92
- maxStableMs: envInt('POSTGEN_MAX_STABLE_MS'),
93
- observeDownTimeoutMs: envInt('POSTGEN_OBSERVE_DOWN_TIMEOUT_MS'),
94
- totalTimeoutMs: envInt('POSTGEN_TOTAL_TIMEOUT_MS'),
95
- },
96
+ opts: Object.fromEntries(Object.entries(rawOpts).filter(([, v]) => v !== undefined)),
96
97
  });
97
98
  touchViteSentinel();
98
99
  })().catch((e) => {