@aifabrix/builder 2.43.0 → 2.44.0

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 (346) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +1 -1
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +31 -0
  7. package/integration/hubspot-test/create-hubspot.js +5 -5
  8. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  9. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  10. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  11. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  12. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  13. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  14. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  15. package/integration/hubspot-test/test.js +35 -43
  16. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  17. package/integration/roundtrip-test-local/README.md +144 -0
  18. package/integration/roundtrip-test-local/application.yaml +13 -0
  19. package/integration/roundtrip-test-local/env.template +15 -0
  20. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  21. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  22. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  23. package/integration/roundtrip-test-local2/README.md +144 -0
  24. package/integration/roundtrip-test-local2/application.yaml +13 -0
  25. package/integration/roundtrip-test-local2/env.template +15 -0
  26. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  27. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  28. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  29. package/integration/test/wizard.yaml +8 -0
  30. package/jest.config.default.js +10 -0
  31. package/jest.config.integration.fixtures.js +22 -0
  32. package/jest.config.integration.js +21 -18
  33. package/jest.config.isolated.js +10 -0
  34. package/jest.projects.js +288 -0
  35. package/lib/api/datasources-core.api.js +3 -3
  36. package/lib/api/dev-mtls-request.js +110 -0
  37. package/lib/api/dev-server-https.js +145 -0
  38. package/lib/api/dev.api.js +133 -144
  39. package/lib/api/index.js +0 -1
  40. package/lib/api/pipeline.api.js +67 -20
  41. package/lib/api/types/dev.types.js +4 -3
  42. package/lib/api/types/pipeline.types.js +8 -5
  43. package/lib/api/types/validation-run.types.js +56 -0
  44. package/lib/api/validation-run.api.js +99 -0
  45. package/lib/api/validation-runner.js +99 -0
  46. package/lib/app/config.js +1 -1
  47. package/lib/app/deploy-status-display.js +2 -2
  48. package/lib/app/deploy.js +7 -6
  49. package/lib/app/display.js +2 -1
  50. package/lib/app/dockerfile.js +3 -2
  51. package/lib/app/down.js +2 -1
  52. package/lib/app/helpers.js +6 -5
  53. package/lib/app/index.js +27 -8
  54. package/lib/app/list.js +7 -6
  55. package/lib/app/push.js +4 -3
  56. package/lib/app/register.js +16 -7
  57. package/lib/app/rotate-secret.js +14 -13
  58. package/lib/app/run-container-start.js +184 -0
  59. package/lib/app/run-docker-fallback.js +108 -0
  60. package/lib/app/run-env-compose.js +30 -42
  61. package/lib/app/run-helpers.js +49 -126
  62. package/lib/app/run-infra-requirements.js +30 -0
  63. package/lib/app/run-resolve-image.js +21 -0
  64. package/lib/app/run.js +74 -21
  65. package/lib/app/show-display.js +1 -1
  66. package/lib/app/show.js +1 -1
  67. package/lib/build/index.js +13 -10
  68. package/lib/cli/index.js +2 -0
  69. package/lib/cli/setup-app.help.js +67 -0
  70. package/lib/cli/setup-app.js +57 -121
  71. package/lib/cli/setup-app.test-commands.js +179 -0
  72. package/lib/cli/setup-auth.js +19 -5
  73. package/lib/cli/setup-credential-deployment.js +22 -8
  74. package/lib/cli/setup-dev-path-commands.js +124 -0
  75. package/lib/cli/setup-dev.js +170 -113
  76. package/lib/cli/setup-environment.js +7 -1
  77. package/lib/cli/setup-external-system.js +62 -22
  78. package/lib/cli/setup-infra.js +126 -47
  79. package/lib/cli/setup-parameters.js +32 -0
  80. package/lib/cli/setup-secrets.js +106 -8
  81. package/lib/cli/setup-service-user.js +1 -1
  82. package/lib/cli/setup-utility.js +36 -20
  83. package/lib/commands/app-down.js +5 -7
  84. package/lib/commands/app-install.js +14 -7
  85. package/lib/commands/app-logs.js +13 -10
  86. package/lib/commands/app-shell.js +4 -1
  87. package/lib/commands/app-test.js +25 -19
  88. package/lib/commands/app.js +22 -10
  89. package/lib/commands/auth-config.js +6 -6
  90. package/lib/commands/auth-status.js +4 -3
  91. package/lib/commands/credential-env.js +4 -3
  92. package/lib/commands/credential-list.js +5 -4
  93. package/lib/commands/credential-push.js +4 -3
  94. package/lib/commands/datasource-unified-test-cli.js +495 -0
  95. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  96. package/lib/commands/datasource-validation-cli.js +129 -0
  97. package/lib/commands/datasource.js +105 -98
  98. package/lib/commands/deployment-list.js +6 -5
  99. package/lib/commands/dev-cli-handlers.js +122 -18
  100. package/lib/commands/dev-down.js +4 -3
  101. package/lib/commands/dev-init.js +231 -116
  102. package/lib/commands/dev-show-display.js +473 -0
  103. package/lib/commands/login-credentials.js +3 -2
  104. package/lib/commands/login-device.js +4 -3
  105. package/lib/commands/login.js +5 -4
  106. package/lib/commands/logout.js +8 -7
  107. package/lib/commands/parameters-validate.js +54 -0
  108. package/lib/commands/repair-datasource.js +314 -68
  109. package/lib/commands/repair-env-template.js +2 -2
  110. package/lib/commands/repair.js +21 -3
  111. package/lib/commands/secrets-list.js +23 -12
  112. package/lib/commands/secrets-remove-all.js +220 -0
  113. package/lib/commands/secrets-remove.js +21 -12
  114. package/lib/commands/secrets-set.js +21 -12
  115. package/lib/commands/secrets-validate.js +4 -4
  116. package/lib/commands/secure.js +10 -9
  117. package/lib/commands/service-user.js +26 -25
  118. package/lib/commands/test-e2e-external.js +27 -1
  119. package/lib/commands/up-common.js +3 -2
  120. package/lib/commands/up-dataplane.js +29 -16
  121. package/lib/commands/up-miso.js +19 -29
  122. package/lib/commands/upload.js +138 -39
  123. package/lib/commands/wizard-core-helpers.js +1 -1
  124. package/lib/commands/wizard-dataplane.js +4 -3
  125. package/lib/commands/wizard-helpers.js +3 -3
  126. package/lib/commands/wizard.js +2 -2
  127. package/lib/core/admin-secrets.js +14 -5
  128. package/lib/core/audit-logger.js +12 -4
  129. package/lib/core/config-attach-extensions.js +46 -0
  130. package/lib/core/config-runtime-paths.js +29 -0
  131. package/lib/core/config.js +55 -56
  132. package/lib/core/diff.js +3 -2
  133. package/lib/core/ensure-encryption-key.js +1 -1
  134. package/lib/core/secrets-ensure-infra.js +77 -0
  135. package/lib/core/secrets-ensure.js +120 -64
  136. package/lib/core/secrets-env-write.js +35 -7
  137. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  138. package/lib/core/secrets.js +200 -37
  139. package/lib/core/templates-env.js +4 -3
  140. package/lib/datasource/abac-validator.js +1 -10
  141. package/lib/datasource/deploy.js +75 -53
  142. package/lib/datasource/field-reference-validator.js +9 -6
  143. package/lib/datasource/integration-context.js +63 -0
  144. package/lib/datasource/list.js +8 -7
  145. package/lib/datasource/log-viewer.js +84 -53
  146. package/lib/datasource/resolve-app.js +4 -4
  147. package/lib/datasource/test-e2e.js +95 -146
  148. package/lib/datasource/test-integration.js +114 -122
  149. package/lib/datasource/unified-validation-run-body.js +65 -0
  150. package/lib/datasource/unified-validation-run-post.js +23 -0
  151. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  152. package/lib/datasource/unified-validation-run.js +92 -0
  153. package/lib/datasource/validate.js +157 -13
  154. package/lib/deployment/deployer.js +4 -3
  155. package/lib/deployment/environment.js +7 -6
  156. package/lib/deployment/push.js +17 -8
  157. package/lib/external-system/delete.js +4 -3
  158. package/lib/external-system/deploy.js +131 -53
  159. package/lib/external-system/download-helpers.js +1 -1
  160. package/lib/external-system/download.js +7 -6
  161. package/lib/external-system/generator.js +92 -6
  162. package/lib/external-system/integration-test-dispatch.js +26 -0
  163. package/lib/external-system/test-execution.js +5 -1
  164. package/lib/external-system/test-helpers.js +0 -4
  165. package/lib/external-system/test-system-level-helpers.js +110 -0
  166. package/lib/external-system/test-system-level.js +83 -44
  167. package/lib/external-system/test.js +59 -8
  168. package/lib/generator/builders.js +23 -11
  169. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  170. package/lib/generator/external.js +16 -4
  171. package/lib/generator/helpers.js +58 -3
  172. package/lib/generator/index.js +4 -0
  173. package/lib/generator/split-readme.js +12 -7
  174. package/lib/generator/split-variables.js +2 -1
  175. package/lib/generator/split.js +1 -1
  176. package/lib/generator/wizard-readme.js +3 -3
  177. package/lib/generator/wizard.js +8 -8
  178. package/lib/infrastructure/compose.js +60 -6
  179. package/lib/infrastructure/helpers.js +201 -29
  180. package/lib/infrastructure/index.js +28 -17
  181. package/lib/infrastructure/services.js +21 -15
  182. package/lib/internal/fs-real-sync.js +104 -0
  183. package/lib/internal/node-fs.js +98 -0
  184. package/lib/parameters/database-secret-values.js +173 -0
  185. package/lib/parameters/infra-kv-discovery.js +121 -0
  186. package/lib/parameters/infra-parameter-catalog.js +458 -0
  187. package/lib/parameters/infra-parameter-validate.js +64 -0
  188. package/lib/schema/application-schema.json +37 -17
  189. package/lib/schema/datasource-test-run.schema.json +493 -0
  190. package/lib/schema/deployment-rules.yaml +102 -63
  191. package/lib/schema/external-datasource.schema.json +1200 -442
  192. package/lib/schema/external-system.schema.json +181 -5
  193. package/lib/schema/flag-map-validation-run.json +31 -0
  194. package/lib/schema/infra-parameter.schema.json +106 -0
  195. package/lib/schema/infra.parameter.yaml +421 -0
  196. package/lib/schema/type/credential-auth-templates.json +40 -0
  197. package/lib/schema/type/document-storage.json +213 -0
  198. package/lib/schema/type/message-service.json +123 -0
  199. package/lib/schema/type/vector-store.json +88 -0
  200. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  201. package/lib/utils/api-error-handler.js +2 -2
  202. package/lib/utils/api.js +49 -14
  203. package/lib/utils/app-register-api.js +3 -2
  204. package/lib/utils/app-register-auth.js +1 -1
  205. package/lib/utils/app-register-config.js +4 -4
  206. package/lib/utils/app-register-display.js +3 -2
  207. package/lib/utils/app-register-validator.js +3 -2
  208. package/lib/utils/app-run-containers.js +26 -22
  209. package/lib/utils/app-scoped-config.js +31 -0
  210. package/lib/utils/app-service-env-from-builder.js +164 -0
  211. package/lib/utils/build-copy.js +1 -1
  212. package/lib/utils/build-helpers.js +20 -20
  213. package/lib/utils/build-resolve-image.js +165 -0
  214. package/lib/utils/cli-layout-chalk.js +8 -0
  215. package/lib/utils/cli-test-layout-chalk.js +267 -0
  216. package/lib/utils/cli-utils.js +88 -11
  217. package/lib/utils/compose-db-passwords.js +138 -0
  218. package/lib/utils/compose-generate-docker-compose.js +216 -0
  219. package/lib/utils/compose-generator.js +197 -291
  220. package/lib/utils/compose-miso-env.js +18 -0
  221. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  222. package/lib/utils/config-paths.js +166 -7
  223. package/lib/utils/config-scoped-resources-preference.js +41 -0
  224. package/lib/utils/controller-deployment-outcome.js +68 -0
  225. package/lib/utils/credential-display.js +2 -2
  226. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  227. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  228. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  229. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  230. package/lib/utils/datasource-test-run-display.js +442 -0
  231. package/lib/utils/datasource-test-run-exit.js +58 -0
  232. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  233. package/lib/utils/datasource-test-run-report-version.js +51 -0
  234. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  235. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  236. package/lib/utils/datasource-validation-watch.js +266 -0
  237. package/lib/utils/declarative-url-ports.js +47 -0
  238. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  239. package/lib/utils/dev-ca-install.js +185 -23
  240. package/lib/utils/dev-cert-helper.js +266 -17
  241. package/lib/utils/dev-hosts-helper.js +307 -0
  242. package/lib/utils/dev-init-cert-hints.js +37 -0
  243. package/lib/utils/dev-init-health-messages.js +52 -0
  244. package/lib/utils/dev-init-resolve.js +86 -0
  245. package/lib/utils/dev-init-ssh-merge.js +65 -0
  246. package/lib/utils/dev-ssh-config-helper.js +196 -0
  247. package/lib/utils/dev-user-groups.js +93 -0
  248. package/lib/utils/docker-build.js +42 -17
  249. package/lib/utils/docker-exec.js +28 -0
  250. package/lib/utils/docker-manifest-public-port.js +116 -0
  251. package/lib/utils/docker-not-running-hint.js +52 -0
  252. package/lib/utils/docker.js +98 -11
  253. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  254. package/lib/utils/env-config-loader.js +10 -91
  255. package/lib/utils/env-copy.js +19 -10
  256. package/lib/utils/env-map.js +35 -8
  257. package/lib/utils/env-template.js +2 -2
  258. package/lib/utils/environment-scoped-resources.js +144 -0
  259. package/lib/utils/error-formatter.js +92 -13
  260. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  261. package/lib/utils/error-formatters/network-errors.js +2 -1
  262. package/lib/utils/error-formatters/permission-errors.js +2 -1
  263. package/lib/utils/error-formatters/validation-errors.js +2 -1
  264. package/lib/utils/external-readme.js +8 -1
  265. package/lib/utils/external-system-display.js +234 -136
  266. package/lib/utils/external-system-local-test-tty.js +389 -0
  267. package/lib/utils/external-system-readiness-core.js +377 -0
  268. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  269. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  270. package/lib/utils/external-system-readiness-display.js +186 -0
  271. package/lib/utils/external-system-test-helpers.js +24 -6
  272. package/lib/utils/external-system-validators.js +30 -12
  273. package/lib/utils/health-check-url.js +119 -0
  274. package/lib/utils/health-check.js +59 -25
  275. package/lib/utils/help-builder.js +11 -8
  276. package/lib/utils/image-version.js +4 -8
  277. package/lib/utils/infra-containers.js +4 -7
  278. package/lib/utils/infra-env-defaults.js +162 -0
  279. package/lib/utils/infra-status-display.js +167 -0
  280. package/lib/utils/infra-status.js +16 -8
  281. package/lib/utils/local-secrets.js +3 -4
  282. package/lib/utils/paths.js +134 -47
  283. package/lib/utils/port-resolver.js +10 -23
  284. package/lib/utils/redis-env-scope.js +62 -0
  285. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  286. package/lib/utils/remote-builder-validation.js +99 -0
  287. package/lib/utils/remote-dev-auth.js +117 -21
  288. package/lib/utils/remote-docker-env.js +67 -15
  289. package/lib/utils/remote-secrets-loader.js +13 -4
  290. package/lib/utils/resolve-docker-image-ref.js +124 -0
  291. package/lib/utils/schema-loader.js +22 -9
  292. package/lib/utils/secrets-bash-kv.js +25 -0
  293. package/lib/utils/secrets-generator.js +169 -49
  294. package/lib/utils/secrets-helpers.js +70 -59
  295. package/lib/utils/secrets-kv-scope.js +60 -0
  296. package/lib/utils/secrets-utils.js +32 -38
  297. package/lib/utils/secrets-validation.js +3 -1
  298. package/lib/utils/secrets-yaml-preserve.js +109 -0
  299. package/lib/utils/ssh-key-helper.js +4 -2
  300. package/lib/utils/template-helpers.js +2 -2
  301. package/lib/utils/test-log-writer.js +3 -3
  302. package/lib/utils/token-manager.js +1 -2
  303. package/lib/utils/url-declarative-public-base.js +188 -0
  304. package/lib/utils/url-declarative-resolve-build.js +493 -0
  305. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  306. package/lib/utils/url-declarative-resolve.js +220 -0
  307. package/lib/utils/url-declarative-token-parse.js +74 -0
  308. package/lib/utils/url-declarative-url-flags.js +50 -0
  309. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  310. package/lib/utils/url-public-path-prefix.js +34 -0
  311. package/lib/utils/urls-local-registry.js +220 -0
  312. package/lib/utils/validation-report-tty-kit.js +77 -0
  313. package/lib/utils/validation-run-poll.js +89 -0
  314. package/lib/utils/validation-run-post-retry.js +73 -0
  315. package/lib/utils/validation-run-request.js +98 -0
  316. package/lib/utils/variable-transformer.js +21 -4
  317. package/lib/utils/yaml-preserve.js +33 -14
  318. package/lib/validation/datasource-warnings.js +56 -0
  319. package/lib/validation/env-template-auth.js +1 -1
  320. package/lib/validation/external-manifest-validator.js +27 -7
  321. package/lib/validation/validate-display.js +37 -31
  322. package/lib/validation/validate.js +4 -13
  323. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  324. package/lib/validation/validator.js +22 -65
  325. package/lib/validation/wizard-config-validator.js +2 -1
  326. package/package.json +7 -3
  327. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  328. package/scripts/diagnose-cli.js +150 -0
  329. package/scripts/install-local.js +304 -55
  330. package/templates/README.md +15 -2
  331. package/templates/applications/dataplane/application.yaml +52 -2
  332. package/templates/applications/dataplane/env.template +75 -17
  333. package/templates/applications/dataplane/rbac.yaml +8 -0
  334. package/templates/applications/keycloak/application.yaml +9 -1
  335. package/templates/applications/keycloak/env.template +15 -6
  336. package/templates/applications/miso-controller/application.yaml +10 -2
  337. package/templates/applications/miso-controller/env.template +42 -12
  338. package/templates/applications/miso-controller/rbac.yaml +5 -0
  339. package/templates/external-system/README.md.hbs +20 -7
  340. package/templates/external-system/deploy.js.hbs +5 -5
  341. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  342. package/templates/infra/compose.yaml.hbs +20 -4
  343. package/templates/python/docker-compose.hbs +16 -0
  344. package/templates/typescript/docker-compose.hbs +16 -0
  345. package/lib/api/external-test.api.js +0 -111
  346. package/lib/schema/env-config.yaml +0 -60
@@ -1,47 +1,89 @@
1
+ # External datasource definition. Validate against lib/schema/external-datasource.schema.json (e.g. aifabrix validate / CI).
2
+ # Normative usage (metadata, FKs, dimensions, expressions, execution vs query) aligns with schema v2.4.1 and the Datasource Rules baseline (Plan 346).
3
+ # key: stable identifier (typically <systemKey>-<entity>); referenced by credentials, deploy, and datasource-chaining CIP steps.
1
4
  key: "{{fullDatasourceKey}}"
5
+ # Short name and description shown in tooling and docs.
2
6
  displayName: "{{datasourceDisplayName}}"
3
7
  description: "{{datasourceDescription}}"
8
+ # Parent external system this datasource belongs to (matches external-system key).
4
9
  systemKey: "{{systemKey}}"
10
+ # entityType: recordStorage = structured rows in DB; documentStorage = same family + binary/large content outside metadata_json;
11
+ # vectorStore = retrieval/embedding external store; messageService = channels/notifications; none = orchestration/API composition ONLY.
12
+ # If none: do NOT add metadataSchema, primaryKey, labelKey, dimensions, fieldMappings, sync, documentStorage, etc. (schema forbids them).
5
13
  entityType: "{{schemaEntityType}}"
14
+ # Fine-grained resource classification (e.g. customer, document); used for UX and policies.
6
15
  resourceType: "{{resourceType}}"
16
+ enabled: true
17
+ # File / config version for this YAML (distinct from execution.cip.version when you add CIP below).
18
+ version: "1.0.0"
19
+ {{#unless (eq schemaEntityType "none")}}
20
+ # primaryKey: normalized attribute names used for get/update/delete and storage keys (must exist in metadataSchema + fieldMappings).
7
21
  primaryKey:
8
22
  {{#each primaryKey}} - "{{this}}"
9
23
  {{/each}}
10
- enabled: true
11
- version: "1.0.0"
12
- fieldMappings:
13
- {{#if dimensions}}
14
- dimensions:
15
- {{#each dimensions}}
16
- {{@key}}: "{{this}}"
24
+ # labelKey: attributes used for display labels (search, pickers); often includes primaryKey + human-readable fields.
25
+ labelKey:
26
+ {{#each labelKey}} - "{{this}}"
27
+ {{/each}}
28
+ # metadataSchema: canonical normalized fields (camelCase). Only index=true / filter=true scalars materialize as DB columns; full shape lives in metadata_json.
29
+ # Allowed on fields: type, format, index, filter, nullable, description, string/number validation keywords. Forbidden: anyOf/oneOf/allOf/not/enum/const in author trees.
30
+ # Datetime: type string + format date-time, UTC. Max structural depth per product rules (~2); avoid deep JSON for filter/join paths.
31
+ metadataSchema:
32
+ type: object
33
+ required:
34
+ {{#each attributeKeysForMetadata}} - "{{this}}"
35
+ {{/each}}
36
+ properties:
37
+ {{#each attributeKeysForMetadata}}
38
+ {{this}}:
39
+ type: string
40
+ {{#if (eq this "externalId")}} index: true
41
+ {{else}}{{#if (eq this "id")}} index: true
42
+ {{else}}{{#if @first}} index: true
43
+ {{else}} filter: true
44
+ {{/if}}{{/if}}{{/if}}
45
+ {{/each}}
46
+ {{#if dimensionBindingEntries}}
47
+ # dimensions: top-level only. type local binds to an indexed metadata field; type fk uses via: [{ fk, dimension }]. Optional for global reference data; expected when ABAC/FK joins apply (Plan 346 section 7).
48
+ # Actors: displayName|email|userId → operator eq; groups|roles → in. If actor is omitted, operator should be omitted (operator has no effect without actor).
49
+ dimensions:
50
+ {{#each dimensionBindingEntries}}
51
+ {{dimKey}}:
52
+ type: local
53
+ field: "{{field}}"
54
+ actor: displayName
55
+ operator: eq
17
56
  {{/each}}
18
- {{else}}
19
- dimensions: {}
20
- # Optional: add country, department, organization for ABAC
21
57
  {{/if}}
58
+ # fieldMappings: normalization-only. Each attribute allows only { expression }. Roots MUST be raw.*, fk.*, or dimension.* (e.g. raw.id, fk.company.metadata.name).
59
+ # Heavy transforms belong upstream, in sync, or in entityType none orchestration — not here. Output keys MUST match metadataSchema properties.
60
+ fieldMappings:
22
61
  attributes:
23
62
  {{#if attributes}}
24
63
  {{#each attributes}}
25
64
  {{@key}}:
26
65
  expression: "{{this.expression}}"
27
- type: {{this.type}}
28
- indexed: {{#if this.indexed}}true{{else}}false{{/if}}
29
66
  {{/each}}
30
67
  {{else}}
31
68
  id:
32
69
  expression: "{{raw.id}}"
33
- type: string
34
- indexed: true
35
70
  name:
36
71
  expression: "{{raw.name}}"
37
- type: string
38
- indexed: false
39
72
  {{/if}}
73
+ # foreignKeys (optional): declare join graph to other storage datasources. name + fields[] (indexed metadata fields) + targetDatasource; acyclic; types must match (Plan 346 sections 6 and 8).
74
+ # foreignKeys:
75
+ # - name: company
76
+ # fields: [companyId]
77
+ # targetDatasource: my-system-company
78
+ {{/unless}}
40
79
  {{#if (eq systemType "openapi")}}
80
+ # openapi: links this datasource to the generated OpenAPI document (same systemKey-api artifact). CIP fetch.openapiRef uses keys below: list, get, …
41
81
  openapi:
42
82
  enabled: true
83
+ # Must match the OpenAPI bundle key published for this system (wizard default: <systemKey>-api).
43
84
  documentKey: "{{systemKey}}-api"
44
85
  operations:
86
+ # Standard names list/get/create/update/delete; operationId and path should match your spec. CIP uses openapiRef: list | get.
45
87
  list:
46
88
  operationId: "list{{entityKey}}"
47
89
  method: GET
@@ -50,168 +92,205 @@ openapi:
50
92
  operationId: "get{{entityKey}}"
51
93
  method: GET
52
94
  path: "/{{entityKey}}/{id}"
95
+ # When true, runtime can derive RBAC hints from OpenAPI metadata where supported.
53
96
  autoRbac: true
54
97
  {{/if}}
55
98
 
56
99
  # --- Optional sections: uncomment or delete as needed ---
57
- # CIP (Custom Integration Pipeline) supports: fetch, paginate, map, filter, output, pythonInline steps.
58
- # Operations: list, get, create, update, delete. Pagination: cursor | page | offset.
100
+ #
101
+ # Query-time (v2.4): public list/get/filter are served from persisted Dataplane DB not live external HTTP on every read (Plan 346 section 11).
102
+ # External APIs: sync jobs and create/update/delete execution paths. CIP fetch→map is for ingestion, writes, or orchestration — populate storage before expecting query APIs.
103
+ #
104
+ # CIP (Composable Integration Pipeline): fetch → [paginate] → [map] → [filter] → output
105
+ # Sources: openapi (openapi.operations.<name>), http (method + path), datasource (another datasource key + operation name). Operation names: ^[a-z][a-zA-Z0-9]*$
106
+ # execution.cip requires version "1.0" and operations.<name>.steps ($defs.cipDefinition). Custom operation keys must match the same pattern as capabilities[].
107
+ #
59
108
  {{#if (eq schemaEntityType "recordStorage")}}
109
+ # sync: external APIs run during sync (Plan 346 section 11). Minimal contract: mode/schedule/batchSize per schema. FK fields on a record should update atomically in one logical write.
60
110
  # sync:
61
111
  # pull:
62
112
  # enabled: true
63
113
  # schedule: "0 * * * *"
114
+ # batchSize: 500
115
+ # validation: structural / pre-persistence checks; quality: post-mapping acceptance (e.g. rejectIf) — see schema when you enable them.
116
+ # capabilities: standard names list, get, create, update, delete + custom names matching ^[a-z][a-zA-Z0-9]*$; must match execution.cip.operations / openapi.operations you implement.
64
117
  # capabilities: [list, get]
65
118
  {{/if}}
66
119
  {{#if (eq schemaEntityType "documentStorage")}}
120
+ # documentStorage: binary/attachment flow — which operation fetches bytes and which metadata field holds extractable text for embeddings.
67
121
  # documentStorage:
68
122
  # enabled: true
69
123
  # binaryOperationRef: get
70
124
  # embeddingField: content
71
125
  {{/if}}
72
126
  {{#if (eq schemaEntityType "vectorStore")}}
127
+ # vectorStore: vector index settings (model id, dimensions, etc. per schema). Uncomment and set to match your embedding deployment.
73
128
  # vectorStore:
74
129
  # enabled: true
75
130
  # embeddingModel: "text-embedding-ada-002"
76
131
  {{/if}}
77
132
  {{#if (eq schemaEntityType "messageService")}}
133
+ # messageService: channel-oriented messaging integration; channels list drives subscription/send surfaces.
78
134
  # messageService:
79
135
  # enabled: true
80
136
  # channels: []
81
137
  {{/if}}
82
138
 
83
- # --- execution: CIP pipeline ---
84
- # Steps: fetch (openapi/http) → paginate (cursor|page|offset) → map (useFieldMappings, inputPath) → filter (enforceAbac, expression) → output (mode: records)
85
- # Pagination: cursor=cursorField+cursorParam | page=pageParam+pageSizeParam | offset=offsetParam+pageSizeParam
86
- # Adjust inputPath to your API ($.results[*], $.items[*], $.value[*], etc.)
87
- {{#if (eq schemaEntityType "recordStorage")}}
139
+ {{#unless (eq schemaEntityType "none")}}
140
+ {{#if (eq systemType "openapi")}}
141
+ # Example CIP (commented): matches openapi.operations list/get for "{{entityKey}}" above — copy, uncomment, tune inputPath/query.
142
+ # Alternative engines: execution.engine python (custom handler) or datasource (chain); see schema execution.* properties.
143
+ #
88
144
  # execution:
89
145
  # engine: cip
90
146
  # cip:
147
+ # version: "1.0"
148
+ # # Optional: idempotency / runtimeContext blocks live alongside version at this level (schema $defs.idempotencyConfig, cipRuntimeContext).
91
149
  # operations:
92
150
  # list:
93
151
  # enabled: true
94
- # description: "List all records"
152
+ # description: "List {{entityKey}} records"
95
153
  # steps:
96
- # - fetch: { source: openapi, openapiRef: list, query: {} }
97
- # - paginate: { strategy: cursor, cursorField: "$.paging.next.after", cursorParam: after, pageSize: 100, maxPages: 100 }
98
- # # Alternative: page → pageParam, pageSizeParam | offset → offsetParam, pageSizeParam
99
- # - map: { useFieldMappings: true, inputPath: "$.results[*]" }
100
- # - filter: { enforceAbac: true }
101
- # # Optional: filter.expression for SQL or JSON filter, e.g. expression: "status = 'active'"
102
- # - output: { mode: records }
154
+ # - fetch:
155
+ # source: openapi
156
+ # openapiRef: list
157
+ # query: {}
158
+ # # expectedItemsPath: "$.results"
159
+ # # - paginate:
160
+ # # strategy: cursor
161
+ # # cursorField: "next_cursor"
162
+ # # cursorParam: "cursor"
163
+ # # pageSize: 100
164
+ # # maxPages: 50
165
+ # - map:
166
+ # useFieldMappings: true
167
+ # # inputPath: JSONPath-like slice over the fetch body; must match list payload (array of raw objects before fieldMappings).
168
+ # inputPath: "$.results[*]"
169
+ # # Try $.items[*], $.data[*], etc. if your list lives under a different key (schema default hint is $.items[*]).
170
+ # # inline: { customField: "\{{raw.custom}}" } # optional field override beside useFieldMappings
171
+ # - filter:
172
+ # enforceAbac: true
173
+ # # expression "@": pass records through JMESPath after ABAC; replace with a predicate when you need server-side row filtering.
174
+ # expression: "@"
175
+ # expressionLanguage: jmespath
176
+ # # abac: { mode: mandatory, policyScope: datasource }
177
+ # - output:
178
+ # mode: records
179
+ # # limit: soft cap on list size; sync jobs may override.
180
+ # # limit: 500
181
+ # # includeConfidence: true # optional per-record scoring when supported
103
182
  # get:
104
183
  # enabled: true
105
- # description: "Get record by ID"
106
- # steps:
107
- # - fetch: { source: openapi, openapiRef: get, query: {} }
108
- # - map: { useFieldMappings: true, inputPath: "$" }
109
- # - filter: { enforceAbac: true }
110
- # - output: { mode: records }
111
- # create:
112
- # steps:
113
- # - fetch: { source: openapi, openapiRef: create, bodyTemplate: "{{body}}" }
114
- # - map: { useFieldMappings: true, inputPath: "$" }
115
- # - output: { mode: records }
116
- # update:
117
- # steps:
118
- # - fetch: { source: openapi, openapiRef: update, bodyTemplate: "{{body}}" }
119
- # - map: { useFieldMappings: true, inputPath: "$" }
120
- # - output: { mode: records }
121
- # delete:
184
+ # description: "Single {{entityKey}} by id (path /{{entityKey}}/{id} on openapi.get)"
122
185
  # steps:
123
- # - fetch: { source: openapi, openapiRef: delete }
124
- # - output: { mode: records }
125
- {{/if}}
126
- {{#if (eq schemaEntityType "documentStorage")}}
186
+ # - fetch:
187
+ # source: openapi
188
+ # openapiRef: get
189
+ # query:
190
+ # id: "{{raw.id}}"
191
+ # # If your API uses a different param name, rename the key; path params are resolved per your OpenAPI operation.
192
+ # # onError: { retry: { maxAttempts: 3 } } # optional per-step error policy (schema $defs.cipOnErrorConfig)
193
+ # - map:
194
+ # useFieldMappings: true
195
+ # # Single-object body: "$" or a path to the entity object inside a wrapper response.
196
+ # inputPath: "$"
197
+ # # Wrapped entity: use "$.data" or "$.result"
198
+ # - filter:
199
+ # enforceAbac: true
200
+ # expression: "@"
201
+ # expressionLanguage: jmespath
202
+ # - output:
203
+ # mode: records
204
+ # # Optional: delegate to another datasource's CIP
205
+ # # related:
206
+ # # enabled: true
207
+ # # steps:
208
+ # # - fetch: { source: datasource, datasource: "other-system-entity", operation: list, parameters: {} }
209
+ # # - output: { mode: records }
210
+ {{else}}
211
+ # Example CIP (commented): no openapi block in this file — use http fetch (or add openapi: first, then use the openapi example pattern).
212
+ # http fetch: method + path are required; query holds static query params (runtime may merge ABAC params).
213
+ #
127
214
  # execution:
128
215
  # engine: cip
129
216
  # cip:
217
+ # version: "1.0"
130
218
  # operations:
131
219
  # list:
132
220
  # enabled: true
133
- # description: "List documents"
134
221
  # steps:
135
- # - fetch: { source: openapi, openapiRef: list, query: {} }
136
- # - paginate: { strategy: offset, offsetParam: skip, pageSizeParam: top, pageSize: 100, maxPages: 100 }
137
- # - map: { useFieldMappings: true, inputPath: "$.value[*]" }
138
- # - filter: { enforceAbac: true }
139
- # - output: { mode: records }
222
+ # - fetch:
223
+ # source: http
224
+ # method: GET
225
+ # path: "/{{entityKey}}"
226
+ # query: {}
227
+ # # headers: { Accept: "application/json" }
228
+ # - map:
229
+ # useFieldMappings: true
230
+ # inputPath: "$.items[*]"
231
+ # - filter:
232
+ # enforceAbac: true
233
+ # expression: "@"
234
+ # expressionLanguage: jmespath
235
+ # - output:
236
+ # mode: records
140
237
  # get:
141
238
  # enabled: true
142
- # description: "Get document by ID"
143
- # steps:
144
- # - fetch: { source: openapi, openapiRef: get, query: {} }
145
- # - map: { useFieldMappings: true, inputPath: "$" }
146
- # - filter: { enforceAbac: true }
147
- # - output: { mode: records }
148
- # create:
149
- # enabled: true
150
- # description: "Upload document"
151
239
  # steps:
152
- # - fetch: { source: openapi, openapiRef: create, bodyTemplate: "{{fileContent}}" }
153
- # - map: { useFieldMappings: true, inputPath: "$" }
154
- # - output: { mode: records }
155
- {{/if}}
156
- {{#if (eq schemaEntityType "vectorStore")}}
157
- # execution:
158
- # engine: cip
159
- # cip:
160
- # operations:
161
- # list:
162
- # steps:
163
- # - fetch: { source: openapi, openapiRef: list, query: {} }
164
- # - map: { useFieldMappings: true, inputPath: "$" }
165
- # - output: { mode: records }
166
- # get:
167
- # steps:
168
- # - fetch: { source: openapi, openapiRef: get, query: {} }
169
- # - map: { useFieldMappings: true, inputPath: "$" }
170
- # - output: { mode: records }
171
- {{/if}}
172
- {{#if (eq schemaEntityType "messageService")}}
173
- # execution:
174
- # engine: cip
175
- # cip:
176
- # operations:
177
- # list:
178
- # steps:
179
- # - fetch: { source: openapi, openapiRef: list, query: {} }
180
- # - map: { useFieldMappings: true, inputPath: "$" }
181
- # - output: { mode: records }
240
+ # - fetch:
241
+ # source: http
242
+ # method: GET
243
+ # # Path template must match your API; {id} is illustrative — align with real route and param names.
244
+ # path: "/{{entityKey}}/{id}"
245
+ # query: {}
246
+ # - map:
247
+ # useFieldMappings: true
248
+ # inputPath: "$"
249
+ # - filter:
250
+ # enforceAbac: true
251
+ # expression: "@"
252
+ # expressionLanguage: jmespath
253
+ # - output:
254
+ # mode: records
182
255
  {{/if}}
256
+ {{/unless}}
183
257
  {{#if (eq schemaEntityType "none")}}
184
- # execution:
258
+ # execution (entityType none — orchestration / API composition only; no storage contract on this datasource):
259
+ # Cross-datasource access without FK is not a query-time join: use FK graph, bridge recordStorage, pre-normalize, or fan-out here (Plan 346 section 5).
185
260
  # engine: cip
186
261
  # cip:
262
+ # version: "1.0"
187
263
  # operations:
188
264
  # list:
189
265
  # steps:
190
266
  # - fetch: { source: openapi, openapiRef: list, query: {} }
191
- # - map: { useFieldMappings: true, inputPath: "$" }
192
- # - output: { mode: records }
193
- # get:
194
- # steps:
195
- # - fetch: { source: openapi, openapiRef: get, query: {} }
196
- # - map: { useFieldMappings: true, inputPath: "$" }
197
267
  # - output: { mode: records }
268
+ # # Chain another datasource (no fieldMappings on this datasource):
269
+ # # chain:
270
+ # # steps:
271
+ # # - fetch: { source: datasource, datasource: "upstream-system-entity", operation: list, parameters: {} }
272
+ # # - output: { mode: records }
198
273
  {{/if}}
199
274
 
200
- # config: ABAC cross-system filters (SQL or JSON)
275
+ # config.extensions: vendor-specific knobs; property names must match ^x[A-Z]… (e.g. xHubSpotFeature). Keeps core schema stable.
201
276
  # config:
202
- # abac:
203
- # crossSystemSql: "country = '{{actor.country}}'"
204
- # # crossSystemJson: { "dimensions.country": { "eq": "{{actor.country}}" } }
277
+ # extensions:
278
+ # xHubSpotFeature: {}
205
279
 
206
- # capabilities: [list, get, create, update, delete]
207
-
208
- # exposed: attributes to expose via MCP/OpenAPI
280
+ # exposed.schema: single public response shape for REST/MCP; values are expressions (metadata.*, dimension.*, fk.*.metadata.*). No implicit fields; use exposed.readonly[] / exposed.omit[] for writes (Plan 346 section 13). exposed.attributes is deprecated.
209
281
  # exposed:
210
- # attributes: [id, name]
282
+ # schema:
283
+ # id: metadata.id
284
+ # name: metadata.name
285
+ # # nested objects and fk.* paths are allowed when foreignKeys exist and join rules pass join rules (section 8)
286
+ # # readonly: [status]
287
+ # # omit: [internalScore]
211
288
 
212
- # metadataSchema: JSON Schema for raw metadata validation
213
- # metadataSchema:
214
- # type: object
215
- # properties:
216
- # id: { type: string }
217
- # name: { type: string }
289
+ # testPayload (optional): fixtures for static expression resolution (raw/fk/dimension); root keys are closed in schema — no typos at top level (Plan 346 section 16).
290
+ # testPayload:
291
+ # mode: smoke
292
+ # payloadTemplate:
293
+ # raw: { id: "1", name: "Example" }
294
+
295
+ # capabilities: root-level array preferred (v2.2+); names must match ^[a-z][a-zA-Z0-9]*$.
296
+ # capabilities: [list, get, create, update, delete]
@@ -17,7 +17,9 @@ services:
17
17
  - "{{postgresPort}}:5432"
18
18
  volumes:
19
19
  - {{#if (eq devId 0)}}postgres_data{{else}}dev{{devId}}_postgres_data{{/if}}:/var/lib/postgresql/data
20
- - ./init-scripts:/docker-entrypoint-initdb.d
20
+ - type: bind
21
+ source: "{{initScriptsBind}}"
22
+ target: /docker-entrypoint-initdb.d
21
23
  networks:
22
24
  - {{networkName}}
23
25
  healthcheck:
@@ -61,7 +63,10 @@ services:
61
63
  - "{{pgadminPort}}:80"
62
64
  volumes:
63
65
  - {{#if (eq devId 0)}}pgadmin_data{{else}}dev{{devId}}_pgadmin_data{{/if}}:/var/lib/pgadmin
64
- - {{infraDir}}:/host-config:ro
66
+ - type: bind
67
+ source: "{{infraDirBind}}"
68
+ target: /host-config
69
+ read_only: true
65
70
  command: >
66
71
  sh -c "
67
72
  if [ -f /host-config/servers.json ]; then
@@ -110,8 +115,13 @@ services:
110
115
  - "--providers.docker=true"
111
116
  - "--providers.docker.exposedbydefault=false"
112
117
  - "--providers.docker.network={{networkName}}"
118
+ - "--providers.docker.allowEmptyServices=true"
119
+ - "--log.level=INFO"
113
120
  - "--entrypoints.web.address=:80"
114
121
  - "--entrypoints.websecure.address=:443"
122
+ {{#if traefik.trustForwardedHeaders}}
123
+ - "--entrypoints.web.forwardedHeaders.insecure=true"
124
+ {{/if}}
115
125
  {{#if traefik.certStore}}
116
126
  {{#if traefik.certFile}}
117
127
  - "--certificatesstores.{{traefik.certStore}}.defaultcertificate.certfile={{traefik.certFile}}"
@@ -126,10 +136,16 @@ services:
126
136
  volumes:
127
137
  - /var/run/docker.sock:/var/run/docker.sock:ro
128
138
  {{#if traefik.certFile}}
129
- - {{traefik.certFile}}:{{traefik.certFile}}:ro
139
+ - type: bind
140
+ source: "{{traefik.certFile}}"
141
+ target: "{{traefik.certFile}}"
142
+ read_only: true
130
143
  {{/if}}
131
144
  {{#if traefik.keyFile}}
132
- - {{traefik.keyFile}}:{{traefik.keyFile}}:ro
145
+ - type: bind
146
+ source: "{{traefik.keyFile}}"
147
+ target: "{{traefik.keyFile}}"
148
+ read_only: true
133
149
  {{/if}}
134
150
  networks:
135
151
  - {{networkName}}
@@ -13,16 +13,28 @@ services:
13
13
  {{#if traefik.tls}}
14
14
  - "traefik.http.routers.{{app.key}}.entrypoints=websecure"
15
15
  - "traefik.http.routers.{{app.key}}.tls=true"
16
+ - "traefik.http.routers.{{app.key}}.service={{app.key}}"
16
17
  {{#if traefik.certStore}}
17
18
  - "traefik.http.routers.{{app.key}}.tls.certstore={{traefik.certStore}}"
18
19
  {{/if}}
20
+ - "traefik.http.routers.{{app.key}}-http.rule=Host(`{{traefik.host}}`) && PathPrefix(`{{traefik.path}}`)"
21
+ - "traefik.http.routers.{{app.key}}-http.entrypoints=web"
22
+ {{#unless (eq traefik.path "/")}}
23
+ {{#if traefik.stripPathPrefix}}
24
+ - "traefik.http.routers.{{app.key}}-http.middlewares={{app.key}}-stripprefix"
25
+ {{/if}}
26
+ {{/unless}}
27
+ - "traefik.http.routers.{{app.key}}-http.service={{app.key}}"
19
28
  {{else}}
20
29
  - "traefik.http.routers.{{app.key}}.entrypoints=web"
30
+ - "traefik.http.routers.{{app.key}}.service={{app.key}}"
21
31
  {{/if}}
22
32
  - "traefik.http.services.{{app.key}}.loadbalancer.server.port={{containerPort}}"
23
33
  {{#unless (eq traefik.path "/")}}
34
+ {{#if traefik.stripPathPrefix}}
24
35
  - "traefik.http.middlewares.{{app.key}}-stripprefix.stripprefix.prefixes={{traefik.path}}"
25
36
  - "traefik.http.routers.{{app.key}}.middlewares={{app.key}}-stripprefix"
37
+ {{/if}}
26
38
  {{/unless}}
27
39
  {{/if}}
28
40
  environment:
@@ -59,7 +71,11 @@ services:
59
71
  {{/if}}
60
72
  {{/if}}
61
73
  healthcheck:
74
+ {{#if healthCheck.bashProbe}}
75
+ test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/127.0.0.1/{{port}} && printf \"GET {{healthCheck.path}} HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && head -n1 <&3 | grep -q \"200 OK\"'"]
76
+ {{else}}
62
77
  test: ["CMD", "curl", "-f", "http://localhost:{{port}}{{healthCheck.path}}"]
78
+ {{/if}}
63
79
  interval: {{healthCheck.interval}}s
64
80
  timeout: 10s
65
81
  retries: 3
@@ -13,16 +13,28 @@ services:
13
13
  {{#if traefik.tls}}
14
14
  - "traefik.http.routers.{{app.key}}.entrypoints=websecure"
15
15
  - "traefik.http.routers.{{app.key}}.tls=true"
16
+ - "traefik.http.routers.{{app.key}}.service={{app.key}}"
16
17
  {{#if traefik.certStore}}
17
18
  - "traefik.http.routers.{{app.key}}.tls.certstore={{traefik.certStore}}"
18
19
  {{/if}}
20
+ - "traefik.http.routers.{{app.key}}-http.rule=Host(`{{traefik.host}}`) && PathPrefix(`{{traefik.path}}`)"
21
+ - "traefik.http.routers.{{app.key}}-http.entrypoints=web"
22
+ {{#unless (eq traefik.path "/")}}
23
+ {{#if traefik.stripPathPrefix}}
24
+ - "traefik.http.routers.{{app.key}}-http.middlewares={{app.key}}-stripprefix"
25
+ {{/if}}
26
+ {{/unless}}
27
+ - "traefik.http.routers.{{app.key}}-http.service={{app.key}}"
19
28
  {{else}}
20
29
  - "traefik.http.routers.{{app.key}}.entrypoints=web"
30
+ - "traefik.http.routers.{{app.key}}.service={{app.key}}"
21
31
  {{/if}}
22
32
  - "traefik.http.services.{{app.key}}.loadbalancer.server.port={{containerPort}}"
23
33
  {{#unless (eq traefik.path "/")}}
34
+ {{#if traefik.stripPathPrefix}}
24
35
  - "traefik.http.middlewares.{{app.key}}-stripprefix.stripprefix.prefixes={{traefik.path}}"
25
36
  - "traefik.http.routers.{{app.key}}.middlewares={{app.key}}-stripprefix"
37
+ {{/if}}
26
38
  {{/unless}}
27
39
  {{/if}}
28
40
  environment:
@@ -59,7 +71,11 @@ services:
59
71
  {{/if}}
60
72
  {{/if}}
61
73
  healthcheck:
74
+ {{#if healthCheck.bashProbe}}
75
+ test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/127.0.0.1/{{port}} && printf \"GET {{healthCheck.path}} HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && head -n1 <&3 | grep -q \"200 OK\"'"]
76
+ {{else}}
62
77
  test: ["CMD", "curl", "-f", "http://localhost:{{port}}{{healthCheck.path}}"]
78
+ {{/if}}
63
79
  interval: {{healthCheck.interval}}s
64
80
  timeout: 10s
65
81
  retries: 3
@@ -1,111 +0,0 @@
1
- /**
2
- * @fileoverview External test API - dataplane external endpoints (test, test-e2e)
3
- * @author AI Fabrix Team
4
- * @version 2.0.0
5
- */
6
-
7
- const { ApiClient } = require('./index');
8
-
9
- /**
10
- * Run E2E test for one datasource (config, credential, sync, data, CIP) via dataplane external API.
11
- * Requires Bearer token or API key; client credentials are not accepted.
12
- * When asyncRun is true, POST returns 202 with { testRunId, status, startedAt }; caller must poll
13
- * getE2ETestRun until status is 'completed' or 'failed'. When asyncRun is false, POST returns 200
14
- * with sync body { steps, success, error?, ... }.
15
- *
16
- * @requiresPermission {Dataplane} external-data-source:read
17
- * @async
18
- * @function testDatasourceE2E
19
- * @param {string} dataplaneUrl - Dataplane base URL
20
- * @param {string} sourceIdOrKey - Source ID or datasource key (e.g. hubspot-test-contacts)
21
- * @param {Object} authConfig - Authentication configuration (must have token or apiKey; client creds rejected)
22
- * @param {Object} [body] - Optional request body (e.g. includeDebug, testCrud, recordId, cleanup, primaryKeyValue)
23
- * @param {Object} [options] - Optional options
24
- * @param {boolean} [options.asyncRun] - If true, request async run (query param asyncRun=true); response may be 202 with testRunId
25
- * @returns {Promise<Object>} Response with success, data (sync: steps/success/error; async start: testRunId/status/startedAt), status
26
- * @throws {Error} If auth lacks Bearer/API_KEY or if test fails
27
- */
28
- async function testDatasourceE2E(dataplaneUrl, sourceIdOrKey, authConfig, body = {}, options = {}) {
29
- if (!authConfig.token && !authConfig.apiKey) {
30
- throw new Error(
31
- 'E2E tests require Bearer token or API key. Run \'aifabrix login\' or configure API key. ' +
32
- 'Client credentials are not supported for external test endpoints.'
33
- );
34
- }
35
- const client = new ApiClient(dataplaneUrl, authConfig);
36
- const postOptions = { body };
37
- if (options.asyncRun === true) {
38
- postOptions.params = { asyncRun: 'true' };
39
- }
40
- return await client.post(`/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test-e2e`, postOptions);
41
- }
42
-
43
- /**
44
- * Poll E2E test run status. Call after testDatasourceE2E with asyncRun true when response has testRunId.
45
- * Same auth as E2E (Bearer or API key).
46
- *
47
- * @requiresPermission {Dataplane} external-data-source:read
48
- * @async
49
- * @function getE2ETestRun
50
- * @param {string} dataplaneUrl - Dataplane base URL
51
- * @param {string} sourceIdOrKey - Source ID or datasource key
52
- * @param {string} testRunId - Test run ID from async start response
53
- * @param {Object} authConfig - Authentication configuration (must have token or apiKey)
54
- * @returns {Promise<Object>} Poll response: { status, completedActions?, steps?, success?, error?, durationSeconds?, debug? }
55
- * @throws {Error} If auth lacks Bearer/API_KEY, or if run not found/expired (404)
56
- */
57
- async function getE2ETestRun(dataplaneUrl, sourceIdOrKey, testRunId, authConfig) {
58
- if (!authConfig.token && !authConfig.apiKey) {
59
- throw new Error(
60
- 'E2E poll requires Bearer token or API key. Run \'aifabrix login\' or configure API key.'
61
- );
62
- }
63
- if (!testRunId || typeof testRunId !== 'string') {
64
- throw new Error('testRunId is required for E2E poll');
65
- }
66
- const client = new ApiClient(dataplaneUrl, authConfig);
67
- const response = await client.get(
68
- `/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test-e2e/${encodeURIComponent(testRunId)}`
69
- );
70
- if (!response.success) {
71
- if (response.status === 404) {
72
- throw new Error(
73
- `E2E test run not found or expired (run ID: ${testRunId}). The run may have been purged or the ID is invalid.`
74
- );
75
- }
76
- throw new Error(response.formattedError || response.error || 'E2E poll failed');
77
- }
78
- return response.data || response;
79
- }
80
-
81
- /**
82
- * Run config test for one datasource via dataplane external API.
83
- * Requires Bearer token or API key; client credentials are not accepted.
84
- *
85
- * @requiresPermission {Dataplane} external-data-source:read
86
- * @async
87
- * @function testDatasourceConfig
88
- * @param {string} dataplaneUrl - Dataplane base URL
89
- * @param {string} sourceIdOrKey - Source ID or datasource key
90
- * @param {Object} authConfig - Authentication configuration
91
- * @param {Object} [body] - Optional request body
92
- * @returns {Promise<Object>} Config test response
93
- * @throws {Error} If auth lacks Bearer/API_KEY or if test fails
94
- */
95
- async function testDatasourceConfig(dataplaneUrl, sourceIdOrKey, authConfig, body = {}) {
96
- if (!authConfig.token && !authConfig.apiKey) {
97
- throw new Error(
98
- 'External config tests require Bearer token or API key. Run \'aifabrix login\' or configure API key.'
99
- );
100
- }
101
- const client = new ApiClient(dataplaneUrl, authConfig);
102
- return await client.post(`/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test`, {
103
- body
104
- });
105
- }
106
-
107
- module.exports = {
108
- testDatasourceE2E,
109
- getE2ETestRun,
110
- testDatasourceConfig
111
- };