create-windy 0.2.7 → 0.2.8

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 (358) hide show
  1. package/README.md +6 -0
  2. package/dist/cli.js +180 -87
  3. package/package.json +1 -1
  4. package/template/.windy-template.json +2 -2
  5. package/template/apps/server/Dockerfile +2 -0
  6. package/template/apps/server/package.json +10 -8
  7. package/template/apps/server/src/access-guards.ts +1 -1
  8. package/template/apps/server/src/admin/routes.test.ts +10 -0
  9. package/template/apps/server/src/admin/routes.ts +4 -2
  10. package/template/apps/server/src/agent/routes.test.ts +1 -1
  11. package/template/apps/server/src/agent/routes.ts +2 -2
  12. package/template/apps/server/src/application-services.ts +3 -0
  13. package/template/apps/server/src/audit/drizzle-log-store.ts +2 -2
  14. package/template/apps/server/src/audit/policy.ts +1 -1
  15. package/template/apps/server/src/audit/recovery-queue.test.ts +1 -1
  16. package/template/apps/server/src/audit/recovery-queue.ts +1 -1
  17. package/template/apps/server/src/audit/redaction.ts +1 -1
  18. package/template/apps/server/src/audit/reliable-writer.test.ts +1 -1
  19. package/template/apps/server/src/audit/reliable-writer.ts +1 -1
  20. package/template/apps/server/src/audit/search-summary.ts +1 -1
  21. package/template/apps/server/src/auth/authentication-provider.test.ts +1 -1
  22. package/template/apps/server/src/auth/credential-service.ts +1 -1
  23. package/template/apps/server/src/auth/drizzle-repository.ts +2 -2
  24. package/template/apps/server/src/auth/drizzle-session-operations.ts +1 -1
  25. package/template/apps/server/src/auth/own-session-routes.test.ts +1 -1
  26. package/template/apps/server/src/auth/password.ts +2 -2
  27. package/template/apps/server/src/auth/repository.ts +1 -1
  28. package/template/apps/server/src/auth/routes.test.ts +1 -1
  29. package/template/apps/server/src/auth/service.ts +1 -1
  30. package/template/apps/server/src/bulk-data/artifact-store.ts +1 -1
  31. package/template/apps/server/src/bulk-data/dictionary-handler.ts +1 -1
  32. package/template/apps/server/src/bulk-data/drizzle-repository.ts +3 -3
  33. package/template/apps/server/src/bulk-data/repository.ts +1 -1
  34. package/template/apps/server/src/bulk-data/routes.test.ts +1 -1
  35. package/template/apps/server/src/bulk-data/routes.ts +1 -1
  36. package/template/apps/server/src/bulk-data/service.test.ts +1 -1
  37. package/template/apps/server/src/bulk-data/service.ts +1 -1
  38. package/template/apps/server/src/bulk-data/types.ts +1 -1
  39. package/template/apps/server/src/configuration/bootstrap.ts +2 -2
  40. package/template/apps/server/src/configuration/definition.ts +2 -2
  41. package/template/apps/server/src/configuration/drizzle-repository.ts +2 -2
  42. package/template/apps/server/src/configuration/repository.ts +1 -1
  43. package/template/apps/server/src/configuration/routes.ts +1 -1
  44. package/template/apps/server/src/configuration/service.ts +1 -1
  45. package/template/apps/server/src/data-access/context.ts +2 -2
  46. package/template/apps/server/src/data-access/query-specification.test.ts +1 -1
  47. package/template/apps/server/src/data-access/scoped-repository.integration.test.ts +1 -1
  48. package/template/apps/server/src/data-access/scoped-repository.ts +1 -1
  49. package/template/apps/server/src/data-access/scoped-resource.test.ts +1 -1
  50. package/template/apps/server/src/data-access/scoped-resource.ts +1 -1
  51. package/template/apps/server/src/data-governance/export/approval-port.ts +1 -1
  52. package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -1
  53. package/template/apps/server/src/data-governance/export/job-runtime.test.ts +2 -2
  54. package/template/apps/server/src/data-governance/export/job-runtime.ts +2 -3
  55. package/template/apps/server/src/data-governance/export/postgres-api-fixture.ts +2 -2
  56. package/template/apps/server/src/data-governance/export/postgres-api.integration.test.ts +1 -1
  57. package/template/apps/server/src/data-governance/export/routes-test-fixture.ts +3 -3
  58. package/template/apps/server/src/data-governance/export/routes.ts +1 -1
  59. package/template/apps/server/src/data-governance/export/scope-snapshot.ts +1 -1
  60. package/template/apps/server/src/data-governance/export/service.ts +2 -2
  61. package/template/apps/server/src/data-governance/export/source.ts +1 -1
  62. package/template/apps/server/src/data-governance/export/types.ts +1 -1
  63. package/template/apps/server/src/data-governance/plaintext-access.test.ts +1 -1
  64. package/template/apps/server/src/data-governance/plaintext-access.ts +1 -1
  65. package/template/apps/server/src/data-governance/plaintext-postgres.integration.test.ts +1 -1
  66. package/template/apps/server/src/data-governance/user-plaintext-routes.ts +1 -1
  67. package/template/apps/server/src/data-governance/user-projection.ts +2 -2
  68. package/template/apps/server/src/example-modules.ts +25 -1
  69. package/template/apps/server/src/feature/manifest-feature-repository.test.ts +1 -1
  70. package/template/apps/server/src/feature/manifest-feature-repository.ts +1 -1
  71. package/template/apps/server/src/feature/routes.ts +3 -6
  72. package/template/apps/server/src/foundation-access.test.ts +1 -1
  73. package/template/apps/server/src/foundation-access.ts +1 -1
  74. package/template/apps/server/src/foundation.ts +21 -7
  75. package/template/apps/server/src/guards.test.ts +1 -1
  76. package/template/apps/server/src/guards.ts +3 -3
  77. package/template/apps/server/src/index.ts +27 -3
  78. package/template/{packages/modules → apps/server}/src/installed-business-modules.ts +2 -2
  79. package/template/apps/server/src/jobs/artifact-service.test.ts +1 -1
  80. package/template/apps/server/src/jobs/artifact-service.ts +2 -2
  81. package/template/apps/server/src/jobs/drizzle-artifact.ts +2 -2
  82. package/template/apps/server/src/jobs/drizzle-claim.ts +1 -1
  83. package/template/apps/server/src/jobs/drizzle-execution-repository.ts +2 -2
  84. package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +1 -1
  85. package/template/apps/server/src/jobs/drizzle-lease.ts +2 -2
  86. package/template/apps/server/src/jobs/drizzle-mappers.ts +3 -3
  87. package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +1 -1
  88. package/template/apps/server/src/jobs/drizzle-repository.integration.test.ts +1 -1
  89. package/template/apps/server/src/jobs/drizzle-repository.ts +3 -3
  90. package/template/apps/server/src/jobs/execution-repository.ts +1 -1
  91. package/template/apps/server/src/jobs/execution.test.ts +2 -2
  92. package/template/apps/server/src/jobs/in-memory-claim.ts +1 -1
  93. package/template/apps/server/src/jobs/in-memory-execution.ts +1 -1
  94. package/template/apps/server/src/jobs/in-memory-lease.ts +1 -1
  95. package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +1 -1
  96. package/template/apps/server/src/jobs/legacy-adapter.test.ts +1 -1
  97. package/template/apps/server/src/jobs/legacy-adapter.ts +1 -1
  98. package/template/apps/server/src/jobs/legacy-service-runtime.ts +4 -2
  99. package/template/apps/server/src/jobs/repository.ts +2 -2
  100. package/template/apps/server/src/jobs/service.ts +2 -2
  101. package/template/apps/server/src/jobs/worker.ts +3 -2
  102. package/template/apps/server/src/license/legacy-license-resolver.ts +1 -1
  103. package/template/apps/server/src/license/license-resolver.test.ts +1 -1
  104. package/template/apps/server/src/license/license-resolver.ts +3 -3
  105. package/template/apps/server/src/license/routes-offline-code.test.ts +2 -2
  106. package/template/apps/server/src/license/routes.ts +1 -1
  107. package/template/apps/server/src/license/runtime-audit-reliability.test.ts +2 -2
  108. package/template/apps/server/src/license/runtime-reminder.test.ts +2 -2
  109. package/template/apps/server/src/license/runtime-service.test.ts +2 -2
  110. package/template/apps/server/src/license/runtime-service.ts +2 -2
  111. package/template/apps/server/src/module-composition.test.ts +1 -1
  112. package/template/apps/server/src/module-composition.ts +1 -1
  113. package/template/apps/server/src/module-host.test.ts +145 -0
  114. package/template/apps/server/src/module-host.ts +110 -0
  115. package/template/apps/server/src/notification/drizzle-repository.ts +2 -2
  116. package/template/apps/server/src/notification/repository.ts +1 -1
  117. package/template/apps/server/src/notification/routes.ts +1 -1
  118. package/template/apps/server/src/pagination.ts +1 -1
  119. package/template/apps/server/src/persistence.integration.test.ts +1 -1
  120. package/template/apps/server/src/persistence.ts +1 -1
  121. package/template/apps/server/src/profile/routes.ts +1 -1
  122. package/template/apps/server/src/route-guards.test.ts +1 -1
  123. package/template/apps/server/src/route-guards.ts +1 -1
  124. package/template/apps/server/src/runtime-feature.ts +125 -0
  125. package/template/apps/server/src/runtime-license.ts +1 -1
  126. package/template/apps/server/src/runtime.test.ts +48 -1
  127. package/template/apps/server/src/runtime.ts +17 -64
  128. package/template/apps/server/src/scheduler/audit.ts +1 -1
  129. package/template/apps/server/src/scheduler/definitions.test.ts +1 -1
  130. package/template/apps/server/src/scheduler/definitions.ts +2 -2
  131. package/template/apps/server/src/scheduler/drizzle-durable-links.ts +1 -1
  132. package/template/apps/server/src/scheduler/drizzle-mappers.ts +1 -1
  133. package/template/apps/server/src/scheduler/drizzle-repository.ts +1 -1
  134. package/template/apps/server/src/scheduler/execution-recorder.ts +1 -1
  135. package/template/apps/server/src/scheduler/history.ts +1 -1
  136. package/template/apps/server/src/scheduler/overview.ts +1 -1
  137. package/template/apps/server/src/scheduler/recovery-service.test.ts +1 -1
  138. package/template/apps/server/src/scheduler/recovery-service.ts +1 -1
  139. package/template/apps/server/src/scheduler/repository.ts +1 -1
  140. package/template/apps/server/src/scheduler/routes.ts +1 -1
  141. package/template/apps/server/src/scheduler/service-idle.test.ts +1 -1
  142. package/template/apps/server/src/scheduler/service.test.ts +1 -1
  143. package/template/apps/server/src/scheduler/service.ts +1 -1
  144. package/template/apps/server/src/scheduler/types.ts +1 -1
  145. package/template/apps/server/src/search/contracts.ts +2 -2
  146. package/template/apps/server/src/search/host.ts +1 -1
  147. package/template/apps/server/src/search/registry.ts +1 -1
  148. package/template/apps/server/src/search/routes.test.ts +1 -1
  149. package/template/apps/server/src/search/routes.ts +1 -1
  150. package/template/apps/server/src/search/service.ts +2 -2
  151. package/template/apps/server/src/search/test-support.ts +2 -2
  152. package/template/apps/server/src/session/routes.ts +1 -1
  153. package/template/apps/server/src/settings/drizzle-repository.ts +2 -2
  154. package/template/apps/server/src/settings/repository.ts +1 -1
  155. package/template/apps/server/src/settings/routes.test.ts +1 -1
  156. package/template/apps/server/src/settings/routes.ts +1 -1
  157. package/template/apps/server/src/settings/runtime.ts +1 -1
  158. package/template/apps/server/src/storage/blob-reference-registry.test.ts +1 -1
  159. package/template/apps/server/src/storage/blob-reference-registry.ts +1 -1
  160. package/template/apps/server/src/storage/drizzle-upload-repository.integration.test.ts +1 -1
  161. package/template/apps/server/src/storage/drizzle-upload-repository.ts +2 -2
  162. package/template/apps/server/src/storage/route-support.ts +1 -1
  163. package/template/apps/server/src/storage/routes.test.ts +1 -1
  164. package/template/apps/server/src/storage/routes.ts +2 -2
  165. package/template/apps/server/src/storage/runtime.ts +6 -4
  166. package/template/apps/server/src/system/audit-routes.ts +1 -1
  167. package/template/apps/server/src/system/department-routes.ts +1 -1
  168. package/template/apps/server/src/system/drizzle-repository.ts +1 -1
  169. package/template/apps/server/src/system/drizzle-scoped-repository.ts +1 -1
  170. package/template/apps/server/src/system/drizzle-system.ts +1 -1
  171. package/template/apps/server/src/system/entities.ts +1 -1
  172. package/template/apps/server/src/system/identity-route-config.ts +1 -1
  173. package/template/apps/server/src/system/interface-catalog.test.ts +3 -3
  174. package/template/apps/server/src/system/interface-catalog.ts +2 -2
  175. package/template/apps/server/src/system/menu-registry.ts +1 -1
  176. package/template/apps/server/src/system/menu-routes.ts +1 -1
  177. package/template/apps/server/src/system/operations.test.ts +1 -1
  178. package/template/apps/server/src/system/operations.ts +1 -1
  179. package/template/apps/server/src/system/redis-health.ts +1 -1
  180. package/template/apps/server/src/system/repository.ts +1 -1
  181. package/template/apps/server/src/system/resource-route-support.ts +1 -1
  182. package/template/apps/server/src/system/route-helpers.ts +1 -1
  183. package/template/apps/server/src/system/route-types.ts +1 -1
  184. package/template/apps/server/src/system/routes.test.ts +1 -1
  185. package/template/apps/server/src/system/routes.ts +1 -1
  186. package/template/apps/server/src/system/user-projection.ts +1 -1
  187. package/template/apps/server/src/work-order/data-scope.integration.test.ts +1 -1
  188. package/template/apps/server/src/work-order/drizzle-repository.integration.test.ts +1 -1
  189. package/template/apps/server/src/work-order/drizzle-repository.ts +2 -2
  190. package/template/apps/server/src/work-order/foundation-modules.test.ts +15 -5
  191. package/template/apps/server/src/work-order/repository.ts +1 -1
  192. package/template/apps/server/src/work-order/routes.test.ts +2 -2
  193. package/template/apps/server/src/work-order/routes.ts +2 -2
  194. package/template/apps/server/src/work-order/search-api.test.ts +3 -3
  195. package/template/apps/server/src/work-order/search-provider.test.ts +3 -3
  196. package/template/apps/server/src/work-order/service.ts +1 -1
  197. package/template/apps/server/src/work-order/task.test.ts +1 -1
  198. package/template/apps/server/src/work-order/task.ts +2 -2
  199. package/template/apps/server/src/workflow/drizzle-repository.integration.test.ts +2 -2
  200. package/template/apps/server/src/workflow/drizzle-repository.ts +3 -3
  201. package/template/apps/server/src/workflow/effects.test.ts +1 -1
  202. package/template/apps/server/src/workflow/effects.ts +1 -1
  203. package/template/apps/server/src/workflow/repository.ts +2 -2
  204. package/template/apps/server/src/workflow/routes.ts +3 -3
  205. package/template/apps/server/src/workflow/service.ts +1 -1
  206. package/template/apps/server/src/workflow/timeout-runtime.test.ts +1 -1
  207. package/template/apps/server/src/workflow/timeout-runtime.ts +2 -2
  208. package/template/apps/web/Dockerfile +2 -0
  209. package/template/apps/web/package.json +4 -4
  210. package/template/apps/web/runtime-server.ts +1 -1
  211. package/template/apps/web/src/app/layouts/AppLayout.vue +6 -0
  212. package/template/apps/web/src/components/auth/PasswordChangeForm.vue +1 -1
  213. package/template/apps/web/src/components/common/DataPagination.vue +1 -1
  214. package/template/apps/web/src/components/license/LicenseActivationCodeForm.vue +1 -1
  215. package/template/apps/web/src/components/license/LicenseFlow.webtest.ts +2 -2
  216. package/template/apps/web/src/composables/useModuleConfigurations.ts +1 -1
  217. package/template/apps/web/src/composables/useWatermarkSettings.ts +1 -0
  218. package/template/apps/web/src/composables/watermark-settings.ts +6 -0
  219. package/template/apps/web/src/composables/watermark-settings.webtest.ts +27 -1
  220. package/template/apps/web/src/layout/AppSidebar.vue +12 -3
  221. package/template/apps/web/src/layout/AppSidebar.webtest.ts +11 -0
  222. package/template/apps/web/src/layout/GlobalWatermark.vue +25 -8
  223. package/template/apps/web/src/layout/GlobalWatermark.webtest.ts +109 -0
  224. package/template/apps/web/src/layout/NavigationSearchDialog.vue +1 -1
  225. package/template/apps/web/src/layout/NotificationMenu.vue +1 -1
  226. package/template/apps/web/src/layout/navigation.ts +5 -1
  227. package/template/apps/web/src/layout/navigation.webtest.ts +1 -1
  228. package/template/apps/web/src/pages/configuration/components/ModuleConfigRollbackDialog.vue +1 -1
  229. package/template/apps/web/src/pages/configuration/components/ModuleConfigVersionList.vue +1 -1
  230. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +1 -1
  231. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.webtest.ts +1 -1
  232. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +1 -1
  233. package/template/apps/web/src/pages/dashboard/dashboard-presenter.webtest.ts +1 -1
  234. package/template/apps/web/src/pages/settings/WatermarkSettingsSection.vue +21 -0
  235. package/template/apps/web/src/pages/system/SystemNotificationsPage.vue +2 -2
  236. package/template/apps/web/src/pages/system/components/AuditActionCell.vue +7 -2
  237. package/template/apps/web/src/pages/system/components/AuditLogFilters.vue +7 -2
  238. package/template/apps/web/src/pages/system/components/NotificationPublishForm.vue +1 -1
  239. package/template/apps/web/src/pages/system/components/SchedulerOperationsPanel.vue +1 -1
  240. package/template/apps/web/src/pages/system/components/SchedulerOperationsPanel.webtest.ts +1 -1
  241. package/template/apps/web/src/pages/system/components/SchedulerRunTable.vue +1 -1
  242. package/template/apps/web/src/pages/system/components/SchedulerRunTable.webtest.ts +1 -1
  243. package/template/apps/web/src/pages/system/components/SchedulerStaleRecoveryForm.vue +1 -1
  244. package/template/apps/web/src/pages/system/components/SchedulerStaleRecoveryForm.webtest.ts +1 -1
  245. package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +1 -1
  246. package/template/apps/web/src/pages/system/components/SystemResourceTable.vue +10 -3
  247. package/template/apps/web/src/pages/system/components/role-policy/RolePermissionTree.vue +1 -1
  248. package/template/apps/web/src/pages/system/components/role-policy/RolePermissionTree.webtest.ts +1 -1
  249. package/template/apps/web/src/pages/system/components/role-policy/RolePolicyForm.vue +1 -1
  250. package/template/apps/web/src/pages/system/components/role-policy/permission-tree.ts +1 -1
  251. package/template/apps/web/src/pages/system/components/role-policy/permission-tree.webtest.ts +1 -1
  252. package/template/apps/web/src/pages/system/composables/useSchedulerOperations.ts +2 -2
  253. package/template/apps/web/src/pages/system/composables/useSchedulerOperations.webtest.ts +1 -1
  254. package/template/apps/web/src/pages/system/composables/useSystemResource.ts +1 -1
  255. package/template/apps/web/src/router/manifest-routes.ts +1 -1
  256. package/template/apps/web/src/router/manifest-routes.webtest.ts +1 -1
  257. package/template/apps/web/src/services/access-api.ts +10 -1
  258. package/template/apps/web/src/services/configuration-api.ts +1 -1
  259. package/template/apps/web/src/services/license-api.ts +1 -1
  260. package/template/apps/web/src/services/notification-api.ts +2 -2
  261. package/template/apps/web/src/services/operations-api.ts +1 -1
  262. package/template/apps/web/src/services/platform-settings-api.ts +2 -2
  263. package/template/apps/web/src/services/profile-api.ts +2 -2
  264. package/template/docs/architecture/durable-jobs.md +5 -0
  265. package/template/docs/architecture/module-manifest-composition.md +14 -7
  266. package/template/docs/architecture/object-storage.md +1 -1
  267. package/template/docs/development/crud-generator.md +4 -1
  268. package/template/docs/platform/audit-reliability.md +1 -1
  269. package/template/package.json +2 -1
  270. package/template/packages/config/package.json +15 -4
  271. package/template/packages/config/src/platform.ts +1 -1
  272. package/template/packages/crud-generator/package.json +1 -1
  273. package/template/packages/crud-generator/src/generator.test.ts +16 -0
  274. package/template/packages/crud-generator/src/templates/domain.ts +1 -1
  275. package/template/packages/crud-generator/src/templates/manifest.ts +2 -2
  276. package/template/packages/crud-generator/src/templates/project.ts +3 -3
  277. package/template/packages/crud-generator/src/templates/repository.ts +1 -1
  278. package/template/packages/crud-generator/src/templates/routes.ts +2 -2
  279. package/template/packages/crud-generator/src/validation.ts +22 -1
  280. package/template/packages/database/package.json +15 -5
  281. package/template/packages/database/src/bundle-validation.ts +218 -0
  282. package/template/packages/database/src/dialects.ts +1 -1
  283. package/template/packages/database/src/runner.test.ts +160 -13
  284. package/template/packages/database/src/runner.ts +95 -77
  285. package/template/packages/database/src/schema/governed-exports.ts +1 -1
  286. package/template/packages/database/src/schema/identity.ts +1 -1
  287. package/template/packages/database/src/schema/license-v1.ts +1 -1
  288. package/template/packages/database/src/schema/notifications.ts +1 -1
  289. package/template/packages/database/src/schema/platform-settings.ts +1 -1
  290. package/template/packages/database/src/schema/workflow.ts +1 -1
  291. package/template/packages/database/src/sql-store.ts +1 -1
  292. package/template/packages/database/src/store.ts +1 -1
  293. package/template/packages/example-work-order/index.ts +1 -0
  294. package/template/packages/example-work-order/package.json +4 -3
  295. package/template/packages/example-work-order/src/contract.ts +1 -1
  296. package/template/packages/example-work-order/src/manifest.ts +8 -3
  297. package/template/packages/example-work-order/src/migration-bundle.test.ts +43 -0
  298. package/template/packages/example-work-order/src/migration-bundle.ts +64 -0
  299. package/template/packages/jobs/index.ts +2 -0
  300. package/template/packages/jobs/package.json +29 -0
  301. package/template/packages/jobs/src/handlers.test.ts +72 -0
  302. package/template/{apps/server/src/jobs/handler-registry.ts → packages/jobs/src/handlers.ts} +4 -4
  303. package/template/{apps/server/src/jobs → packages/jobs/src}/types.ts +7 -1
  304. package/template/packages/{license-sdk → jobs}/tsconfig.json +0 -1
  305. package/template/packages/modules/index.ts +1 -1
  306. package/template/packages/modules/package.json +15 -5
  307. package/template/packages/modules/src/catalog-validation.ts +123 -0
  308. package/template/packages/modules/src/composition.test.ts +75 -2
  309. package/template/packages/modules/src/composition.ts +4 -2
  310. package/template/packages/modules/src/manifest.ts +7 -12
  311. package/template/packages/modules/src/menu-composition.ts +1 -1
  312. package/template/packages/modules/src/system-api-binding.ts +1 -1
  313. package/template/packages/modules/src/system-api-data-governance.ts +1 -1
  314. package/template/packages/modules/src/system-api-permissions.ts +1 -1
  315. package/template/packages/modules/src/system-data-governance.ts +1 -1
  316. package/template/packages/modules/src/system-features.ts +1 -1
  317. package/template/packages/modules/src/system-governed-export-bindings.ts +1 -1
  318. package/template/packages/modules/src/system-module-catalog.ts +1 -1
  319. package/template/packages/server-sdk/index.ts +5 -0
  320. package/template/packages/server-sdk/package.json +25 -0
  321. package/template/packages/server-sdk/src/module-host.ts +29 -0
  322. package/template/packages/server-sdk/tsconfig.json +16 -0
  323. package/template/packages/shared/index.ts +2 -0
  324. package/template/packages/shared/package.json +14 -3
  325. package/template/packages/shared/src/audit.ts +22 -1
  326. package/template/packages/shared/src/license-catalog.test.ts +17 -0
  327. package/template/packages/shared/src/license-catalog.ts +33 -0
  328. package/template/packages/shared/src/migration.ts +39 -0
  329. package/template/packages/storage/package.json +14 -3
  330. package/template/packages/license-sdk/index.ts +0 -13
  331. package/template/packages/license-sdk/package.json +0 -18
  332. package/template/packages/license-sdk/src/bounded-json-body.test.ts +0 -65
  333. package/template/packages/license-sdk/src/bounded-json-body.ts +0 -135
  334. package/template/packages/license-sdk/src/canonical-json.test.ts +0 -28
  335. package/template/packages/license-sdk/src/canonical-json.ts +0 -104
  336. package/template/packages/license-sdk/src/client.test.ts +0 -82
  337. package/template/packages/license-sdk/src/client.ts +0 -86
  338. package/template/packages/license-sdk/src/device.ts +0 -46
  339. package/template/packages/license-sdk/src/file-storage.test.ts +0 -80
  340. package/template/packages/license-sdk/src/file-storage.ts +0 -77
  341. package/template/packages/license-sdk/src/installation.test.ts +0 -241
  342. package/template/packages/license-sdk/src/installation.ts +0 -150
  343. package/template/packages/license-sdk/src/license-parser.ts +0 -56
  344. package/template/packages/license-sdk/src/offline-code-base32.ts +0 -57
  345. package/template/packages/license-sdk/src/offline-code-decompression.ts +0 -55
  346. package/template/packages/license-sdk/src/offline-code-limits.ts +0 -10
  347. package/template/packages/license-sdk/src/offline-code-wire.ts +0 -72
  348. package/template/packages/license-sdk/src/offline-code.test.ts +0 -172
  349. package/template/packages/license-sdk/src/offline-code.ts +0 -319
  350. package/template/packages/license-sdk/src/payload.test.ts +0 -72
  351. package/template/packages/license-sdk/src/payload.ts +0 -201
  352. package/template/packages/license-sdk/src/storage.ts +0 -64
  353. package/template/packages/license-sdk/src/test-fixtures.ts +0 -59
  354. package/template/packages/license-sdk/src/v1-test-vector.ts +0 -49
  355. package/template/packages/license-sdk/src/validation.test.ts +0 -62
  356. package/template/packages/license-sdk/src/validation.ts +0 -143
  357. package/template/packages/license-sdk/src/verification.test.ts +0 -97
  358. package/template/packages/license-sdk/src/verification.ts +0 -199
@@ -1,23 +1,20 @@
1
1
  import { describe, expect, test } from "bun:test";
2
- import type { ModuleManifest } from "@windy/modules";
2
+ import {
3
+ MIGRATION_BUNDLE_FORMAT_VERSION,
4
+ type MigrationBundle,
5
+ type MigrationManifestSource,
6
+ } from "@southwind-ai/shared";
3
7
  import { PlatformMigrationRunner } from "./runner.js";
4
8
  import { InMemoryMigrationHistoryStore } from "./store.js";
5
9
 
6
10
  function moduleFixture(
7
11
  name: string,
8
12
  dependencies: string[] = [],
9
- ): ModuleManifest {
13
+ ): MigrationManifestSource {
10
14
  return {
11
15
  name,
12
16
  version: "0.1.0",
13
- label: name,
14
- description: `${name} module`,
15
17
  dependencies,
16
- menus: [],
17
- adminRoutes: [],
18
- permissions: [],
19
- apiPermissions: [],
20
- features: [],
21
18
  migrations: [
22
19
  {
23
20
  id: `${name}.001`,
@@ -32,10 +29,30 @@ function moduleFixture(
32
29
  },
33
30
  ],
34
31
  schemaExports: [],
35
- tasks: [],
36
- tools: [],
37
- providers: [],
38
- auditActions: [],
32
+ };
33
+ }
34
+
35
+ function bundleFixture(
36
+ module: string,
37
+ ids: readonly string[] = [`${module}.001`],
38
+ dependencies: readonly string[] = [],
39
+ ): MigrationBundle {
40
+ return {
41
+ formatVersion: MIGRATION_BUNDLE_FORMAT_VERSION,
42
+ module,
43
+ version: "1.0.0",
44
+ dependencies,
45
+ migrations: ids.map((id, index) => ({
46
+ id,
47
+ module,
48
+ description: `migration ${index + 1}`,
49
+ direction: "up",
50
+ checksum: `sha256:${module}-${index + 1}`,
51
+ dependsOn: index === 0 ? [] : [ids[index - 1]],
52
+ async run(context) {
53
+ await context.execute({ sql: `select '${id}'` });
54
+ },
55
+ })),
39
56
  };
40
57
  }
41
58
 
@@ -93,4 +110,134 @@ describe("PlatformMigrationRunner", () => {
93
110
  expect(report.applied).toEqual(["audit.001"]);
94
111
  expect(executed).toEqual(["create table audit (id varchar(36))"]);
95
112
  });
113
+
114
+ test("fresh bundle 按模块与迁移依赖顺序执行并记录 checksum", async () => {
115
+ const store = new InMemoryMigrationHistoryStore();
116
+ const executed: string[] = [];
117
+ const runner = new PlatformMigrationRunner({
118
+ dialect: "postgresql",
119
+ store,
120
+ execute: async ({ sql }) => {
121
+ executed.push(sql);
122
+ },
123
+ });
124
+ const feature = bundleFixture(
125
+ "feature",
126
+ ["feature.002", "feature.001"],
127
+ ["system"],
128
+ );
129
+ feature.migrations[0].dependsOn = ["feature.001"];
130
+ feature.migrations[1].dependsOn = [];
131
+
132
+ const report = await runner.runBundles([feature, bundleFixture("system")]);
133
+
134
+ expect(report.applied).toEqual([
135
+ "system.001",
136
+ "feature.001",
137
+ "feature.002",
138
+ ]);
139
+ expect(executed).toEqual([
140
+ "select 'system.001'",
141
+ "select 'feature.001'",
142
+ "select 'feature.002'",
143
+ ]);
144
+ expect((await store.listApplied())[0]?.checksum).toBe("sha256:system-1");
145
+ });
146
+
147
+ test("repeat bundle 跳过 checksum 相同的已应用迁移", async () => {
148
+ const store = new InMemoryMigrationHistoryStore();
149
+ const runner = new PlatformMigrationRunner({
150
+ dialect: "postgresql",
151
+ store,
152
+ });
153
+ const bundle = bundleFixture("orders");
154
+
155
+ await runner.runBundles([bundle]);
156
+ const repeated = await runner.runBundles([bundle]);
157
+
158
+ expect(repeated.applied).toEqual([]);
159
+ expect(repeated.planned[0]).toMatchObject({
160
+ id: "orders.001",
161
+ checksum: "sha256:orders-1",
162
+ skipped: true,
163
+ skipReason: "already-applied",
164
+ });
165
+ });
166
+
167
+ test("执行失败后停止后续 migration", async () => {
168
+ const executed: string[] = [];
169
+ const bundle = bundleFixture("orders", [
170
+ "orders.001",
171
+ "orders.002",
172
+ "orders.003",
173
+ ]);
174
+ const runner = new PlatformMigrationRunner({
175
+ dialect: "postgresql",
176
+ store: new InMemoryMigrationHistoryStore(),
177
+ execute: async ({ sql }) => {
178
+ executed.push(sql);
179
+ if (sql.includes("002")) throw new Error("database unavailable");
180
+ },
181
+ });
182
+
183
+ const report = await runner.runBundles([bundle]);
184
+
185
+ expect(report.applied).toEqual(["orders.001"]);
186
+ expect(report.failed).toEqual([
187
+ { id: "orders.002", error: "database unavailable" },
188
+ ]);
189
+ expect(executed).toEqual(["select 'orders.001'", "select 'orders.002'"]);
190
+ });
191
+
192
+ test("拒绝错误模块归属和重复 migration id", async () => {
193
+ const runner = new PlatformMigrationRunner({
194
+ dialect: "postgresql",
195
+ store: new InMemoryMigrationHistoryStore(),
196
+ });
197
+ const wrongOwner = bundleFixture("orders");
198
+ wrongOwner.migrations[0].module = "billing";
199
+
200
+ await expect(runner.planBundles([wrongOwner])).rejects.toThrow(
201
+ "模块归属应为 orders",
202
+ );
203
+
204
+ const first = bundleFixture("orders", ["shared.001"]);
205
+ const second = bundleFixture("billing", ["shared.001"]);
206
+ await expect(runner.planBundles([first, second])).rejects.toThrow(
207
+ "Migration ID 重复:shared.001",
208
+ );
209
+ });
210
+
211
+ test("拒绝已应用 migration 的 checksum 漂移", async () => {
212
+ const store = new InMemoryMigrationHistoryStore();
213
+ const runner = new PlatformMigrationRunner({
214
+ dialect: "postgresql",
215
+ store,
216
+ });
217
+ const bundle = bundleFixture("orders");
218
+ await runner.runBundles([bundle]);
219
+ bundle.migrations[0].checksum = "sha256:changed";
220
+
221
+ await expect(runner.planBundles([bundle])).rejects.toThrow(
222
+ "checksum 与当前 Bundle 不一致",
223
+ );
224
+ });
225
+
226
+ test("Manifest schemaExports 只能引用所属 bundle migration", async () => {
227
+ const manifest = moduleFixture("orders");
228
+ manifest.schemaExports = [
229
+ {
230
+ key: "orders.schema",
231
+ migrationIds: ["orders.missing"],
232
+ },
233
+ ];
234
+ const runner = new PlatformMigrationRunner({
235
+ dialect: "postgresql",
236
+ store: new InMemoryMigrationHistoryStore(),
237
+ });
238
+
239
+ await expect(runner.plan([manifest])).rejects.toThrow(
240
+ "Bundle 中不存在的 Migration:orders.missing",
241
+ );
242
+ });
96
243
  });
@@ -1,11 +1,18 @@
1
- import type { MigrationDefinition, ModuleManifest } from "@windy/modules";
2
1
  import type {
2
+ BundleMigrationDefinition,
3
3
  DatabaseCompatibilityAdapter,
4
4
  DatabaseDialect,
5
+ MigrationBundle,
6
+ MigrationManifestSource,
5
7
  MigrationStatement,
6
- } from "@windy/shared";
8
+ } from "@southwind-ai/shared";
9
+ import {
10
+ normalizeManifestBundles,
11
+ orderBundleMigrations,
12
+ validateAndOrderBundles,
13
+ } from "./bundle-validation.js";
7
14
  import { createDialectAdapter } from "./dialects.js";
8
- import type { MigrationHistoryStore } from "./store.js";
15
+ import type { MigrationHistoryEntry, MigrationHistoryStore } from "./store.js";
9
16
 
10
17
  export interface MigrationRunnerOptions {
11
18
  dialect: DatabaseDialect;
@@ -19,8 +26,9 @@ export interface MigrationPlanItem {
19
26
  module: string;
20
27
  description: string;
21
28
  direction: "up" | "down";
29
+ checksum: string;
22
30
  skipped: boolean;
23
- skipReason?: string;
31
+ skipReason?: "already-applied";
24
32
  }
25
33
 
26
34
  export interface MigrationRunReport {
@@ -47,45 +55,51 @@ export class PlatformMigrationRunner {
47
55
  this.now = options.now || (() => new Date());
48
56
  }
49
57
 
50
- async plan(modules: ModuleManifest[]): Promise<MigrationPlanItem[]> {
51
- const appliedIds = new Set(
52
- (await this.options.store.listApplied()).map((entry) => entry.id),
53
- );
58
+ async plan(modules: readonly MigrationManifestSource[]) {
59
+ return this.planBundles(normalizeManifestBundles(modules));
60
+ }
54
61
 
55
- return sortModulesByDependency(modules).flatMap((module) =>
56
- module.migrations.map((migration) => ({
57
- id: migration.id,
58
- module: migration.module,
59
- description: migration.description,
60
- direction: migration.direction,
61
- skipped: appliedIds.has(migration.id),
62
- skipReason: appliedIds.has(migration.id)
63
- ? "already-applied"
64
- : undefined,
65
- })),
62
+ async planBundles(
63
+ bundles: readonly MigrationBundle[],
64
+ ): Promise<MigrationPlanItem[]> {
65
+ const ordered = validateAndOrderBundles(bundles);
66
+ const applied = appliedById(await this.options.store.listApplied());
67
+ return ordered.flatMap((bundle) =>
68
+ orderBundleMigrations(bundle).map((migration) =>
69
+ planItem(migration, applied.get(migration.id)),
70
+ ),
66
71
  );
67
72
  }
68
73
 
69
74
  async run(
70
- modules: ModuleManifest[],
75
+ modules: readonly MigrationManifestSource[],
76
+ dryRun = false,
77
+ ): Promise<MigrationRunReport> {
78
+ return this.runBundles(normalizeManifestBundles(modules), dryRun);
79
+ }
80
+
81
+ async runBundles(
82
+ bundles: readonly MigrationBundle[],
71
83
  dryRun = false,
72
84
  ): Promise<MigrationRunReport> {
73
85
  const startedAt = this.now().toISOString();
74
- const planned = await this.plan(modules);
75
- const migrations = collectMigrations(modules);
86
+ const ordered = validateAndOrderBundles(bundles);
87
+ const planned = await this.planBundles(ordered);
88
+ const migrations = new Map(
89
+ ordered.flatMap((bundle) =>
90
+ bundle.migrations.map(
91
+ (migration) => [migration.id, migration] as const,
92
+ ),
93
+ ),
94
+ );
76
95
  const applied: string[] = [];
77
96
  const failed: Array<{ id: string; error: string }> = [];
78
97
  const statements: MigrationStatement[] = [];
79
98
 
80
99
  for (const item of planned) {
81
- if (item.skipped) {
82
- continue;
83
- }
84
-
100
+ if (item.skipped) continue;
85
101
  const migration = migrations.get(item.id);
86
- if (!migration) {
87
- continue;
88
- }
102
+ if (!migration) throw new Error(`Migration ${item.id} 不存在`);
89
103
 
90
104
  const stepStartedAt = this.now().toISOString();
91
105
  const stepStatements: MigrationStatement[] = [];
@@ -97,34 +111,19 @@ export class PlatformMigrationRunner {
97
111
  execute: async (statement) => {
98
112
  statements.push(statement);
99
113
  stepStatements.push(statement);
100
- if (!dryRun) {
101
- await this.executeStatement(statement);
102
- }
114
+ if (!dryRun) await this.executeStatement(statement);
103
115
  },
104
116
  });
105
117
  applied.push(item.id);
106
- await this.options.store.record({
107
- id: item.id,
108
- module: item.module,
109
- direction: item.direction,
110
- status: "applied",
111
- startedAt: stepStartedAt,
112
- finishedAt: this.now().toISOString(),
113
- statements: stepStatements.map((statement) => statement.sql),
114
- });
118
+ if (!dryRun) {
119
+ await this.recordResult(item, stepStartedAt, stepStatements);
120
+ }
115
121
  } catch (error) {
116
122
  const message = error instanceof Error ? error.message : String(error);
117
123
  failed.push({ id: item.id, error: message });
118
- await this.options.store.record({
119
- id: item.id,
120
- module: item.module,
121
- direction: item.direction,
122
- status: "failed",
123
- startedAt: stepStartedAt,
124
- finishedAt: this.now().toISOString(),
125
- statements: stepStatements.map((statement) => statement.sql),
126
- error: message,
127
- });
124
+ if (!dryRun) {
125
+ await this.recordResult(item, stepStartedAt, stepStatements, message);
126
+ }
128
127
  break;
129
128
  }
130
129
  }
@@ -140,36 +139,55 @@ export class PlatformMigrationRunner {
140
139
  statements,
141
140
  };
142
141
  }
143
- }
144
142
 
145
- function collectMigrations(
146
- modules: ModuleManifest[],
147
- ): Map<string, MigrationDefinition> {
148
- return new Map(
149
- modules
150
- .flatMap((module) => module.migrations)
151
- .map((migration) => [migration.id, migration]),
152
- );
143
+ private async recordResult(
144
+ item: MigrationPlanItem,
145
+ startedAt: string,
146
+ statements: readonly MigrationStatement[],
147
+ error?: string,
148
+ ): Promise<void> {
149
+ await this.options.store.record({
150
+ id: item.id,
151
+ module: item.module,
152
+ direction: item.direction,
153
+ status: error ? "failed" : "applied",
154
+ checksum: item.checksum,
155
+ startedAt,
156
+ finishedAt: this.now().toISOString(),
157
+ statements: statements.map(({ sql }) => sql),
158
+ error,
159
+ });
160
+ }
153
161
  }
154
162
 
155
- function sortModulesByDependency(modules: ModuleManifest[]): ModuleManifest[] {
156
- const pending = new Map(modules.map((module) => [module.name, module]));
157
- const sorted: ModuleManifest[] = [];
163
+ function appliedById(entries: readonly MigrationHistoryEntry[]) {
164
+ return new Map(entries.map((entry) => [entry.id, entry]));
165
+ }
158
166
 
159
- while (pending.size > 0) {
160
- const ready = Array.from(pending.values()).find((module) =>
161
- (module.dependencies || []).every(
162
- (dependency) => !pending.has(dependency),
163
- ),
167
+ function planItem(
168
+ migration: BundleMigrationDefinition,
169
+ applied: MigrationHistoryEntry | undefined,
170
+ ): MigrationPlanItem {
171
+ if (applied?.module !== undefined && applied.module !== migration.module) {
172
+ throw new Error(
173
+ `已应用 Migration ${migration.id} 归属 ${applied.module},当前归属 ${migration.module}`,
164
174
  );
165
-
166
- if (!ready) {
167
- throw new Error("模块依赖存在循环,无法生成迁移计划");
168
- }
169
-
170
- sorted.push(ready);
171
- pending.delete(ready.name);
172
175
  }
173
-
174
- return sorted;
176
+ if (
177
+ applied?.checksum !== undefined &&
178
+ applied.checksum !== migration.checksum
179
+ ) {
180
+ throw new Error(
181
+ `已应用 Migration ${migration.id} checksum 与当前 Bundle 不一致`,
182
+ );
183
+ }
184
+ return {
185
+ id: migration.id,
186
+ module: migration.module,
187
+ description: migration.description,
188
+ direction: migration.direction,
189
+ checksum: migration.checksum,
190
+ skipped: Boolean(applied),
191
+ skipReason: applied ? "already-applied" : undefined,
192
+ };
175
193
  }
@@ -1,5 +1,5 @@
1
1
  import { sql } from "drizzle-orm";
2
- import type { LifecycleStatus } from "@windy/shared";
2
+ import type { LifecycleStatus } from "@southwind-ai/shared";
3
3
  import {
4
4
  boolean,
5
5
  check,
@@ -12,7 +12,7 @@ import {
12
12
  } from "drizzle-orm/pg-core";
13
13
  import { sql } from "drizzle-orm";
14
14
  import { auditColumns, idColumn, statusColumn } from "./common.js";
15
- import type { CredentialState } from "@windy/shared";
15
+ import type { CredentialState } from "@southwind-ai/shared";
16
16
 
17
17
  export const departments = pgTable(
18
18
  "departments",
@@ -1,4 +1,4 @@
1
- import type { LicenseV1Claims, LicenseVersionKey } from "@windy/shared";
1
+ import type { LicenseV1Claims, LicenseVersionKey } from "@southwind-ai/shared";
2
2
  import { sql } from "drizzle-orm";
3
3
  import {
4
4
  check,
@@ -8,7 +8,7 @@ import {
8
8
  uniqueIndex,
9
9
  varchar,
10
10
  } from "drizzle-orm/pg-core";
11
- import type { TargetRef } from "@windy/shared";
11
+ import type { TargetRef } from "@southwind-ai/shared";
12
12
  import { auditColumns, idColumn, statusColumn } from "./common.js";
13
13
  import { users } from "./identity.js";
14
14
 
@@ -2,7 +2,7 @@
2
2
  export {};
3
3
 
4
4
  // @windy-module system.configuration begin
5
- import type { ModuleConfigDiffEntry, ModuleConfigValues } from "@windy/shared";
5
+ import type { ModuleConfigDiffEntry, ModuleConfigValues } from "@southwind-ai/shared";
6
6
  import {
7
7
  index,
8
8
  integer,
@@ -10,7 +10,7 @@ import {
10
10
  uniqueIndex,
11
11
  varchar,
12
12
  } from "drizzle-orm/pg-core";
13
- import type { CandidateRole, TargetRef, WorkItem } from "@windy/shared";
13
+ import type { CandidateRole, TargetRef, WorkItem } from "@southwind-ai/shared";
14
14
 
15
15
  export const workflowWorkItems = pgTable(
16
16
  "workflow_work_items",
@@ -1,4 +1,4 @@
1
- import type { MigrationStatement } from "@windy/shared";
1
+ import type { MigrationStatement } from "@southwind-ai/shared";
2
2
  import type { MigrationHistoryEntry, MigrationHistoryStore } from "./store.js";
3
3
 
4
4
  export interface QueryResult<Row> {
@@ -1,4 +1,4 @@
1
- import type { ISODateTime } from "@windy/shared";
1
+ import type { ISODateTime } from "@southwind-ai/shared";
2
2
 
3
3
  export type MigrationStatus = "applied" | "failed";
4
4
 
@@ -1,3 +1,4 @@
1
1
  export * from "./src/contract.js";
2
2
  export * from "./src/manifest.js";
3
+ export * from "./src/migration-bundle.js";
3
4
  export * from "./src/schema.js";
@@ -1,13 +1,14 @@
1
1
  {
2
- "name": "@windy/example-work-order",
2
+ "name": "@southwind-ai/example-work-order",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@windy/shared": "workspace:*",
7
+ "@southwind-ai/shared": "workspace:*",
8
8
  "zod": "^4.4.3"
9
9
  },
10
10
  "exports": {
11
- ".": "./index.ts"
11
+ ".": "./index.ts",
12
+ "./migration-bundle": "./src/migration-bundle.ts"
12
13
  }
13
14
  }
@@ -2,7 +2,7 @@ import type {
2
2
  EntityAuditFields,
3
3
  LifecycleStatus,
4
4
  PageResult,
5
- } from "@windy/shared";
5
+ } from "@southwind-ai/shared";
6
6
 
7
7
  export const workOrderPriorities = ["low", "medium", "high"] as const;
8
8
  export const workOrderWorkflowStatuses = [
@@ -2,7 +2,11 @@ import {
2
2
  defineSearchProvider,
3
3
  featureKey,
4
4
  licenseVersionKey,
5
- } from "@windy/shared";
5
+ } from "@southwind-ai/shared";
6
+ import {
7
+ WORK_ORDER_INITIAL_MIGRATION_ID,
8
+ workOrderMigrationBundle,
9
+ } from "./migration-bundle.js";
6
10
 
7
11
  const FEATURE_KEY = featureKey("work-order.ticket");
8
12
 
@@ -41,12 +45,13 @@ export function workOrderModule() {
41
45
  ],
42
46
  },
43
47
  ],
44
- migrations: [],
48
+ migrations: [...workOrderMigrationBundle.migrations],
49
+ migrationBundle: workOrderMigrationBundle,
45
50
  schemaExports: [
46
51
  {
47
52
  key: "work-order.database.schema",
48
53
  exportName: "workOrders",
49
- migrationIds: ["0018_cheerful_alex_power"],
54
+ migrationIds: [WORK_ORDER_INITIAL_MIGRATION_ID],
50
55
  },
51
56
  ],
52
57
  tasks: [
@@ -0,0 +1,43 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import type {
3
+ DatabaseCompatibilityAdapter,
4
+ MigrationStatement,
5
+ } from "@southwind-ai/shared";
6
+ import { workOrderModule } from "./manifest.js";
7
+ import {
8
+ WORK_ORDER_INITIAL_MIGRATION_ID,
9
+ workOrderMigrationBundle,
10
+ } from "./migration-bundle.js";
11
+
12
+ describe("示例工单 Migration Bundle", () => {
13
+ test("业务包自持 bundle 并与 Manifest Schema Export 闭环", () => {
14
+ const manifest = workOrderModule();
15
+
16
+ expect(manifest.migrationBundle).toBe(workOrderMigrationBundle);
17
+ expect(manifest.migrations.map(({ id }) => id)).toEqual([
18
+ WORK_ORDER_INITIAL_MIGRATION_ID,
19
+ ]);
20
+ expect(manifest.schemaExports[0]?.migrationIds).toEqual([
21
+ WORK_ORDER_INITIAL_MIGRATION_ID,
22
+ ]);
23
+ });
24
+
25
+ test("安装 SQL 只包含 work_orders 表与索引且使用幂等建表", async () => {
26
+ const statements: MigrationStatement[] = [];
27
+ await workOrderMigrationBundle.migrations[0].run({
28
+ dialect: "postgresql",
29
+ dryRun: true,
30
+ adapter: {} as DatabaseCompatibilityAdapter,
31
+ execute(statement) {
32
+ statements.push(statement);
33
+ return Promise.resolve();
34
+ },
35
+ });
36
+ const sql = statements.map(({ sql: statement }) => statement).join("\n");
37
+
38
+ expect(sql).toContain("create table if not exists work_orders");
39
+ expect(sql).toContain("create index if not exists idx_work_orders_owner");
40
+ expect(sql).not.toContain("feature_flags");
41
+ expect(sql).not.toContain("license");
42
+ });
43
+ });
@@ -0,0 +1,64 @@
1
+ import {
2
+ MIGRATION_BUNDLE_FORMAT_VERSION,
3
+ type MigrationBundle,
4
+ type MigrationExecutionContext,
5
+ } from "@southwind-ai/shared";
6
+
7
+ export const WORK_ORDER_INITIAL_MIGRATION_ID =
8
+ "work-order.0001.create-work-orders";
9
+
10
+ export const workOrderMigrationBundle: MigrationBundle = {
11
+ formatVersion: MIGRATION_BUNDLE_FORMAT_VERSION,
12
+ module: "work-order",
13
+ version: "0.1.0",
14
+ migrations: [
15
+ {
16
+ id: WORK_ORDER_INITIAL_MIGRATION_ID,
17
+ module: "work-order",
18
+ description: "创建示例工单表及查询索引",
19
+ direction: "up",
20
+ checksum:
21
+ "sha256:cb97709a8680fabf46bff40e33d29e12255969bb54d232d7ea633324dc77ce33",
22
+ async run(context) {
23
+ for (const statement of workOrderStatements(context)) {
24
+ await context.execute({ sql: statement });
25
+ }
26
+ },
27
+ },
28
+ ],
29
+ };
30
+
31
+ function workOrderStatements(context: MigrationExecutionContext): string[] {
32
+ const timestamp =
33
+ context.dialect === "mysql" ? "datetime" : "timestamp with time zone";
34
+ const createTable = `create table if not exists work_orders (
35
+ id varchar(64) primary key not null,
36
+ title varchar(120) not null,
37
+ description text not null,
38
+ priority varchar(24) not null,
39
+ workflow_status varchar(32) not null,
40
+ owner_id varchar(64) not null,
41
+ department_id varchar(64),
42
+ status varchar(32) not null,
43
+ created_at ${timestamp} default current_timestamp not null,
44
+ created_by varchar(64) not null,
45
+ updated_at ${timestamp} default current_timestamp not null,
46
+ updated_by varchar(64) not null,
47
+ deleted_at ${timestamp},
48
+ deleted_by varchar(64)
49
+ )`;
50
+ const optionalClause =
51
+ context.dialect === "postgresql" || context.dialect === "kingbase"
52
+ ? " if not exists"
53
+ : "";
54
+ const indexes = [
55
+ ["idx_work_orders_owner", "owner_id"],
56
+ ["idx_work_orders_department", "department_id"],
57
+ ["idx_work_orders_status", "status"],
58
+ ["idx_work_orders_workflow", "workflow_status"],
59
+ ].map(
60
+ ([name, column]) =>
61
+ `create index${optionalClause} ${name} on work_orders (${column})`,
62
+ );
63
+ return [createTable, ...indexes];
64
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./src/handlers.js";
2
+ export * from "./src/types.js";