@tailor-platform/sdk 2.0.0-next.1 → 2.0.0-next.11

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 (478) hide show
  1. package/CHANGELOG.md +1056 -24
  2. package/README.md +9 -9
  3. package/agent-skills/{tailor-sdk → tailor}/SKILL.md +3 -1
  4. package/dist/aigateway-DR4Kwuik.mjs +9 -0
  5. package/dist/aigateway-DR4Kwuik.mjs.map +1 -0
  6. package/dist/{application-DqS1yBg3.mjs → application-CM6hKnSK.mjs} +2155 -2008
  7. package/dist/application-CM6hKnSK.mjs.map +1 -0
  8. package/dist/application-CXNaUNhv.mjs +3 -0
  9. package/dist/authconnection-CZvi9ANm.mjs +9 -0
  10. package/dist/authconnection-CZvi9ANm.mjs.map +1 -0
  11. package/dist/brand-Eo4pLXPJ.mjs.map +1 -1
  12. package/dist/cli/cache/bundle-cache.d.mts +2 -0
  13. package/dist/cli/cache/store.d.mts +1 -0
  14. package/dist/cli/cache/types.d.mts +1 -0
  15. package/dist/cli/commands/api/api-call.d.mts +19 -0
  16. package/dist/cli/commands/api/index.d.mts +4 -0
  17. package/dist/cli/commands/deploy/aigateway.d.mts +5 -0
  18. package/dist/cli/commands/deploy/application.d.mts +7 -0
  19. package/dist/cli/commands/deploy/apply-phases.d.mts +14 -0
  20. package/dist/cli/commands/deploy/auth.d.mts +5 -0
  21. package/dist/cli/commands/deploy/deploy.d.mts +35 -0
  22. package/dist/cli/commands/deploy/executor.d.mts +7 -0
  23. package/dist/cli/commands/deploy/function-registry-types.d.mts +12 -0
  24. package/dist/cli/commands/deploy/function-registry.d.mts +6 -0
  25. package/dist/cli/commands/deploy/idp.d.mts +5 -0
  26. package/dist/cli/commands/deploy/label.d.mts +2 -0
  27. package/dist/cli/commands/deploy/resolver.d.mts +5 -0
  28. package/dist/cli/commands/deploy/secret-manager.d.mts +5 -0
  29. package/dist/cli/commands/deploy/staticwebsite.d.mts +5 -0
  30. package/dist/cli/commands/deploy/tailordb/index.d.mts +10 -0
  31. package/dist/cli/commands/deploy/types.d.mts +4 -0
  32. package/dist/cli/commands/deploy/workflow-execution-policy.d.mts +2 -0
  33. package/dist/cli/commands/deploy/workflow.d.mts +4 -0
  34. package/dist/cli/commands/executor/get.d.mts +19 -0
  35. package/dist/cli/commands/executor/jobs.d.mts +85 -0
  36. package/dist/cli/commands/executor/list.d.mts +18 -0
  37. package/dist/cli/commands/executor/transform.d.mts +42 -0
  38. package/dist/cli/commands/executor/trigger.d.mts +30 -0
  39. package/dist/cli/commands/executor/webhook.d.mts +21 -0
  40. package/dist/cli/commands/function/get.d.mts +17 -0
  41. package/dist/cli/commands/function/list.d.mts +21 -0
  42. package/dist/cli/commands/function/transform.d.mts +12 -0
  43. package/dist/cli/commands/generate/options.d.mts +6 -0
  44. package/dist/cli/commands/generate/seed/bundler.d.mts +27 -0
  45. package/dist/cli/commands/generate/service.d.mts +15 -0
  46. package/dist/cli/commands/machineuser/list.d.mts +26 -0
  47. package/dist/cli/commands/machineuser/token.d.mts +21 -0
  48. package/dist/cli/commands/oauth2client/get.d.mts +17 -0
  49. package/dist/cli/commands/oauth2client/list.d.mts +19 -0
  50. package/dist/cli/commands/oauth2client/transform.d.mts +21 -0
  51. package/dist/cli/commands/organization/folder/create.d.mts +17 -0
  52. package/dist/cli/commands/organization/folder/delete.d.mts +15 -0
  53. package/dist/cli/commands/organization/folder/get.d.mts +16 -0
  54. package/dist/cli/commands/organization/folder/list.d.mts +21 -0
  55. package/dist/cli/commands/organization/folder/update.d.mts +17 -0
  56. package/dist/cli/commands/organization/get.d.mts +15 -0
  57. package/dist/cli/commands/organization/list.d.mts +14 -0
  58. package/dist/cli/commands/organization/transform.d.mts +29 -0
  59. package/dist/cli/commands/organization/tree.d.mts +24 -0
  60. package/dist/cli/commands/organization/update.d.mts +16 -0
  61. package/dist/cli/commands/remove.d.mts +15 -0
  62. package/dist/cli/commands/show.d.mts +39 -0
  63. package/dist/cli/commands/staticwebsite/deploy.d.mts +19 -0
  64. package/dist/cli/commands/tailordb/migrate/bundler.d.mts +29 -0
  65. package/dist/cli/commands/tailordb/migrate/config.d.mts +18 -0
  66. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +246 -0
  67. package/dist/cli/commands/tailordb/migrate/generate.d.mts +16 -0
  68. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +5 -0
  69. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +208 -0
  70. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +98 -0
  71. package/dist/cli/commands/tailordb/migrate/types.d.mts +7 -0
  72. package/dist/cli/commands/tailordb/truncate.d.mts +18 -0
  73. package/dist/cli/commands/workflow/executions.d.mts +62 -0
  74. package/dist/cli/commands/workflow/get.d.mts +21 -0
  75. package/dist/cli/commands/workflow/list.d.mts +18 -0
  76. package/dist/cli/commands/workflow/resume.d.mts +22 -0
  77. package/dist/cli/commands/workflow/start.d.mts +48 -0
  78. package/dist/cli/commands/workflow/status.d.mts +6 -0
  79. package/dist/cli/commands/workflow/transform.d.mts +34 -0
  80. package/dist/cli/commands/workflow/wait.d.mts +15 -0
  81. package/dist/cli/commands/workflow/waiter.d.mts +23 -0
  82. package/dist/cli/commands/workspace/app/health.d.mts +17 -0
  83. package/dist/cli/commands/workspace/app/list.d.mts +21 -0
  84. package/dist/cli/commands/workspace/app/transform.d.mts +20 -0
  85. package/dist/cli/commands/workspace/create.d.mts +27 -0
  86. package/dist/cli/commands/workspace/delete.d.mts +14 -0
  87. package/dist/cli/commands/workspace/get.d.mts +16 -0
  88. package/dist/cli/commands/workspace/list.d.mts +17 -0
  89. package/dist/cli/commands/workspace/restore.d.mts +14 -0
  90. package/dist/cli/commands/workspace/transform.d.mts +20 -0
  91. package/dist/cli/commands/workspace/user/invite.d.mts +21 -0
  92. package/dist/cli/commands/workspace/user/list.d.mts +21 -0
  93. package/dist/cli/commands/workspace/user/remove.d.mts +16 -0
  94. package/dist/cli/commands/workspace/user/transform.d.mts +9 -0
  95. package/dist/cli/commands/workspace/user/update.d.mts +21 -0
  96. package/dist/cli/index.mjs +12 -5481
  97. package/dist/cli/lib.d.mts +86 -21048
  98. package/dist/cli/lib.mjs +245 -46
  99. package/dist/cli/lib.mjs.map +1 -1
  100. package/dist/cli/main.d.mts +23 -0
  101. package/dist/cli/main.mjs +6777 -0
  102. package/dist/cli/main.mjs.map +1 -0
  103. package/dist/cli/query/index.d.mts +38 -0
  104. package/dist/cli/services/application.d.mts +12 -0
  105. package/dist/cli/services/auth/service.d.mts +3 -0
  106. package/dist/cli/services/executor/service.d.mts +1 -0
  107. package/dist/cli/services/http-adapter/bundler.d.mts +4 -0
  108. package/dist/cli/services/http-adapter/service.d.mts +2 -0
  109. package/dist/cli/services/resolver/service.d.mts +1 -0
  110. package/dist/cli/services/tailordb/service.d.mts +3 -0
  111. package/dist/cli/services/workflow/bundler.d.mts +3 -0
  112. package/dist/cli/services/workflow/service.d.mts +1 -0
  113. package/dist/cli/shared/args.d.mts +13 -0
  114. package/dist/cli/shared/client.d.mts +1298 -0
  115. package/dist/cli/shared/config-loader.d.mts +32 -0
  116. package/dist/cli/shared/context.d.mts +29 -0
  117. package/dist/cli/shared/error-json.d.mts +23 -0
  118. package/dist/cli/shared/readonly-guard.d.mts +25 -0
  119. package/dist/cli/shared/script-executor.d.mts +77 -0
  120. package/dist/cli/shared/seed-chunker.d.mts +45 -0
  121. package/dist/cli/shared/seed-context.d.mts +49 -0
  122. package/dist/cli/shared/tailordb-namespaces.d.mts +40 -0
  123. package/dist/cli/shared/tsconfig-paths-plugin.d.mts +2 -0
  124. package/dist/cli/shared/type-generator.d.mts +20 -0
  125. package/dist/cli/shared/workspace-name.d.mts +1 -0
  126. package/dist/cli/ts-hook.d.mts +4 -0
  127. package/dist/cli/ts-hook.mjs +333 -0
  128. package/dist/completion/zsh-worker.zsh +1471 -1217
  129. package/dist/configure/config/index.d.mts +20 -0
  130. package/dist/configure/config/types.d.mts +134 -0
  131. package/dist/configure/index.d.mts +135 -8
  132. package/dist/configure/index.mjs +558 -36
  133. package/dist/configure/index.mjs.map +1 -1
  134. package/dist/configure/services/aigateway/index.d.mts +16 -0
  135. package/dist/configure/services/aigateway/types.d.mts +10 -0
  136. package/dist/configure/services/auth/index.d.mts +33 -0
  137. package/dist/configure/services/auth/types.d.mts +168 -0
  138. package/dist/configure/services/executor/executor.d.mts +70 -0
  139. package/dist/configure/services/executor/index.d.mts +9 -0
  140. package/dist/configure/services/executor/operation.d.mts +50 -0
  141. package/dist/configure/services/executor/trigger/event.d.mts +514 -0
  142. package/dist/configure/services/executor/trigger/index.d.mts +7 -0
  143. package/dist/configure/services/executor/trigger/schedule.d.mts +24 -0
  144. package/dist/configure/services/executor/trigger/webhook.d.mts +43 -0
  145. package/dist/configure/services/executor/types.d.mts +2 -0
  146. package/dist/configure/services/http-adapter/http-adapter.d.mts +124 -0
  147. package/dist/configure/services/http-adapter/index.d.mts +2 -0
  148. package/dist/configure/services/idp/index.d.mts +60 -0
  149. package/dist/configure/services/idp/permission.d.mts +64 -0
  150. package/dist/configure/services/idp/types.d.mts +23 -0
  151. package/dist/configure/services/index.d.mts +40 -0
  152. package/dist/configure/services/resolver/index.d.mts +6 -0
  153. package/dist/configure/services/resolver/permission.d.mts +64 -0
  154. package/dist/configure/services/resolver/resolver.d.mts +88 -0
  155. package/dist/configure/services/resolver/types.d.mts +5 -0
  156. package/dist/configure/services/secrets/index.d.mts +37 -0
  157. package/dist/configure/services/secrets/types.d.mts +10 -0
  158. package/dist/configure/services/staticwebsite/index.d.mts +18 -0
  159. package/dist/configure/services/staticwebsite/types.d.mts +10 -0
  160. package/dist/configure/services/tailordb/index.d.mts +3 -0
  161. package/dist/configure/services/tailordb/permission.d.mts +103 -0
  162. package/dist/configure/services/tailordb/schema.d.mts +486 -0
  163. package/dist/configure/services/tailordb/types.d.mts +198 -0
  164. package/dist/configure/services/workflow/execution-policy.d.mts +70 -0
  165. package/dist/configure/services/workflow/execution-policy.types.d.mts +103 -0
  166. package/dist/configure/services/workflow/index.d.mts +9 -0
  167. package/dist/configure/services/workflow/job.d.mts +92 -0
  168. package/dist/configure/services/workflow/types.d.mts +2 -0
  169. package/dist/configure/services/workflow/wait-point.d.mts +72 -0
  170. package/dist/configure/services/workflow/workflow.d.mts +66 -0
  171. package/dist/configure/types/aigateway-name.d.mts +12 -0
  172. package/dist/configure/types/connection-name.d.mts +12 -0
  173. package/dist/configure/types/field.d.mts +8 -0
  174. package/dist/configure/types/field.types.d.mts +70 -0
  175. package/dist/configure/types/idp-name.d.mts +12 -0
  176. package/dist/configure/types/index.d.mts +5 -0
  177. package/dist/configure/types/machine-user.d.mts +2 -0
  178. package/dist/configure/types/permission-operand.types.d.mts +20 -0
  179. package/dist/configure/types/type.d.mts +73 -0
  180. package/dist/{context-Bd266-ru.mjs → context-DYQVYWqZ.mjs} +4 -5
  181. package/dist/context-DYQVYWqZ.mjs.map +1 -0
  182. package/dist/{crashreport-BsjAkFWw.mjs → crashreport-B5LqCTfF.mjs} +10 -11
  183. package/dist/{crashreport-BsjAkFWw.mjs.map → crashreport-B5LqCTfF.mjs.map} +1 -1
  184. package/dist/{crashreport-pr6Rhvza.mjs → crashreport-eI7ty7ok.mjs} +1 -1
  185. package/dist/{errors-Dtf2WPaW.mjs → errors-D7583Zz7.mjs} +18 -2
  186. package/dist/errors-D7583Zz7.mjs.map +1 -0
  187. package/dist/{file-_oUZo76X.mjs → file-BUcmVIH2.mjs} +12 -22
  188. package/dist/file-BUcmVIH2.mjs.map +1 -0
  189. package/dist/{globals-Crz8o65k.mjs → globals-TfAVItuK.mjs} +32 -55
  190. package/dist/globals-TfAVItuK.mjs.map +1 -0
  191. package/dist/iconv-QWaZh0TT.mjs +38 -0
  192. package/dist/iconv-QWaZh0TT.mjs.map +1 -0
  193. package/dist/{idp-BDbK5gjm.mjs → idp-RA_swu-h.mjs} +12 -5
  194. package/dist/idp-RA_swu-h.mjs.map +1 -0
  195. package/dist/{interceptor-D-q1rvRl.mjs → interceptor-e33JtsC-.mjs} +2 -2
  196. package/dist/interceptor-e33JtsC-.mjs.map +1 -0
  197. package/dist/kysely/index.d.mts +5 -7
  198. package/dist/logger-BtX0suGY.mjs +48 -0
  199. package/dist/logger-BtX0suGY.mjs.map +1 -0
  200. package/dist/logger-CXQq9YIp.mjs +317 -0
  201. package/dist/logger-CXQq9YIp.mjs.map +1 -0
  202. package/dist/node-builtins-CmaL2Cbq.mjs +36 -0
  203. package/dist/node-builtins-CmaL2Cbq.mjs.map +1 -0
  204. package/dist/parser/service/auth/index.d.mts +1 -0
  205. package/dist/parser/service/auth/schema.d.mts +3 -0
  206. package/dist/parser/service/http-adapter/index.d.mts +1 -0
  207. package/dist/parser/service/http-adapter/schema.d.mts +1 -0
  208. package/dist/parser/service/idp/types.d.mts +5 -0
  209. package/dist/parser/service/tailordb/type-source.d.mts +10 -0
  210. package/dist/parser/service/tailordb/types.d.mts +131 -0
  211. package/dist/platform-serialize-RoRtBS0v.mjs +46 -0
  212. package/dist/platform-serialize-RoRtBS0v.mjs.map +1 -0
  213. package/dist/plugin/builtin/enum-constants/index.d.mts +15 -1
  214. package/dist/plugin/builtin/enum-constants/index.mjs +115 -2
  215. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -0
  216. package/dist/plugin/builtin/file-utils/index.d.mts +15 -1
  217. package/dist/plugin/builtin/file-utils/index.mjs +149 -2
  218. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -0
  219. package/dist/plugin/builtin/kysely-type/index.d.mts +15 -1
  220. package/dist/plugin/builtin/kysely-type/index.mjs +274 -2
  221. package/dist/plugin/builtin/kysely-type/index.mjs.map +1 -0
  222. package/dist/plugin/builtin/seed/index.d.mts +46 -2
  223. package/dist/plugin/builtin/seed/index.mjs +1 -1
  224. package/dist/plugin/builtin/seed/seed-type-processor.d.mts +21 -0
  225. package/dist/plugin/builtin/seed/types.d.mts +2 -0
  226. package/dist/plugin/get-generated-type.d.mts +16 -0
  227. package/dist/plugin/index.d.mts +3 -117
  228. package/dist/plugin/index.mjs +1 -1
  229. package/dist/plugin/index.mjs.map +1 -1
  230. package/dist/plugin/manager.d.mts +2 -0
  231. package/dist/plugin/types.d.mts +242 -0
  232. package/dist/plugin/with-context.d.mts +101 -0
  233. package/dist/{runtime-n9NCkjee.mjs → register-ts-hook-LYV7zH-e.mjs} +9652 -4479
  234. package/dist/register-ts-hook-LYV7zH-e.mjs.map +1 -0
  235. package/dist/{registry-DdsYlL_P.mjs → registry-BIGVUrMB.mjs} +12 -9
  236. package/dist/registry-BIGVUrMB.mjs.map +1 -0
  237. package/dist/{repl-editor-DmGr9zMw.mjs → repl-editor-BCozyiNq.mjs} +6 -5
  238. package/dist/{repl-editor-DmGr9zMw.mjs.map → repl-editor-BCozyiNq.mjs.map} +1 -1
  239. package/dist/runtime/aigateway.d.mts +25 -0
  240. package/dist/runtime/aigateway.mjs +3 -0
  241. package/dist/runtime/authconnection.d.mts +21 -2
  242. package/dist/runtime/authconnection.mjs +2 -2
  243. package/dist/runtime/context.d.mts +54 -2
  244. package/dist/runtime/context.mjs +2 -2
  245. package/dist/runtime/field-parse.d.mts +10 -0
  246. package/dist/runtime/file.d.mts +170 -2
  247. package/dist/runtime/file.mjs +2 -2
  248. package/dist/runtime/globals.d.mts +38 -20
  249. package/dist/runtime/iconv.d.mts +73 -2
  250. package/dist/runtime/iconv.mjs +2 -2
  251. package/dist/runtime/idp.d.mts +129 -2
  252. package/dist/runtime/idp.mjs +2 -2
  253. package/dist/runtime/index.d.mts +48 -9
  254. package/dist/runtime/index.mjs +10 -8
  255. package/dist/runtime/logger.d.mts +98 -0
  256. package/dist/runtime/logger.mjs +3 -0
  257. package/dist/runtime/secretmanager.d.mts +41 -2
  258. package/dist/runtime/secretmanager.mjs +2 -2
  259. package/dist/runtime/types.d.mts +25 -0
  260. package/dist/runtime/workflow.d.mts +106 -2
  261. package/dist/runtime/workflow.mjs +2 -2
  262. package/dist/{schema-BhkpP5Hw.mjs → schema--xYWRGfe.mjs} +288 -229
  263. package/dist/schema--xYWRGfe.mjs.map +1 -0
  264. package/dist/{secret-file-DBqZhjFQ.mjs → secret-file-C3J4Gy8r.mjs} +2 -2
  265. package/dist/{secret-file-DBqZhjFQ.mjs.map → secret-file-C3J4Gy8r.mjs.map} +1 -1
  266. package/dist/secretmanager-CYlpffsz.mjs +13 -0
  267. package/dist/secretmanager-CYlpffsz.mjs.map +1 -0
  268. package/dist/secretmanager-IY4UvinW.mjs +131 -0
  269. package/dist/secretmanager-IY4UvinW.mjs.map +1 -0
  270. package/dist/seed/index.d.mts +4 -4
  271. package/dist/seed-B-yckgQY.mjs +483 -0
  272. package/dist/seed-B-yckgQY.mjs.map +1 -0
  273. package/dist/{service-DU1mVzri.mjs → service-B5WynBHQ.mjs} +3 -3
  274. package/dist/{service-DU1mVzri.mjs.map → service-B5WynBHQ.mjs.map} +1 -1
  275. package/dist/service-M7OYziQP.mjs +3 -0
  276. package/dist/service-k1xy_A5G.mjs +864 -0
  277. package/dist/service-k1xy_A5G.mjs.map +1 -0
  278. package/dist/service_pb-D5--My_M.mjs +167 -0
  279. package/dist/service_pb-D5--My_M.mjs.map +1 -0
  280. package/dist/service_pb-i8CmnQP4.mjs +3 -0
  281. package/dist/tailor-proto/src/tailor/v1/aigateway_pb.d.mts +203 -0
  282. package/dist/tailor-proto/src/tailor/v1/aigateway_resource_pb.d.mts +57 -0
  283. package/dist/tailor-proto/src/tailor/v1/application_pb.d.mts +420 -0
  284. package/dist/tailor-proto/src/tailor/v1/application_resource_pb.d.mts +160 -0
  285. package/dist/tailor-proto/src/tailor/v1/auth_pb.d.mts +2069 -0
  286. package/dist/tailor-proto/src/tailor/v1/auth_resource_pb.d.mts +865 -0
  287. package/dist/tailor-proto/src/tailor/v1/events_pb.d.mts +111 -0
  288. package/dist/tailor-proto/src/tailor/v1/events_resource_pb.d.mts +68 -0
  289. package/dist/tailor-proto/src/tailor/v1/executor_pb.d.mts +438 -0
  290. package/dist/tailor-proto/src/tailor/v1/executor_resource_pb.d.mts +586 -0
  291. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +192 -0
  292. package/dist/tailor-proto/src/tailor/v1/function_registry_pb.d.mts +450 -0
  293. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +191 -0
  294. package/dist/tailor-proto/src/tailor/v1/http_adapter_resource_pb.d.mts +49 -0
  295. package/dist/tailor-proto/src/tailor/v1/idp_pb.d.mts +406 -0
  296. package/dist/tailor-proto/src/tailor/v1/idp_resource_pb.d.mts +429 -0
  297. package/dist/tailor-proto/src/tailor/v1/metadata_pb.d.mts +72 -0
  298. package/dist/tailor-proto/src/tailor/v1/metadata_resource_pb.d.mts +16 -0
  299. package/dist/tailor-proto/src/tailor/v1/meter_pb.d.mts +308 -0
  300. package/dist/tailor-proto/src/tailor/v1/pipeline_pb.d.mts +590 -0
  301. package/dist/tailor-proto/src/tailor/v1/pipeline_resource_pb.d.mts +329 -0
  302. package/dist/tailor-proto/src/tailor/v1/resource_pb.d.mts +112 -0
  303. package/dist/tailor-proto/src/tailor/v1/secret_manager_pb.d.mts +345 -0
  304. package/dist/tailor-proto/src/tailor/v1/secret_manager_resource_pb.d.mts +53 -0
  305. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +3658 -0
  306. package/dist/tailor-proto/src/tailor/v1/stateflow_pb.d.mts +186 -0
  307. package/dist/tailor-proto/src/tailor/v1/stateflow_resource_pb.d.mts +28 -0
  308. package/dist/tailor-proto/src/tailor/v1/staticwebsite_pb.d.mts +428 -0
  309. package/dist/tailor-proto/src/tailor/v1/staticwebsite_resource_pb.d.mts +89 -0
  310. package/dist/tailor-proto/src/tailor/v1/tailordb_pb.d.mts +683 -0
  311. package/dist/tailor-proto/src/tailor/v1/tailordb_resource_pb.d.mts +796 -0
  312. package/dist/tailor-proto/src/tailor/v1/telemetryrouter_pb.d.mts +329 -0
  313. package/dist/tailor-proto/src/tailor/v1/telemetryrouter_resource_pb.d.mts +207 -0
  314. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +961 -0
  315. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +330 -0
  316. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +2014 -0
  317. package/dist/tailor-proto/src/tailor/v1/workspace_resource_pb.d.mts +482 -0
  318. package/dist/{telemetry-CdqJEzkj.mjs → telemetry-BRVdwh14.mjs} +3 -3
  319. package/dist/telemetry-BRVdwh14.mjs.map +1 -0
  320. package/dist/telemetry-CkbkeJxl.mjs +3 -0
  321. package/dist/test-env-key-D7UkZp99.mjs +75 -0
  322. package/dist/test-env-key-D7UkZp99.mjs.map +1 -0
  323. package/dist/types/aigateway.generated.d.mts +12 -0
  324. package/dist/types/app-config.generated.d.mts +4 -0
  325. package/dist/types/auth-connection.generated.d.mts +33 -0
  326. package/dist/types/auth.generated.d.mts +188 -0
  327. package/dist/types/executor.generated.d.mts +229 -0
  328. package/dist/types/helpers.d.mts +40 -0
  329. package/dist/types/http-adapter.generated.d.mts +28 -0
  330. package/dist/types/idp.generated.d.mts +626 -0
  331. package/dist/types/resolver.generated.d.mts +82 -0
  332. package/dist/types/secrets.generated.d.mts +14 -0
  333. package/dist/types/staticwebsite.generated.d.mts +14 -0
  334. package/dist/types/tailordb.generated.d.mts +468 -0
  335. package/dist/types/workflow.generated.d.mts +17 -0
  336. package/dist/user-agent-Bgsszb5I.mjs +28 -0
  337. package/dist/user-agent-Bgsszb5I.mjs.map +1 -0
  338. package/dist/utils/test/index.d.mts +5 -100
  339. package/dist/utils/test/index.mjs +38 -189
  340. package/dist/utils/test/index.mjs.map +1 -1
  341. package/dist/vitest/environment.d.mts +1 -2
  342. package/dist/vitest/environment.mjs +2 -2
  343. package/dist/vitest/environment.mjs.map +1 -1
  344. package/dist/vitest/index.d.mts +17 -431
  345. package/dist/vitest/index.mjs +1234 -67
  346. package/dist/vitest/index.mjs.map +1 -1
  347. package/dist/vitest/mock-kysely.d.mts +61 -0
  348. package/dist/vitest/mock.d.mts +10 -0
  349. package/dist/vitest/mocks/aigateway.d.mts +40 -0
  350. package/dist/vitest/mocks/authconnection.d.mts +38 -0
  351. package/dist/vitest/mocks/file.d.mts +58 -0
  352. package/dist/vitest/mocks/iconv.d.mts +51 -0
  353. package/dist/vitest/mocks/idp.d.mts +60 -0
  354. package/dist/vitest/mocks/logger.d.mts +45 -0
  355. package/dist/vitest/mocks/secretmanager.d.mts +44 -0
  356. package/dist/vitest/mocks/tailordb.d.mts +115 -0
  357. package/dist/vitest/mocks/workflow.d.mts +148 -0
  358. package/dist/vitest/setup.d.mts +1 -2
  359. package/dist/vitest/setup.mjs +2 -2
  360. package/dist/vitest/workflow-local.d.mts +41 -0
  361. package/dist/workflow-Bamae_Yc.mjs +34 -0
  362. package/dist/workflow-Bamae_Yc.mjs.map +1 -0
  363. package/dist/{client-z_oHGVNy.mjs → workspace_resource_pb-DXnO2AT-.mjs} +57 -621
  364. package/dist/workspace_resource_pb-DXnO2AT-.mjs.map +1 -0
  365. package/docs/cli/application.md +150 -250
  366. package/docs/cli/auth.md +51 -295
  367. package/docs/cli/completion.md +1 -25
  368. package/docs/cli/crashreport.md +3 -61
  369. package/docs/cli/executor.md +72 -183
  370. package/docs/cli/function.md +16 -132
  371. package/docs/cli/organization.md +11 -221
  372. package/docs/cli/plugin.md +29 -0
  373. package/docs/cli/query.md +2 -22
  374. package/docs/cli/secret.md +71 -251
  375. package/docs/cli/setup.md +138 -40
  376. package/docs/cli/skills.md +50 -39
  377. package/docs/cli/staticwebsite.md +32 -180
  378. package/docs/cli/tailordb.md +89 -413
  379. package/docs/cli/upgrade.md +2 -22
  380. package/docs/cli/user.md +78 -247
  381. package/docs/cli/workflow.md +150 -172
  382. package/docs/cli/workspace.md +167 -538
  383. package/docs/cli-reference.md +214 -96
  384. package/docs/configuration.md +90 -6
  385. package/docs/github-actions.md +72 -24
  386. package/docs/migration/v2.md +1613 -0
  387. package/docs/multi-environment.md +29 -7
  388. package/docs/plugin/custom.md +4 -4
  389. package/docs/plugin/index.md +8 -8
  390. package/docs/quickstart.md +8 -7
  391. package/docs/runtime.md +18 -9
  392. package/docs/services/aigateway.md +20 -2
  393. package/docs/services/auth.md +51 -59
  394. package/docs/services/executor.md +91 -6
  395. package/docs/services/http-adapter.md +16 -1
  396. package/docs/services/idp.md +62 -7
  397. package/docs/services/resolver.md +67 -11
  398. package/docs/services/secret.md +11 -11
  399. package/docs/services/staticwebsite.md +8 -2
  400. package/docs/services/tailordb-migration.md +55 -29
  401. package/docs/services/tailordb.md +205 -102
  402. package/docs/services/workflow.md +163 -55
  403. package/docs/testing.md +244 -143
  404. package/package.json +61 -46
  405. package/postinstall.mjs +4 -6
  406. package/dist/application-DB2r36Et.mjs +0 -3
  407. package/dist/application-DqS1yBg3.mjs.map +0 -1
  408. package/dist/authconnection-D2MhtTN5.mjs +0 -15
  409. package/dist/authconnection-D2MhtTN5.mjs.map +0 -1
  410. package/dist/authconnection-DvUQAjQS.d.mts +0 -39
  411. package/dist/cli/erd-viewer-assets/app.js +0 -1181
  412. package/dist/cli/erd-viewer-assets/index.html +0 -73
  413. package/dist/cli/erd-viewer-assets/serve.json +0 -13
  414. package/dist/cli/erd-viewer-assets/styles.css +0 -789
  415. package/dist/cli/index.d.mts +0 -5
  416. package/dist/cli/index.mjs.map +0 -1
  417. package/dist/client-Dbohmtkv.mjs +0 -3
  418. package/dist/client-z_oHGVNy.mjs.map +0 -1
  419. package/dist/context-Bd266-ru.mjs.map +0 -1
  420. package/dist/context-BuuIb8CC.d.mts +0 -68
  421. package/dist/enum-constants-j9QBF0cB.mjs +0 -116
  422. package/dist/enum-constants-j9QBF0cB.mjs.map +0 -1
  423. package/dist/errors-Dtf2WPaW.mjs.map +0 -1
  424. package/dist/field-DOsJCPFa.mjs +0 -22
  425. package/dist/field-DOsJCPFa.mjs.map +0 -1
  426. package/dist/file-BB8Vs9O_.d.mts +0 -250
  427. package/dist/file-_oUZo76X.mjs.map +0 -1
  428. package/dist/file-utils-DcyIPFQh.mjs +0 -150
  429. package/dist/file-utils-DcyIPFQh.mjs.map +0 -1
  430. package/dist/globals-Crz8o65k.mjs.map +0 -1
  431. package/dist/http-adapter.generated-WgMnb7Sb.d.mts +0 -580
  432. package/dist/iconv-Co-TOPuH.d.mts +0 -122
  433. package/dist/iconv-D2vi8G36.mjs +0 -63
  434. package/dist/iconv-D2vi8G36.mjs.map +0 -1
  435. package/dist/idp-BDbK5gjm.mjs.map +0 -1
  436. package/dist/idp-DrhVrLmV.d.mts +0 -160
  437. package/dist/index-5vPyRu1y.d.mts +0 -18
  438. package/dist/index-B7AKc18V.d.mts +0 -47
  439. package/dist/index-BlpzXncY.d.mts +0 -1016
  440. package/dist/index-CK7u9isy.d.mts +0 -46
  441. package/dist/index-CNYe5lnW.d.mts +0 -18
  442. package/dist/index-DjUdWlzf.d.mts +0 -18
  443. package/dist/index-ZePLwxw7.d.mts +0 -208
  444. package/dist/interceptor-D-q1rvRl.mjs.map +0 -1
  445. package/dist/job-fuc3j1Ma.mjs +0 -53
  446. package/dist/job-fuc3j1Ma.mjs.map +0 -1
  447. package/dist/kysely-type-DR8uzZTA.mjs +0 -274
  448. package/dist/kysely-type-DR8uzZTA.mjs.map +0 -1
  449. package/dist/logger-CxF-Ex5d.mjs +0 -220
  450. package/dist/logger-CxF-Ex5d.mjs.map +0 -1
  451. package/dist/mock-BjFj5o1I.mjs +0 -804
  452. package/dist/mock-BjFj5o1I.mjs.map +0 -1
  453. package/dist/registry-DdsYlL_P.mjs.map +0 -1
  454. package/dist/rolldown-runtime-DXywRVcq.mjs +0 -20
  455. package/dist/runtime-n9NCkjee.mjs.map +0 -1
  456. package/dist/schema-BhkpP5Hw.mjs.map +0 -1
  457. package/dist/secretmanager-B3n4KHfm.d.mts +0 -55
  458. package/dist/secretmanager-BVxw3ih_.mjs +0 -24
  459. package/dist/secretmanager-BVxw3ih_.mjs.map +0 -1
  460. package/dist/seed-jf3008-h.mjs +0 -1160
  461. package/dist/seed-jf3008-h.mjs.map +0 -1
  462. package/dist/service-CCL8ruDf.mjs +0 -459
  463. package/dist/service-CCL8ruDf.mjs.map +0 -1
  464. package/dist/service-D6yonf2I.mjs +0 -3
  465. package/dist/telemetry-CdqJEzkj.mjs.map +0 -1
  466. package/dist/telemetry-ClwW5ohF.mjs +0 -3
  467. package/dist/test-env-key-D9kM6ETE.mjs +0 -49
  468. package/dist/test-env-key-D9kM6ETE.mjs.map +0 -1
  469. package/dist/types-B2RpYyA_.mjs +0 -371
  470. package/dist/types-B2RpYyA_.mjs.map +0 -1
  471. package/dist/types-ClhIrW_C.mjs +0 -4
  472. package/dist/types-DCUhgpyI.d.mts +0 -784
  473. package/dist/types-DhO_VEZd.d.mts +0 -574
  474. package/dist/types-DwDgacni.d.mts +0 -338
  475. package/dist/workflow-BbKvGLQg.d.mts +0 -96
  476. package/dist/workflow-DgemCAz3.mjs +0 -38
  477. package/dist/workflow-DgemCAz3.mjs.map +0 -1
  478. package/dist/workflow.generated-DtQwEo-x.d.mts +0 -671
@@ -1,1181 +0,0 @@
1
- const TABLE_WIDTH = 260;
2
- const TABLE_HEIGHT = 62;
3
- const FIELD_ROW_HEIGHT = 28;
4
- const FIELD_SECTION_BORDER_HEIGHT = 1;
5
- const X_GAP = 240;
6
- const Y_GAP = 56;
7
- const CARDINALITY_MARKER_WIDTH = 50;
8
- const CROW_FOOT_TIP_OFFSET = 0;
9
- const CROW_FOOT_JOIN_OFFSET = 18;
10
- const CARDINALITY_OUTER_OFFSET = 32;
11
- const DRAG_THRESHOLD = 4;
12
- const FIT_PADDING = 80;
13
- const MIN_ZOOM = 0.25;
14
- const MAX_ZOOM = 2.2;
15
- const DEFAULT_SHOW_MODE = "TABLE_NAME";
16
- const SHOW_MODE_OPTIONS = [
17
- { value: "ALL_FIELDS", label: "All Fields" },
18
- { value: "TABLE_NAME", label: "Table Name" },
19
- { value: "KEY_ONLY", label: "Key Only" },
20
- ];
21
-
22
- const elements = {
23
- main: document.querySelector(".main"),
24
- namespace: document.getElementById("namespace"),
25
- revision: document.getElementById("revision"),
26
- search: document.getElementById("search"),
27
- tableSummary: document.getElementById("table-count-summary"),
28
- toggleAllTables: document.getElementById("toggle-all-tables"),
29
- tableList: document.getElementById("table-list"),
30
- canvas: document.getElementById("canvas"),
31
- world: document.getElementById("world"),
32
- edges: document.getElementById("edges"),
33
- nodes: document.getElementById("nodes"),
34
- details: document.getElementById("details"),
35
- emptyState: document.getElementById("empty-state"),
36
- status: document.getElementById("status"),
37
- zoomIn: document.getElementById("zoom-in"),
38
- zoomOut: document.getElementById("zoom-out"),
39
- zoomLabel: document.getElementById("zoom-label"),
40
- fitView: document.getElementById("fit-view"),
41
- showMode: document.getElementById("show-mode"),
42
- showModeMenu: document.getElementById("show-mode-menu"),
43
- copyLink: document.getElementById("copy-link"),
44
- };
45
-
46
- let schema;
47
- let layout;
48
- let selectedTable;
49
- let searchText = "";
50
- let viewport = { x: 32, y: 32, z: 1 };
51
- let hasZoomFromHash = false;
52
- let userAdjustedViewport = false;
53
- let hashUpdatesDisabled = false;
54
- let showMode = DEFAULT_SHOW_MODE;
55
- let activeCardDrag;
56
- let activeCanvasPan;
57
- let activeViewportAnimation;
58
- let suppressNextCanvasClick = false;
59
- const manualNodePositions = new Map();
60
- const hiddenTableNames = new Set();
61
-
62
- function escapeHtml(value) {
63
- return String(value ?? "")
64
- .replaceAll("&", "&")
65
- .replaceAll("<", "&lt;")
66
- .replaceAll(">", "&gt;")
67
- .replaceAll('"', "&quot;");
68
- }
69
-
70
- function clamp(value, min, max) {
71
- return Math.min(max, Math.max(min, value));
72
- }
73
-
74
- function tableByName(name) {
75
- return schema?.tables.find((table) => table.name === name);
76
- }
77
-
78
- function showModeOption(value) {
79
- return SHOW_MODE_OPTIONS.find((option) => option.value === value);
80
- }
81
-
82
- function isTableHidden(tableName) {
83
- return hiddenTableNames.has(tableName);
84
- }
85
-
86
- function visibleTables() {
87
- return schema.tables.filter((table) => !isTableHidden(table.name));
88
- }
89
-
90
- function visibleTableNames() {
91
- return visibleTables().map((table) => table.name);
92
- }
93
-
94
- function readHashState() {
95
- const params = new URLSearchParams(location.hash.slice(1));
96
- selectedTable = params.get("table") || undefined;
97
- const nextShowMode = params.get("show");
98
- if (showModeOption(nextShowMode)) {
99
- showMode = nextShowMode;
100
- }
101
- hiddenTableNames.clear();
102
- for (const tableName of (params.get("hidden") || "").split(",")) {
103
- if (tableName) hiddenTableNames.add(tableName);
104
- }
105
- const z = Number(params.get("z"));
106
- if (params.has("z") && Number.isFinite(z)) {
107
- viewport = { ...viewport, z: clamp(z, MIN_ZOOM, MAX_ZOOM) };
108
- hasZoomFromHash = true;
109
- }
110
- }
111
-
112
- function writeHashState() {
113
- if (hashUpdatesDisabled) return;
114
- const params = new URLSearchParams();
115
- if (selectedTable) params.set("table", selectedTable);
116
- if (showMode !== DEFAULT_SHOW_MODE) params.set("show", showMode);
117
- if (hiddenTableNames.size > 0) {
118
- params.set("hidden", [...hiddenTableNames].toSorted((a, b) => a.localeCompare(b)).join(","));
119
- }
120
- params.set("z", viewport.z.toFixed(3));
121
- try {
122
- history.replaceState(null, "", `#${params.toString()}`);
123
- } catch {
124
- // Disable further hash writes once they fail (e.g. sandboxed artifact
125
- // preview) so panning/zooming does not throw on every frame.
126
- hashUpdatesDisabled = true;
127
- }
128
- }
129
-
130
- const SCHEMA_BLOCK_PATTERN =
131
- /<script type="application\/json" id="erd-schema">([\s\S]*?)<\/script>/;
132
-
133
- // Read the schema from the embedded `#erd-schema` data block in the current
134
- // document (the viewer is always a self-contained HTML).
135
- function embeddedSchema() {
136
- if (typeof document === "undefined") return undefined;
137
- const element = document.getElementById("erd-schema");
138
- if (!element) return undefined;
139
- try {
140
- return JSON.parse(element.textContent);
141
- } catch {
142
- return undefined;
143
- }
144
- }
145
-
146
- // Re-fetch the served HTML and extract its embedded schema. Used by watch mode
147
- // to pick up rebuilds without a separate schema.json.
148
- async function fetchServedSchema() {
149
- const response = await fetch(`./?t=${Date.now()}`, { cache: "no-store" });
150
- if (!response.ok) {
151
- throw new Error(`Failed to load ERD (${response.status})`);
152
- }
153
- const match = SCHEMA_BLOCK_PATTERN.exec(await response.text());
154
- if (!match) {
155
- throw new Error("ERD schema block not found.");
156
- }
157
- return JSON.parse(match[1]);
158
- }
159
-
160
- function isKeyColumn(column) {
161
- return Boolean(column.primaryKey || column.unique || column.index || column.relation);
162
- }
163
-
164
- function columnsForShowMode(table) {
165
- if (showMode === "ALL_FIELDS") return table.columns;
166
- if (showMode === "KEY_ONLY") return table.columns.filter(isKeyColumn);
167
- return [];
168
- }
169
-
170
- function cardHeight(table) {
171
- const fieldCount = columnsForShowMode(table).length;
172
- return (
173
- TABLE_HEIGHT +
174
- (fieldCount > 0 ? FIELD_SECTION_BORDER_HEIGHT : 0) +
175
- fieldCount * FIELD_ROW_HEIGHT
176
- );
177
- }
178
-
179
- function computeRanks(tables, relations) {
180
- const ranks = new Map(tables.map((table) => [table.name, 0]));
181
- for (let i = 0; i < tables.length; i += 1) {
182
- let changed = false;
183
- for (const relation of relations) {
184
- const targetRank = ranks.get(relation.targetTable) ?? 0;
185
- const sourceRank = ranks.get(relation.sourceTable) ?? 0;
186
- if (sourceRank <= targetRank && relation.sourceTable !== relation.targetTable) {
187
- ranks.set(relation.sourceTable, targetRank + 1);
188
- changed = true;
189
- }
190
- }
191
- if (!changed) break;
192
- }
193
- return ranks;
194
- }
195
-
196
- function computeLayout(nextSchema) {
197
- const tables = nextSchema.tables.toSorted((a, b) => a.name.localeCompare(b.name));
198
- const ranks = computeRanks(tables, nextSchema.relations);
199
- const layers = new Map();
200
- for (const table of tables) {
201
- const rank = ranks.get(table.name) ?? 0;
202
- if (!layers.has(rank)) layers.set(rank, []);
203
- layers.get(rank).push(table);
204
- }
205
-
206
- const nodes = new Map();
207
- for (const rank of [...layers.keys()].toSorted((a, b) => a - b)) {
208
- const layerTables = layers.get(rank).toSorted((a, b) => a.name.localeCompare(b.name));
209
- let y = 0;
210
- for (const table of layerTables) {
211
- const height = cardHeight(table);
212
- const x = rank * (TABLE_WIDTH + X_GAP);
213
- nodes.set(table.name, { x, y, width: TABLE_WIDTH, height });
214
- y += height + Y_GAP;
215
- }
216
- }
217
-
218
- return {
219
- nodes,
220
- ...layoutBounds(nodes),
221
- };
222
- }
223
-
224
- function layoutBounds(nodes, tableNames) {
225
- const includedNames = tableNames ? new Set(tableNames) : undefined;
226
- let minX = Infinity;
227
- let minY = Infinity;
228
- let maxX = -Infinity;
229
- let maxY = -Infinity;
230
- for (const [tableName, node] of nodes) {
231
- if (includedNames && !includedNames.has(tableName)) continue;
232
- minX = Math.min(minX, node.x);
233
- minY = Math.min(minY, node.y);
234
- maxX = Math.max(maxX, node.x + node.width);
235
- maxY = Math.max(maxY, node.y + node.height);
236
- }
237
-
238
- if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
239
- return { x: 0, y: 0, width: TABLE_WIDTH, height: TABLE_HEIGHT };
240
- }
241
-
242
- return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
243
- }
244
-
245
- function visibleLayoutBounds() {
246
- return layoutBounds(layout.nodes, visibleTableNames());
247
- }
248
-
249
- function applyManualNodePositions() {
250
- for (const [tableName, position] of manualNodePositions) {
251
- const node = layout.nodes.get(tableName);
252
- if (node) {
253
- node.x = position.x;
254
- node.y = position.y;
255
- }
256
- }
257
- Object.assign(layout, layoutBounds(layout.nodes));
258
- }
259
-
260
- function isTableRelatedToSelection(tableName) {
261
- if (!selectedTable) return true;
262
- if (tableName === selectedTable) return true;
263
- return schema.relations.some(
264
- (relation) =>
265
- (relation.sourceTable === selectedTable && relation.targetTable === tableName) ||
266
- (relation.targetTable === selectedTable && relation.sourceTable === tableName),
267
- );
268
- }
269
-
270
- function matchesSearch(table) {
271
- if (!searchText) return true;
272
- const needle = searchText.toLowerCase();
273
- return (
274
- table.name.toLowerCase().includes(needle) ||
275
- table.columns.some((column) => column.name.toLowerCase().includes(needle))
276
- );
277
- }
278
-
279
- function eyeIcon(hidden) {
280
- if (hidden) {
281
- return `
282
- <svg class="eye-icon" viewBox="0 0 24 24" aria-hidden="true">
283
- <path d="M3 3l18 18"></path>
284
- <path d="M10.6 10.6a2 2 0 0 0 2.8 2.8"></path>
285
- <path d="M8.4 5.6A9.3 9.3 0 0 1 12 5c5 0 8.4 4.1 9.5 6.2a2 2 0 0 1 0 1.6 14.3 14.3 0 0 1-2.7 3.5"></path>
286
- <path d="M6.1 6.9a14.7 14.7 0 0 0-3.6 4.3 2 2 0 0 0 0 1.6C3.6 14.9 7 19 12 19a9.8 9.8 0 0 0 4-.8"></path>
287
- </svg>
288
- `;
289
- }
290
-
291
- return `
292
- <svg class="eye-icon" viewBox="0 0 24 24" aria-hidden="true">
293
- <path d="M2.5 11.2C3.6 9.1 7 5 12 5s8.4 4.1 9.5 6.2a2 2 0 0 1 0 1.6C20.4 14.9 17 19 12 19s-8.4-4.1-9.5-6.2a2 2 0 0 1 0-1.6Z"></path>
294
- <circle cx="12" cy="12" r="3"></circle>
295
- </svg>
296
- `;
297
- }
298
-
299
- function renderHeader() {
300
- elements.namespace.textContent = schema.namespace;
301
- elements.revision.textContent = `${schema.tables.length} tables / ${schema.relations.length} relations / ${schema.revision}`;
302
- const visibleCount = visibleTables().length;
303
- elements.tableSummary.textContent =
304
- visibleCount === schema.tables.length
305
- ? String(schema.tables.length)
306
- : `${visibleCount}/${schema.tables.length}`;
307
- const allTablesHidden = schema.tables.length > 0 && visibleCount === 0;
308
- const allTableVisibilityLabel = allTablesHidden ? "Show all tables" : "Hide all tables";
309
- elements.toggleAllTables.disabled = schema.tables.length === 0;
310
- elements.toggleAllTables.innerHTML = eyeIcon(allTablesHidden);
311
- elements.toggleAllTables.setAttribute("aria-label", allTableVisibilityLabel);
312
- elements.toggleAllTables.title = allTableVisibilityLabel;
313
- }
314
-
315
- function renderTableList() {
316
- const tables = schema.tables.filter(matchesSearch);
317
- elements.tableList.innerHTML = tables
318
- .map((table) => {
319
- const hidden = isTableHidden(table.name);
320
- const visibilityLabel = hidden ? "Show" : "Hide";
321
- return `
322
- <div class="table-list-row ${hidden ? "is-hidden" : ""}">
323
- <button
324
- type="button"
325
- class="table-select"
326
- data-table="${escapeHtml(table.name)}"
327
- aria-current="${table.name === selectedTable}"
328
- >
329
- <span class="table-list-icon" aria-hidden="true"></span>
330
- <span>${escapeHtml(table.name)}</span>
331
- </button>
332
- <button
333
- type="button"
334
- class="table-visibility-toggle"
335
- data-table="${escapeHtml(table.name)}"
336
- aria-label="${visibilityLabel} table ${escapeHtml(table.name)}"
337
- title="${visibilityLabel}"
338
- >
339
- ${eyeIcon(hidden)}
340
- </button>
341
- </div>
342
- `;
343
- })
344
- .join("");
345
-
346
- elements.tableList.querySelectorAll(".table-select").forEach((button) => {
347
- button.addEventListener("click", () => {
348
- selectTable(button.dataset.table);
349
- });
350
- });
351
- elements.tableList.querySelectorAll(".table-visibility-toggle").forEach((button) => {
352
- button.addEventListener("click", (event) => {
353
- event.stopPropagation();
354
- toggleTableVisibility(button.dataset.table);
355
- });
356
- });
357
- }
358
-
359
- function tableFieldRows(table) {
360
- const columns = columnsForShowMode(table);
361
- if (columns.length === 0) return "";
362
-
363
- return `
364
- <div class="table-fields">
365
- ${columns
366
- .map(
367
- (column) => `
368
- <div class="table-field ${isKeyColumn(column) ? "is-key" : ""}">
369
- <span class="field-name">${escapeHtml(column.name)}</span>
370
- <span class="field-type">${escapeHtml(column.type)}${column.array ? "[]" : ""}</span>
371
- </div>
372
- `,
373
- )
374
- .join("")}
375
- </div>
376
- `;
377
- }
378
-
379
- function renderNodes() {
380
- elements.nodes.innerHTML = schema.tables
381
- .filter((table) => !isTableHidden(table.name))
382
- .map((table) => {
383
- const node = layout.nodes.get(table.name);
384
- const related = isTableRelatedToSelection(table.name);
385
- const muted = !matchesSearch(table) || !related;
386
- return `
387
- <button
388
- type="button"
389
- class="table-card ${table.name === selectedTable ? "is-selected" : ""} ${related ? "is-related" : ""} ${muted ? "is-muted" : ""}"
390
- data-table="${escapeHtml(table.name)}"
391
- aria-label="Focus table ${escapeHtml(table.name)}"
392
- aria-pressed="${table.name === selectedTable}"
393
- style="left: ${node.x}px; top: ${node.y}px; height: ${node.height}px"
394
- >
395
- <div class="table-head">
396
- <span class="table-icon" aria-hidden="true"></span>
397
- <div class="table-name">${escapeHtml(table.name)}</div>
398
- </div>
399
- ${tableFieldRows(table)}
400
- </button>
401
- `;
402
- })
403
- .join("");
404
-
405
- elements.nodes.querySelectorAll(".table-card").forEach(wireTableCard);
406
- }
407
-
408
- function wireTableCard(card) {
409
- card.addEventListener("click", (event) => {
410
- event.stopPropagation();
411
- suppressNextCanvasClick = false;
412
- if (card.dataset.dragged === "true") {
413
- event.preventDefault();
414
- card.dataset.dragged = "false";
415
- return;
416
- }
417
- selectTable(card.dataset.table);
418
- });
419
-
420
- card.addEventListener("pointerdown", (event) => {
421
- if (event.button !== 0) return;
422
- cancelViewportAnimation();
423
- const tableName = card.dataset.table;
424
- const node = layout.nodes.get(tableName);
425
- if (!node) return;
426
-
427
- activeCardDrag = {
428
- card,
429
- moved: false,
430
- pointerId: event.pointerId,
431
- startClientX: event.clientX,
432
- startClientY: event.clientY,
433
- startX: node.x,
434
- startY: node.y,
435
- tableName,
436
- };
437
- card.setPointerCapture(event.pointerId);
438
- });
439
-
440
- card.addEventListener("pointermove", (event) => {
441
- if (!activeCardDrag || activeCardDrag.pointerId !== event.pointerId) return;
442
-
443
- const screenDeltaX = event.clientX - activeCardDrag.startClientX;
444
- const screenDeltaY = event.clientY - activeCardDrag.startClientY;
445
- if (!activeCardDrag.moved && Math.hypot(screenDeltaX, screenDeltaY) < DRAG_THRESHOLD) {
446
- return;
447
- }
448
-
449
- event.preventDefault();
450
- activeCardDrag.moved = true;
451
- activeCardDrag.card.classList.add("is-dragging");
452
- moveTableCard(
453
- activeCardDrag.tableName,
454
- activeCardDrag.card,
455
- activeCardDrag.startX + screenDeltaX / viewport.z,
456
- activeCardDrag.startY + screenDeltaY / viewport.z,
457
- );
458
- });
459
-
460
- card.addEventListener("pointerup", finishCardDrag);
461
- card.addEventListener("pointercancel", finishCardDrag);
462
- }
463
-
464
- function moveTableCard(tableName, card, x, y) {
465
- const node = layout.nodes.get(tableName);
466
- if (!node) return;
467
-
468
- userAdjustedViewport = true;
469
- node.x = Math.round(x);
470
- node.y = Math.round(y);
471
- manualNodePositions.set(tableName, { x: node.x, y: node.y });
472
- Object.assign(layout, layoutBounds(layout.nodes));
473
- card.style.left = `${node.x}px`;
474
- card.style.top = `${node.y}px`;
475
- renderEdges();
476
- }
477
-
478
- function finishCardDrag(event) {
479
- if (!activeCardDrag || activeCardDrag.pointerId !== event.pointerId) return;
480
-
481
- if (activeCardDrag.card.hasPointerCapture(event.pointerId)) {
482
- activeCardDrag.card.releasePointerCapture(event.pointerId);
483
- }
484
- activeCardDrag.card.classList.remove("is-dragging");
485
- if (activeCardDrag.moved) {
486
- event.preventDefault();
487
- activeCardDrag.card.dataset.dragged = "true";
488
- selectedTable = activeCardDrag.tableName;
489
- activeCardDrag = undefined;
490
- renderAll({ center: false });
491
- return;
492
- }
493
-
494
- activeCardDrag = undefined;
495
- }
496
-
497
- function edgeGeometry(source, target) {
498
- const sourceRight = source.x < target.x;
499
- const direction = sourceRight ? 1 : -1;
500
- const sourceNodeX = sourceRight ? source.x + source.width : source.x;
501
- const targetNodeX = sourceRight ? target.x : target.x + target.width;
502
- const sy = source.y + source.height / 2;
503
- const ty = target.y + target.height / 2;
504
- const sx = sourceNodeX + direction * CARDINALITY_MARKER_WIDTH;
505
- const tx = targetNodeX - direction * CARDINALITY_MARKER_WIDTH;
506
- const bend = Math.max(80, Math.abs(tx - sx) * 0.45);
507
- const c1x = sx + (sourceRight ? bend : -bend);
508
- const c2x = tx + (sourceRight ? -bend : bend);
509
- return {
510
- d: `M ${sx} ${sy} C ${c1x} ${sy}, ${c2x} ${ty}, ${tx} ${ty}`,
511
- sourceNodePoint: { x: sourceNodeX, y: sy },
512
- targetNodePoint: { x: targetNodeX, y: ty },
513
- sourceRight,
514
- };
515
- }
516
-
517
- function sourceColumnForRelation(relation) {
518
- const table = tableByName(relation.sourceTable);
519
- const sourceColumn = relation.sourceColumns[0];
520
- return table?.columns.find((column) => column.name === sourceColumn);
521
- }
522
-
523
- function normalizedRelationType(relation) {
524
- if (["1-1", "oneToOne"].includes(relation.relationType)) return "1-1";
525
- if (["n-1", "N-1", "manyToOne"].includes(relation.relationType)) return "n-1";
526
- return relation.relationType || "foreignKey";
527
- }
528
-
529
- function relationCardinality(relation) {
530
- const sourceColumn = sourceColumnForRelation(relation);
531
- const relationType = normalizedRelationType(relation);
532
- const sourceMultiple =
533
- relationType === "n-1" ||
534
- relationType === "keyOnly" ||
535
- (relationType === "foreignKey" && sourceColumn?.unique !== true);
536
- const targetMultiple = relationType === "keyOnly" && sourceColumn?.array === true;
537
-
538
- return {
539
- source: { min: 0, max: sourceMultiple ? "n" : 1 },
540
- target: { min: relation.required ? 1 : 0, max: targetMultiple ? "n" : 1 },
541
- };
542
- }
543
-
544
- function oneMarker(x, y) {
545
- return `
546
- <line x1="${x}" y1="${y - 10}" x2="${x}" y2="${y + 10}"></line>
547
- `;
548
- }
549
-
550
- function cardinalityMarker(cardinality, point, sideSign, selected) {
551
- const crowFootTip = CROW_FOOT_TIP_OFFSET;
552
- const crowFootJoin = CROW_FOOT_JOIN_OFFSET;
553
- const outer = CARDINALITY_OUTER_OFFSET;
554
- const markerEndX = point.x + sideSign * CARDINALITY_MARKER_WIDTH;
555
- const parts = [
556
- `<line class="edge-cardinality-line" x1="${point.x}" y1="${point.y}" x2="${markerEndX}" y2="${point.y}"></line>`,
557
- ];
558
-
559
- if (cardinality.max === "n") {
560
- const baseX = point.x + sideSign * crowFootJoin;
561
- const endX = point.x + sideSign * crowFootTip;
562
- parts.push(`
563
- <line x1="${baseX}" y1="${point.y}" x2="${endX}" y2="${point.y - 11}"></line>
564
- <line x1="${baseX}" y1="${point.y}" x2="${endX}" y2="${point.y + 11}"></line>
565
- `);
566
- if (cardinality.min === 0) {
567
- parts.push(`<circle cx="${point.x + sideSign * outer}" cy="${point.y}" r="6"></circle>`);
568
- } else {
569
- parts.push(oneMarker(point.x + sideSign * outer, point.y));
570
- }
571
- } else {
572
- parts.push(oneMarker(point.x + sideSign * crowFootJoin, point.y));
573
- if (cardinality.min === 0) {
574
- parts.push(`<circle cx="${point.x + sideSign * outer}" cy="${point.y}" r="6"></circle>`);
575
- } else {
576
- parts.push(oneMarker(point.x + sideSign * outer, point.y));
577
- }
578
- }
579
-
580
- return `
581
- <g class="edge-cardinality ${selected ? "is-selected" : ""}">
582
- ${parts.join("")}
583
- </g>
584
- `;
585
- }
586
-
587
- function renderEdges() {
588
- const bounds = visibleLayoutBounds();
589
- elements.edges.setAttribute("width", String(bounds.width + 400));
590
- elements.edges.setAttribute("height", String(bounds.height + 400));
591
- elements.edges.innerHTML = schema.relations
592
- .map((relation) => {
593
- if (isTableHidden(relation.sourceTable) || isTableHidden(relation.targetTable)) return "";
594
- const source = layout.nodes.get(relation.sourceTable);
595
- const target = layout.nodes.get(relation.targetTable);
596
- if (!source || !target) return "";
597
- const selected =
598
- relation.sourceTable === selectedTable || relation.targetTable === selectedTable;
599
- const geometry = edgeGeometry(source, target);
600
- const cardinality = relationCardinality(relation);
601
- const direction = geometry.sourceRight ? 1 : -1;
602
- return `
603
- <path class="edge ${selected ? "is-selected" : ""}" d="${geometry.d}"></path>
604
- ${cardinalityMarker(cardinality.source, geometry.sourceNodePoint, direction, selected)}
605
- ${cardinalityMarker(cardinality.target, geometry.targetNodePoint, -direction, selected)}
606
- `;
607
- })
608
- .join("");
609
- }
610
-
611
- function relationRows(table, direction) {
612
- const relations = schema.relations.filter((relation) =>
613
- direction === "out" ? relation.sourceTable === table.name : relation.targetTable === table.name,
614
- );
615
- if (relations.length === 0) return `<p>None</p>`;
616
- return `
617
- <div class="detail-list">
618
- ${relations
619
- .map((relation) => {
620
- const label =
621
- direction === "out"
622
- ? `${relation.sourceColumns.join(", ")} -> ${relation.targetTable}.${relation.targetColumns.join(", ")}`
623
- : `${relation.sourceTable}.${relation.sourceColumns.join(", ")} -> ${relation.targetColumns.join(", ")}`;
624
- return `<div class="detail-row"><strong>${escapeHtml(label)}</strong><code>${escapeHtml(relation.kind)}</code></div>`;
625
- })
626
- .join("")}
627
- </div>
628
- `;
629
- }
630
-
631
- function columnPills(column) {
632
- const pills = [];
633
- if (column.primaryKey) pills.push("primary");
634
- if (column.required) pills.push("required");
635
- if (column.array) pills.push("array");
636
- if (column.unique) pills.push("unique");
637
- if (column.index) pills.push("index");
638
- if (column.relation) pills.push(`${column.relation.targetTable}.${column.relation.targetColumn}`);
639
- if (column.enumValues?.length) pills.push(...column.enumValues);
640
- if (column.validations) pills.push(`${column.validations} validations`);
641
- if (column.hooks?.create) pills.push("create hook");
642
- if (column.hooks?.update) pills.push("update hook");
643
- return pills.length
644
- ? `<div class="pill-wrap">${pills.map((pill) => `<span class="pill">${escapeHtml(pill)}</span>`).join("")}</div>`
645
- : "";
646
- }
647
-
648
- function renderDetails() {
649
- const table = selectedTable ? tableByName(selectedTable) : undefined;
650
- if (!table) {
651
- elements.details.hidden = true;
652
- elements.details.innerHTML = "";
653
- elements.main.classList.add("is-details-collapsed");
654
- return;
655
- }
656
-
657
- elements.details.hidden = false;
658
- elements.main.classList.remove("is-details-collapsed");
659
- elements.details.innerHTML = `
660
- <div class="details-inner">
661
- <section>
662
- <h2><span class="table-icon" aria-hidden="true"></span>${escapeHtml(table.name)}</h2>
663
- <p>${escapeHtml(table.description || table.pluralForm)}</p>
664
- </section>
665
- <section class="details-section">
666
- <h3>Outgoing Relations</h3>
667
- ${relationRows(table, "out")}
668
- </section>
669
- <section class="details-section">
670
- <h3>Incoming Relations</h3>
671
- ${relationRows(table, "in")}
672
- </section>
673
- <section class="details-section">
674
- <h3>Columns</h3>
675
- <div class="detail-list">
676
- ${table.columns
677
- .map(
678
- (column) => `
679
- <div class="detail-row">
680
- <div>
681
- <strong>${escapeHtml(column.name)}</strong>
682
- ${column.description ? `<p>${escapeHtml(column.description)}</p>` : ""}
683
- ${columnPills(column)}
684
- </div>
685
- <code>${escapeHtml(column.type)}${column.array ? "[]" : ""}</code>
686
- </div>
687
- `,
688
- )
689
- .join("")}
690
- </div>
691
- </section>
692
- ${
693
- table.indexes.length
694
- ? `<section class="details-section">
695
- <h3>Indexes</h3>
696
- <div class="detail-list">
697
- ${table.indexes
698
- .map(
699
- (index) => `
700
- <div class="detail-row">
701
- <strong>${escapeHtml(index.name)}</strong>
702
- <code>${escapeHtml(index.fields.join(", "))}${index.unique ? " unique" : ""}</code>
703
- </div>
704
- `,
705
- )
706
- .join("")}
707
- </div>
708
- </section>`
709
- : ""
710
- }
711
- ${
712
- table.source?.kind === "plugin"
713
- ? `<section class="details-section">
714
- <h3>Source</h3>
715
- <div class="detail-row">
716
- <strong>${escapeHtml(table.source.pluginId)}</strong>
717
- <code>${escapeHtml(table.source.generatedTypeKind || "plugin")}</code>
718
- </div>
719
- </section>`
720
- : ""
721
- }
722
- </div>
723
- `;
724
- }
725
-
726
- function checkIcon() {
727
- return `
728
- <svg class="check-icon" viewBox="0 0 24 24" aria-hidden="true">
729
- <path d="M20 6 9 17l-5-5"></path>
730
- </svg>
731
- `;
732
- }
733
-
734
- function renderShowModeControls() {
735
- const selectedOption = showModeOption(showMode) ?? showModeOption(DEFAULT_SHOW_MODE);
736
- elements.showMode.innerHTML = `
737
- <span>${escapeHtml(selectedOption.label)}</span>
738
- <span class="show-mode-caret" aria-hidden="true"></span>
739
- `;
740
- elements.showMode.setAttribute("aria-label", `Show mode: ${selectedOption.label}`);
741
- elements.showModeMenu.innerHTML = SHOW_MODE_OPTIONS.map(
742
- (option) => `
743
- <button
744
- type="button"
745
- class="show-mode-option"
746
- role="menuitemradio"
747
- aria-checked="${option.value === showMode}"
748
- data-show-mode="${option.value}"
749
- >
750
- <span>${escapeHtml(option.label)}</span>
751
- <span class="show-mode-check">${option.value === showMode ? checkIcon() : ""}</span>
752
- </button>
753
- `,
754
- ).join("");
755
-
756
- elements.showModeMenu.querySelectorAll(".show-mode-option").forEach((button) => {
757
- button.addEventListener("click", () => {
758
- setShowMode(button.dataset.showMode);
759
- });
760
- });
761
- }
762
-
763
- function setShowModeMenuOpen(open) {
764
- elements.showMode.setAttribute("aria-expanded", String(open));
765
- elements.showModeMenu.hidden = !open;
766
- }
767
-
768
- function setShowMode(nextShowMode) {
769
- if (!showModeOption(nextShowMode)) return;
770
- setShowModeMenuOpen(false);
771
- if (showMode === nextShowMode) return;
772
-
773
- showMode = nextShowMode;
774
- renderAll({ center: false });
775
- }
776
-
777
- function toggleTableVisibility(tableName) {
778
- if (!tableName) return;
779
- if (hiddenTableNames.has(tableName)) {
780
- hiddenTableNames.delete(tableName);
781
- } else {
782
- hiddenTableNames.add(tableName);
783
- }
784
- clearSelectionIfHidden();
785
- renderAll({ center: false });
786
- }
787
-
788
- function setAllTableVisibility(hidden) {
789
- if (!schema) return;
790
- hiddenTableNames.clear();
791
- if (hidden) {
792
- for (const table of schema.tables) {
793
- hiddenTableNames.add(table.name);
794
- }
795
- }
796
- clearSelectionIfHidden();
797
- renderAll({ center: false });
798
- }
799
-
800
- function clearSelectionIfHidden() {
801
- if (selectedTable && isTableHidden(selectedTable)) {
802
- selectedTable = undefined;
803
- }
804
- }
805
-
806
- function toggleAllTableVisibility() {
807
- if (!schema) return;
808
- setAllTableVisibility(visibleTables().length > 0);
809
- }
810
-
811
- function cancelViewportAnimation() {
812
- if (!activeViewportAnimation) return;
813
- cancelAnimationFrame(activeViewportAnimation.frame);
814
- activeViewportAnimation = undefined;
815
- }
816
-
817
- function easeOutCubic(value) {
818
- return 1 - (1 - value) ** 3;
819
- }
820
-
821
- function animateViewportTo(targetViewport) {
822
- cancelViewportAnimation();
823
- const startViewport = { ...viewport };
824
- const duration = 360;
825
- let startedAt;
826
-
827
- activeViewportAnimation = { frame: undefined };
828
- const step = () => {
829
- const now = Date.now();
830
- startedAt ??= now;
831
- const progress = clamp((now - startedAt) / duration, 0, 1);
832
- const eased = easeOutCubic(progress);
833
- viewport = {
834
- x: startViewport.x + (targetViewport.x - startViewport.x) * eased,
835
- y: startViewport.y + (targetViewport.y - startViewport.y) * eased,
836
- z: startViewport.z + (targetViewport.z - startViewport.z) * eased,
837
- };
838
- applyTransform();
839
-
840
- if (progress < 1) {
841
- activeViewportAnimation.frame = requestAnimationFrame(step);
842
- return;
843
- }
844
-
845
- viewport = targetViewport;
846
- activeViewportAnimation = undefined;
847
- applyTransform();
848
- };
849
-
850
- activeViewportAnimation.frame = requestAnimationFrame(step);
851
- }
852
-
853
- function applyTransform() {
854
- elements.world.style.transform = `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.z})`;
855
- elements.canvas.style.backgroundPosition = `${viewport.x}px ${viewport.y}px`;
856
- elements.canvas.style.backgroundSize = `${Math.max(4, 22 * viewport.z)}px ${Math.max(4, 22 * viewport.z)}px`;
857
- elements.zoomLabel.textContent = `${Math.round(viewport.z * 100)}%`;
858
- writeHashState();
859
- }
860
-
861
- function centeredViewportForTable(tableName) {
862
- const node = layout?.nodes.get(tableName);
863
- if (!node || isTableHidden(tableName)) return;
864
-
865
- const rect = elements.canvas.getBoundingClientRect();
866
- return {
867
- ...viewport,
868
- x: Math.round(rect.width / 2 - (node.x + node.width / 2) * viewport.z),
869
- y: Math.round(rect.height / 2 - (node.y + node.height / 2) * viewport.z),
870
- };
871
- }
872
-
873
- function fitView() {
874
- cancelViewportAnimation();
875
- if (!layout || visibleTables().length === 0) return;
876
- const bounds = visibleLayoutBounds();
877
- const rect = elements.canvas.getBoundingClientRect();
878
- const scale = clamp(
879
- Math.min(
880
- (rect.width - FIT_PADDING) / Math.max(bounds.width, 1),
881
- (rect.height - FIT_PADDING) / Math.max(bounds.height, 1),
882
- ),
883
- MIN_ZOOM,
884
- 1.2,
885
- );
886
- viewport = {
887
- z: scale,
888
- x: Math.round((rect.width - bounds.width * scale) / 2 - bounds.x * scale),
889
- y: Math.round((rect.height - bounds.height * scale) / 2 - bounds.y * scale),
890
- };
891
- applyTransform();
892
- }
893
-
894
- function centerVisibleBounds() {
895
- if (!layout || visibleTables().length === 0) return;
896
- const bounds = visibleLayoutBounds();
897
- const rect = elements.canvas.getBoundingClientRect();
898
- viewport = {
899
- z: viewport.z,
900
- x: Math.round((rect.width - bounds.width * viewport.z) / 2 - bounds.x * viewport.z),
901
- y: Math.round((rect.height - bounds.height * viewport.z) / 2 - bounds.y * viewport.z),
902
- };
903
- applyTransform();
904
- }
905
-
906
- // Determine the on-load viewport from URL state: focus the selected table, fall
907
- // back to the persisted zoom, and otherwise fit the whole diagram. Pan offsets
908
- // are intentionally not persisted in the URL.
909
- function applyInitialView() {
910
- if (selectedTable && !isTableHidden(selectedTable)) {
911
- const nextViewport = centeredViewportForTable(selectedTable);
912
- if (nextViewport) {
913
- cancelViewportAnimation();
914
- viewport = nextViewport;
915
- applyTransform();
916
- return;
917
- }
918
- }
919
- if (hasZoomFromHash) {
920
- centerVisibleBounds();
921
- return;
922
- }
923
- fitView();
924
- }
925
-
926
- function renderAll(options = {}) {
927
- layout = computeLayout(schema);
928
- applyManualNodePositions();
929
- elements.emptyState.textContent =
930
- schema.tables.length === 0 ? "No TailorDB types found." : "No visible tables.";
931
- elements.emptyState.hidden = visibleTables().length > 0;
932
- renderHeader();
933
- renderTableList();
934
- renderShowModeControls();
935
- renderEdges();
936
- renderNodes();
937
- renderDetails();
938
- if (options.fit) {
939
- fitView();
940
- return;
941
- }
942
- if (options.center && selectedTable) {
943
- const nextViewport = centeredViewportForTable(selectedTable);
944
- if (nextViewport) {
945
- if (options.smooth) {
946
- animateViewportTo(nextViewport);
947
- } else {
948
- cancelViewportAnimation();
949
- viewport = nextViewport;
950
- applyTransform();
951
- }
952
- return;
953
- }
954
- }
955
- applyTransform();
956
- }
957
-
958
- function selectTable(tableName, options = {}) {
959
- if (!tableName) return;
960
- if (selectedTable === tableName) {
961
- selectedTable = undefined;
962
- renderAll({ center: false });
963
- return;
964
- }
965
-
966
- selectedTable = tableName;
967
- userAdjustedViewport = true;
968
- renderAll({ center: options.center !== false, smooth: options.smooth !== false });
969
- }
970
-
971
- function clearTableSelection() {
972
- if (!selectedTable) return;
973
- selectedTable = undefined;
974
- renderAll({ center: false });
975
- }
976
-
977
- function zoomAt(nextZoom, clientX, clientY) {
978
- cancelViewportAnimation();
979
- userAdjustedViewport = true;
980
- const rect = elements.canvas.getBoundingClientRect();
981
- const worldX = (clientX - rect.left - viewport.x) / viewport.z;
982
- const worldY = (clientY - rect.top - viewport.y) / viewport.z;
983
- const z = clamp(nextZoom, MIN_ZOOM, MAX_ZOOM);
984
- viewport = {
985
- z,
986
- x: clientX - rect.left - worldX * z,
987
- y: clientY - rect.top - worldY * z,
988
- };
989
- applyTransform();
990
- }
991
-
992
- function panBy(deltaX, deltaY) {
993
- cancelViewportAnimation();
994
- userAdjustedViewport = true;
995
- viewport = {
996
- ...viewport,
997
- x: viewport.x - deltaX,
998
- y: viewport.y - deltaY,
999
- };
1000
- applyTransform();
1001
- }
1002
-
1003
- function startCanvasPan(event) {
1004
- if (event.button !== 0 || event.target.closest("button, input, .canvas-toolbar")) return;
1005
- cancelViewportAnimation();
1006
-
1007
- activeCanvasPan = {
1008
- moved: false,
1009
- pointerId: event.pointerId,
1010
- startClientX: event.clientX,
1011
- startClientY: event.clientY,
1012
- startX: viewport.x,
1013
- startY: viewport.y,
1014
- };
1015
- elements.canvas.setPointerCapture(event.pointerId);
1016
- }
1017
-
1018
- function moveCanvasPan(event) {
1019
- if (!activeCanvasPan || activeCanvasPan.pointerId !== event.pointerId) return;
1020
- if ((event.buttons & 1) === 0) {
1021
- finishCanvasPan(event);
1022
- return;
1023
- }
1024
-
1025
- const deltaX = event.clientX - activeCanvasPan.startClientX;
1026
- const deltaY = event.clientY - activeCanvasPan.startClientY;
1027
- if (!activeCanvasPan.moved && Math.hypot(deltaX, deltaY) < DRAG_THRESHOLD) return;
1028
-
1029
- event.preventDefault();
1030
- activeCanvasPan.moved = true;
1031
- userAdjustedViewport = true;
1032
- elements.canvas.classList.add("is-panning");
1033
- viewport = {
1034
- ...viewport,
1035
- x: activeCanvasPan.startX + deltaX,
1036
- y: activeCanvasPan.startY + deltaY,
1037
- };
1038
- applyTransform();
1039
- }
1040
-
1041
- function finishCanvasPan(event) {
1042
- if (!activeCanvasPan || activeCanvasPan.pointerId !== event.pointerId) return;
1043
-
1044
- if (elements.canvas.hasPointerCapture(event.pointerId)) {
1045
- elements.canvas.releasePointerCapture(event.pointerId);
1046
- }
1047
- if (activeCanvasPan.moved) {
1048
- event.preventDefault();
1049
- suppressNextCanvasClick = true;
1050
- }
1051
- activeCanvasPan = undefined;
1052
- elements.canvas.classList.remove("is-panning");
1053
- }
1054
-
1055
- function wireInteractions() {
1056
- elements.search.addEventListener("input", () => {
1057
- searchText = elements.search.value.trim();
1058
- renderAll();
1059
- });
1060
-
1061
- elements.zoomIn.addEventListener("click", () => {
1062
- const rect = elements.canvas.getBoundingClientRect();
1063
- zoomAt(viewport.z * 1.2, rect.left + rect.width / 2, rect.top + rect.height / 2);
1064
- });
1065
- elements.zoomOut.addEventListener("click", () => {
1066
- const rect = elements.canvas.getBoundingClientRect();
1067
- zoomAt(viewport.z / 1.2, rect.left + rect.width / 2, rect.top + rect.height / 2);
1068
- });
1069
- elements.fitView.addEventListener("click", fitView);
1070
- elements.toggleAllTables.addEventListener("click", toggleAllTableVisibility);
1071
- elements.showMode.addEventListener("click", () => {
1072
- setShowModeMenuOpen(elements.showModeMenu.hidden);
1073
- });
1074
- elements.copyLink.addEventListener("click", async () => {
1075
- try {
1076
- await navigator.clipboard.writeText(location.href);
1077
- showStatus("Link copied");
1078
- } catch {
1079
- showStatus("Copy failed", true);
1080
- }
1081
- });
1082
-
1083
- elements.canvas.addEventListener("click", (event) => {
1084
- if (suppressNextCanvasClick) {
1085
- suppressNextCanvasClick = false;
1086
- return;
1087
- }
1088
- if (event.target.closest("button, input, .canvas-toolbar")) return;
1089
- clearTableSelection();
1090
- });
1091
- elements.canvas.addEventListener(
1092
- "wheel",
1093
- (event) => {
1094
- event.preventDefault();
1095
- if (event.ctrlKey || event.metaKey) {
1096
- zoomAt(viewport.z * Math.exp(-event.deltaY * 0.001), event.clientX, event.clientY);
1097
- return;
1098
- }
1099
-
1100
- if (event.shiftKey) {
1101
- const deltaX = event.deltaX || event.deltaY;
1102
- panBy(deltaX, 0);
1103
- return;
1104
- }
1105
-
1106
- // Touchpads report horizontal swipes via deltaX without a modifier key.
1107
- panBy(event.deltaX, event.deltaY);
1108
- },
1109
- { passive: false },
1110
- );
1111
- elements.canvas.addEventListener("pointerdown", startCanvasPan);
1112
- elements.canvas.addEventListener("pointermove", moveCanvasPan);
1113
- elements.canvas.addEventListener("pointerup", finishCanvasPan);
1114
- elements.canvas.addEventListener("pointercancel", finishCanvasPan);
1115
- elements.canvas.addEventListener("lostpointercapture", finishCanvasPan);
1116
-
1117
- document.addEventListener("pointerdown", (event) => {
1118
- if (!event.target.closest(".show-mode-control")) {
1119
- setShowModeMenuOpen(false);
1120
- }
1121
- });
1122
- window.addEventListener("keydown", (event) => {
1123
- if (event.key === "Escape") setShowModeMenuOpen(false);
1124
- });
1125
- window.addEventListener("resize", () => {
1126
- if (!userAdjustedViewport) applyInitialView();
1127
- });
1128
- }
1129
-
1130
- function showStatus(message, danger = false) {
1131
- elements.status.hidden = false;
1132
- elements.status.textContent = message;
1133
- elements.status.style.color = danger ? "var(--danger)" : "var(--accent)";
1134
- clearTimeout(showStatus.timer);
1135
- showStatus.timer = setTimeout(() => {
1136
- elements.status.hidden = true;
1137
- }, 3000);
1138
- }
1139
-
1140
- function startPolling() {
1141
- const params = new URLSearchParams(location.search);
1142
- if (params.get("watch") !== "1") return;
1143
-
1144
- setInterval(async () => {
1145
- try {
1146
- const nextSchema = await fetchServedSchema();
1147
- if (nextSchema.revision !== schema.revision) {
1148
- schema = nextSchema;
1149
- if (selectedTable && !tableByName(selectedTable)) {
1150
- selectedTable = undefined;
1151
- }
1152
- clearSelectionIfHidden();
1153
- renderAll();
1154
- showStatus("Schema updated");
1155
- }
1156
- } catch (error) {
1157
- showStatus(String(error), true);
1158
- }
1159
- }, 1500);
1160
- }
1161
-
1162
- async function main() {
1163
- readHashState();
1164
- wireInteractions();
1165
- try {
1166
- schema = embeddedSchema() ?? (await fetchServedSchema());
1167
- if (selectedTable && !tableByName(selectedTable)) {
1168
- selectedTable = undefined;
1169
- }
1170
- clearSelectionIfHidden();
1171
- renderAll();
1172
- applyInitialView();
1173
- startPolling();
1174
- } catch (error) {
1175
- elements.namespace.textContent = "TailorDB ERD";
1176
- elements.revision.textContent = "Schema load failed";
1177
- showStatus(String(error), true);
1178
- }
1179
- }
1180
-
1181
- main();