@ankhorage/infra 4.1.12 → 5.1.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 (528) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +21 -32
  3. package/dist/cli/bin.d.ts +1 -8
  4. package/dist/cli/bin.d.ts.map +1 -1
  5. package/dist/cli/bin.js +2 -34
  6. package/dist/cli/bin.js.map +1 -1
  7. package/dist/cli/commands/destroy.d.ts +11 -0
  8. package/dist/cli/commands/destroy.d.ts.map +1 -0
  9. package/dist/cli/commands/destroy.js +51 -0
  10. package/dist/cli/commands/destroy.js.map +1 -0
  11. package/dist/cli/commands/down.d.ts +11 -0
  12. package/dist/cli/commands/down.d.ts.map +1 -0
  13. package/dist/cli/commands/down.js +27 -0
  14. package/dist/cli/commands/down.js.map +1 -0
  15. package/dist/cli/commands/generate.d.ts +11 -0
  16. package/dist/cli/commands/generate.d.ts.map +1 -0
  17. package/dist/cli/commands/generate.js +29 -0
  18. package/dist/cli/commands/generate.js.map +1 -0
  19. package/dist/cli/commands/outputs.d.ts +11 -0
  20. package/dist/cli/commands/outputs.d.ts.map +1 -0
  21. package/dist/cli/commands/outputs.js +25 -0
  22. package/dist/cli/commands/outputs.js.map +1 -0
  23. package/dist/cli/commands/plan.d.ts +11 -0
  24. package/dist/cli/commands/plan.d.ts.map +1 -0
  25. package/dist/cli/commands/plan.js +19 -0
  26. package/dist/cli/commands/plan.js.map +1 -0
  27. package/dist/cli/commands/status.d.ts +11 -0
  28. package/dist/cli/commands/status.d.ts.map +1 -0
  29. package/dist/cli/commands/status.js +19 -0
  30. package/dist/cli/commands/status.js.map +1 -0
  31. package/dist/cli/commands/up.d.ts +11 -0
  32. package/dist/cli/commands/up.d.ts.map +1 -0
  33. package/dist/cli/commands/up.js +28 -0
  34. package/dist/cli/commands/up.js.map +1 -0
  35. package/dist/cli/commands/validate.d.ts +11 -0
  36. package/dist/cli/commands/validate.d.ts.map +1 -0
  37. package/dist/cli/commands/validate.js +19 -0
  38. package/dist/cli/commands/validate.js.map +1 -0
  39. package/dist/cli/constants.d.ts +66 -0
  40. package/dist/cli/constants.d.ts.map +1 -0
  41. package/dist/cli/constants.js +19 -0
  42. package/dist/cli/constants.js.map +1 -0
  43. package/dist/cli/createDefaultInfraCommandContext.d.ts +4 -0
  44. package/dist/cli/createDefaultInfraCommandContext.d.ts.map +1 -0
  45. package/dist/{commandContext.js → cli/createDefaultInfraCommandContext.js} +4 -3
  46. package/dist/cli/createDefaultInfraCommandContext.js.map +1 -0
  47. package/dist/cli/createInfraRuntimeProvider.d.ts +5 -0
  48. package/dist/cli/createInfraRuntimeProvider.d.ts.map +1 -0
  49. package/dist/cli/createInfraRuntimeProvider.js +22 -0
  50. package/dist/cli/createInfraRuntimeProvider.js.map +1 -0
  51. package/dist/cli/createProviderCommandDescriptors.d.ts +4 -0
  52. package/dist/cli/createProviderCommandDescriptors.d.ts.map +1 -0
  53. package/dist/cli/createProviderCommandDescriptors.js +6 -0
  54. package/dist/cli/createProviderCommandDescriptors.js.map +1 -0
  55. package/dist/cli/findInfraCommand.d.ts +4 -0
  56. package/dist/cli/findInfraCommand.d.ts.map +1 -0
  57. package/dist/cli/findInfraCommand.js +6 -0
  58. package/dist/cli/findInfraCommand.js.map +1 -0
  59. package/dist/cli/index.d.ts +3 -8
  60. package/dist/cli/index.d.ts.map +1 -1
  61. package/dist/cli/index.js +2 -24
  62. package/dist/cli/index.js.map +1 -1
  63. package/dist/cli/renderInfraRootHelp.d.ts +3 -0
  64. package/dist/cli/renderInfraRootHelp.d.ts.map +1 -0
  65. package/dist/cli/renderInfraRootHelp.js +21 -0
  66. package/dist/cli/renderInfraRootHelp.js.map +1 -0
  67. package/dist/cli/renderUnknownInfraCommand.d.ts +3 -0
  68. package/dist/cli/renderUnknownInfraCommand.d.ts.map +1 -0
  69. package/dist/cli/renderUnknownInfraCommand.js +5 -0
  70. package/dist/cli/renderUnknownInfraCommand.js.map +1 -0
  71. package/dist/cli/runInfraCliAsync.d.ts +10 -0
  72. package/dist/cli/runInfraCliAsync.d.ts.map +1 -0
  73. package/dist/cli/runInfraCliAsync.js +34 -0
  74. package/dist/cli/runInfraCliAsync.js.map +1 -0
  75. package/dist/cli/runInfraCommandAsync.d.ts +4 -0
  76. package/dist/cli/runInfraCommandAsync.d.ts.map +1 -0
  77. package/dist/cli/runInfraCommandAsync.js +100 -0
  78. package/dist/cli/runInfraCommandAsync.js.map +1 -0
  79. package/dist/cli/utils/prepareInfraCommandOperationAsync.d.ts +4 -0
  80. package/dist/cli/utils/prepareInfraCommandOperationAsync.d.ts.map +1 -0
  81. package/dist/cli/utils/prepareInfraCommandOperationAsync.js +45 -0
  82. package/dist/cli/utils/prepareInfraCommandOperationAsync.js.map +1 -0
  83. package/dist/cli/utils/requireInfraSuccess.d.ts +7 -0
  84. package/dist/cli/utils/requireInfraSuccess.d.ts.map +1 -0
  85. package/dist/cli/utils/requireInfraSuccess.js +17 -0
  86. package/dist/cli/utils/requireInfraSuccess.js.map +1 -0
  87. package/dist/cli/utils/resolveInfraPersistence.d.ts +4 -0
  88. package/dist/cli/utils/resolveInfraPersistence.d.ts.map +1 -0
  89. package/dist/cli/utils/resolveInfraPersistence.js +17 -0
  90. package/dist/cli/utils/resolveInfraPersistence.js.map +1 -0
  91. package/dist/cli/utils/writeInfraEnvironmentOutputs.d.ts +5 -0
  92. package/dist/cli/utils/writeInfraEnvironmentOutputs.d.ts.map +1 -0
  93. package/dist/cli/utils/writeInfraEnvironmentOutputs.js +16 -0
  94. package/dist/cli/utils/writeInfraEnvironmentOutputs.js.map +1 -0
  95. package/dist/cli/utils/writeInfraStructured.d.ts +4 -0
  96. package/dist/cli/utils/writeInfraStructured.d.ts.map +1 -0
  97. package/dist/cli/utils/writeInfraStructured.js +8 -0
  98. package/dist/cli/utils/writeInfraStructured.js.map +1 -0
  99. package/dist/constants.d.ts +10 -0
  100. package/dist/constants.d.ts.map +1 -0
  101. package/dist/{packageMetadata.js → constants.js} +6 -3
  102. package/dist/constants.js.map +1 -0
  103. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.d.ts +4 -0
  104. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.d.ts.map +1 -0
  105. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js +35 -0
  106. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js.map +1 -0
  107. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.d.ts +4 -0
  108. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.d.ts.map +1 -0
  109. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.js +23 -0
  110. package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.js.map +1 -0
  111. package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.d.ts +4 -0
  112. package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.d.ts.map +1 -0
  113. package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.js +9 -0
  114. package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.js.map +1 -0
  115. package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.d.ts +5 -0
  116. package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.d.ts.map +1 -0
  117. package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.js +28 -0
  118. package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.js.map +1 -0
  119. package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.d.ts +4 -0
  120. package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.d.ts.map +1 -0
  121. package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.js +7 -0
  122. package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.js.map +1 -0
  123. package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.d.ts +7 -0
  124. package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.d.ts.map +1 -0
  125. package/dist/{project.js → features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.js} +10 -34
  126. package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.js.map +1 -0
  127. package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.d.ts +5 -0
  128. package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.d.ts.map +1 -0
  129. package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.js +28 -0
  130. package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.js.map +1 -0
  131. package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.d.ts +4 -0
  132. package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.d.ts.map +1 -0
  133. package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.js +16 -0
  134. package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.js.map +1 -0
  135. package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.d.ts +9 -0
  136. package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.d.ts.map +1 -0
  137. package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.js +2 -0
  138. package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.js.map +1 -0
  139. package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.d.ts +4 -0
  140. package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.d.ts.map +1 -0
  141. package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.js +15 -0
  142. package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.js.map +1 -0
  143. package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.d.ts +4 -0
  144. package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.d.ts.map +1 -0
  145. package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.js +84 -0
  146. package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.js.map +1 -0
  147. package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.d.ts +4 -0
  148. package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.d.ts.map +1 -0
  149. package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.js +55 -0
  150. package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.js.map +1 -0
  151. package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.d.ts +4 -0
  152. package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.d.ts.map +1 -0
  153. package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.js +38 -0
  154. package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.js.map +1 -0
  155. package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.d.ts +4 -0
  156. package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.d.ts.map +1 -0
  157. package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.js +34 -0
  158. package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.js.map +1 -0
  159. package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.d.ts +4 -0
  160. package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.d.ts.map +1 -0
  161. package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.js +57 -0
  162. package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.js.map +1 -0
  163. package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.d.ts +5 -0
  164. package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.d.ts.map +1 -0
  165. package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.js +109 -0
  166. package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.js.map +1 -0
  167. package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.d.ts +6 -0
  168. package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.d.ts.map +1 -0
  169. package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.js +181 -0
  170. package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.js.map +1 -0
  171. package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.d.ts +4 -0
  172. package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.d.ts.map +1 -0
  173. package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.js +68 -0
  174. package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.js.map +1 -0
  175. package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts +4 -0
  176. package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts.map +1 -0
  177. package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js +98 -0
  178. package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js.map +1 -0
  179. package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.d.ts +5 -0
  180. package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.d.ts.map +1 -0
  181. package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.js +17 -0
  182. package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.js.map +1 -0
  183. package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.d.ts +4 -0
  184. package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.d.ts.map +1 -0
  185. package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.js +13 -0
  186. package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.js.map +1 -0
  187. package/dist/features/environment-lifecycle/composition/createInfraCommandServices.d.ts +4 -0
  188. package/dist/features/environment-lifecycle/composition/createInfraCommandServices.d.ts.map +1 -0
  189. package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js +43 -0
  190. package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js.map +1 -0
  191. package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.d.ts +4 -0
  192. package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.d.ts.map +1 -0
  193. package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.js +123 -0
  194. package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.js.map +1 -0
  195. package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.d.ts +4 -0
  196. package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.d.ts.map +1 -0
  197. package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.js +54 -0
  198. package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.js.map +1 -0
  199. package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.d.ts +5 -0
  200. package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.d.ts.map +1 -0
  201. package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.js +39 -0
  202. package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.js.map +1 -0
  203. package/dist/features/environment-lifecycle/utils/appendInfraFailure.d.ts +7 -0
  204. package/dist/features/environment-lifecycle/utils/appendInfraFailure.d.ts.map +1 -0
  205. package/dist/features/environment-lifecycle/utils/appendInfraFailure.js +5 -0
  206. package/dist/features/environment-lifecycle/utils/appendInfraFailure.js.map +1 -0
  207. package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.d.ts +5 -0
  208. package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.d.ts.map +1 -0
  209. package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.js +13 -0
  210. package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.js.map +1 -0
  211. package/dist/features/environment-lifecycle/utils/createInfraFailure.d.ts +4 -0
  212. package/dist/features/environment-lifecycle/utils/createInfraFailure.d.ts.map +1 -0
  213. package/dist/features/environment-lifecycle/utils/createInfraFailure.js +5 -0
  214. package/dist/features/environment-lifecycle/utils/createInfraFailure.js.map +1 -0
  215. package/dist/features/environment-lifecycle/utils/createInfraLedger.d.ts +12 -0
  216. package/dist/features/environment-lifecycle/utils/createInfraLedger.d.ts.map +1 -0
  217. package/dist/features/environment-lifecycle/utils/createInfraLedger.js +14 -0
  218. package/dist/features/environment-lifecycle/utils/createInfraLedger.js.map +1 -0
  219. package/dist/features/environment-lifecycle/utils/infraIdentityKey.d.ts +4 -0
  220. package/dist/features/environment-lifecycle/utils/infraIdentityKey.d.ts.map +1 -0
  221. package/dist/features/environment-lifecycle/utils/infraIdentityKey.js +5 -0
  222. package/dist/features/environment-lifecycle/utils/infraIdentityKey.js.map +1 -0
  223. package/dist/features/environment-lifecycle/utils/isInfraStoredState.d.ts +4 -0
  224. package/dist/features/environment-lifecycle/utils/isInfraStoredState.d.ts.map +1 -0
  225. package/dist/features/environment-lifecycle/utils/isInfraStoredState.js +103 -0
  226. package/dist/features/environment-lifecycle/utils/isInfraStoredState.js.map +1 -0
  227. package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.d.ts +4 -0
  228. package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.d.ts.map +1 -0
  229. package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.js +10 -0
  230. package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.js.map +1 -0
  231. package/dist/features/environment-lifecycle/utils/mergeInfraResources.d.ts +4 -0
  232. package/dist/features/environment-lifecycle/utils/mergeInfraResources.d.ts.map +1 -0
  233. package/dist/features/environment-lifecycle/utils/mergeInfraResources.js +10 -0
  234. package/dist/features/environment-lifecycle/utils/mergeInfraResources.js.map +1 -0
  235. package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.d.ts +3 -0
  236. package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.d.ts.map +1 -0
  237. package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.js +8 -0
  238. package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.js.map +1 -0
  239. package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts +4 -0
  240. package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts.map +1 -0
  241. package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js +11 -0
  242. package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js.map +1 -0
  243. package/dist/features/environment-lifecycle/utils/resolveProjectFile.d.ts +3 -0
  244. package/dist/features/environment-lifecycle/utils/resolveProjectFile.d.ts.map +1 -0
  245. package/dist/features/environment-lifecycle/utils/resolveProjectFile.js +19 -0
  246. package/dist/features/environment-lifecycle/utils/resolveProjectFile.js.map +1 -0
  247. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.d.ts +4 -0
  248. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.d.ts.map +1 -0
  249. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.js +6 -0
  250. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.js.map +1 -0
  251. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.d.ts +4 -0
  252. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.d.ts.map +1 -0
  253. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.js +6 -0
  254. package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.js.map +1 -0
  255. package/dist/index.d.ts +16 -6
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +14 -15
  258. package/dist/index.js.map +1 -1
  259. package/dist/metadata/index.d.ts +1 -1
  260. package/dist/metadata/index.d.ts.map +1 -1
  261. package/dist/metadata/index.js +1 -1
  262. package/dist/metadata/index.js.map +1 -1
  263. package/dist/project/index.d.ts +8 -5
  264. package/dist/project/index.d.ts.map +1 -1
  265. package/dist/project/index.js +7 -5
  266. package/dist/project/index.js.map +1 -1
  267. package/dist/readme-usage.js +17 -26
  268. package/dist/readme-usage.js.map +1 -1
  269. package/dist/testSupport.d.ts +1 -1
  270. package/dist/testSupport.d.ts.map +1 -1
  271. package/dist/testSupport.js +11 -1
  272. package/dist/testSupport.js.map +1 -1
  273. package/dist/types/infraCli.d.ts +91 -0
  274. package/dist/types/infraCli.d.ts.map +1 -0
  275. package/dist/types/infraCli.js +2 -0
  276. package/dist/types/infraCli.js.map +1 -0
  277. package/dist/types/infraOrchestration.d.ts +84 -0
  278. package/dist/types/infraOrchestration.d.ts.map +1 -0
  279. package/dist/types/infraOrchestration.js +2 -0
  280. package/dist/types/infraOrchestration.js.map +1 -0
  281. package/dist/types/infraProject.d.ts +43 -0
  282. package/dist/types/infraProject.d.ts.map +1 -0
  283. package/dist/types/infraProject.js +2 -0
  284. package/dist/types/infraProject.js.map +1 -0
  285. package/package.json +20 -10
  286. package/src/adapterPackages.integration.test.ts +79 -0
  287. package/src/cli/bin.ts +2 -61
  288. package/src/cli/cli.test.ts +35 -126
  289. package/src/cli/commands/destroy.ts +57 -0
  290. package/src/cli/commands/down.ts +28 -0
  291. package/src/cli/commands/generate.ts +34 -0
  292. package/src/cli/commands/outputs.ts +25 -0
  293. package/src/cli/commands/plan.ts +20 -0
  294. package/src/cli/commands/status.ts +20 -0
  295. package/src/cli/commands/up.ts +29 -0
  296. package/src/cli/commands/validate.ts +20 -0
  297. package/src/cli/constants.ts +19 -0
  298. package/src/cli/createDefaultInfraCommandContext.ts +17 -0
  299. package/src/cli/createInfraRuntimeProvider.ts +35 -0
  300. package/src/cli/createProviderCommandDescriptors.ts +8 -0
  301. package/src/cli/findInfraCommand.ts +7 -0
  302. package/src/cli/index.test.ts +12 -20
  303. package/src/cli/index.ts +7 -49
  304. package/src/cli/renderInfraRootHelp.ts +23 -0
  305. package/src/cli/renderUnknownInfraCommand.ts +4 -0
  306. package/src/cli/runInfraCliAsync.ts +51 -0
  307. package/src/cli/runInfraCommandAsync.ts +114 -0
  308. package/src/cli/utils/prepareInfraCommandOperationAsync.ts +64 -0
  309. package/src/cli/utils/requireInfraSuccess.ts +24 -0
  310. package/src/cli/utils/resolveInfraPersistence.ts +22 -0
  311. package/src/cli/utils/writeInfraEnvironmentOutputs.ts +24 -0
  312. package/src/cli/utils/writeInfraStructured.ts +11 -0
  313. package/src/commands.test.ts +198 -196
  314. package/src/{packageMetadata.ts → constants.ts} +5 -2
  315. package/src/environmentLifecycle.test.ts +193 -0
  316. package/src/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.ts +52 -0
  317. package/src/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.ts +32 -0
  318. package/src/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.ts +10 -0
  319. package/src/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.ts +34 -0
  320. package/src/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.ts +12 -0
  321. package/src/{project.ts → features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.ts} +10 -45
  322. package/src/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.ts +34 -0
  323. package/src/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.ts +21 -0
  324. package/src/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.ts +10 -0
  325. package/src/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.ts +25 -0
  326. package/src/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.ts +119 -0
  327. package/src/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.ts +65 -0
  328. package/src/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.ts +51 -0
  329. package/src/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.ts +41 -0
  330. package/src/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.ts +67 -0
  331. package/src/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.ts +137 -0
  332. package/src/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.ts +257 -0
  333. package/src/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.ts +80 -0
  334. package/src/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.ts +126 -0
  335. package/src/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.ts +25 -0
  336. package/src/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.ts +21 -0
  337. package/src/features/environment-lifecycle/composition/createInfraCommandServices.ts +47 -0
  338. package/src/features/environment-lifecycle/composition/createProjectInfraLifecycle.ts +157 -0
  339. package/src/features/environment-lifecycle/domain/orderInfraPlanActions.ts +64 -0
  340. package/src/features/environment-lifecycle/domain/resolveInfraEnvironment.ts +62 -0
  341. package/src/features/environment-lifecycle/utils/appendInfraFailure.ts +9 -0
  342. package/src/features/environment-lifecycle/utils/createInfraExecutionContext.ts +24 -0
  343. package/src/features/environment-lifecycle/utils/createInfraFailure.ts +6 -0
  344. package/src/features/environment-lifecycle/utils/createInfraLedger.ts +30 -0
  345. package/src/features/environment-lifecycle/utils/infraIdentityKey.ts +6 -0
  346. package/src/features/environment-lifecycle/utils/isInfraStoredState.ts +141 -0
  347. package/src/features/environment-lifecycle/utils/mergeInfraOutputs.ts +14 -0
  348. package/src/features/environment-lifecycle/utils/mergeInfraResources.ts +14 -0
  349. package/src/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.ts +7 -0
  350. package/src/features/environment-lifecycle/utils/resolveInfraStatePath.ts +12 -0
  351. package/src/features/environment-lifecycle/utils/resolveProjectFile.ts +22 -0
  352. package/src/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.ts +15 -0
  353. package/src/features/environment-lifecycle/utils/retainUnchangedAdapterResources.ts +15 -0
  354. package/src/index.test.ts +22 -315
  355. package/src/index.ts +41 -53
  356. package/src/infraComposition.integration.test.ts +128 -0
  357. package/src/infraOperations.test.ts +386 -0
  358. package/src/infraUp.test.ts +260 -0
  359. package/src/metadata/index.ts +1 -1
  360. package/src/package.test.ts +4 -2
  361. package/src/project/index.test.ts +10 -188
  362. package/src/project/index.ts +15 -22
  363. package/src/project.test.ts +39 -189
  364. package/src/projectContractsParser.test.ts +2 -2
  365. package/src/projectInfrastructure.test.ts +121 -167
  366. package/src/projectLifecycle.test.ts +136 -0
  367. package/src/readme-usage.ts +17 -26
  368. package/src/testSupport.ts +12 -2
  369. package/src/types/infraCli.ts +115 -0
  370. package/src/types/infraOrchestration.ts +126 -0
  371. package/src/types/infraProject.ts +58 -0
  372. package/dist/adapters/minikube/auth/index.d.ts +0 -8
  373. package/dist/adapters/minikube/auth/index.d.ts.map +0 -1
  374. package/dist/adapters/minikube/auth/index.js +0 -29
  375. package/dist/adapters/minikube/auth/index.js.map +0 -1
  376. package/dist/adapters/minikube/auth/oauthRuntime.d.ts +0 -4
  377. package/dist/adapters/minikube/auth/oauthRuntime.d.ts.map +0 -1
  378. package/dist/adapters/minikube/auth/oauthRuntime.js +0 -138
  379. package/dist/adapters/minikube/auth/oauthRuntime.js.map +0 -1
  380. package/dist/adapters/minikube/auth/supabase/index.d.ts +0 -7
  381. package/dist/adapters/minikube/auth/supabase/index.d.ts.map +0 -1
  382. package/dist/adapters/minikube/auth/supabase/index.js +0 -232
  383. package/dist/adapters/minikube/auth/supabase/index.js.map +0 -1
  384. package/dist/adapters/minikube/auth/supabase/profile.d.ts +0 -20
  385. package/dist/adapters/minikube/auth/supabase/profile.d.ts.map +0 -1
  386. package/dist/adapters/minikube/auth/supabase/profile.js +0 -452
  387. package/dist/adapters/minikube/auth/supabase/profile.js.map +0 -1
  388. package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts +0 -7
  389. package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts.map +0 -1
  390. package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js +0 -104
  391. package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js.map +0 -1
  392. package/dist/adapters/minikube/authz/cerbos/index.d.ts +0 -13
  393. package/dist/adapters/minikube/authz/cerbos/index.d.ts.map +0 -1
  394. package/dist/adapters/minikube/authz/cerbos/index.js +0 -382
  395. package/dist/adapters/minikube/authz/cerbos/index.js.map +0 -1
  396. package/dist/adapters/minikube/authz/index.d.ts +0 -9
  397. package/dist/adapters/minikube/authz/index.d.ts.map +0 -1
  398. package/dist/adapters/minikube/authz/index.js +0 -23
  399. package/dist/adapters/minikube/authz/index.js.map +0 -1
  400. package/dist/adapters/minikube/base/index.d.ts +0 -14
  401. package/dist/adapters/minikube/base/index.d.ts.map +0 -1
  402. package/dist/adapters/minikube/base/index.js +0 -3433
  403. package/dist/adapters/minikube/base/index.js.map +0 -1
  404. package/dist/adapters/minikube/base/supabaseMigrations.d.ts +0 -2
  405. package/dist/adapters/minikube/base/supabaseMigrations.d.ts.map +0 -1
  406. package/dist/adapters/minikube/base/supabaseMigrations.js +0 -6
  407. package/dist/adapters/minikube/base/supabaseMigrations.js.map +0 -1
  408. package/dist/adapters/minikube/contracts.d.ts +0 -34
  409. package/dist/adapters/minikube/contracts.d.ts.map +0 -1
  410. package/dist/adapters/minikube/contracts.js +0 -10
  411. package/dist/adapters/minikube/contracts.js.map +0 -1
  412. package/dist/adapters/minikube/index.d.ts +0 -3
  413. package/dist/adapters/minikube/index.d.ts.map +0 -1
  414. package/dist/adapters/minikube/index.js +0 -136
  415. package/dist/adapters/minikube/index.js.map +0 -1
  416. package/dist/adapters/minikube/secrets/index.d.ts +0 -7
  417. package/dist/adapters/minikube/secrets/index.d.ts.map +0 -1
  418. package/dist/adapters/minikube/secrets/index.js +0 -13
  419. package/dist/adapters/minikube/secrets/index.js.map +0 -1
  420. package/dist/adapters/minikube/secrets/supabase-vault/index.d.ts +0 -8
  421. package/dist/adapters/minikube/secrets/supabase-vault/index.d.ts.map +0 -1
  422. package/dist/adapters/minikube/secrets/supabase-vault/index.js +0 -118
  423. package/dist/adapters/minikube/secrets/supabase-vault/index.js.map +0 -1
  424. package/dist/adapters/minikube/storage/index.d.ts +0 -7
  425. package/dist/adapters/minikube/storage/index.d.ts.map +0 -1
  426. package/dist/adapters/minikube/storage/index.js +0 -77
  427. package/dist/adapters/minikube/storage/index.js.map +0 -1
  428. package/dist/adapters/minikube/storage/supabase/index.d.ts +0 -7
  429. package/dist/adapters/minikube/storage/supabase/index.d.ts.map +0 -1
  430. package/dist/adapters/minikube/storage/supabase/index.js +0 -82
  431. package/dist/adapters/minikube/storage/supabase/index.js.map +0 -1
  432. package/dist/authRedirects.d.ts +0 -19
  433. package/dist/authRedirects.d.ts.map +0 -1
  434. package/dist/authRedirects.js +0 -80
  435. package/dist/authRedirects.js.map +0 -1
  436. package/dist/authTargetRedirects.d.ts +0 -12
  437. package/dist/authTargetRedirects.d.ts.map +0 -1
  438. package/dist/authTargetRedirects.js +0 -32
  439. package/dist/authTargetRedirects.js.map +0 -1
  440. package/dist/commandContext.d.ts +0 -12
  441. package/dist/commandContext.d.ts.map +0 -1
  442. package/dist/commandContext.js.map +0 -1
  443. package/dist/commands.d.ts +0 -95
  444. package/dist/commands.d.ts.map +0 -1
  445. package/dist/commands.js +0 -256
  446. package/dist/commands.js.map +0 -1
  447. package/dist/infraValidation.d.ts +0 -4
  448. package/dist/infraValidation.d.ts.map +0 -1
  449. package/dist/infraValidation.js +0 -63
  450. package/dist/infraValidation.js.map +0 -1
  451. package/dist/packageMetadata.d.ts +0 -10
  452. package/dist/packageMetadata.d.ts.map +0 -1
  453. package/dist/packageMetadata.js.map +0 -1
  454. package/dist/project.d.ts +0 -14
  455. package/dist/project.d.ts.map +0 -1
  456. package/dist/project.js.map +0 -1
  457. package/dist/projectDatabase.d.ts +0 -5
  458. package/dist/projectDatabase.d.ts.map +0 -1
  459. package/dist/projectDatabase.js +0 -22
  460. package/dist/projectDatabase.js.map +0 -1
  461. package/dist/projectEnvironment.d.ts +0 -6
  462. package/dist/projectEnvironment.d.ts.map +0 -1
  463. package/dist/projectEnvironment.js +0 -45
  464. package/dist/projectEnvironment.js.map +0 -1
  465. package/dist/projectInfrastructure.d.ts +0 -38
  466. package/dist/projectInfrastructure.d.ts.map +0 -1
  467. package/dist/projectInfrastructure.js +0 -145
  468. package/dist/projectInfrastructure.js.map +0 -1
  469. package/dist/runtime.d.ts +0 -54
  470. package/dist/runtime.d.ts.map +0 -1
  471. package/dist/runtime.js +0 -151
  472. package/dist/runtime.js.map +0 -1
  473. package/dist/secretStore.d.ts +0 -19
  474. package/dist/secretStore.d.ts.map +0 -1
  475. package/dist/secretStore.js +0 -22
  476. package/dist/secretStore.js.map +0 -1
  477. package/dist/types.d.ts +0 -70
  478. package/dist/types.d.ts.map +0 -1
  479. package/dist/types.js +0 -2
  480. package/dist/types.js.map +0 -1
  481. package/src/adapters/minikube/README.md +0 -115
  482. package/src/adapters/minikube/appRuntimeServing.test.ts +0 -28
  483. package/src/adapters/minikube/auth/index.ts +0 -40
  484. package/src/adapters/minikube/auth/oauthRuntime.ts +0 -163
  485. package/src/adapters/minikube/auth/supabase/index.test.ts +0 -227
  486. package/src/adapters/minikube/auth/supabase/index.ts +0 -293
  487. package/src/adapters/minikube/auth/supabase/oauthRuntime.test.ts +0 -154
  488. package/src/adapters/minikube/auth/supabase/profile.integration.test.ts +0 -1028
  489. package/src/adapters/minikube/auth/supabase/profile.ts +0 -526
  490. package/src/adapters/minikube/auth/supabase/providerAssignments.test.ts +0 -36
  491. package/src/adapters/minikube/auth/targetAwareOAuthRuntime.test.ts +0 -83
  492. package/src/adapters/minikube/auth/targetAwareOAuthRuntime.ts +0 -136
  493. package/src/adapters/minikube/authz/cerbos/index.ts +0 -486
  494. package/src/adapters/minikube/authz/index.ts +0 -32
  495. package/src/adapters/minikube/base/appImageBuild.test.ts +0 -352
  496. package/src/adapters/minikube/base/index.test.ts +0 -693
  497. package/src/adapters/minikube/base/index.ts +0 -3763
  498. package/src/adapters/minikube/base/portForwardRuntime.test.ts +0 -624
  499. package/src/adapters/minikube/base/supabaseMigrations.test.ts +0 -168
  500. package/src/adapters/minikube/base/supabaseMigrations.ts +0 -5
  501. package/src/adapters/minikube/base/twoAppIsolation.integration.test.ts +0 -898
  502. package/src/adapters/minikube/base/upgradeReconciliation.test.ts +0 -135
  503. package/src/adapters/minikube/contracts.ts +0 -46
  504. package/src/adapters/minikube/index.ts +0 -172
  505. package/src/adapters/minikube/secrets/index.test.ts +0 -147
  506. package/src/adapters/minikube/secrets/index.ts +0 -19
  507. package/src/adapters/minikube/secrets/supabase-vault/index.ts +0 -139
  508. package/src/adapters/minikube/storage/index.ts +0 -91
  509. package/src/adapters/minikube/storage/supabase/index.ts +0 -108
  510. package/src/apiInfrastructure.test.ts +0 -69
  511. package/src/authRedirects.test.ts +0 -63
  512. package/src/authRedirects.ts +0 -113
  513. package/src/authTargetRedirects.test.ts +0 -62
  514. package/src/authTargetRedirects.ts +0 -46
  515. package/src/commandContext.ts +0 -27
  516. package/src/commands.ts +0 -404
  517. package/src/generatedApiLedgerCleanup.test.ts +0 -72
  518. package/src/infraApiValidation.test.ts +0 -42
  519. package/src/infraValidation.ts +0 -99
  520. package/src/minikubeImageLifecycle.test.ts +0 -35
  521. package/src/projectDatabase.ts +0 -27
  522. package/src/projectEnvironment.ts +0 -51
  523. package/src/projectInfrastructure.ts +0 -221
  524. package/src/runtime.test.ts +0 -124
  525. package/src/runtime.ts +0 -234
  526. package/src/secretStore.test.ts +0 -76
  527. package/src/secretStore.ts +0 -44
  528. package/src/types.ts +0 -82
@@ -1,3433 +0,0 @@
1
- import { resolveSupabaseProfileModel } from '../auth/supabase/profile';
2
- import { getSupabaseMigrationCommandScript } from './supabaseMigrations';
3
- export const APP_NAMESPACE = 'app';
4
- const SUPABASE_NAMESPACE = 'supabase';
5
- const SUPABASE_IMAGES = {
6
- postgres: 'supabase/postgres:17.6.1.136',
7
- auth: 'supabase/gotrue:v2.189.0',
8
- rest: 'postgrest/postgrest:v14.12',
9
- realtime: 'supabase/realtime:v2.102.3',
10
- storage: 'supabase/storage-api:v1.60.4',
11
- imgproxy: 'darthsim/imgproxy:v3.30.1',
12
- meta: 'supabase/postgres-meta:v0.96.6',
13
- gateway: 'kong/kong:3.9.1',
14
- studio: 'supabase/studio:2026.07.07-sha-a6a04f2',
15
- };
16
- const PORT_BASE = 18080;
17
- const PORT_BUCKET_SIZE = 20;
18
- const PORT_BUCKET_COUNT = 1000;
19
- const PORT_REFERENCE_SLUG = 'my-app';
20
- export function generateMinikubeBaseArtifacts(args) {
21
- const { manifest, appSlug, appRuntimeEnabled, extraResources, providerNamespaces, providerLifecycle, extraEnvEntries, } = args;
22
- const root = 'infra/minikube';
23
- const k8sRoot = `${root}/k8s`;
24
- const scriptsRoot = `${root}/scripts`;
25
- const appImageRoot = `${root}/app-image`;
26
- const defaultAppImage = getDefaultAppImage(appSlug);
27
- const supabaseHostPorts = resolveSupabaseHostPorts(appSlug);
28
- const authScope = manifest.auth?.scope ?? 'none';
29
- const authProvider = manifest.auth?.provider ?? 'none';
30
- const authzEngine = manifest.auth?.authorization?.engine ?? 'none';
31
- const databaseProvider = manifest.database?.provider ?? 'none';
32
- const secretStoreProvider = manifest.secretStore?.provider ?? 'none';
33
- const storageMetadata = resolveAppInfraStorageMetadata(manifest);
34
- const profileModel = resolveSupabaseProfileModel(manifest);
35
- const oauthProviders = resolveSupabaseOAuthProviders(manifest);
36
- const monitoringEnabled = manifest.deployment?.monitoring === true;
37
- const domain = manifest.networking?.domain ?? '';
38
- const supabaseKubernetesEnabled = authProvider === 'supabase' ||
39
- databaseProvider === 'supabase' ||
40
- storageMetadata !== null ||
41
- secretStoreProvider === 'supabase-vault';
42
- const supabaseResources = supabaseKubernetesEnabled ? getSupabaseResourceFiles(k8sRoot) : [];
43
- const namespaceResources = [
44
- 'namespaces/app.yaml',
45
- ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),
46
- ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),
47
- ];
48
- return [
49
- {
50
- path: `${root}/README.md`,
51
- content: getReadmeMarkdown({
52
- appSlug,
53
- appRuntimeEnabled,
54
- defaultAppImage,
55
- monitoringEnabled,
56
- authProvider,
57
- authzEngine,
58
- extraResources,
59
- supabaseHostPorts,
60
- supabaseKubernetesEnabled,
61
- profileModel,
62
- oauthProviders,
63
- providerNamespaces,
64
- providerLifecycle,
65
- }),
66
- },
67
- {
68
- path: `${root}/.env.example`,
69
- content: getEnvExample({
70
- appSlug,
71
- domain,
72
- extraEnvEntries,
73
- defaultAppImage,
74
- supabaseHostPorts,
75
- supabaseKubernetesEnabled,
76
- oauthProviders,
77
- }),
78
- },
79
- {
80
- path: `${k8sRoot}/namespaces/app.yaml`,
81
- content: getNamespaceManifest(APP_NAMESPACE),
82
- },
83
- ...(supabaseKubernetesEnabled
84
- ? [
85
- {
86
- path: `${k8sRoot}/namespaces/supabase.yaml`,
87
- content: getNamespaceManifest(SUPABASE_NAMESPACE),
88
- },
89
- ]
90
- : []),
91
- ...providerNamespaces.map((namespace) => ({
92
- path: `${k8sRoot}/namespaces/${namespace}.yaml`,
93
- content: getNamespaceManifest(namespace),
94
- })),
95
- ...(appRuntimeEnabled
96
- ? [
97
- {
98
- path: `${k8sRoot}/app.configmap.yaml`,
99
- content: getAppConfigMap({
100
- appSlug,
101
- authScope,
102
- authProvider,
103
- databaseProvider,
104
- secretStoreProvider,
105
- storageMetadata,
106
- monitoringEnabled,
107
- domain,
108
- }),
109
- },
110
- {
111
- path: `${k8sRoot}/app/deployment.yaml`,
112
- content: getAppDeploymentManifest(defaultAppImage),
113
- },
114
- {
115
- path: `${k8sRoot}/app/service.yaml`,
116
- content: getAppServiceManifest(),
117
- },
118
- ]
119
- : []),
120
- ...supabaseResources,
121
- {
122
- path: `${k8sRoot}/kustomization.yaml`,
123
- content: getKustomizationManifest({
124
- namespaceResources,
125
- appRuntimeEnabled,
126
- supabaseEnabled: supabaseKubernetesEnabled,
127
- extraResources,
128
- }),
129
- },
130
- {
131
- path: `${scriptsRoot}/up.sh`,
132
- content: getUpScript({
133
- appSlug,
134
- appRuntimeEnabled,
135
- defaultAppImage,
136
- supabaseKubernetesEnabled,
137
- profileModel,
138
- secretStoreProvider,
139
- supabaseHostPorts,
140
- oauthProviders,
141
- providerLifecycle,
142
- }),
143
- executable: true,
144
- },
145
- {
146
- path: `${scriptsRoot}/build-app-image.sh`,
147
- content: getBuildAppImageScript({ appSlug, defaultAppImage }),
148
- executable: true,
149
- },
150
- {
151
- path: `${scriptsRoot}/port-forward.sh`,
152
- content: getPortForwardScript({
153
- appSlug,
154
- appRuntimeEnabled,
155
- supabaseKubernetesEnabled,
156
- supabaseHostPorts,
157
- }),
158
- executable: true,
159
- },
160
- {
161
- path: `${scriptsRoot}/down.sh`,
162
- content: getDownScript(appSlug),
163
- executable: true,
164
- },
165
- {
166
- path: `${scriptsRoot}/reset.sh`,
167
- content: getResetScript({
168
- appSlug,
169
- supabaseKubernetesEnabled,
170
- providerNamespaces,
171
- }),
172
- executable: true,
173
- },
174
- {
175
- path: `${scriptsRoot}/destroy.sh`,
176
- content: getDestroyScript(appSlug),
177
- executable: true,
178
- },
179
- {
180
- path: `${scriptsRoot}/status.sh`,
181
- content: getStatusScript({
182
- appSlug,
183
- appRuntimeEnabled,
184
- supabaseKubernetesEnabled,
185
- profileModel,
186
- supabaseHostPorts,
187
- providerNamespaces,
188
- providerLifecycle,
189
- }),
190
- executable: true,
191
- },
192
- {
193
- path: `${appImageRoot}/Dockerfile`,
194
- content: getAppImageDockerfile(),
195
- },
196
- ];
197
- }
198
- function getReadmeMarkdown(args) {
199
- const { appSlug, appRuntimeEnabled, defaultAppImage, monitoringEnabled, authProvider, authzEngine, extraResources, supabaseHostPorts, supabaseKubernetesEnabled, profileModel, oauthProviders, providerNamespaces, providerLifecycle, } = args;
200
- const resourceLines = [
201
- 'namespaces/app.yaml',
202
- ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),
203
- ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),
204
- ...(appRuntimeEnabled ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml'] : []),
205
- ...(supabaseKubernetesEnabled
206
- ? [
207
- 'supabase/bootstrap.sql',
208
- 'supabase/postgres.init.configmap.yaml',
209
- 'supabase/postgres.pvc.yaml',
210
- 'supabase/postgres.yaml',
211
- 'supabase/auth.yaml',
212
- 'supabase/rest.yaml',
213
- 'supabase/realtime.yaml',
214
- 'supabase/storage.yaml',
215
- 'supabase/imgproxy.yaml',
216
- 'supabase/meta.yaml',
217
- 'supabase/gateway.template.yml',
218
- 'supabase/kong-entrypoint.sh',
219
- 'supabase/gateway.yaml',
220
- 'supabase/studio.yaml',
221
- ]
222
- : []),
223
- ...extraResources,
224
- ]
225
- .map((resource) => `- \`k8s/${resource}\``)
226
- .join('\n');
227
- const resetNamespaces = [
228
- APP_NAMESPACE,
229
- ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),
230
- ...providerNamespaces,
231
- ];
232
- const resetDescription = `deletes and recreates namespaces ${resetNamespaces
233
- .map((namespace) => `\`${namespace}\``)
234
- .join(', ')} inside the existing profile. This removes app-owned Kubernetes state and provider-owned PVC data for reset namespaces`;
235
- const providerNamespaceLine = providerNamespaces.length > 0
236
- ? `- Provider namespaces: \`${providerNamespaces.join('`, `')}\`\n`
237
- : '';
238
- const providerLifecycleLines = providerLifecycle.length > 0
239
- ? `## Provider Lifecycle Contributions\n\n${providerLifecycle
240
- .map((provider) => {
241
- const readiness = provider.readinessChecks.length > 0
242
- ? provider.readinessChecks
243
- .map((check) => `\`${check.resource}\` in namespace \`${check.namespace}\``)
244
- .join(', ')
245
- : 'none';
246
- const endpoints = provider.endpoints.length > 0
247
- ? provider.endpoints
248
- .map((endpoint) => `\`${endpoint.name}\` = \`${endpoint.url}\``)
249
- .join(', ')
250
- : 'none';
251
- return `- \`${provider.id}\`: namespace \`${provider.namespace}\`; readiness ${readiness}; endpoints ${endpoints}`;
252
- })
253
- .join('\n')}`
254
- : '';
255
- const oauthDescription = oauthProviders.length > 0
256
- ? `\nConfigured OAuth providers are wired into GoTrue through generated \`GOTRUE_EXTERNAL_*\` runtime keys. The keys are named in \`.env.example\`; values must come from trusted secret resolution for the configured \`credentialsRef\` entries.`
257
- : '';
258
- const runtimeForwardDescription = appRuntimeEnabled
259
- ? supabaseKubernetesEnabled
260
- ? '`app` and `supabase-gateway`'
261
- : '`app`'
262
- : supabaseKubernetesEnabled
263
- ? '`supabase-gateway`'
264
- : 'no host endpoints';
265
- return `# Minikube Infra
266
-
267
- This directory is generated from \`ankh.config.json\` (infra manifest).
268
-
269
- ## Ownership Model
270
-
271
- - App slug / Minikube profile: \`${appSlug}\`
272
- - App runtime: \`${appRuntimeEnabled ? `deployment/app-runtime in namespace ${APP_NAMESPACE}` : 'disabled (no enabled Web deploy target)'}\`
273
- - Supabase namespace: \`${supabaseKubernetesEnabled ? SUPABASE_NAMESPACE : 'unused'}\`
274
- ${providerNamespaceLine}- Default app image: \`${defaultAppImage}\`
275
-
276
- One app owns one complete Minikube profile. Provider-owned workloads are separated by
277
- Kubernetes namespace inside that profile. There is no shared \`minikube\` profile and no
278
- host-level Supabase Compose runtime.
279
-
280
- ## Quick Start
281
-
282
- 1. Copy env template:
283
- \`\`\`bash
284
- cp .env.example .env
285
- \`\`\`
286
- 2. Adjust optional values in \`.env\`; missing Supabase development secrets are generated by \`up.sh\`.
287
- 3. Start infra:
288
- \`\`\`bash
289
- ./scripts/up.sh
290
- \`\`\`
291
- 4. Check status:
292
- \`\`\`bash
293
- ./scripts/status.sh
294
- \`\`\`
295
- 5. Stop the app-owned cluster without deleting data:
296
- \`\`\`bash
297
- ./scripts/down.sh
298
- \`\`\`
299
-
300
- ## Lifecycle Semantics
301
-
302
- - \`up.sh\`: starts \`minikube -p ${appSlug}\`, deploys provider namespaces, runs migrations with CLI telemetry disabled for that command, starts slug-owned port-forwards${appRuntimeEnabled ? ', and deploys the Web app runtime' : ''}.
303
- - \`down.sh\`: stops slug-owned port-forwards, then stops \`minikube -p ${appSlug}\`. Persistent data remains in the profile.
304
- - \`reset.sh\`: requires \`ANKH_RESET_CONFIRM=${appSlug}\`; ${resetDescription}. It does not delete the Minikube profile.
305
- - \`destroy.sh\`: deletes only \`minikube -p ${appSlug}\`.
306
-
307
- ### Port-forward groups
308
-
309
- - \`./scripts/port-forward.sh start runtime\` idempotently ensures ${runtimeForwardDescription}, the generated host endpoints required by the running application. The same group supports \`stop\` and \`status\`.
310
- - \`runtime\` excludes \`studio\` and \`db-migration\`, which are operational/bootstrap endpoints.
311
- - \`all\` retains every generated forward, including operational/bootstrap endpoints.
312
- - Concrete targets remain available for individual lifecycle control.
313
-
314
- ## Generated Resources
315
-
316
- ${resourceLines}
317
-
318
- ## Supabase Runtime
319
-
320
- Supabase runtime ownership is Kubernetes. Migration authoring/history remains Supabase
321
- migration files. Migration execution targets the Kubernetes Postgres endpoint through
322
- \`SUPABASE_TELEMETRY_DISABLED=1 supabase --yes migration up --db-url "$SUPABASE_DB_URL"\`.
323
- The migration process does not require stdin. \`--yes\` remains defense in depth for future
324
- CLI prompts; it is not the hang fix. Command-scoped telemetry disable avoids the unbounded
325
- telemetry shutdown in Supabase CLI 2.106.0 when PostHog is blocked, without changing the
326
- user's persistent telemetry preference. Migration failures stop \`up.sh\`, and the completion
327
- message is printed only after a zero exit status. No migration deadline is added; using a
328
- current Supabase CLI remains recommended.
329
-
330
- Supabase manifests are generated from the current official Supabase self-hosting Docker
331
- topology, service documentation, environment-variable contracts, and pinned official images.
332
- Kubernetes/Helm is treated as community-driven upstream guidance, not an official
333
- distribution copied by this generator.
334
- ${oauthDescription}
335
-
336
- Pinned images:
337
-
338
- - Postgres: \`${SUPABASE_IMAGES.postgres}\`
339
- - Auth: \`${SUPABASE_IMAGES.auth}\`
340
- - PostgREST: \`${SUPABASE_IMAGES.rest}\`
341
- - Realtime: \`${SUPABASE_IMAGES.realtime}\`
342
- - Storage: \`${SUPABASE_IMAGES.storage}\`
343
- - Gateway: \`${SUPABASE_IMAGES.gateway}\`
344
- - Studio: \`${SUPABASE_IMAGES.studio}\`
345
-
346
- ## Host URLs
347
-
348
- ${appRuntimeEnabled ? `- App: \`http://127.0.0.1:${supabaseHostPorts.app}\`\n` : ''}- Supabase gateway: \`http://127.0.0.1:${supabaseHostPorts.gateway}\`
349
- - Studio: \`http://127.0.0.1:${supabaseHostPorts.studio}\`
350
- - DB migration endpoint: \`127.0.0.1:${supabaseHostPorts.db}\`
351
-
352
- ## App Image Export
353
-
354
- \`build-app-image.sh\` requires the app-installed \`node_modules/.bin/expo\` and never resolves
355
- Expo globally or through the network. It clears the Expo/Metro bundler cache before every web
356
- export. Expo inlines \`EXPO_PUBLIC_*\` values into the browser bundle, so cache invalidation
357
- ensures a rotated browser-safe Supabase URL or anon key replaces the previous value before the
358
- Docker image is built. Privileged Supabase credentials are not written to the app's public env
359
- file.
360
-
361
- ## Runtime Conventions
362
-
363
- - Monitoring requested: \`${monitoringEnabled ? 'true' : 'false'}\`
364
- - Auth provider: \`${authProvider}\`
365
- - Authorization engine: \`${authzEngine}\`
366
- ${profileModel.enabled ? '- Generated profile reconciliation lives in `supabase/generated/auth_profiles.sql` and records checksum state in `ankhorage_internal.generated_schema_state`.\n' : ''}
367
- ${providerLifecycleLines}
368
- `;
369
- }
370
- function getEnvExample(args) {
371
- const { appSlug, domain, extraEnvEntries, defaultAppImage, supabaseHostPorts, oauthProviders } = args;
372
- const baseEntries = [
373
- '# App-owned Minikube profile configuration',
374
- `ANKH_APP_SLUG=${appSlug}`,
375
- 'MINIKUBE_DRIVER=docker',
376
- 'APP_BUILD_ENABLED=true',
377
- 'APP_SOURCE_DIR=',
378
- 'APP_WEB_EXPORT_DIR=.ankh/web-export',
379
- `APP_IMAGE=${defaultAppImage}`,
380
- 'APP_IMAGE_SYNC_STRATEGY=docker-load',
381
- 'APP_IMAGE_CLEANUP_ON_DESTROY=true',
382
- 'APP_IMAGE_CLEANUP_MINIKUBE=true',
383
- 'APP_IMAGE_CLEANUP_DOCKER=true',
384
- `APP_PORT_FORWARD_LOCAL_PORT=${supabaseHostPorts.app}`,
385
- 'APP_PORT_FORWARD_REMOTE_PORT=80',
386
- `SUPABASE_GATEWAY_FORWARD_LOCAL_PORT=${supabaseHostPorts.gateway}`,
387
- 'SUPABASE_GATEWAY_FORWARD_REMOTE_PORT=8000',
388
- `SUPABASE_STUDIO_FORWARD_LOCAL_PORT=${supabaseHostPorts.studio}`,
389
- 'SUPABASE_STUDIO_FORWARD_REMOTE_PORT=3000',
390
- `SUPABASE_DB_FORWARD_LOCAL_PORT=${supabaseHostPorts.db}`,
391
- 'SUPABASE_DB_FORWARD_REMOTE_PORT=5432',
392
- 'APP_REPLICAS=1',
393
- 'APP_FORCE_ROLLOUT_RESTART=true',
394
- '',
395
- '# Optional private registry auth for APP_IMAGE',
396
- 'APP_IMAGE_PULL_SECRET_NAME=',
397
- 'APP_IMAGE_PULL_SECRET_SERVER=ghcr.io',
398
- 'APP_IMAGE_PULL_SECRET_USERNAME=',
399
- 'APP_IMAGE_PULL_SECRET_PASSWORD=',
400
- 'APP_IMAGE_PULL_SECRET_EMAIL=',
401
- '',
402
- '# Optional app networking domain',
403
- `APP_DOMAIN=${domain}`,
404
- '',
405
- '# Supabase Kubernetes runtime secrets',
406
- 'POSTGRES_PASSWORD=',
407
- 'JWT_SECRET=',
408
- 'SUPABASE_ANON_KEY=',
409
- 'SUPABASE_SERVICE_ROLE_KEY=',
410
- 'SUPABASE_PUBLISHABLE_KEY=',
411
- 'SUPABASE_SECRET_KEY=',
412
- 'DASHBOARD_USERNAME=supabase',
413
- 'DASHBOARD_PASSWORD=',
414
- 'SECRET_KEY_BASE=',
415
- 'REALTIME_DB_ENC_KEY=',
416
- 'PG_META_CRYPTO_KEY=',
417
- 'S3_PROTOCOL_ACCESS_KEY_ID=',
418
- 'S3_PROTOCOL_ACCESS_KEY_SECRET=',
419
- 'JWT_EXPIRY=3600',
420
- 'SITE_URL=',
421
- 'OAUTH_NATIVE_REDIRECT_URLS=',
422
- 'ADDITIONAL_REDIRECT_URLS=',
423
- 'SUPABASE_PUBLIC_URL=',
424
- 'API_EXTERNAL_URL=',
425
- 'ENABLE_EMAIL_SIGNUP=true',
426
- 'ENABLE_EMAIL_AUTOCONFIRM=true',
427
- 'SMTP_ADMIN_EMAIL=admin@example.com',
428
- 'SMTP_HOST=localhost',
429
- 'SMTP_PORT=2500',
430
- 'SMTP_USER=',
431
- 'SMTP_PASS=',
432
- 'SMTP_SENDER_NAME=Ankhorage',
433
- 'PGRST_DB_SCHEMAS=public,storage,graphql_public',
434
- 'PGRST_DB_MAX_ROWS=1000',
435
- 'PGRST_DB_EXTRA_SEARCH_PATH=public',
436
- 'GLOBAL_S3_BUCKET=stub',
437
- 'STORAGE_TENANT_ID=stub',
438
- 'REGION=stub',
439
- 'SUPABASE_DB_URL=',
440
- 'EXPO_PUBLIC_SUPABASE_URL=',
441
- 'EXPO_PUBLIC_SUPABASE_ANON_KEY=',
442
- ...getOAuthEnvExampleEntries(oauthProviders),
443
- '',
444
- '# Adapter-provided runtime keys',
445
- ];
446
- const merged = [...baseEntries, ...extraEnvEntries];
447
- const unique = [];
448
- for (const entry of merged) {
449
- if (!unique.includes(entry))
450
- unique.push(entry);
451
- }
452
- return `${unique.join('\n')}\n`;
453
- }
454
- function getOAuthEnvExampleEntries(providers) {
455
- if (providers.length === 0)
456
- return [];
457
- return [
458
- '',
459
- '# OAuth provider runtime values resolved from trusted credentialsRef entries',
460
- ...providers.flatMap((provider) => [
461
- `# ${provider.id}: ${provider.credentialsRef}`,
462
- `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=`,
463
- `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=`,
464
- `GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=`,
465
- ]),
466
- ];
467
- }
468
- function getOAuthScriptEnvDefaults(providers) {
469
- if (providers.length === 0)
470
- return '';
471
- return providers
472
- .map((provider) => ` export GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID="\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}"
473
- export GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET="\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}"
474
- export GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI="\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI:-\${API_EXTERNAL_URL}/callback}"`)
475
- .join('\n');
476
- }
477
- function getOAuthRuntimeSecretLines(providers) {
478
- if (providers.length === 0)
479
- return '';
480
- return providers
481
- .map((provider) => `GOTRUE_EXTERNAL_${provider.envPrefix}_ENABLED=true
482
- GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID}
483
- GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET}
484
- GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI}`)
485
- .join('\n');
486
- }
487
- function getOAuthRuntimeValidationScript(providers) {
488
- if (providers.length === 0)
489
- return '';
490
- const checks = providers
491
- .map((provider) => ` if [[ -z "\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}" || -z "\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}" ]]; then
492
- echo "OAuth provider ${provider.id} requires trusted runtime values GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID and GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET from credentialsRef ${provider.credentialsRef}."
493
- exit 1
494
- fi`)
495
- .join('\n');
496
- return `
497
- # OAuth provider secrets must be resolved by trusted host code before Kubernetes sync.
498
- ${checks}`;
499
- }
500
- function getSupabaseOAuthCallbackRoute(providers) {
501
- return providers[0]?.callbackRoute ?? '/auth/callback';
502
- }
503
- function getOAuthVaultResolutionScript(args) {
504
- const { appSlug, oauthProviders, secretStoreProvider } = args;
505
- if (secretStoreProvider !== 'supabase-vault' || oauthProviders.length === 0) {
506
- return `
507
- resolve_oauth_credentials_from_vault() {
508
- return 0
509
- }
510
- `;
511
- }
512
- const lines = oauthProviders
513
- .map((provider) => {
514
- const ref = escapeSingleQuotedSql(provider.credentialsRef);
515
- const idKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID`;
516
- const secretKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET`;
517
- return ` if [[ -z "\${${idKey}:-}" || -z "\${${secretKey}:-}" ]]; then
518
- local resolved_client_id resolved_client_secret
519
- resolved_client_id="$(resolve_vault_secret_field '${ref}' 'clientId')"
520
- resolved_client_secret="$(resolve_vault_secret_field '${ref}' 'clientSecret')"
521
- if [[ -n "\${resolved_client_id}" ]]; then
522
- export ${idKey}="\${resolved_client_id}"
523
- fi
524
- if [[ -n "\${resolved_client_secret}" ]]; then
525
- export ${secretKey}="\${resolved_client_secret}"
526
- fi
527
- fi`;
528
- })
529
- .join('\n');
530
- return `
531
- resolve_vault_secret_field() {
532
- local ref="\${1}"
533
- local field="\${2}"
534
- psql "\${SUPABASE_DB_URL}" -v ON_ERROR_STOP=1 -Atq -c "select coalesce(decrypted.decrypted_secret::jsonb ->> '\${field}', '') from ankh_secret_store.secret_metadata metadata join vault.decrypted_secrets decrypted on decrypted.id = metadata.vault_secret_id where metadata.project_id = '${escapeSingleQuotedSql(appSlug)}' and metadata.environment = 'local' and metadata.secret_ref = '\${ref}' limit 1;" 2>/dev/null || true
535
- }
536
-
537
- resolve_oauth_credentials_from_vault() {
538
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
539
- return 0
540
- fi
541
-
542
- ${lines}
543
- }
544
- `;
545
- }
546
- function escapeSingleQuotedSql(value) {
547
- return value.replace(/'/gu, "''");
548
- }
549
- function escapeShellDoubleQuoted(value) {
550
- return value.replace(/["\\$`]/gu, (char) => `\\${char}`);
551
- }
552
- function getProviderLifecycleStageScripts(providerLifecycle) {
553
- return `${getProviderLifecycleCommandFunction({
554
- functionName: 'run_provider_migrations',
555
- emptyReturn: 'return 0',
556
- commands: providerLifecycle.flatMap((provider) => provider.migrationCommands.map((command) => ({
557
- providerId: provider.id,
558
- label: command.label,
559
- command: command.command,
560
- }))),
561
- })}
562
-
563
- ${getProviderLifecycleCommandFunction({
564
- functionName: 'run_provider_reconciliation',
565
- emptyReturn: 'return 0',
566
- commands: providerLifecycle.flatMap((provider) => provider.reconciliationCommands.map((command) => ({
567
- providerId: provider.id,
568
- label: command.label,
569
- command: command.command,
570
- }))),
571
- })}
572
-
573
- ${getProviderReadinessFunction(providerLifecycle)}`;
574
- }
575
- function getProviderLifecycleCommandFunction(args) {
576
- if (args.commands.length === 0) {
577
- return `${args.functionName}() {
578
- ${args.emptyReturn}
579
- }`;
580
- }
581
- const body = args.commands
582
- .map((command) => ` echo "Running provider ${escapeShellDoubleQuoted(command.providerId)} ${escapeShellDoubleQuoted(command.label)}."
583
- ${indentShellBlock(command.command.trim(), 2)}`)
584
- .join('\n\n');
585
- return `${args.functionName}() {
586
- ${body}
587
- }`;
588
- }
589
- function getProviderReadinessFunction(providerLifecycle) {
590
- const checks = providerLifecycle.flatMap((provider) => provider.readinessChecks.map((check) => ({ providerId: provider.id, ...check })));
591
- if (checks.length === 0) {
592
- return `wait_for_provider_readiness() {
593
- return 0
594
- }`;
595
- }
596
- const body = checks
597
- .map((check) => ` kubectl --context "\${PROFILE}" -n "${escapeShellDoubleQuoted(check.namespace)}" rollout status "${escapeShellDoubleQuoted(check.resource)}" --timeout=${check.timeoutSeconds}s`)
598
- .join('\n');
599
- return `wait_for_provider_readiness() {
600
- ${body}
601
- }`;
602
- }
603
- function getProviderStatusScript(providerLifecycle) {
604
- if (providerLifecycle.length === 0) {
605
- return '';
606
- }
607
- return providerLifecycle
608
- .map((provider) => {
609
- const endpointLines = provider.endpoints
610
- .map((endpoint) => ` echo "- provider ${escapeShellDoubleQuoted(provider.id)} endpoint/${escapeShellDoubleQuoted(endpoint.name)}: ${escapeShellDoubleQuoted(endpoint.url)}"`)
611
- .join('\n');
612
- const readinessLines = provider.readinessChecks
613
- .map((check) => ` if kubectl --context "\${PROFILE}" -n "${escapeShellDoubleQuoted(check.namespace)}" rollout status "${escapeShellDoubleQuoted(check.resource)}" --timeout=5s >/dev/null 2>&1; then
614
- echo "- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(check.label)}: ready"
615
- else
616
- echo "- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(check.label)}: not ready"
617
- fi`)
618
- .join('\n');
619
- const customStatusLines = provider.statusChecks
620
- .map((check) => ` echo "Running provider ${escapeShellDoubleQuoted(provider.id)} status check ${escapeShellDoubleQuoted(check.label)}."
621
- ${indentShellBlock(check.command.trim(), 2)}`)
622
- .join('\n');
623
- return [endpointLines, readinessLines, customStatusLines].filter(Boolean).join('\n');
624
- })
625
- .filter(Boolean)
626
- .join('\n');
627
- }
628
- function indentShellBlock(value, spaces) {
629
- const indent = ' '.repeat(spaces);
630
- return value
631
- .split('\n')
632
- .map((line) => `${indent}${line}`)
633
- .join('\n');
634
- }
635
- function getNamespaceManifest(namespace) {
636
- return `apiVersion: v1
637
- kind: Namespace
638
- metadata:
639
- name: ${namespace}
640
- labels:
641
- app.kubernetes.io/part-of: ankhorage
642
- ankhorage.io/namespace-role: ${namespace}
643
- `;
644
- }
645
- function getAppConfigMap(args) {
646
- const { appSlug, authScope, authProvider, databaseProvider, secretStoreProvider, storageMetadata, monitoringEnabled, domain, } = args;
647
- const storageLines = storageMetadata
648
- ? ` STORAGE_PROVIDER: "${storageMetadata.provider}"
649
- STORAGE_BUCKETS: "${escapeYamlDoubleQuoted(storageMetadata.bucketsCsv)}"
650
- STORAGE_DEFAULT_BUCKET: "${escapeYamlDoubleQuoted(storageMetadata.defaultBucket)}"
651
- `
652
- : '';
653
- return `apiVersion: v1
654
- kind: ConfigMap
655
- metadata:
656
- name: app-infra-config
657
- namespace: ${APP_NAMESPACE}
658
- data:
659
- ANKH_APP_SLUG: "${appSlug}"
660
- DEPLOYMENT_TARGET: "minikube"
661
- APP_NAMESPACE: "${APP_NAMESPACE}"
662
- SUPABASE_NAMESPACE: "${SUPABASE_NAMESPACE}"
663
- MONITORING_ENABLED: "${monitoringEnabled ? 'true' : 'false'}"
664
- AUTH_SCOPE: "${authScope}"
665
- AUTH_PROVIDER: "${authProvider}"
666
- DATABASE_PROVIDER: "${databaseProvider}"
667
- SECRET_STORE_PROVIDER: "${secretStoreProvider}"
668
- ${storageLines} NETWORK_DOMAIN: "${escapeYamlDoubleQuoted(domain)}"
669
- `;
670
- }
671
- function resolveAppInfraStorageMetadata(manifest) {
672
- const spec = manifest.storage;
673
- if (!spec)
674
- return null;
675
- const buckets = normalizeBuckets(spec.buckets);
676
- if (buckets.length === 0)
677
- return null;
678
- const [defaultBucket] = buckets;
679
- if (!defaultBucket)
680
- return null;
681
- if (spec.provider === 'supabase') {
682
- return {
683
- provider: 'supabase',
684
- bucketsCsv: buckets.join(','),
685
- defaultBucket,
686
- };
687
- }
688
- if (spec.provider === 'auto') {
689
- const shouldResolveToSupabase = manifest.database?.provider === 'supabase' || manifest.auth?.provider === 'supabase';
690
- if (!shouldResolveToSupabase)
691
- return null;
692
- return {
693
- provider: 'supabase',
694
- bucketsCsv: buckets.join(','),
695
- defaultBucket,
696
- };
697
- }
698
- return null;
699
- }
700
- function resolveSupabaseOAuthProviders(manifest) {
701
- const oauth = manifest.auth?.oauth;
702
- if (!oauth?.enabled)
703
- return [];
704
- const callbackRoute = normalizeOAuthCallbackRoute(oauth.callbackRoute);
705
- return oauth.providers
706
- .filter((provider) => provider.enabled !== false)
707
- .map((provider) => {
708
- const id = provider.id.trim();
709
- const credentialsRef = provider.credentialsRef?.trim();
710
- if (!credentialsRef) {
711
- throw new Error(`OAuth provider "${id}" is enabled but does not define credentialsRef.`);
712
- }
713
- const envPrefix = id
714
- .toUpperCase()
715
- .replace(/[^A-Z0-9]+/gu, '_')
716
- .replace(/^_+|_+$/gu, '');
717
- if (!envPrefix) {
718
- throw new Error(`OAuth provider "${id}" cannot be mapped to GoTrue environment keys.`);
719
- }
720
- return {
721
- id,
722
- envPrefix,
723
- credentialsRef,
724
- callbackRoute,
725
- };
726
- });
727
- }
728
- function normalizeOAuthCallbackRoute(rawRoute) {
729
- const trimmedRoute = rawRoute?.trim();
730
- const route = trimmedRoute && trimmedRoute.length > 0 ? trimmedRoute : '/auth/callback';
731
- const withLeadingSlash = route.startsWith('/') ? route : `/${route}`;
732
- return withLeadingSlash.replace(/\/+/gu, '/');
733
- }
734
- function normalizeBuckets(rawBuckets) {
735
- const normalized = [];
736
- const seen = new Set();
737
- for (const raw of rawBuckets) {
738
- const bucket = raw.trim();
739
- if (!bucket)
740
- continue;
741
- if (seen.has(bucket))
742
- continue;
743
- seen.add(bucket);
744
- normalized.push(bucket);
745
- }
746
- return normalized;
747
- }
748
- function getKustomizationManifest(args) {
749
- const supabaseResources = args.supabaseEnabled
750
- ? [
751
- 'supabase/postgres.init.configmap.yaml',
752
- 'supabase/postgres.pvc.yaml',
753
- 'supabase/postgres.yaml',
754
- 'supabase/auth.yaml',
755
- 'supabase/rest.yaml',
756
- 'supabase/realtime.yaml',
757
- 'supabase/imgproxy.yaml',
758
- 'supabase/storage.yaml',
759
- 'supabase/meta.yaml',
760
- 'supabase/gateway.yaml',
761
- 'supabase/studio.yaml',
762
- ]
763
- : [];
764
- const resources = [
765
- ...args.namespaceResources,
766
- ...(args.appRuntimeEnabled
767
- ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml']
768
- : []),
769
- ...supabaseResources,
770
- ...args.extraResources,
771
- ];
772
- const resourceLines = resources.map((resource) => ` - ${resource}`).join('\n');
773
- return `apiVersion: kustomize.config.k8s.io/v1beta1
774
- kind: Kustomization
775
- resources:
776
- ${resourceLines}
777
- `;
778
- }
779
- function getAppDeploymentManifest(defaultAppImage) {
780
- return `apiVersion: apps/v1
781
- kind: Deployment
782
- metadata:
783
- name: app-runtime
784
- namespace: ${APP_NAMESPACE}
785
- labels:
786
- app.kubernetes.io/name: app-runtime
787
- spec:
788
- replicas: 1
789
- selector:
790
- matchLabels:
791
- app.kubernetes.io/name: app-runtime
792
- template:
793
- metadata:
794
- labels:
795
- app.kubernetes.io/name: app-runtime
796
- spec:
797
- containers:
798
- - name: app
799
- image: ${defaultAppImage}
800
- imagePullPolicy: IfNotPresent
801
- ports:
802
- - containerPort: 8080
803
- name: http
804
- envFrom:
805
- - configMapRef:
806
- name: app-infra-config
807
- - configMapRef:
808
- name: app-runtime-auth-env
809
- optional: true
810
- - configMapRef:
811
- name: app-runtime-storage-env
812
- optional: true
813
- - secretRef:
814
- name: supabase-public-runtime
815
- optional: true
816
- readinessProbe:
817
- httpGet:
818
- path: /
819
- port: http
820
- initialDelaySeconds: 5
821
- periodSeconds: 10
822
- livenessProbe:
823
- httpGet:
824
- path: /
825
- port: http
826
- initialDelaySeconds: 15
827
- periodSeconds: 20
828
- `;
829
- }
830
- function getAppServiceManifest() {
831
- return `apiVersion: v1
832
- kind: Service
833
- metadata:
834
- name: app-runtime
835
- namespace: ${APP_NAMESPACE}
836
- labels:
837
- app.kubernetes.io/name: app-runtime
838
- spec:
839
- type: ClusterIP
840
- selector:
841
- app.kubernetes.io/name: app-runtime
842
- ports:
843
- - name: http
844
- port: 80
845
- targetPort: http
846
- `;
847
- }
848
- function getSupabaseResourceFiles(k8sRoot) {
849
- return [
850
- {
851
- path: `${k8sRoot}/supabase/bootstrap.sql`,
852
- content: getSupabaseBootstrapSql(),
853
- },
854
- {
855
- path: `${k8sRoot}/supabase/postgres.init.configmap.yaml`,
856
- content: getSupabasePostgresInitConfigMap(),
857
- },
858
- {
859
- path: `${k8sRoot}/supabase/postgres.pvc.yaml`,
860
- content: getSupabasePvcManifest('supabase-postgres-data', '20Gi'),
861
- },
862
- {
863
- path: `${k8sRoot}/supabase/postgres.yaml`,
864
- content: getSupabasePostgresManifest(),
865
- },
866
- {
867
- path: `${k8sRoot}/supabase/auth.yaml`,
868
- content: getSupabaseAuthManifest(),
869
- },
870
- {
871
- path: `${k8sRoot}/supabase/rest.yaml`,
872
- content: getSupabaseRestManifest(),
873
- },
874
- {
875
- path: `${k8sRoot}/supabase/realtime.yaml`,
876
- content: getSupabaseRealtimeManifest(),
877
- },
878
- {
879
- path: `${k8sRoot}/supabase/storage.yaml`,
880
- content: getSupabaseStorageManifest(),
881
- },
882
- {
883
- path: `${k8sRoot}/supabase/imgproxy.yaml`,
884
- content: getSupabaseImgproxyManifest(),
885
- },
886
- {
887
- path: `${k8sRoot}/supabase/meta.yaml`,
888
- content: getSupabaseMetaManifest(),
889
- },
890
- {
891
- path: `${k8sRoot}/supabase/gateway.template.yml`,
892
- content: getSupabaseGatewayTemplate(),
893
- },
894
- {
895
- path: `${k8sRoot}/supabase/kong-entrypoint.sh`,
896
- content: getSupabaseKongEntrypointScript(),
897
- executable: true,
898
- },
899
- {
900
- path: `${k8sRoot}/supabase/gateway.yaml`,
901
- content: getSupabaseGatewayManifest(),
902
- },
903
- {
904
- path: `${k8sRoot}/supabase/studio.yaml`,
905
- content: getSupabaseStudioManifest(),
906
- },
907
- ];
908
- }
909
- function getSupabaseBootstrapSql() {
910
- return `-- Generated from the official Supabase self-hosting Docker database bootstrap contract.
911
- -- Applied by scripts/up.sh after Postgres is ready and before Supabase services start.
912
- \\set pgpass \`echo "$POSTGRES_PASSWORD"\`
913
- \\set jwt_secret \`echo "$JWT_SECRET"\`
914
- \\set jwt_exp \`echo "$JWT_EXP"\`
915
-
916
- DO $$
917
- BEGIN
918
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN
919
- CREATE ROLE anon NOLOGIN NOINHERIT;
920
- END IF;
921
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN
922
- CREATE ROLE authenticated NOLOGIN NOINHERIT;
923
- END IF;
924
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'service_role') THEN
925
- CREATE ROLE service_role NOLOGIN NOINHERIT BYPASSRLS;
926
- END IF;
927
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticator') THEN
928
- CREATE ROLE authenticator NOINHERIT LOGIN;
929
- END IF;
930
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_admin') THEN
931
- CREATE ROLE supabase_admin LOGIN CREATEROLE CREATEDB REPLICATION BYPASSRLS;
932
- END IF;
933
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_auth_admin') THEN
934
- CREATE ROLE supabase_auth_admin LOGIN CREATEROLE;
935
- END IF;
936
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_storage_admin') THEN
937
- CREATE ROLE supabase_storage_admin LOGIN CREATEROLE;
938
- END IF;
939
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_functions_admin') THEN
940
- CREATE ROLE supabase_functions_admin LOGIN CREATEROLE;
941
- END IF;
942
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgbouncer') THEN
943
- CREATE ROLE pgbouncer LOGIN;
944
- END IF;
945
- END
946
- $$;
947
-
948
- ALTER ROLE authenticator WITH PASSWORD :'pgpass';
949
- ALTER ROLE pgbouncer WITH PASSWORD :'pgpass';
950
- ALTER ROLE supabase_auth_admin WITH PASSWORD :'pgpass';
951
- ALTER ROLE supabase_functions_admin WITH PASSWORD :'pgpass';
952
- ALTER ROLE supabase_storage_admin WITH PASSWORD :'pgpass';
953
- ALTER ROLE supabase_admin WITH PASSWORD :'pgpass';
954
-
955
- GRANT anon, authenticated, service_role TO authenticator;
956
- GRANT anon, authenticated, service_role TO supabase_storage_admin;
957
- GRANT postgres TO supabase_auth_admin;
958
- GRANT postgres TO supabase_storage_admin;
959
- GRANT postgres TO supabase_functions_admin;
960
- GRANT pg_monitor TO supabase_admin;
961
-
962
- CREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_auth_admin;
963
- CREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION supabase_storage_admin;
964
- CREATE SCHEMA IF NOT EXISTS graphql_public;
965
- CREATE SCHEMA IF NOT EXISTS _realtime AUTHORIZATION supabase_admin;
966
-
967
- GRANT USAGE ON SCHEMA public, graphql_public TO anon, authenticated, service_role;
968
- GRANT USAGE ON SCHEMA auth TO supabase_auth_admin;
969
- GRANT USAGE ON SCHEMA storage TO supabase_storage_admin, anon, authenticated, service_role;
970
- GRANT USAGE ON SCHEMA _realtime TO supabase_admin;
971
-
972
- ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO anon, authenticated, service_role;
973
- ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO anon, authenticated, service_role;
974
-
975
- ALTER DATABASE postgres SET "app.settings.jwt_secret" TO :'jwt_secret';
976
- ALTER DATABASE postgres SET "app.settings.jwt_exp" TO :'jwt_exp';
977
-
978
- SELECT 'CREATE DATABASE _supabase WITH OWNER supabase_admin'
979
- WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '_supabase')\\gexec
980
- `;
981
- }
982
- function getSupabasePostgresInitConfigMap() {
983
- return `apiVersion: v1
984
- kind: ConfigMap
985
- metadata:
986
- name: supabase-postgres-init
987
- namespace: ${SUPABASE_NAMESPACE}
988
- data:
989
- 99-ankhorage-local-dev-extensions.sql: |
990
- -- Local Minikube bootstrap for extension setup performed before runtime migrations.
991
- alter role postgres with superuser;
992
- grant pg_read_server_files to postgres;
993
- grant pg_read_server_files to supabase_admin;
994
- grant execute on function pg_read_file(text) to public;
995
- grant execute on function pg_read_file(text, bigint, bigint) to public;
996
- `;
997
- }
998
- function getSupabasePvcManifest(name, size) {
999
- return `apiVersion: v1
1000
- kind: PersistentVolumeClaim
1001
- metadata:
1002
- name: ${name}
1003
- namespace: ${SUPABASE_NAMESPACE}
1004
- spec:
1005
- accessModes:
1006
- - ReadWriteOnce
1007
- resources:
1008
- requests:
1009
- storage: ${size}
1010
- `;
1011
- }
1012
- function getSupabasePostgresManifest() {
1013
- return `apiVersion: v1
1014
- kind: Service
1015
- metadata:
1016
- name: postgres
1017
- namespace: ${SUPABASE_NAMESPACE}
1018
- spec:
1019
- selector:
1020
- app.kubernetes.io/name: supabase-postgres
1021
- ports:
1022
- - name: postgres
1023
- port: 5432
1024
- targetPort: postgres
1025
- ---
1026
- apiVersion: apps/v1
1027
- kind: Deployment
1028
- metadata:
1029
- name: postgres
1030
- namespace: ${SUPABASE_NAMESPACE}
1031
- spec:
1032
- replicas: 1
1033
- selector:
1034
- matchLabels:
1035
- app.kubernetes.io/name: supabase-postgres
1036
- template:
1037
- metadata:
1038
- labels:
1039
- app.kubernetes.io/name: supabase-postgres
1040
- spec:
1041
- containers:
1042
- - name: postgres
1043
- image: ${SUPABASE_IMAGES.postgres}
1044
- imagePullPolicy: IfNotPresent
1045
- ports:
1046
- - containerPort: 5432
1047
- name: postgres
1048
- env:
1049
- - name: POSTGRES_USER
1050
- value: postgres
1051
- - name: POSTGRES_PASSWORD
1052
- valueFrom:
1053
- secretKeyRef:
1054
- name: supabase-runtime-secrets
1055
- key: POSTGRES_PASSWORD
1056
- - name: PGPASSWORD
1057
- valueFrom:
1058
- secretKeyRef:
1059
- name: supabase-runtime-secrets
1060
- key: POSTGRES_PASSWORD
1061
- - name: POSTGRES_DB
1062
- value: postgres
1063
- - name: PGDATABASE
1064
- value: postgres
1065
- - name: PGPORT
1066
- value: "5432"
1067
- - name: POSTGRES_PORT
1068
- value: "5432"
1069
- - name: POSTGRES_HOST
1070
- value: /var/run/postgresql
1071
- - name: JWT_SECRET
1072
- valueFrom:
1073
- secretKeyRef:
1074
- name: supabase-runtime-secrets
1075
- key: JWT_SECRET
1076
- - name: JWT_EXP
1077
- valueFrom:
1078
- configMapKeyRef:
1079
- name: supabase-runtime-config
1080
- key: JWT_EXPIRY
1081
- volumeMounts:
1082
- - name: data
1083
- mountPath: /var/lib/postgresql/data
1084
- - name: init-scripts
1085
- mountPath: /docker-entrypoint-initdb.d/99-ankhorage-local-dev-extensions.sql
1086
- subPath: 99-ankhorage-local-dev-extensions.sql
1087
- readinessProbe:
1088
- exec:
1089
- command: ["pg_isready", "-U", "postgres"]
1090
- initialDelaySeconds: 15
1091
- periodSeconds: 5
1092
- livenessProbe:
1093
- exec:
1094
- command: ["pg_isready", "-U", "postgres"]
1095
- initialDelaySeconds: 30
1096
- periodSeconds: 10
1097
- args:
1098
- - postgres
1099
- - -c
1100
- - config_file=/etc/postgresql/postgresql.conf
1101
- - -c
1102
- - log_min_messages=fatal
1103
- volumes:
1104
- - name: data
1105
- persistentVolumeClaim:
1106
- claimName: supabase-postgres-data
1107
- - name: init-scripts
1108
- configMap:
1109
- name: supabase-postgres-init
1110
- `;
1111
- }
1112
- function getSupabaseAuthManifest() {
1113
- return `apiVersion: v1
1114
- kind: Service
1115
- metadata:
1116
- name: auth
1117
- namespace: ${SUPABASE_NAMESPACE}
1118
- spec:
1119
- selector:
1120
- app.kubernetes.io/name: supabase-auth
1121
- ports:
1122
- - name: http
1123
- port: 9999
1124
- targetPort: http
1125
- ---
1126
- apiVersion: apps/v1
1127
- kind: Deployment
1128
- metadata:
1129
- name: auth
1130
- namespace: ${SUPABASE_NAMESPACE}
1131
- spec:
1132
- replicas: 1
1133
- selector:
1134
- matchLabels:
1135
- app.kubernetes.io/name: supabase-auth
1136
- template:
1137
- metadata:
1138
- labels:
1139
- app.kubernetes.io/name: supabase-auth
1140
- spec:
1141
- containers:
1142
- - name: auth
1143
- image: ${SUPABASE_IMAGES.auth}
1144
- imagePullPolicy: IfNotPresent
1145
- ports:
1146
- - containerPort: 9999
1147
- name: http
1148
- env:
1149
- - name: GOTRUE_API_HOST
1150
- value: "0.0.0.0"
1151
- - name: GOTRUE_API_PORT
1152
- value: "9999"
1153
- - name: API_EXTERNAL_URL
1154
- valueFrom:
1155
- configMapKeyRef:
1156
- name: supabase-runtime-config
1157
- key: API_EXTERNAL_URL
1158
- - name: GOTRUE_SITE_URL
1159
- valueFrom:
1160
- configMapKeyRef:
1161
- name: supabase-runtime-config
1162
- key: SITE_URL
1163
- - name: GOTRUE_URI_ALLOW_LIST
1164
- valueFrom:
1165
- configMapKeyRef:
1166
- name: supabase-runtime-config
1167
- key: ADDITIONAL_REDIRECT_URLS
1168
- - name: GOTRUE_JWT_ISSUER
1169
- valueFrom:
1170
- configMapKeyRef:
1171
- name: supabase-runtime-config
1172
- key: API_EXTERNAL_URL
1173
- - name: GOTRUE_DB_DRIVER
1174
- value: postgres
1175
- - name: GOTRUE_DB_DATABASE_URL
1176
- value: "postgres://supabase_auth_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=auth&sslmode=disable"
1177
- - name: GOTRUE_JWT_AUD
1178
- value: authenticated
1179
- - name: GOTRUE_JWT_DEFAULT_GROUP_NAME
1180
- value: authenticated
1181
- - name: GOTRUE_JWT_ADMIN_ROLES
1182
- value: service_role
1183
- - name: GOTRUE_JWT_EXP
1184
- valueFrom:
1185
- configMapKeyRef:
1186
- name: supabase-runtime-config
1187
- key: JWT_EXPIRY
1188
- - name: GOTRUE_JWT_SECRET
1189
- valueFrom:
1190
- secretKeyRef:
1191
- name: supabase-runtime-secrets
1192
- key: JWT_SECRET
1193
- - name: GOTRUE_EXTERNAL_EMAIL_ENABLED
1194
- valueFrom:
1195
- configMapKeyRef:
1196
- name: supabase-runtime-config
1197
- key: ENABLE_EMAIL_SIGNUP
1198
- - name: GOTRUE_MAILER_AUTOCONFIRM
1199
- valueFrom:
1200
- configMapKeyRef:
1201
- name: supabase-runtime-config
1202
- key: ENABLE_EMAIL_AUTOCONFIRM
1203
- - name: GOTRUE_SMTP_ADMIN_EMAIL
1204
- valueFrom:
1205
- configMapKeyRef:
1206
- name: supabase-runtime-config
1207
- key: SMTP_ADMIN_EMAIL
1208
- - name: GOTRUE_SMTP_HOST
1209
- valueFrom:
1210
- configMapKeyRef:
1211
- name: supabase-runtime-config
1212
- key: SMTP_HOST
1213
- - name: GOTRUE_SMTP_PORT
1214
- valueFrom:
1215
- configMapKeyRef:
1216
- name: supabase-runtime-config
1217
- key: SMTP_PORT
1218
- - name: GOTRUE_SMTP_USER
1219
- valueFrom:
1220
- secretKeyRef:
1221
- name: supabase-runtime-secrets
1222
- key: SMTP_USER
1223
- - name: GOTRUE_SMTP_PASS
1224
- valueFrom:
1225
- secretKeyRef:
1226
- name: supabase-runtime-secrets
1227
- key: SMTP_PASS
1228
- - name: GOTRUE_SMTP_SENDER_NAME
1229
- valueFrom:
1230
- configMapKeyRef:
1231
- name: supabase-runtime-config
1232
- key: SMTP_SENDER_NAME
1233
- envFrom:
1234
- - secretRef:
1235
- name: supabase-runtime-secrets
1236
- - configMapRef:
1237
- name: supabase-runtime-config
1238
- readinessProbe:
1239
- httpGet:
1240
- path: /health
1241
- port: http
1242
- initialDelaySeconds: 10
1243
- periodSeconds: 10
1244
- `;
1245
- }
1246
- function getSupabaseRestManifest() {
1247
- return `apiVersion: v1
1248
- kind: Service
1249
- metadata:
1250
- name: rest
1251
- namespace: ${SUPABASE_NAMESPACE}
1252
- spec:
1253
- selector:
1254
- app.kubernetes.io/name: supabase-rest
1255
- ports:
1256
- - name: http
1257
- port: 3000
1258
- targetPort: http
1259
- ---
1260
- apiVersion: apps/v1
1261
- kind: Deployment
1262
- metadata:
1263
- name: rest
1264
- namespace: ${SUPABASE_NAMESPACE}
1265
- spec:
1266
- replicas: 1
1267
- selector:
1268
- matchLabels:
1269
- app.kubernetes.io/name: supabase-rest
1270
- template:
1271
- metadata:
1272
- labels:
1273
- app.kubernetes.io/name: supabase-rest
1274
- spec:
1275
- containers:
1276
- - name: rest
1277
- image: ${SUPABASE_IMAGES.rest}
1278
- imagePullPolicy: IfNotPresent
1279
- ports:
1280
- - containerPort: 3000
1281
- name: http
1282
- env:
1283
- - name: PGRST_DB_URI
1284
- value: "postgres://authenticator:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres"
1285
- - name: PGRST_DB_SCHEMAS
1286
- valueFrom:
1287
- configMapKeyRef:
1288
- name: supabase-runtime-config
1289
- key: PGRST_DB_SCHEMAS
1290
- - name: PGRST_DB_ANON_ROLE
1291
- value: anon
1292
- - name: PGRST_JWT_SECRET
1293
- valueFrom:
1294
- secretKeyRef:
1295
- name: supabase-runtime-secrets
1296
- key: JWT_SECRET
1297
- - name: PGRST_DB_USE_LEGACY_GUCS
1298
- value: "false"
1299
- envFrom:
1300
- - secretRef:
1301
- name: supabase-runtime-secrets
1302
- - configMapRef:
1303
- name: supabase-runtime-config
1304
- `;
1305
- }
1306
- function getSupabaseRealtimeManifest() {
1307
- return `apiVersion: v1
1308
- kind: Service
1309
- metadata:
1310
- name: realtime
1311
- namespace: ${SUPABASE_NAMESPACE}
1312
- spec:
1313
- selector:
1314
- app.kubernetes.io/name: supabase-realtime
1315
- ports:
1316
- - name: http
1317
- port: 4000
1318
- targetPort: http
1319
- ---
1320
- apiVersion: apps/v1
1321
- kind: Deployment
1322
- metadata:
1323
- name: realtime
1324
- namespace: ${SUPABASE_NAMESPACE}
1325
- spec:
1326
- replicas: 1
1327
- selector:
1328
- matchLabels:
1329
- app.kubernetes.io/name: supabase-realtime
1330
- template:
1331
- metadata:
1332
- labels:
1333
- app.kubernetes.io/name: supabase-realtime
1334
- spec:
1335
- containers:
1336
- - name: realtime
1337
- image: ${SUPABASE_IMAGES.realtime}
1338
- imagePullPolicy: IfNotPresent
1339
- ports:
1340
- - containerPort: 4000
1341
- name: http
1342
- env:
1343
- - name: PORT
1344
- value: "4000"
1345
- - name: DB_HOST
1346
- value: "postgres.${SUPABASE_NAMESPACE}.svc.cluster.local"
1347
- - name: DB_PORT
1348
- value: "5432"
1349
- - name: DB_NAME
1350
- value: postgres
1351
- - name: DB_USER
1352
- value: supabase_admin
1353
- - name: DB_PASSWORD
1354
- valueFrom:
1355
- secretKeyRef:
1356
- name: supabase-runtime-secrets
1357
- key: POSTGRES_PASSWORD
1358
- - name: API_JWT_SECRET
1359
- valueFrom:
1360
- secretKeyRef:
1361
- name: supabase-runtime-secrets
1362
- key: JWT_SECRET
1363
- - name: SECRET_KEY_BASE
1364
- valueFrom:
1365
- secretKeyRef:
1366
- name: supabase-runtime-secrets
1367
- key: SECRET_KEY_BASE
1368
- - name: DB_AFTER_CONNECT_QUERY
1369
- value: "SET search_path TO _realtime"
1370
- - name: DB_ENC_KEY
1371
- valueFrom:
1372
- secretKeyRef:
1373
- name: supabase-runtime-secrets
1374
- key: REALTIME_DB_ENC_KEY
1375
- - name: METRICS_JWT_SECRET
1376
- valueFrom:
1377
- secretKeyRef:
1378
- name: supabase-runtime-secrets
1379
- key: JWT_SECRET
1380
- - name: APP_NAME
1381
- value: realtime
1382
- - name: SEED_SELF_HOST
1383
- value: "true"
1384
- - name: RUN_JANITOR
1385
- value: "true"
1386
- - name: DISABLE_HEALTHCHECK_LOGGING
1387
- value: "true"
1388
- `;
1389
- }
1390
- function getSupabaseStorageManifest() {
1391
- return `${getSupabasePvcManifest('supabase-storage-data', '10Gi')}
1392
- ---
1393
- apiVersion: v1
1394
- kind: Service
1395
- metadata:
1396
- name: storage
1397
- namespace: ${SUPABASE_NAMESPACE}
1398
- spec:
1399
- selector:
1400
- app.kubernetes.io/name: supabase-storage
1401
- ports:
1402
- - name: http
1403
- port: 5000
1404
- targetPort: http
1405
- ---
1406
- apiVersion: apps/v1
1407
- kind: Deployment
1408
- metadata:
1409
- name: storage
1410
- namespace: ${SUPABASE_NAMESPACE}
1411
- spec:
1412
- replicas: 1
1413
- selector:
1414
- matchLabels:
1415
- app.kubernetes.io/name: supabase-storage
1416
- template:
1417
- metadata:
1418
- labels:
1419
- app.kubernetes.io/name: supabase-storage
1420
- spec:
1421
- containers:
1422
- - name: storage
1423
- image: ${SUPABASE_IMAGES.storage}
1424
- imagePullPolicy: IfNotPresent
1425
- ports:
1426
- - containerPort: 5000
1427
- name: http
1428
- env:
1429
- - name: ANON_KEY
1430
- valueFrom:
1431
- secretKeyRef:
1432
- name: supabase-runtime-secrets
1433
- key: SUPABASE_ANON_KEY
1434
- - name: SERVICE_KEY
1435
- valueFrom:
1436
- secretKeyRef:
1437
- name: supabase-runtime-secrets
1438
- key: SUPABASE_SERVICE_ROLE_KEY
1439
- - name: AUTH_JWT_SECRET
1440
- valueFrom:
1441
- secretKeyRef:
1442
- name: supabase-runtime-secrets
1443
- key: JWT_SECRET
1444
- - name: DATABASE_URL
1445
- value: "postgres://supabase_storage_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=storage&sslmode=disable"
1446
- - name: POSTGREST_URL
1447
- value: "http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000"
1448
- - name: STORAGE_BACKEND
1449
- value: file
1450
- - name: STORAGE_PUBLIC_URL
1451
- valueFrom:
1452
- configMapKeyRef:
1453
- name: supabase-runtime-config
1454
- key: SUPABASE_PUBLIC_URL
1455
- - name: REQUEST_ALLOW_X_FORWARDED_PATH
1456
- value: "true"
1457
- - name: FILE_SIZE_LIMIT
1458
- value: "52428800"
1459
- - name: FILE_STORAGE_BACKEND_PATH
1460
- value: /var/lib/storage
1461
- - name: TENANT_ID
1462
- value: stub
1463
- - name: REGION
1464
- value: local
1465
- - name: GLOBAL_S3_BUCKET
1466
- value: local
1467
- - name: IMGPROXY_URL
1468
- value: "http://imgproxy.${SUPABASE_NAMESPACE}.svc.cluster.local:5001"
1469
- envFrom:
1470
- - secretRef:
1471
- name: supabase-runtime-secrets
1472
- - configMapRef:
1473
- name: supabase-runtime-config
1474
- volumeMounts:
1475
- - name: storage
1476
- mountPath: /var/lib/storage
1477
- volumes:
1478
- - name: storage
1479
- persistentVolumeClaim:
1480
- claimName: supabase-storage-data
1481
- `;
1482
- }
1483
- function getSupabaseImgproxyManifest() {
1484
- return `apiVersion: v1
1485
- kind: Service
1486
- metadata:
1487
- name: imgproxy
1488
- namespace: ${SUPABASE_NAMESPACE}
1489
- spec:
1490
- selector:
1491
- app.kubernetes.io/name: supabase-imgproxy
1492
- ports:
1493
- - name: http
1494
- port: 5001
1495
- targetPort: http
1496
- ---
1497
- apiVersion: apps/v1
1498
- kind: Deployment
1499
- metadata:
1500
- name: imgproxy
1501
- namespace: ${SUPABASE_NAMESPACE}
1502
- spec:
1503
- replicas: 1
1504
- selector:
1505
- matchLabels:
1506
- app.kubernetes.io/name: supabase-imgproxy
1507
- template:
1508
- metadata:
1509
- labels:
1510
- app.kubernetes.io/name: supabase-imgproxy
1511
- spec:
1512
- containers:
1513
- - name: imgproxy
1514
- image: ${SUPABASE_IMAGES.imgproxy}
1515
- imagePullPolicy: IfNotPresent
1516
- ports:
1517
- - containerPort: 5001
1518
- name: http
1519
- env:
1520
- - name: IMGPROXY_BIND
1521
- value: ":5001"
1522
- `;
1523
- }
1524
- function getSupabaseMetaManifest() {
1525
- return `apiVersion: v1
1526
- kind: Service
1527
- metadata:
1528
- name: meta
1529
- namespace: ${SUPABASE_NAMESPACE}
1530
- spec:
1531
- selector:
1532
- app.kubernetes.io/name: supabase-meta
1533
- ports:
1534
- - name: http
1535
- port: 8080
1536
- targetPort: http
1537
- ---
1538
- apiVersion: apps/v1
1539
- kind: Deployment
1540
- metadata:
1541
- name: meta
1542
- namespace: ${SUPABASE_NAMESPACE}
1543
- spec:
1544
- replicas: 1
1545
- selector:
1546
- matchLabels:
1547
- app.kubernetes.io/name: supabase-meta
1548
- template:
1549
- metadata:
1550
- labels:
1551
- app.kubernetes.io/name: supabase-meta
1552
- spec:
1553
- containers:
1554
- - name: meta
1555
- image: ${SUPABASE_IMAGES.meta}
1556
- imagePullPolicy: IfNotPresent
1557
- ports:
1558
- - containerPort: 8080
1559
- name: http
1560
- env:
1561
- - name: PG_META_PORT
1562
- value: "8080"
1563
- - name: PG_META_DB_HOST
1564
- value: "postgres.${SUPABASE_NAMESPACE}.svc.cluster.local"
1565
- - name: PG_META_DB_PORT
1566
- value: "5432"
1567
- - name: PG_META_DB_NAME
1568
- value: postgres
1569
- - name: PG_META_DB_USER
1570
- value: postgres
1571
- - name: PG_META_DB_PASSWORD
1572
- valueFrom:
1573
- secretKeyRef:
1574
- name: supabase-runtime-secrets
1575
- key: POSTGRES_PASSWORD
1576
- - name: CRYPTO_KEY
1577
- valueFrom:
1578
- secretKeyRef:
1579
- name: supabase-runtime-secrets
1580
- key: PG_META_CRYPTO_KEY
1581
- `;
1582
- }
1583
- function getSupabaseGatewayTemplate() {
1584
- return `_format_version: "2.1"
1585
- _transform: true
1586
-
1587
- consumers:
1588
- - username: DASHBOARD
1589
- - username: anon
1590
- keyauth_credentials:
1591
- - key: $SUPABASE_ANON_KEY
1592
- - key: $SUPABASE_PUBLISHABLE_KEY
1593
- - username: service_role
1594
- keyauth_credentials:
1595
- - key: $SUPABASE_SERVICE_KEY
1596
- - key: $SUPABASE_SECRET_KEY
1597
-
1598
- acls:
1599
- - consumer: anon
1600
- group: anon
1601
- - consumer: service_role
1602
- group: admin
1603
-
1604
- basicauth_credentials:
1605
- - consumer: DASHBOARD
1606
- username: "$DASHBOARD_USERNAME"
1607
- password: "$DASHBOARD_PASSWORD"
1608
-
1609
- services:
1610
- - name: auth-v1-open
1611
- url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/verify
1612
- routes:
1613
- - name: auth-v1-open
1614
- strip_path: true
1615
- paths: [/auth/v1/verify]
1616
- plugins:
1617
- - name: cors
1618
- - name: auth-v1-open-callback
1619
- url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/callback
1620
- routes:
1621
- - name: auth-v1-open-callback
1622
- strip_path: true
1623
- paths: [/auth/v1/callback]
1624
- plugins:
1625
- - name: cors
1626
- - name: auth-v1-open-authorize
1627
- url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/authorize
1628
- routes:
1629
- - name: auth-v1-open-authorize
1630
- strip_path: true
1631
- paths: [/auth/v1/authorize]
1632
- plugins:
1633
- - name: cors
1634
- - name: auth-v1-open-jwks
1635
- url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/.well-known/jwks.json
1636
- routes:
1637
- - name: auth-v1-open-jwks
1638
- strip_path: true
1639
- paths: [/auth/v1/.well-known/jwks.json]
1640
- plugins:
1641
- - name: cors
1642
- - name: auth-v1
1643
- url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/
1644
- routes:
1645
- - name: auth-v1-all
1646
- strip_path: true
1647
- paths: [/auth/v1/]
1648
- plugins:
1649
- - name: cors
1650
- - name: key-auth
1651
- config:
1652
- hide_credentials: false
1653
- - name: request-transformer
1654
- config:
1655
- add:
1656
- headers:
1657
- - "Authorization: $LUA_AUTH_EXPR"
1658
- replace:
1659
- headers:
1660
- - "Authorization: $LUA_AUTH_EXPR"
1661
- - name: acl
1662
- config:
1663
- hide_groups_header: true
1664
- allow: [admin, anon]
1665
- - name: rest-v1
1666
- url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/
1667
- routes:
1668
- - name: rest-v1-all
1669
- strip_path: true
1670
- paths: [/rest/v1/]
1671
- plugins:
1672
- - name: cors
1673
- - name: key-auth
1674
- config:
1675
- hide_credentials: false
1676
- - name: request-transformer
1677
- config:
1678
- add:
1679
- headers:
1680
- - "Authorization: $LUA_AUTH_EXPR"
1681
- replace:
1682
- headers:
1683
- - "Authorization: $LUA_AUTH_EXPR"
1684
- - name: acl
1685
- config:
1686
- hide_groups_header: true
1687
- allow: [admin, anon]
1688
- - name: graphql-v1
1689
- url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/rpc/graphql
1690
- routes:
1691
- - name: graphql-v1-all
1692
- strip_path: true
1693
- paths: [/graphql/v1]
1694
- plugins:
1695
- - name: cors
1696
- - name: key-auth
1697
- config:
1698
- hide_credentials: false
1699
- - name: request-transformer
1700
- config:
1701
- add:
1702
- headers:
1703
- - "Content-Profile: graphql_public"
1704
- - "Authorization: $LUA_AUTH_EXPR"
1705
- replace:
1706
- headers:
1707
- - "Authorization: $LUA_AUTH_EXPR"
1708
- - name: acl
1709
- config:
1710
- hide_groups_header: true
1711
- allow: [admin, anon]
1712
- - name: realtime-v1-ws
1713
- url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/socket
1714
- protocol: ws
1715
- routes:
1716
- - name: realtime-v1-ws
1717
- strip_path: true
1718
- paths: [/realtime/v1/]
1719
- plugins:
1720
- - name: cors
1721
- - name: key-auth
1722
- config:
1723
- hide_credentials: false
1724
- - name: request-transformer
1725
- config:
1726
- add:
1727
- headers:
1728
- - "x-api-key:$LUA_RT_WS_EXPR"
1729
- replace:
1730
- querystring:
1731
- - "apikey:$LUA_RT_WS_EXPR"
1732
- - name: acl
1733
- config:
1734
- hide_groups_header: true
1735
- allow: [admin, anon]
1736
- - name: realtime-v1-rest-openapi
1737
- url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/openapi
1738
- protocol: http
1739
- routes:
1740
- - name: realtime-v1-rest-openapi
1741
- strip_path: true
1742
- paths: [/realtime/v1/api/openapi]
1743
- plugins:
1744
- - name: request-termination
1745
- config:
1746
- status_code: 403
1747
- message: "Access is forbidden."
1748
- - name: realtime-v1-rest-tenants
1749
- url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/tenants
1750
- protocol: http
1751
- routes:
1752
- - name: realtime-v1-rest-tenants
1753
- strip_path: true
1754
- paths: [/realtime/v1/api/tenants]
1755
- plugins:
1756
- - name: request-termination
1757
- config:
1758
- status_code: 403
1759
- message: "Access is forbidden."
1760
- - name: realtime-v1-rest
1761
- url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api
1762
- protocol: http
1763
- routes:
1764
- - name: realtime-v1-rest
1765
- strip_path: true
1766
- paths: [/realtime/v1/api]
1767
- plugins:
1768
- - name: cors
1769
- - name: key-auth
1770
- config:
1771
- hide_credentials: false
1772
- - name: request-transformer
1773
- config:
1774
- add:
1775
- headers:
1776
- - "Authorization: $LUA_AUTH_EXPR"
1777
- replace:
1778
- headers:
1779
- - "Authorization: $LUA_AUTH_EXPR"
1780
- - name: acl
1781
- config:
1782
- hide_groups_header: true
1783
- allow: [admin, anon]
1784
- - name: storage-v1
1785
- url: http://storage.${SUPABASE_NAMESPACE}.svc.cluster.local:5000/
1786
- routes:
1787
- - name: storage-v1-all
1788
- strip_path: true
1789
- paths: [/storage/v1/]
1790
- plugins:
1791
- - name: cors
1792
- - name: request-transformer
1793
- config:
1794
- add:
1795
- headers:
1796
- - "Authorization: $LUA_AUTH_EXPR"
1797
- replace:
1798
- headers:
1799
- - "Authorization: $LUA_AUTH_EXPR"
1800
- - name: post-function
1801
- config:
1802
- access:
1803
- - |
1804
- local auth = kong.request.get_header("authorization")
1805
- if auth == nil or auth == "" or auth:find("^%s*$") then
1806
- kong.service.request.clear_header("authorization")
1807
- end
1808
- - name: meta
1809
- url: http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080/
1810
- routes:
1811
- - name: meta-all
1812
- strip_path: true
1813
- paths: [/pg/]
1814
- plugins:
1815
- - name: key-auth
1816
- config:
1817
- hide_credentials: false
1818
- - name: acl
1819
- config:
1820
- hide_groups_header: true
1821
- allow: [admin]
1822
- - name: dashboard
1823
- url: http://studio.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/
1824
- routes:
1825
- - name: dashboard-all
1826
- strip_path: true
1827
- paths: [/]
1828
- plugins:
1829
- - name: cors
1830
- - name: basic-auth
1831
- config:
1832
- hide_credentials: true
1833
- `;
1834
- }
1835
- function getSupabaseKongEntrypointScript() {
1836
- return `#!/bin/sh
1837
- set -eu
1838
-
1839
- if [ -n "\${SUPABASE_SECRET_KEY:-}" ] && [ -n "\${SUPABASE_PUBLISHABLE_KEY:-}" ]; then
1840
- export LUA_AUTH_EXPR="\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or (headers.apikey == '\${SUPABASE_SECRET_KEY}' and 'Bearer \${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (headers.apikey == '\${SUPABASE_PUBLISHABLE_KEY}' and 'Bearer \${ANON_KEY_ASYMMETRIC:-}') or headers.apikey)"
1841
- export LUA_RT_WS_EXPR="\\$((query_params.apikey == '\${SUPABASE_SECRET_KEY}' and '\${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (query_params.apikey == '\${SUPABASE_PUBLISHABLE_KEY}' and '\${ANON_KEY_ASYMMETRIC:-}') or query_params.apikey)"
1842
- else
1843
- export LUA_AUTH_EXPR="\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or headers.apikey)"
1844
- export LUA_RT_WS_EXPR="\\$(query_params.apikey)"
1845
- fi
1846
-
1847
- awk '{
1848
- result = ""
1849
- rest = $0
1850
- while (match(rest, /\\$[A-Za-z_][A-Za-z_0-9]*/)) {
1851
- varname = substr(rest, RSTART + 1, RLENGTH - 1)
1852
- if (varname in ENVIRON) {
1853
- result = result substr(rest, 1, RSTART - 1) ENVIRON[varname]
1854
- } else {
1855
- result = result substr(rest, 1, RSTART + RLENGTH - 1)
1856
- }
1857
- rest = substr(rest, RSTART + RLENGTH)
1858
- }
1859
- print result rest
1860
- }' /home/kong/temp.yml > "\${KONG_DECLARATIVE_CONFIG}"
1861
-
1862
- sed -i '/^[[:space:]]*- key:[[:space:]]*$/d' "\${KONG_DECLARATIVE_CONFIG}"
1863
-
1864
- exec /entrypoint.sh kong docker-start
1865
- `;
1866
- }
1867
- function getSupabaseGatewayManifest() {
1868
- return `apiVersion: v1
1869
- kind: Service
1870
- metadata:
1871
- name: gateway
1872
- namespace: ${SUPABASE_NAMESPACE}
1873
- spec:
1874
- selector:
1875
- app.kubernetes.io/name: supabase-gateway
1876
- ports:
1877
- - name: http
1878
- port: 8000
1879
- targetPort: http
1880
- ---
1881
- apiVersion: apps/v1
1882
- kind: Deployment
1883
- metadata:
1884
- name: gateway
1885
- namespace: ${SUPABASE_NAMESPACE}
1886
- spec:
1887
- replicas: 1
1888
- selector:
1889
- matchLabels:
1890
- app.kubernetes.io/name: supabase-gateway
1891
- template:
1892
- metadata:
1893
- labels:
1894
- app.kubernetes.io/name: supabase-gateway
1895
- spec:
1896
- containers:
1897
- - name: gateway
1898
- image: ${SUPABASE_IMAGES.gateway}
1899
- imagePullPolicy: IfNotPresent
1900
- ports:
1901
- - containerPort: 8000
1902
- name: http
1903
- env:
1904
- - name: KONG_DATABASE
1905
- value: "off"
1906
- - name: KONG_DECLARATIVE_CONFIG
1907
- value: /usr/local/kong/kong.yml
1908
- - name: KONG_ROUTER_FLAVOR
1909
- value: expressions
1910
- - name: KONG_DNS_ORDER
1911
- value: LAST,A,CNAME
1912
- - name: KONG_DNS_NOT_FOUND_TTL
1913
- value: "1"
1914
- - name: KONG_PLUGINS
1915
- value: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction,post-function
1916
- - name: KONG_PROXY_LISTEN
1917
- value: "0.0.0.0:8000"
1918
- - name: SUPABASE_SERVICE_KEY
1919
- valueFrom:
1920
- secretKeyRef:
1921
- name: supabase-runtime-secrets
1922
- key: SUPABASE_SERVICE_ROLE_KEY
1923
- envFrom:
1924
- - secretRef:
1925
- name: supabase-runtime-secrets
1926
- volumeMounts:
1927
- - name: config
1928
- mountPath: /home/kong/temp.yml
1929
- subPath: temp.yml
1930
- readOnly: true
1931
- - name: entrypoint
1932
- mountPath: /home/kong/kong-entrypoint.sh
1933
- subPath: kong-entrypoint.sh
1934
- readOnly: true
1935
- command: ["/bin/sh", "/home/kong/kong-entrypoint.sh"]
1936
- readinessProbe:
1937
- exec:
1938
- command: ["kong", "health"]
1939
- initialDelaySeconds: 10
1940
- periodSeconds: 10
1941
- volumes:
1942
- - name: config
1943
- configMap:
1944
- name: supabase-gateway-config
1945
- - name: entrypoint
1946
- configMap:
1947
- name: supabase-kong-entrypoint
1948
- defaultMode: 0755
1949
- `;
1950
- }
1951
- function getSupabaseStudioManifest() {
1952
- return `apiVersion: v1
1953
- kind: Service
1954
- metadata:
1955
- name: studio
1956
- namespace: ${SUPABASE_NAMESPACE}
1957
- spec:
1958
- selector:
1959
- app.kubernetes.io/name: supabase-studio
1960
- ports:
1961
- - name: http
1962
- port: 3000
1963
- targetPort: http
1964
- ---
1965
- apiVersion: apps/v1
1966
- kind: Deployment
1967
- metadata:
1968
- name: studio
1969
- namespace: ${SUPABASE_NAMESPACE}
1970
- spec:
1971
- replicas: 1
1972
- selector:
1973
- matchLabels:
1974
- app.kubernetes.io/name: supabase-studio
1975
- template:
1976
- metadata:
1977
- labels:
1978
- app.kubernetes.io/name: supabase-studio
1979
- spec:
1980
- containers:
1981
- - name: studio
1982
- image: ${SUPABASE_IMAGES.studio}
1983
- imagePullPolicy: IfNotPresent
1984
- ports:
1985
- - containerPort: 3000
1986
- name: http
1987
- env:
1988
- - name: HOSTNAME
1989
- value: "0.0.0.0"
1990
- - name: STUDIO_PG_META_URL
1991
- value: "http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080"
1992
- - name: SUPABASE_URL
1993
- value: "http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000"
1994
- - name: SUPABASE_PUBLIC_URL
1995
- valueFrom:
1996
- configMapKeyRef:
1997
- name: supabase-runtime-config
1998
- key: SUPABASE_PUBLIC_URL
1999
- - name: SUPABASE_ANON_KEY
2000
- valueFrom:
2001
- secretKeyRef:
2002
- name: supabase-runtime-secrets
2003
- key: SUPABASE_ANON_KEY
2004
- - name: SUPABASE_SERVICE_KEY
2005
- valueFrom:
2006
- secretKeyRef:
2007
- name: supabase-runtime-secrets
2008
- key: SUPABASE_SERVICE_ROLE_KEY
2009
- - name: AUTH_JWT_SECRET
2010
- valueFrom:
2011
- secretKeyRef:
2012
- name: supabase-runtime-secrets
2013
- key: JWT_SECRET
2014
- envFrom:
2015
- - secretRef:
2016
- name: supabase-runtime-secrets
2017
- - configMapRef:
2018
- name: supabase-runtime-config
2019
- `;
2020
- }
2021
- function getUpScript(args) {
2022
- const { appSlug, appRuntimeEnabled, defaultAppImage, supabaseKubernetesEnabled, profileModel, secretStoreProvider, supabaseHostPorts, oauthProviders, providerLifecycle, } = args;
2023
- const oauthEnvDefaults = getOAuthScriptEnvDefaults(oauthProviders);
2024
- const oauthRuntimeSecretLines = getOAuthRuntimeSecretLines(oauthProviders);
2025
- const oauthValidation = getOAuthRuntimeValidationScript(oauthProviders);
2026
- const oauthCallbackRoute = getSupabaseOAuthCallbackRoute(oauthProviders);
2027
- const providerLifecycleStageScripts = getProviderLifecycleStageScripts(providerLifecycle);
2028
- const oauthVaultResolution = getOAuthVaultResolutionScript({
2029
- appSlug,
2030
- oauthProviders,
2031
- secretStoreProvider,
2032
- });
2033
- const supabaseMigrationCommand = getSupabaseMigrationCommandScript();
2034
- const disabledAppRuntimeReconciliation = appRuntimeEnabled
2035
- ? ''
2036
- : `reconcile_disabled_app_runtime() {
2037
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" delete deployment/app-runtime service/app-runtime configmap/app-infra-config --ignore-not-found
2038
- "\${PORT_FORWARD_SCRIPT}" stop obsolete
2039
- }
2040
- `;
2041
- const reconcileDisabledAppRuntime = appRuntimeEnabled ? '' : 'reconcile_disabled_app_runtime';
2042
- return `#!/usr/bin/env bash
2043
- set -Eeuo pipefail
2044
-
2045
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
2046
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
2047
- K8S_DIR="\${ROOT_DIR}/k8s"
2048
- BUILD_SCRIPT="\${SCRIPT_DIR}/build-app-image.sh"
2049
- PORT_FORWARD_SCRIPT="\${SCRIPT_DIR}/port-forward.sh"
2050
- APP_SLUG="${appSlug}"
2051
- PROFILE="\${ANKH_APP_SLUG:-}"
2052
- DRIVER="\${MINIKUBE_DRIVER:-}"
2053
- APP_NAMESPACE="${APP_NAMESPACE}"
2054
- SUPABASE_NAMESPACE="${SUPABASE_NAMESPACE}"
2055
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
2056
- APP_RUNTIME_ENABLED="${appRuntimeEnabled ? 'true' : 'false'}"
2057
- APP_BUILD_ENABLED="\${APP_BUILD_ENABLED:-}"
2058
- APP_SOURCE_DIR="\${APP_SOURCE_DIR:-}"
2059
- APP_WEB_EXPORT_DIR="\${APP_WEB_EXPORT_DIR:-}"
2060
- APP_IMAGE="\${APP_IMAGE:-}"
2061
- APP_IMAGE_SYNC_STRATEGY="\${APP_IMAGE_SYNC_STRATEGY:-}"
2062
- APP_REPLICAS="\${APP_REPLICAS:-}"
2063
- APP_FORCE_ROLLOUT_RESTART="\${APP_FORCE_ROLLOUT_RESTART:-}"
2064
- APP_IMAGE_PULL_SECRET_NAME="\${APP_IMAGE_PULL_SECRET_NAME:-}"
2065
- APP_IMAGE_PULL_SECRET_SERVER="\${APP_IMAGE_PULL_SECRET_SERVER:-}"
2066
- APP_IMAGE_PULL_SECRET_USERNAME="\${APP_IMAGE_PULL_SECRET_USERNAME:-}"
2067
- APP_IMAGE_PULL_SECRET_PASSWORD="\${APP_IMAGE_PULL_SECRET_PASSWORD:-}"
2068
- APP_IMAGE_PULL_SECRET_EMAIL="\${APP_IMAGE_PULL_SECRET_EMAIL:-}"
2069
- APP_PORT_FORWARD_LOCAL_PORT="\${APP_PORT_FORWARD_LOCAL_PORT:-}"
2070
- SUPABASE_GATEWAY_FORWARD_LOCAL_PORT="\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-}"
2071
- SUPABASE_DB_FORWARD_LOCAL_PORT="\${SUPABASE_DB_FORWARD_LOCAL_PORT:-}"
2072
- SUPABASE_DB_URL="\${SUPABASE_DB_URL:-}"
2073
- SUPABASE_PROFILE_ENABLED="${profileModel.enabled ? 'true' : 'false'}"
2074
- SUPABASE_PROFILE_RECONCILE_FILE="\${ROOT_DIR}/supabase/generated/auth_profiles.sql"
2075
-
2076
- require_command() {
2077
- if ! command -v "\${1}" >/dev/null 2>&1; then
2078
- echo "\${1} is required but not installed."
2079
- exit 1
2080
- fi
2081
- }
2082
-
2083
- load_env_file_preserving_process_env() {
2084
- local line trimmed key value current
2085
- if [[ ! -f "\${ROOT_DIR}/.env" ]]; then
2086
- return 0
2087
- fi
2088
-
2089
- while IFS= read -r line || [[ -n "\${line}" ]]; do
2090
- trimmed="$(printf '%s' "\${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
2091
- if [[ -z "\${trimmed}" || "\${trimmed}" == \\#* || "\${trimmed}" != *=* ]]; then
2092
- continue
2093
- fi
2094
-
2095
- key="\${trimmed%%=*}"
2096
- value="\${trimmed#*=}"
2097
- key="\${key//[[:space:]]/}"
2098
- value="$(printf '%s' "\${value}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
2099
- value="\${value%\\"}"
2100
- value="\${value#\\"}"
2101
- value="\${value%\\'}"
2102
- value="\${value#\\'}"
2103
- current="\${!key:-}"
2104
- if [[ -n "\${current}" ]]; then
2105
- continue
2106
- fi
2107
- export "\${key}=\${value}"
2108
- done < "\${ROOT_DIR}/.env"
2109
- }
2110
-
2111
- env_file_value() {
2112
- local key="\${1}"
2113
- if [[ ! -f "\${ROOT_DIR}/.env" ]]; then
2114
- return 0
2115
- fi
2116
- awk -F= -v key="\${key}" '$1 == key { value = substr($0, index($0, "=") + 1) } END { print value }' "\${ROOT_DIR}/.env"
2117
- }
2118
-
2119
- env_file_has_key() {
2120
- local key="\${1}"
2121
- if [[ ! -f "\${ROOT_DIR}/.env" ]]; then
2122
- return 1
2123
- fi
2124
- awk -F= -v key="\${key}" '$1 == key { found = 1 } END { exit found ? 0 : 1 }' "\${ROOT_DIR}/.env"
2125
- }
2126
-
2127
- write_env_value() {
2128
- local key="\${1}"
2129
- local value="\${2}"
2130
- local tmp_env
2131
- mkdir -p "\${ROOT_DIR}"
2132
- touch "\${ROOT_DIR}/.env"
2133
- tmp_env="$(mktemp)"
2134
- awk -F= -v key="\${key}" -v value="\${value}" '
2135
- $1 == key {
2136
- print key "=" value
2137
- found = 1
2138
- next
2139
- }
2140
- { print }
2141
- END {
2142
- if (!found) print key "=" value
2143
- }
2144
- ' "\${ROOT_DIR}/.env" > "\${tmp_env}"
2145
- mv "\${tmp_env}" "\${ROOT_DIR}/.env"
2146
- }
2147
-
2148
- write_key_value_file_value() {
2149
- local file_path="\${1}"
2150
- local key="\${2}"
2151
- local value="\${3}"
2152
- local tmp_env
2153
- mkdir -p "$(dirname "\${file_path}")"
2154
- touch "\${file_path}"
2155
- tmp_env="$(mktemp)"
2156
- awk -F= -v key="\${key}" -v value="\${value}" '
2157
- $1 == key {
2158
- print key "=" value
2159
- found = 1
2160
- next
2161
- }
2162
- { print }
2163
- END {
2164
- if (!found) print key "=" value
2165
- }
2166
- ' "\${file_path}" > "\${tmp_env}"
2167
- mv "\${tmp_env}" "\${file_path}"
2168
- }
2169
-
2170
- sync_app_public_supabase_env() {
2171
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2172
- return 0
2173
- fi
2174
-
2175
- if [[ -z "\${APP_SOURCE_DIR:-}" ]]; then
2176
- echo "APP_SOURCE_DIR is required to write app Supabase public environment."
2177
- exit 1
2178
- fi
2179
-
2180
- local app_env_file="\${APP_SOURCE_DIR}/.env.local"
2181
- write_key_value_file_value "\${app_env_file}" "EXPO_PUBLIC_SUPABASE_URL" "\${EXPO_PUBLIC_SUPABASE_URL}"
2182
- write_key_value_file_value "\${app_env_file}" "EXPO_PUBLIC_SUPABASE_ANON_KEY" "\${EXPO_PUBLIC_SUPABASE_ANON_KEY}"
2183
- }
2184
-
2185
- set_required_env_default() {
2186
- local key="\${1}"
2187
- local value="\${2}"
2188
- local current="\${!key:-}"
2189
- if [[ -n "\${current}" ]]; then
2190
- write_env_value "\${key}" "\${current}"
2191
- return 0
2192
- fi
2193
-
2194
- current="$(env_file_value "\${key}")"
2195
- if [[ -n "\${current}" ]]; then
2196
- export "\${key}=\${current}"
2197
- return 0
2198
- fi
2199
-
2200
- write_env_value "\${key}" "\${value}"
2201
- export "\${key}=\${value}"
2202
- }
2203
-
2204
- set_optional_env_default() {
2205
- local key="\${1}"
2206
- local value="\${2}"
2207
- local current="\${!key:-}"
2208
- if env_file_has_key "\${key}"; then
2209
- export "\${key}=\${current}"
2210
- return 0
2211
- fi
2212
- if [[ -n "\${current}" ]]; then
2213
- write_env_value "\${key}" "\${current}"
2214
- return 0
2215
- fi
2216
- write_env_value "\${key}" "\${value}"
2217
- export "\${key}=\${value}"
2218
- }
2219
-
2220
- set_env_default() {
2221
- set_required_env_default "\${1}" "\${2}"
2222
- }
2223
-
2224
- derive_additional_redirect_urls() {
2225
- local callback_route="${oauthCallbackRoute}"
2226
- local callback_path="\${callback_route#/}"
2227
- local site_url_without_slash="\${SITE_URL%/}"
2228
- local urls="\${site_url_without_slash},\${site_url_without_slash}/\${callback_path}"
2229
- if [[ -n "\${OAUTH_NATIVE_REDIRECT_URLS:-}" ]]; then
2230
- urls="\${urls},\${OAUTH_NATIVE_REDIRECT_URLS}"
2231
- fi
2232
- printf '%s' "\${urls}"
2233
- }
2234
-
2235
- random_base64() {
2236
- openssl rand -base64 "\${1}" | tr -d '\\n'
2237
- }
2238
-
2239
- random_hex() {
2240
- openssl rand -hex "\${1}" | tr -d '\\n'
2241
- }
2242
-
2243
- base64url() {
2244
- openssl base64 -A | tr '+/' '-_' | tr -d '='
2245
- }
2246
-
2247
- generate_supabase_jwt() {
2248
- local role="\${1}"
2249
- local iat exp header payload signature
2250
- iat="$(date +%s)"
2251
- exp="$((iat + 315360000))"
2252
- header="$(printf '{"alg":"HS256","typ":"JWT"}' | base64url)"
2253
- payload="$(printf '{"role":"%s","iss":"supabase-demo","iat":%s,"exp":%s}' "\${role}" "\${iat}" "\${exp}" | base64url)"
2254
- signature="$(printf '%s.%s' "\${header}" "\${payload}" | openssl dgst -binary -sha256 -hmac "\${JWT_SECRET}" | base64url)"
2255
- printf '%s.%s.%s' "\${header}" "\${payload}" "\${signature}"
2256
- }
2257
-
2258
- ensure_supabase_runtime_env() {
2259
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2260
- return 0
2261
- fi
2262
-
2263
- require_command openssl
2264
-
2265
- set_required_env_default POSTGRES_PASSWORD "$(random_hex 32)"
2266
- set_required_env_default JWT_SECRET "$(random_base64 48)"
2267
- set_required_env_default SUPABASE_ANON_KEY "$(generate_supabase_jwt anon)"
2268
- set_required_env_default SUPABASE_SERVICE_ROLE_KEY "$(generate_supabase_jwt service_role)"
2269
- set_required_env_default DASHBOARD_USERNAME "supabase"
2270
- set_required_env_default DASHBOARD_PASSWORD "$(random_base64 24)"
2271
- set_required_env_default SECRET_KEY_BASE "$(random_base64 48)"
2272
- set_required_env_default REALTIME_DB_ENC_KEY "$(random_hex 8)"
2273
- set_required_env_default PG_META_CRYPTO_KEY "$(random_base64 32)"
2274
- set_required_env_default S3_PROTOCOL_ACCESS_KEY_ID "$(random_hex 16)"
2275
- set_required_env_default S3_PROTOCOL_ACCESS_KEY_SECRET "$(random_hex 32)"
2276
- set_required_env_default JWT_EXPIRY "3600"
2277
- set_required_env_default SUPABASE_GATEWAY_FORWARD_LOCAL_PORT "\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}"
2278
- set_required_env_default APP_PORT_FORWARD_LOCAL_PORT "\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}"
2279
- set_required_env_default SUPABASE_PUBLIC_URL "http://127.0.0.1:\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}"
2280
- set_required_env_default API_EXTERNAL_URL "\${SUPABASE_PUBLIC_URL}/auth/v1"
2281
- set_required_env_default SITE_URL "http://127.0.0.1:\${APP_PORT_FORWARD_LOCAL_PORT}"
2282
- export OAUTH_NATIVE_REDIRECT_URLS="\${OAUTH_NATIVE_REDIRECT_URLS:-}"
2283
- set_required_env_default ADDITIONAL_REDIRECT_URLS "$(derive_additional_redirect_urls)"
2284
- set_required_env_default ENABLE_EMAIL_SIGNUP "true"
2285
- set_required_env_default ENABLE_EMAIL_AUTOCONFIRM "true"
2286
- set_required_env_default SMTP_ADMIN_EMAIL "admin@example.com"
2287
- set_required_env_default SMTP_HOST "localhost"
2288
- set_required_env_default SMTP_PORT "2500"
2289
- set_optional_env_default SMTP_USER ""
2290
- set_optional_env_default SMTP_PASS ""
2291
- set_required_env_default SMTP_SENDER_NAME "Ankhorage"
2292
- set_required_env_default PGRST_DB_SCHEMAS "public,storage,graphql_public"
2293
- set_required_env_default PGRST_DB_MAX_ROWS "1000"
2294
- set_required_env_default PGRST_DB_EXTRA_SEARCH_PATH "public"
2295
- set_required_env_default GLOBAL_S3_BUCKET "stub"
2296
- set_required_env_default STORAGE_TENANT_ID "stub"
2297
- set_required_env_default REGION "stub"
2298
- set_required_env_default SUPABASE_DB_FORWARD_LOCAL_PORT "\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}"
2299
- set_required_env_default SUPABASE_DB_URL "postgres://postgres:\${POSTGRES_PASSWORD}@127.0.0.1:\${SUPABASE_DB_FORWARD_LOCAL_PORT}/postgres?sslmode=disable"
2300
- set_required_env_default EXPO_PUBLIC_SUPABASE_URL "\${SUPABASE_PUBLIC_URL}"
2301
- set_required_env_default EXPO_PUBLIC_SUPABASE_ANON_KEY "\${SUPABASE_ANON_KEY}"
2302
- ${oauthEnvDefaults}
2303
- }
2304
- ${oauthVaultResolution}
2305
-
2306
- sync_supabase_secrets() {
2307
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2308
- return 0
2309
- fi
2310
-
2311
- local tmp_runtime tmp_public
2312
- tmp_runtime="$(mktemp)"
2313
- tmp_public="$(mktemp)"
2314
- trap 'rm -f "\${tmp_runtime}" "\${tmp_public}"' EXIT
2315
-
2316
- cat > "\${tmp_runtime}" <<EOF
2317
- POSTGRES_PASSWORD=\${POSTGRES_PASSWORD}
2318
- JWT_SECRET=\${JWT_SECRET}
2319
- SUPABASE_ANON_KEY=\${SUPABASE_ANON_KEY}
2320
- SUPABASE_SERVICE_ROLE_KEY=\${SUPABASE_SERVICE_ROLE_KEY}
2321
- SUPABASE_PUBLISHABLE_KEY=\${SUPABASE_PUBLISHABLE_KEY:-}
2322
- SUPABASE_SECRET_KEY=\${SUPABASE_SECRET_KEY:-}
2323
- DASHBOARD_USERNAME=\${DASHBOARD_USERNAME:-supabase}
2324
- DASHBOARD_PASSWORD=\${DASHBOARD_PASSWORD:-}
2325
- SMTP_USER=\${SMTP_USER:-}
2326
- SMTP_PASS=\${SMTP_PASS:-}
2327
- SECRET_KEY_BASE=\${SECRET_KEY_BASE}
2328
- REALTIME_DB_ENC_KEY=\${REALTIME_DB_ENC_KEY}
2329
- PG_META_CRYPTO_KEY=\${PG_META_CRYPTO_KEY}
2330
- S3_PROTOCOL_ACCESS_KEY_ID=\${S3_PROTOCOL_ACCESS_KEY_ID}
2331
- S3_PROTOCOL_ACCESS_KEY_SECRET=\${S3_PROTOCOL_ACCESS_KEY_SECRET}
2332
- ${oauthRuntimeSecretLines}
2333
- EOF
2334
-
2335
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" create secret generic supabase-runtime-secrets --from-env-file="\${tmp_runtime}" --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" apply -f -
2336
-
2337
- cat > "\${tmp_public}" <<EOF
2338
- EXPO_PUBLIC_SUPABASE_URL=\${EXPO_PUBLIC_SUPABASE_URL}
2339
- EXPO_PUBLIC_SUPABASE_ANON_KEY=\${EXPO_PUBLIC_SUPABASE_ANON_KEY}
2340
- SUPABASE_URL=http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000
2341
- SUPABASE_ANON_KEY=\${SUPABASE_ANON_KEY}
2342
- EOF
2343
-
2344
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" create secret generic supabase-public-runtime --from-env-file="\${tmp_public}" --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" apply -f -
2345
-
2346
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" create configmap supabase-runtime-config \
2347
- --from-literal=SUPABASE_PUBLIC_URL="\${SUPABASE_PUBLIC_URL}" \
2348
- --from-literal=API_EXTERNAL_URL="\${API_EXTERNAL_URL}" \
2349
- --from-literal=SITE_URL="\${SITE_URL}" \
2350
- --from-literal=ADDITIONAL_REDIRECT_URLS="\${ADDITIONAL_REDIRECT_URLS}" \
2351
- --from-literal=JWT_EXPIRY="\${JWT_EXPIRY}" \
2352
- --from-literal=ENABLE_EMAIL_SIGNUP="\${ENABLE_EMAIL_SIGNUP}" \
2353
- --from-literal=ENABLE_EMAIL_AUTOCONFIRM="\${ENABLE_EMAIL_AUTOCONFIRM}" \
2354
- --from-literal=SMTP_ADMIN_EMAIL="\${SMTP_ADMIN_EMAIL}" \
2355
- --from-literal=SMTP_HOST="\${SMTP_HOST}" \
2356
- --from-literal=SMTP_PORT="\${SMTP_PORT}" \
2357
- --from-literal=SMTP_SENDER_NAME="\${SMTP_SENDER_NAME}" \
2358
- --from-literal=PGRST_DB_SCHEMAS="\${PGRST_DB_SCHEMAS}" \
2359
- --from-literal=PGRST_DB_MAX_ROWS="\${PGRST_DB_MAX_ROWS}" \
2360
- --from-literal=PGRST_DB_EXTRA_SEARCH_PATH="\${PGRST_DB_EXTRA_SEARCH_PATH}" \
2361
- --from-literal=GLOBAL_S3_BUCKET="\${GLOBAL_S3_BUCKET}" \
2362
- --from-literal=STORAGE_TENANT_ID="\${STORAGE_TENANT_ID}" \
2363
- --from-literal=REGION="\${REGION}" \
2364
- --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" apply -f -
2365
-
2366
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" create configmap supabase-gateway-config \
2367
- --from-file=temp.yml="\${K8S_DIR}/supabase/gateway.template.yml" \
2368
- --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" apply -f -
2369
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" create configmap supabase-kong-entrypoint \
2370
- --from-file=kong-entrypoint.sh="\${K8S_DIR}/supabase/kong-entrypoint.sh" \
2371
- --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" apply -f -
2372
-
2373
- rm -f "\${tmp_runtime}" "\${tmp_public}"
2374
- trap - EXIT
2375
- }
2376
-
2377
- docker_load_image_to_minikube() {
2378
- if command -v docker >/dev/null 2>&1 && docker image inspect "\${APP_IMAGE}" >/dev/null 2>&1; then
2379
- minikube -p "\${PROFILE}" image load --daemon=true --overwrite=true "\${APP_IMAGE}" >/dev/null
2380
- return 0
2381
- fi
2382
-
2383
- return 1
2384
- }
2385
-
2386
- run_supabase_migrations() {
2387
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2388
- return 0
2389
- fi
2390
-
2391
- export SUPABASE_DB_URL PGSSLMODE=disable
2392
-
2393
- if [[ -d "\${ROOT_DIR}/supabase/migrations" ]]; then
2394
- require_command supabase
2395
- (
2396
- cd "\${ROOT_DIR}"
2397
- ${indentShellBlock(supabaseMigrationCommand, 6)}
2398
- )
2399
- fi
2400
- }
2401
-
2402
- reconcile_supabase_profile() {
2403
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2404
- return 0
2405
- fi
2406
- if [[ "\${SUPABASE_PROFILE_ENABLED}" == "true" && -f "\${SUPABASE_PROFILE_RECONCILE_FILE}" ]]; then
2407
- psql "\${SUPABASE_DB_URL}" -v ON_ERROR_STOP=1 -q -f "\${SUPABASE_PROFILE_RECONCILE_FILE}"
2408
- fi
2409
- }
2410
-
2411
- reload_postgrest_schema() {
2412
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2413
- return 0
2414
- fi
2415
-
2416
- psql "\${SUPABASE_DB_URL}" -v ON_ERROR_STOP=1 -q -c "notify pgrst, 'reload schema';"
2417
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout restart deployment/rest >/dev/null
2418
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/rest --timeout=600s
2419
- }
2420
-
2421
- bootstrap_supabase_vault_migration() {
2422
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2423
- return 0
2424
- fi
2425
- if [[ -f "\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql" ]]; then
2426
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c "alter role postgres with superuser;"
2427
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c "create schema if not exists vault; grant pg_read_server_files to postgres; grant pg_read_server_files to supabase_admin; grant execute on function pg_read_file(text) to public; grant execute on function pg_read_file(text, bigint, bigint) to public;"
2428
- psql "\${SUPABASE_DB_URL}" -v ON_ERROR_STOP=1 -q -f "\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql"
2429
- fi
2430
- }
2431
-
2432
- bootstrap_supabase_database() {
2433
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2434
- return 0
2435
- fi
2436
-
2437
- require_command psql
2438
- export POSTGRES_PASSWORD JWT_SECRET JWT_EXP="\${JWT_EXPIRY}" POSTGRES_USER=postgres
2439
- psql "\${SUPABASE_DB_URL}" -v ON_ERROR_STOP=1 -q -f "\${K8S_DIR}/supabase/bootstrap.sql"
2440
- }
2441
-
2442
- wait_for_supabase_database() {
2443
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2444
- return 0
2445
- fi
2446
-
2447
- require_command psql
2448
- if ! "\${PORT_FORWARD_SCRIPT}" start db-migration; then
2449
- echo "Failed to start db-migration port-forward for Supabase bootstrap."
2450
- "\${PORT_FORWARD_SCRIPT}" status db-migration || true
2451
- exit 1
2452
- fi
2453
- for attempt in {1..60}; do
2454
- if PGPASSWORD="\${POSTGRES_PASSWORD}" psql -h 127.0.0.1 -p "\${SUPABASE_DB_FORWARD_LOCAL_PORT}" -U postgres -d postgres -v ON_ERROR_STOP=1 -Atq -c 'select 1' >/dev/null 2>&1; then
2455
- return 0
2456
- fi
2457
- sleep 2
2458
- done
2459
-
2460
- echo "Postgres did not accept SQL connections as postgres before bootstrap."
2461
- "\${PORT_FORWARD_SCRIPT}" status db-migration || true
2462
- exit 1
2463
- }
2464
-
2465
- apply_supabase_runtime_workloads() {
2466
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2467
- return 0
2468
- fi
2469
-
2470
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/auth.yaml"
2471
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/rest.yaml"
2472
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/realtime.yaml"
2473
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/imgproxy.yaml"
2474
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/storage.yaml"
2475
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/meta.yaml"
2476
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/gateway.yaml"
2477
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/studio.yaml"
2478
- }
2479
-
2480
- apply_namespace_manifests() {
2481
- local namespace_manifest
2482
- for namespace_manifest in "\${K8S_DIR}"/namespaces/*.yaml; do
2483
- kubectl --context "\${PROFILE}" apply -f "\${namespace_manifest}"
2484
- done
2485
- }
2486
-
2487
- ${disabledAppRuntimeReconciliation}
2488
- ${providerLifecycleStageScripts}
2489
-
2490
- load_env_file_preserving_process_env
2491
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
2492
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
2493
- DRIVER="\${MINIKUBE_DRIVER:-docker}"
2494
- APP_BUILD_ENABLED="\${APP_BUILD_ENABLED:-true}"
2495
- APP_SOURCE_DIR="\${APP_SOURCE_DIR:-$(cd "\${ROOT_DIR}/../.." && pwd)}"
2496
- APP_WEB_EXPORT_DIR="\${APP_WEB_EXPORT_DIR:-.ankh/web-export}"
2497
- APP_IMAGE="\${APP_IMAGE:-${defaultAppImage}}"
2498
- APP_IMAGE_SYNC_STRATEGY="\${APP_IMAGE_SYNC_STRATEGY:-docker-load}"
2499
- APP_REPLICAS="\${APP_REPLICAS:-1}"
2500
- APP_FORCE_ROLLOUT_RESTART="\${APP_FORCE_ROLLOUT_RESTART:-true}"
2501
- APP_IMAGE_PULL_SECRET_NAME="\${APP_IMAGE_PULL_SECRET_NAME:-}"
2502
- APP_IMAGE_PULL_SECRET_SERVER="\${APP_IMAGE_PULL_SECRET_SERVER:-ghcr.io}"
2503
- APP_IMAGE_PULL_SECRET_USERNAME="\${APP_IMAGE_PULL_SECRET_USERNAME:-}"
2504
- APP_IMAGE_PULL_SECRET_PASSWORD="\${APP_IMAGE_PULL_SECRET_PASSWORD:-}"
2505
- APP_IMAGE_PULL_SECRET_EMAIL="\${APP_IMAGE_PULL_SECRET_EMAIL:-}"
2506
- APP_PORT_FORWARD_LOCAL_PORT="\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}"
2507
- SUPABASE_GATEWAY_FORWARD_LOCAL_PORT="\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}"
2508
- SUPABASE_DB_FORWARD_LOCAL_PORT="\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}"
2509
- SUPABASE_DB_URL="\${SUPABASE_DB_URL:-}"
2510
-
2511
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
2512
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
2513
- exit 1
2514
- fi
2515
-
2516
- cleanup_failed_up() {
2517
- "\${PORT_FORWARD_SCRIPT}" stop all >/dev/null 2>&1 || true
2518
- }
2519
-
2520
- trap cleanup_failed_up ERR
2521
-
2522
- require_command minikube
2523
- require_command kubectl
2524
- ensure_supabase_runtime_env
2525
- sync_app_public_supabase_env
2526
-
2527
- HOST_STATUS="$(minikube -p "\${PROFILE}" status --format='{{.Host}}' 2>/dev/null || true)"
2528
- if [[ "\${HOST_STATUS}" != "Running" ]]; then
2529
- minikube start -p "\${PROFILE}" --driver="\${DRIVER}"
2530
- fi
2531
-
2532
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" == "true" ]]; then
2533
- apply_namespace_manifests
2534
- sync_supabase_secrets
2535
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/postgres.init.configmap.yaml"
2536
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/postgres.pvc.yaml"
2537
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/supabase/postgres.yaml"
2538
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/postgres --timeout=900s
2539
- wait_for_supabase_database
2540
- bootstrap_supabase_database
2541
- bootstrap_supabase_vault_migration
2542
- resolve_oauth_credentials_from_vault
2543
- ${oauthValidation}
2544
- sync_supabase_secrets
2545
- apply_supabase_runtime_workloads
2546
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/auth --timeout=600s
2547
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/rest --timeout=600s
2548
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/realtime --timeout=600s
2549
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/storage --timeout=600s
2550
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/gateway --timeout=600s
2551
- kubectl --context "\${PROFILE}" -n "\${SUPABASE_NAMESPACE}" rollout status deployment/studio --timeout=600s
2552
- run_supabase_migrations
2553
- reconcile_supabase_profile
2554
- reload_postgrest_schema
2555
- "\${PORT_FORWARD_SCRIPT}" start supabase-gateway >/dev/null
2556
- "\${PORT_FORWARD_SCRIPT}" start studio >/dev/null
2557
- else
2558
- kubectl --context "\${PROFILE}" apply -k "\${K8S_DIR}"
2559
- fi
2560
-
2561
- if [[ "\${APP_RUNTIME_ENABLED}" == "true" && "\${APP_BUILD_ENABLED}" == "true" ]]; then
2562
- if [[ ! -x "\${BUILD_SCRIPT}" ]]; then
2563
- echo "Missing build helper script: \${BUILD_SCRIPT}"
2564
- exit 1
2565
- fi
2566
-
2567
- "\${BUILD_SCRIPT}"
2568
- fi
2569
-
2570
- if [[ "\${APP_WEB_EXPORT_DIR}" = /* ]]; then
2571
- EXPORT_DIR="\${APP_WEB_EXPORT_DIR}"
2572
- else
2573
- EXPORT_DIR="\${APP_SOURCE_DIR}/\${APP_WEB_EXPORT_DIR}"
2574
- fi
2575
-
2576
- if [[ "\${APP_RUNTIME_ENABLED}" == "true" ]]; then
2577
- case "\${APP_IMAGE_SYNC_STRATEGY}" in
2578
- minikube-build)
2579
- if [[ ! -f "\${EXPORT_DIR}/index.html" ]]; then
2580
- echo "Expected web export output not found at \${EXPORT_DIR}/index.html"
2581
- exit 1
2582
- fi
2583
- minikube -p "\${PROFILE}" image build -t "\${APP_IMAGE}" -f "\${ROOT_DIR}/app-image/Dockerfile" "\${EXPORT_DIR}" >/dev/null
2584
- ;;
2585
- docker-load)
2586
- if ! docker_load_image_to_minikube; then
2587
- echo "Skipping docker-load image sync; local Docker image \${APP_IMAGE} not found."
2588
- fi
2589
- ;;
2590
- none)
2591
- echo "Skipping local image sync (APP_IMAGE_SYNC_STRATEGY=none)."
2592
- ;;
2593
- *)
2594
- echo "Unsupported APP_IMAGE_SYNC_STRATEGY=\${APP_IMAGE_SYNC_STRATEGY}. Use minikube-build, docker-load, or none."
2595
- exit 1
2596
- ;;
2597
- esac
2598
- fi
2599
-
2600
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" == "true" ]]; then
2601
- kubectl --context "\${PROFILE}" apply -k "\${K8S_DIR}"
2602
- fi
2603
-
2604
- ${reconcileDisabledAppRuntime}
2605
- wait_for_provider_readiness
2606
- run_provider_migrations
2607
- run_provider_reconciliation
2608
-
2609
- if [[ "\${APP_RUNTIME_ENABLED}" == "true" ]]; then
2610
- if [[ -n "\${APP_IMAGE_PULL_SECRET_NAME}" ]]; then
2611
- if [[ -z "\${APP_IMAGE_PULL_SECRET_USERNAME}" || -z "\${APP_IMAGE_PULL_SECRET_PASSWORD}" ]]; then
2612
- echo "APP_IMAGE_PULL_SECRET_NAME is set, but username/password are missing."
2613
- exit 1
2614
- fi
2615
-
2616
- SECRET_EMAIL_ARG=()
2617
- if [[ -n "\${APP_IMAGE_PULL_SECRET_EMAIL}" ]]; then
2618
- SECRET_EMAIL_ARG=(--docker-email="\${APP_IMAGE_PULL_SECRET_EMAIL}")
2619
- fi
2620
-
2621
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" create secret docker-registry "\${APP_IMAGE_PULL_SECRET_NAME}" --docker-server="\${APP_IMAGE_PULL_SECRET_SERVER}" --docker-username="\${APP_IMAGE_PULL_SECRET_USERNAME}" --docker-password="\${APP_IMAGE_PULL_SECRET_PASSWORD}" "\${SECRET_EMAIL_ARG[@]}" --dry-run=client -o yaml | kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" apply -f -
2622
-
2623
- PULL_SECRET_PATCH="$(cat <<EOF
2624
- {"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"\${APP_IMAGE_PULL_SECRET_NAME}"}]}}}}
2625
- EOF
2626
- )"
2627
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" patch deployment app-runtime --type=merge --patch "\${PULL_SECRET_PATCH}" >/dev/null
2628
- else
2629
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" patch deployment app-runtime --type=json --patch='[{"op":"remove","path":"/spec/template/spec/imagePullSecrets"}]' >/dev/null 2>&1 || true
2630
- fi
2631
-
2632
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" set image deployment/app-runtime app="\${APP_IMAGE}" >/dev/null
2633
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" scale deployment/app-runtime --replicas="\${APP_REPLICAS}" >/dev/null
2634
-
2635
- if [[ "\${APP_FORCE_ROLLOUT_RESTART}" == "true" ]]; then
2636
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" rollout restart deployment/app-runtime >/dev/null
2637
- fi
2638
-
2639
- kubectl --context "\${PROFILE}" -n "\${APP_NAMESPACE}" rollout status deployment/app-runtime --timeout=180s >/dev/null
2640
- "\${PORT_FORWARD_SCRIPT}" start app >/dev/null
2641
- fi
2642
-
2643
- trap - ERR
2644
- echo "Minikube infrastructure for '\${PROFILE}' is running."
2645
- `;
2646
- }
2647
- function getBuildAppImageScript(args) {
2648
- const { appSlug, defaultAppImage } = args;
2649
- return `#!/usr/bin/env bash
2650
- set -euo pipefail
2651
-
2652
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
2653
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
2654
- DOCKERFILE_PATH="\${ROOT_DIR}/app-image/Dockerfile"
2655
- APP_SLUG="${appSlug}"
2656
-
2657
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
2658
- set -a
2659
- # shellcheck disable=SC1090
2660
- source "\${ROOT_DIR}/.env"
2661
- set +a
2662
- fi
2663
-
2664
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
2665
- APP_BUILD_ENABLED="\${APP_BUILD_ENABLED:-true}"
2666
- APP_SOURCE_DIR="\${APP_SOURCE_DIR:-$(cd "\${ROOT_DIR}/../.." && pwd)}"
2667
- APP_WEB_EXPORT_DIR="\${APP_WEB_EXPORT_DIR:-.ankh/web-export}"
2668
- APP_IMAGE="\${APP_IMAGE:-${defaultAppImage}}"
2669
-
2670
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
2671
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
2672
- exit 1
2673
- fi
2674
-
2675
- if [[ "\${APP_BUILD_ENABLED}" != "true" ]]; then
2676
- echo "Skipping app image build (APP_BUILD_ENABLED=\${APP_BUILD_ENABLED})."
2677
- exit 0
2678
- fi
2679
-
2680
- if [[ ! -f "\${APP_SOURCE_DIR}/package.json" ]]; then
2681
- echo "APP_SOURCE_DIR does not look like an app root: \${APP_SOURCE_DIR}"
2682
- exit 1
2683
- fi
2684
-
2685
- if [[ ! -f "\${DOCKERFILE_PATH}" ]]; then
2686
- echo "Dockerfile for app image build is missing: \${DOCKERFILE_PATH}"
2687
- exit 1
2688
- fi
2689
-
2690
- EXPO_CLI="\${APP_SOURCE_DIR}/node_modules/.bin/expo"
2691
- if [[ ! -x "\${EXPO_CLI}" ]]; then
2692
- echo "App-owned Expo CLI is missing: \${EXPO_CLI}" >&2
2693
- echo "Run 'bun install --frozen-lockfile' in \${APP_SOURCE_DIR} before building the app image." >&2
2694
- exit 1
2695
- fi
2696
-
2697
- if ! command -v docker >/dev/null 2>&1; then
2698
- echo "docker is required to build app image."
2699
- exit 1
2700
- fi
2701
-
2702
- (
2703
- cd "\${APP_SOURCE_DIR}"
2704
- "\${EXPO_CLI}" export --platform web --clear --output-dir "\${APP_WEB_EXPORT_DIR}"
2705
- )
2706
-
2707
- if [[ "\${APP_WEB_EXPORT_DIR}" = /* ]]; then
2708
- EXPORT_DIR="\${APP_WEB_EXPORT_DIR}"
2709
- else
2710
- EXPORT_DIR="\${APP_SOURCE_DIR}/\${APP_WEB_EXPORT_DIR}"
2711
- fi
2712
-
2713
- if [[ ! -f "\${EXPORT_DIR}/index.html" ]]; then
2714
- echo "Expected web export output not found at \${EXPORT_DIR}/index.html"
2715
- exit 1
2716
- fi
2717
-
2718
- docker build -t "\${APP_IMAGE}" \
2719
- --label "ankhorage.kind=generated-app" \
2720
- --label "ankhorage.app_slug=\${PROFILE}" \
2721
- --label "ankhorage.image=\${APP_IMAGE}" \
2722
- -f "\${DOCKERFILE_PATH}" \
2723
- "\${EXPORT_DIR}"
2724
- echo "Built app image: \${APP_IMAGE} (profile: \${PROFILE})"
2725
- `;
2726
- }
2727
- function getAppImageDockerfile() {
2728
- return `FROM nginx:1.27-alpine
2729
-
2730
- RUN cat <<'EOF' > /etc/nginx/conf.d/default.conf
2731
- server {
2732
- listen 8080;
2733
- absolute_redirect off;
2734
- server_name _;
2735
- root /usr/share/nginx/html;
2736
- index index.html;
2737
-
2738
- location / {
2739
- try_files $uri $uri/ /index.html;
2740
- }
2741
- }
2742
- EOF
2743
-
2744
- COPY . /usr/share/nginx/html
2745
-
2746
- EXPOSE 8080
2747
-
2748
- CMD ["nginx", "-g", "daemon off;"]
2749
- `;
2750
- }
2751
- function getPortForwardScript(args) {
2752
- const { appSlug, appRuntimeEnabled, supabaseKubernetesEnabled, supabaseHostPorts } = args;
2753
- const runtimeForwardNames = [
2754
- ...(appRuntimeEnabled ? ['app'] : []),
2755
- ...(supabaseKubernetesEnabled ? ['supabase-gateway'] : []),
2756
- ];
2757
- const allForwardNames = [
2758
- ...runtimeForwardNames,
2759
- ...(supabaseKubernetesEnabled ? ['studio', 'db-migration'] : []),
2760
- ];
2761
- const managedForwardNames = ['app', 'supabase-gateway', 'studio', 'db-migration'];
2762
- const obsoleteForwardNames = managedForwardNames.filter((name) => !allForwardNames.includes(name));
2763
- const appTargetCase = ` app)
2764
- echo "${APP_NAMESPACE} service/app-runtime \${APP_PORT_FORWARD_LOCAL_PORT} \${APP_PORT_FORWARD_REMOTE_PORT}"
2765
- ;;`;
2766
- const supabaseTargetCases = ` supabase-gateway)
2767
- echo "${SUPABASE_NAMESPACE} service/gateway \${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT} \${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT}"
2768
- ;;
2769
- studio)
2770
- echo "${SUPABASE_NAMESPACE} service/studio \${SUPABASE_STUDIO_FORWARD_LOCAL_PORT} \${SUPABASE_STUDIO_FORWARD_REMOTE_PORT}"
2771
- ;;
2772
- db-migration)
2773
- echo "${SUPABASE_NAMESPACE} service/postgres \${SUPABASE_DB_FORWARD_LOCAL_PORT} \${SUPABASE_DB_FORWARD_REMOTE_PORT}"
2774
- ;;`;
2775
- const concreteForwardNames = [
2776
- ...(appRuntimeEnabled ? ['app'] : []),
2777
- ...(supabaseKubernetesEnabled ? ['supabase-gateway', 'studio', 'db-migration'] : []),
2778
- ];
2779
- const forwardUsage = [...concreteForwardNames, 'runtime', 'all'].join('|');
2780
- const forwardNamesDescription = concreteForwardNames.length > 0
2781
- ? `${concreteForwardNames.join(', ')}, runtime, or all`
2782
- : 'runtime or all';
2783
- return `#!/usr/bin/env bash
2784
- set -euo pipefail
2785
-
2786
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
2787
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
2788
- STATE_DIR="\${ROOT_DIR}/.state/forwards"
2789
- APP_SLUG="${appSlug}"
2790
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
2791
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
2792
- APP_RUNTIME_ENABLED="${appRuntimeEnabled ? 'true' : 'false'}"
2793
- APP_PORT_FORWARD_LOCAL_PORT="\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}"
2794
- APP_PORT_FORWARD_REMOTE_PORT="\${APP_PORT_FORWARD_REMOTE_PORT:-80}"
2795
- SUPABASE_GATEWAY_FORWARD_LOCAL_PORT="\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}"
2796
- SUPABASE_GATEWAY_FORWARD_REMOTE_PORT="\${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT:-8000}"
2797
- SUPABASE_STUDIO_FORWARD_LOCAL_PORT="\${SUPABASE_STUDIO_FORWARD_LOCAL_PORT:-${supabaseHostPorts.studio}}"
2798
- SUPABASE_STUDIO_FORWARD_REMOTE_PORT="\${SUPABASE_STUDIO_FORWARD_REMOTE_PORT:-3000}"
2799
- SUPABASE_DB_FORWARD_LOCAL_PORT="\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}"
2800
- SUPABASE_DB_FORWARD_REMOTE_PORT="\${SUPABASE_DB_FORWARD_REMOTE_PORT:-5432}"
2801
- RUNTIME_FORWARD_NAMES=(${runtimeForwardNames.join(' ')})
2802
- ALL_FORWARD_NAMES=(${allForwardNames.join(' ')})
2803
- MANAGED_FORWARD_NAMES=(${managedForwardNames.join(' ')})
2804
- OBSOLETE_FORWARD_NAMES=(${obsoleteForwardNames.join(' ')})
2805
-
2806
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
2807
- set -a
2808
- # shellcheck disable=SC1090
2809
- source "\${ROOT_DIR}/.env"
2810
- set +a
2811
- fi
2812
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
2813
- APP_RUNTIME_ENABLED="${appRuntimeEnabled ? 'true' : 'false'}"
2814
-
2815
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
2816
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
2817
- exit 1
2818
- fi
2819
-
2820
- if ! command -v kubectl >/dev/null 2>&1; then
2821
- echo "kubectl is required but not installed."
2822
- exit 1
2823
- fi
2824
-
2825
- mkdir -p "\${STATE_DIR}"
2826
-
2827
- pid_file_for() {
2828
- echo "\${STATE_DIR}/\${PROFILE}-\${1}.pid"
2829
- }
2830
-
2831
- target_for() {
2832
- case "\${1}" in
2833
- ${appTargetCase}
2834
- ${supabaseTargetCases}
2835
- *)
2836
- echo "Unknown forward '\${1}'. Use ${forwardNamesDescription}." >&2
2837
- return 1
2838
- ;;
2839
- esac
2840
- }
2841
-
2842
- is_pid_running() {
2843
- local pid="\${1}"
2844
- [[ -n "\${pid}" ]] && kill -0 "\${pid}" >/dev/null 2>&1
2845
- }
2846
-
2847
- is_port_accepting() {
2848
- local port="\${1}"
2849
- (echo >/dev/tcp/127.0.0.1/"\${port}") >/dev/null 2>&1
2850
- }
2851
-
2852
- print_forward_log_tail() {
2853
- local name="\${1}"
2854
- local log_file="\${STATE_DIR}/\${PROFILE}-\${name}.log"
2855
- if [[ -s "\${log_file}" ]]; then
2856
- echo "\${name}: recent kubectl port-forward log:"
2857
- tail -n 20 "\${log_file}"
2858
- fi
2859
- }
2860
-
2861
- process_command_for_pid() {
2862
- local pid="\${1}"
2863
- ps -p "\${pid}" -o command= 2>/dev/null || true
2864
- }
2865
-
2866
- process_name_for_pid() {
2867
- local pid="\${1}"
2868
- ps -p "\${pid}" -o comm= 2>/dev/null || true
2869
- }
2870
-
2871
- is_owned_forward_process() {
2872
- local pid="\${1}"
2873
- local namespace="\${2}"
2874
- local resource="\${3}"
2875
- local local_port="\${4}"
2876
- local remote_port="\${5}"
2877
- local command
2878
- local process_name
2879
- command="$(process_command_for_pid "\${pid}")"
2880
- process_name="$(process_name_for_pid "\${pid}")"
2881
-
2882
- case "\${process_name}" in
2883
- *kubectl) ;;
2884
- *) return 1 ;;
2885
- esac
2886
-
2887
- case "\${command}" in
2888
- *"kubectl --context \${PROFILE} -n \${namespace} port-forward \${resource} \${local_port}:\${remote_port}"*)
2889
- return 0
2890
- ;;
2891
- *)
2892
- return 1
2893
- ;;
2894
- esac
2895
- }
2896
-
2897
- handle_non_owned_forward_pid() {
2898
- local name="\${1}"
2899
- local pid="\${2}"
2900
- local pid_file="\${3}"
2901
- local local_port="\${4}"
2902
- echo "\${name}: stale pid file pointed at non-owned live pid \${pid}; removing ownership record \${pid_file}"
2903
- rm -f "\${pid_file}"
2904
-
2905
- if is_port_accepting "\${local_port}"; then
2906
- echo "\${name}: port occupied by non-owned process on local port \${local_port}"
2907
- return 1
2908
- fi
2909
-
2910
- return 0
2911
- }
2912
-
2913
- terminate_forward_process() {
2914
- local name="\${1}"
2915
- local pid="\${2}"
2916
- local namespace="\${3}"
2917
- local resource="\${4}"
2918
- local local_port="\${5}"
2919
- local remote_port="\${6}"
2920
-
2921
- if [[ -z "\${pid}" ]]; then
2922
- return 0
2923
- fi
2924
-
2925
- if is_pid_running "\${pid}" && ! is_owned_forward_process "\${pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}"; then
2926
- echo "\${name}: refusing to terminate non-owned live pid \${pid}"
2927
- return 1
2928
- fi
2929
-
2930
- if is_pid_running "\${pid}"; then
2931
- kill "\${pid}" >/dev/null 2>&1 || true
2932
- for attempt in {1..20}; do
2933
- if ! is_pid_running "\${pid}"; then
2934
- break
2935
- fi
2936
- sleep 0.25
2937
- done
2938
- fi
2939
-
2940
- if is_pid_running "\${pid}"; then
2941
- kill -KILL "\${pid}" >/dev/null 2>&1 || true
2942
- for attempt in {1..20}; do
2943
- if ! is_pid_running "\${pid}"; then
2944
- break
2945
- fi
2946
- sleep 0.25
2947
- done
2948
- fi
2949
-
2950
- if is_pid_running "\${pid}"; then
2951
- echo "\${name}: failed to stop owned port-forward pid \${pid}"
2952
- return 1
2953
- fi
2954
-
2955
- for attempt in {1..20}; do
2956
- if ! is_port_accepting "\${local_port}"; then
2957
- return 0
2958
- fi
2959
- sleep 0.25
2960
- done
2961
-
2962
- echo "\${name}: owned port-forward pid \${pid} stopped, but local port \${local_port} is still accepting connections"
2963
- return 1
2964
- }
2965
-
2966
- start_forward() {
2967
- local name="\${1}"
2968
- local pid_file
2969
- pid_file="$(pid_file_for "\${name}")"
2970
- read -r namespace resource local_port remote_port <<<"$(target_for "\${name}")"
2971
-
2972
- if [[ "\${name}" == "app" && "\${APP_RUNTIME_ENABLED}" != "true" ]]; then
2973
- echo "\${name}: skipped (Web app runtime disabled)"
2974
- return 0
2975
- fi
2976
-
2977
- if [[ -f "\${pid_file}" ]]; then
2978
- local existing_pid
2979
- existing_pid="$(cat "\${pid_file}")"
2980
- if is_pid_running "\${existing_pid}"; then
2981
- if ! is_owned_forward_process "\${existing_pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}"; then
2982
- handle_non_owned_forward_pid "\${name}" "\${existing_pid}" "\${pid_file}" "\${local_port}" || return 1
2983
- elif is_port_accepting "\${local_port}"; then
2984
- echo "\${name}: running (pid \${existing_pid})"
2985
- return 0
2986
- else
2987
- echo "\${name}: stale running pid \${existing_pid} was not accepting local port \${local_port}; restarting"
2988
- terminate_forward_process "\${name}" "\${existing_pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}" || return 1
2989
- rm -f "\${pid_file}"
2990
- fi
2991
- else
2992
- rm -f "\${pid_file}"
2993
- fi
2994
- fi
2995
-
2996
- if [[ "\${namespace}" == "${SUPABASE_NAMESPACE}" && "\${SUPABASE_RUNTIME_ENABLED}" != "true" ]]; then
2997
- echo "\${name}: skipped (Supabase Kubernetes disabled)"
2998
- return 0
2999
- fi
3000
-
3001
- if ! kubectl --context "\${PROFILE}" -n "\${namespace}" get "\${resource}" >/dev/null 2>&1; then
3002
- echo "\${name}: target \${namespace}/\${resource} not found"
3003
- return 1
3004
- fi
3005
-
3006
- for start_attempt in {1..5}; do
3007
- nohup kubectl --context "\${PROFILE}" -n "\${namespace}" port-forward "\${resource}" "\${local_port}:\${remote_port}" >"\${STATE_DIR}/\${PROFILE}-\${name}.log" 2>&1 &
3008
- local pid="$!"
3009
- echo "\${pid}" > "\${pid_file}"
3010
-
3011
- for readiness_attempt in {1..20}; do
3012
- if ! is_pid_running "\${pid}"; then
3013
- rm -f "\${pid_file}"
3014
- if [[ "\${start_attempt}" -lt 5 ]]; then
3015
- echo "\${name}: port-forward attempt \${start_attempt} exited before readiness; retrying"
3016
- sleep 2
3017
- break
3018
- fi
3019
-
3020
- echo "\${name}: failed to start local port \${local_port} for \${namespace}/\${resource}:\${remote_port} after \${start_attempt} attempts"
3021
- print_forward_log_tail "\${name}"
3022
- return 1
3023
- fi
3024
- if is_port_accepting "\${local_port}"; then
3025
- sleep 1
3026
- if is_pid_running "\${pid}" && is_port_accepting "\${local_port}"; then
3027
- sleep 0.5
3028
- if is_pid_running "\${pid}"; then
3029
- echo "\${name}: started (pid \${pid}, local port \${local_port})"
3030
- return 0
3031
- fi
3032
- fi
3033
- fi
3034
- sleep 0.5
3035
- done
3036
-
3037
- if [[ -f "\${pid_file}" ]]; then
3038
- terminate_forward_process "\${name}" "\${pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}" || return 1
3039
- rm -f "\${pid_file}"
3040
-
3041
- if [[ "\${start_attempt}" -lt 5 ]]; then
3042
- echo "\${name}: port-forward attempt \${start_attempt} did not become ready; retrying"
3043
- sleep 2
3044
- else
3045
- echo "\${name}: did not become ready on local port \${local_port} for \${namespace}/\${resource}:\${remote_port} after \${start_attempt} attempts"
3046
- print_forward_log_tail "\${name}"
3047
- return 1
3048
- fi
3049
- fi
3050
- done
3051
-
3052
- return 1
3053
- }
3054
-
3055
- stop_forward() {
3056
- local name="\${1}"
3057
- local pid_file
3058
- pid_file="$(pid_file_for "\${name}")"
3059
- read -r namespace resource local_port remote_port <<<"$(target_for "\${name}")"
3060
- if [[ ! -f "\${pid_file}" ]]; then
3061
- echo "\${name}: stopped"
3062
- return 0
3063
- fi
3064
-
3065
- local pid
3066
- pid="$(cat "\${pid_file}")"
3067
- if is_pid_running "\${pid}" && ! is_owned_forward_process "\${pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}"; then
3068
- handle_non_owned_forward_pid "\${name}" "\${pid}" "\${pid_file}" "\${local_port}" || return 1
3069
- echo "\${name}: stopped"
3070
- return 0
3071
- fi
3072
-
3073
- terminate_forward_process "\${name}" "\${pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}" || return 1
3074
- rm -f "\${pid_file}"
3075
- echo "\${name}: stopped"
3076
- }
3077
-
3078
- status_forward() {
3079
- local name="\${1}"
3080
- local pid_file
3081
- pid_file="$(pid_file_for "\${name}")"
3082
- if [[ ! -f "\${pid_file}" ]]; then
3083
- echo "\${name}: stopped"
3084
- return 0
3085
- fi
3086
-
3087
- local pid
3088
- pid="$(cat "\${pid_file}")"
3089
- if is_pid_running "\${pid}"; then
3090
- read -r namespace resource local_port remote_port <<<"$(target_for "\${name}")"
3091
- if ! is_owned_forward_process "\${pid}" "\${namespace}" "\${resource}" "\${local_port}" "\${remote_port}"; then
3092
- echo "\${name}: stale_pid_non_owned=\${pid}"
3093
- rm -f "\${pid_file}"
3094
- return 0
3095
- fi
3096
- if is_port_accepting "\${local_port}"; then
3097
- echo "\${name}: running pid=\${pid} url=127.0.0.1:\${local_port} target=\${namespace}/\${resource}:\${remote_port}"
3098
- return 0
3099
- fi
3100
- echo "\${name}: not ready pid=\${pid} url=127.0.0.1:\${local_port} target=\${namespace}/\${resource}:\${remote_port}"
3101
- return 0
3102
- fi
3103
-
3104
- echo "\${name}: crashed stale_pid=\${pid}"
3105
- rm -f "\${pid_file}"
3106
- }
3107
-
3108
- for_each_forward() {
3109
- local action="\${1}"
3110
- shift
3111
- local name
3112
- while [[ "\${#}" -gt 0 ]]; do
3113
- name="\${1}"
3114
- shift
3115
- "\${action}_forward" "\${name}"
3116
- done
3117
- }
3118
-
3119
- ACTION="\${1:-start}"
3120
- NAME="\${2:-all}"
3121
-
3122
- case "\${ACTION}:\${NAME}" in
3123
- start:runtime) for_each_forward start ${runtimeForwardNames.join(' ')} ;;
3124
- stop:runtime)
3125
- for_each_forward stop ${runtimeForwardNames.join(' ')}
3126
- for_each_forward stop ${obsoleteForwardNames.join(' ')}
3127
- ;;
3128
- status:runtime) for_each_forward status ${runtimeForwardNames.join(' ')} ;;
3129
- start:all) for_each_forward start ${allForwardNames.join(' ')} ;;
3130
- stop:all) for_each_forward stop ${managedForwardNames.join(' ')} ;;
3131
- status:all) for_each_forward status ${allForwardNames.join(' ')} ;;
3132
- stop:obsolete) for_each_forward stop ${obsoleteForwardNames.join(' ')} ;;
3133
- start:*) start_forward "\${NAME}" ;;
3134
- stop:*) stop_forward "\${NAME}" ;;
3135
- status:*) status_forward "\${NAME}" ;;
3136
- *)
3137
- echo "Usage: ./scripts/port-forward.sh {start|stop|status} {${forwardUsage}}"
3138
- exit 1
3139
- ;;
3140
- esac
3141
- `;
3142
- }
3143
- function getDownScript(appSlug) {
3144
- return `#!/usr/bin/env bash
3145
- set -euo pipefail
3146
-
3147
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
3148
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
3149
- APP_SLUG="${appSlug}"
3150
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
3151
-
3152
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
3153
- set -a
3154
- # shellcheck disable=SC1090
3155
- source "\${ROOT_DIR}/.env"
3156
- set +a
3157
- fi
3158
-
3159
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
3160
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
3161
- exit 1
3162
- fi
3163
-
3164
- "\${SCRIPT_DIR}/port-forward.sh" stop all >/dev/null || true
3165
-
3166
- if command -v minikube >/dev/null 2>&1; then
3167
- minikube stop -p "\${PROFILE}"
3168
- else
3169
- echo "minikube is required but not installed."
3170
- exit 1
3171
- fi
3172
-
3173
- echo "Stopped Minikube profile '\${PROFILE}'. Persistent data remains in the profile."
3174
- `;
3175
- }
3176
- function getResetScript(args) {
3177
- const { appSlug, supabaseKubernetesEnabled, providerNamespaces } = args;
3178
- const resetNamespaces = [
3179
- APP_NAMESPACE,
3180
- ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),
3181
- ...providerNamespaces,
3182
- ];
3183
- const resetNamespaceCommands = resetNamespaces
3184
- .map((namespace) => `kubectl --context "\${PROFILE}" delete namespace ${namespace} --ignore-not-found
3185
- kubectl --context "\${PROFILE}" apply -f "\${K8S_DIR}/namespaces/${namespace}.yaml"`)
3186
- .join('\n');
3187
- const resetScope = `Kubernetes namespaces ${resetNamespaces.join(', ')}`;
3188
- const resetDataDescription = `reset.sh deletes and recreates namespaces ${resetNamespaces.join(', ')}. This resets app workloads and provider-owned data in those namespaces. It does not delete the Minikube profile.`;
3189
- const completionDescription = `Reset namespaces ${resetNamespaces.join(', ')}`;
3190
- return `#!/usr/bin/env bash
3191
- set -euo pipefail
3192
-
3193
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
3194
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
3195
- K8S_DIR="\${ROOT_DIR}/k8s"
3196
- APP_SLUG="${appSlug}"
3197
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
3198
- CONFIRM="\${ANKH_RESET_CONFIRM:-}"
3199
-
3200
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
3201
- set -a
3202
- # shellcheck disable=SC1090
3203
- source "\${ROOT_DIR}/.env"
3204
- set +a
3205
- fi
3206
-
3207
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
3208
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
3209
- exit 1
3210
- fi
3211
-
3212
- if [[ "\${CONFIRM}" != "\${APP_SLUG}" ]]; then
3213
- echo "Refusing reset. Set ANKH_RESET_CONFIRM=\${APP_SLUG} to reset ${resetScope} inside profile '\${PROFILE}'."
3214
- echo "${resetDataDescription}"
3215
- exit 1
3216
- fi
3217
-
3218
- if ! command -v kubectl >/dev/null 2>&1; then
3219
- echo "kubectl is required but not installed."
3220
- exit 1
3221
- fi
3222
-
3223
- "\${SCRIPT_DIR}/port-forward.sh" stop all >/dev/null || true
3224
- ${resetNamespaceCommands}
3225
- echo "${completionDescription} for profile '\${PROFILE}'. Run ./scripts/up.sh to recreate runtime secrets, migrations, forwards, and app rollout."
3226
- `;
3227
- }
3228
- function getDestroyScript(appSlug) {
3229
- return `#!/usr/bin/env bash
3230
- set -euo pipefail
3231
-
3232
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
3233
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
3234
- APP_SLUG="${appSlug}"
3235
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
3236
-
3237
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
3238
- set -a
3239
- # shellcheck disable=SC1090
3240
- source "\${ROOT_DIR}/.env"
3241
- set +a
3242
- fi
3243
-
3244
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
3245
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
3246
- exit 1
3247
- fi
3248
-
3249
- "\${SCRIPT_DIR}/port-forward.sh" stop all >/dev/null || true
3250
- minikube delete -p "\${PROFILE}"
3251
- echo "Deleted Minikube profile '\${PROFILE}'."
3252
- `;
3253
- }
3254
- function getStatusScript(args) {
3255
- const { appSlug, appRuntimeEnabled, supabaseKubernetesEnabled, profileModel, supabaseHostPorts, providerNamespaces, providerLifecycle, } = args;
3256
- const namespaces = [
3257
- APP_NAMESPACE,
3258
- ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),
3259
- ...providerNamespaces,
3260
- ].join(' ');
3261
- const providerStatusScript = getProviderStatusScript(providerLifecycle);
3262
- return `#!/usr/bin/env bash
3263
- set -euo pipefail
3264
-
3265
- SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
3266
- ROOT_DIR="$(cd "\${SCRIPT_DIR}/.." && pwd)"
3267
- APP_SLUG="${appSlug}"
3268
- PROFILE="\${ANKH_APP_SLUG:-${appSlug}}"
3269
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
3270
- SUPABASE_PROFILE_ENABLED="${profileModel.enabled ? 'true' : 'false'}"
3271
- SUPABASE_GATEWAY_FORWARD_LOCAL_PORT="\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}"
3272
-
3273
- if [[ -f "\${ROOT_DIR}/.env" ]]; then
3274
- set -a
3275
- # shellcheck disable=SC1090
3276
- source "\${ROOT_DIR}/.env"
3277
- set +a
3278
- fi
3279
- SUPABASE_RUNTIME_ENABLED="${supabaseKubernetesEnabled ? 'true' : 'false'}"
3280
-
3281
- if [[ "\${PROFILE}" != "\${APP_SLUG}" ]]; then
3282
- echo "ANKH_APP_SLUG must remain the generated canonical slug '\${APP_SLUG}' for this infra directory."
3283
- exit 1
3284
- fi
3285
-
3286
- echo "Infra status for profile: \${PROFILE}"
3287
-
3288
- if ! command -v minikube >/dev/null 2>&1; then
3289
- echo "- minikube: missing"
3290
- exit 1
3291
- fi
3292
-
3293
- HOST_STATUS="$(minikube -p "\${PROFILE}" status --format='{{.Host}}' 2>/dev/null || true)"
3294
- echo "- minikube host: \${HOST_STATUS:-missing}"
3295
-
3296
- if [[ "\${HOST_STATUS}" != "Running" ]]; then
3297
- echo "- cluster: stopped"
3298
- "\${SCRIPT_DIR}/port-forward.sh" status all || true
3299
- exit 0
3300
- fi
3301
-
3302
- if ! command -v kubectl >/dev/null 2>&1; then
3303
- echo "- kubectl: missing"
3304
- exit 1
3305
- fi
3306
-
3307
- check_secret_key() {
3308
- local secret="\${1}"
3309
- local key="\${2}"
3310
- local encoded
3311
- encoded="$(kubectl --context "\${PROFILE}" -n ${SUPABASE_NAMESPACE} get secret "\${secret}" -o "jsonpath={.data.\${key}}" 2>/dev/null || true)"
3312
- if [[ -n "\${encoded}" ]]; then
3313
- echo "- secret/\${secret}:\${key}: present"
3314
- else
3315
- echo "- secret/\${secret}:\${key}: missing"
3316
- fi
3317
- }
3318
-
3319
- postgres_query() {
3320
- local sql="\${1}"
3321
- kubectl --context "\${PROFILE}" -n ${SUPABASE_NAMESPACE} exec deployment/postgres -- psql -U postgres -d postgres -Atq -c "\${sql}" 2>/dev/null || true
3322
- }
3323
-
3324
- for namespace in ${namespaces}; do
3325
- if kubectl --context "\${PROFILE}" get namespace "\${namespace}" >/dev/null 2>&1; then
3326
- echo "- namespace/\${namespace}: present"
3327
- kubectl --context "\${PROFILE}" -n "\${namespace}" get pods
3328
- else
3329
- echo "- namespace/\${namespace}: missing"
3330
- fi
3331
- done
3332
-
3333
- if [[ "${appRuntimeEnabled ? 'true' : 'false'}" == "true" ]] && kubectl --context "\${PROFILE}" -n ${APP_NAMESPACE} get deployment app-runtime >/dev/null 2>&1; then
3334
- kubectl --context "\${PROFILE}" -n ${APP_NAMESPACE} rollout status deployment/app-runtime --timeout=5s >/dev/null 2>&1 && echo "- app-runtime: ready" || echo "- app-runtime: not ready"
3335
- fi
3336
-
3337
- ${providerStatusScript}
3338
-
3339
- if [[ "\${SUPABASE_RUNTIME_ENABLED}" == "true" ]]; then
3340
- for deployment in postgres auth rest realtime storage gateway studio; do
3341
- if kubectl --context "\${PROFILE}" -n ${SUPABASE_NAMESPACE} get deployment "\${deployment}" >/dev/null 2>&1; then
3342
- kubectl --context "\${PROFILE}" -n ${SUPABASE_NAMESPACE} rollout status "deployment/\${deployment}" --timeout=5s >/dev/null 2>&1 && echo "- supabase/\${deployment}: ready" || echo "- supabase/\${deployment}: not ready"
3343
- else
3344
- echo "- supabase/\${deployment}: missing"
3345
- fi
3346
- done
3347
-
3348
- for key in POSTGRES_PASSWORD JWT_SECRET SUPABASE_ANON_KEY SUPABASE_SERVICE_ROLE_KEY SECRET_KEY_BASE REALTIME_DB_ENC_KEY PG_META_CRYPTO_KEY; do
3349
- check_secret_key supabase-runtime-secrets "\${key}"
3350
- done
3351
-
3352
- db_check="$(postgres_query 'select 1')"
3353
- if [[ "\${db_check}" == "1" ]]; then
3354
- echo "- postgres connectivity: ok"
3355
- else
3356
- echo "- postgres connectivity: failed"
3357
- fi
3358
-
3359
- migration_count="$(postgres_query "select count(*) from supabase_migrations.schema_migrations" || true)"
3360
- if [[ "\${migration_count}" =~ ^[0-9]+$ ]]; then
3361
- echo "- migration history: \${migration_count} applied"
3362
- else
3363
- echo "- migration history: unavailable"
3364
- fi
3365
-
3366
- if [[ "\${SUPABASE_PROFILE_ENABLED}" == "true" ]]; then
3367
- profile_state="$(postgres_query "select count(*) from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'" || true)"
3368
- if [[ "\${profile_state}" =~ ^[1-9][0-9]*$ ]]; then
3369
- echo "- profile reconciliation: applied"
3370
- else
3371
- echo "- profile reconciliation: missing"
3372
- fi
3373
- else
3374
- state_table="$(postgres_query "select to_regclass('ankhorage_internal.generated_schema_state') is not null" || true)"
3375
- if [[ "\${state_table}" != "t" ]]; then
3376
- echo "- profile reconciliation: disabled"
3377
- else
3378
- profile_state="$(postgres_query "select coalesce((select case when table_name is null then 'stale-state-missing-table-name' when to_regclass(format('public.%I', table_name)) is null then 'stale-state-missing-table:' || table_name else 'stale-state-table-present:' || table_name end from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'), 'disabled')" || true)"
3379
- if [[ "\${profile_state}" == "disabled" ]]; then
3380
- echo "- profile reconciliation: disabled"
3381
- else
3382
- echo "- profile reconciliation: unexpected \${profile_state}"
3383
- fi
3384
- fi
3385
- fi
3386
-
3387
- vault_state="$(postgres_query "select exists(select 1 from pg_namespace where nspname = 'vault')" || true)"
3388
- if [[ "\${vault_state}" == "t" ]]; then
3389
- echo "- vault schema: present"
3390
- else
3391
- echo "- vault schema: absent"
3392
- fi
3393
-
3394
- if command -v curl >/dev/null 2>&1; then
3395
- public_url="\${SUPABASE_PUBLIC_URL:-http://127.0.0.1:\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}}"
3396
- if curl -fsS "\${public_url}/auth/v1/health" >/dev/null 2>&1; then
3397
- echo "- supabase public endpoint: ok (\${public_url})"
3398
- else
3399
- echo "- supabase public endpoint: unavailable (\${public_url})"
3400
- fi
3401
- fi
3402
- fi
3403
-
3404
- "\${SCRIPT_DIR}/port-forward.sh" status all || true
3405
- `;
3406
- }
3407
- function getDefaultAppImage(appSlug) {
3408
- return `ankh/${appSlug}:dev`;
3409
- }
3410
- function resolveSupabaseHostPorts(appSlug) {
3411
- const base = PORT_BASE + resolvePortBucket(appSlug) * PORT_BUCKET_SIZE;
3412
- return {
3413
- app: base,
3414
- gateway: base + 1,
3415
- studio: base + 2,
3416
- db: base + 3,
3417
- };
3418
- }
3419
- function resolvePortBucket(appSlug) {
3420
- const rawBucket = hashSlug(appSlug) - hashSlug(PORT_REFERENCE_SLUG);
3421
- return (rawBucket + PORT_BUCKET_COUNT) % PORT_BUCKET_COUNT;
3422
- }
3423
- function hashSlug(value) {
3424
- let hash = 0;
3425
- for (const char of value) {
3426
- hash = (hash * 31 + char.charCodeAt(0)) % PORT_BUCKET_COUNT;
3427
- }
3428
- return hash;
3429
- }
3430
- function escapeYamlDoubleQuoted(value) {
3431
- return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
3432
- }
3433
- //# sourceMappingURL=index.js.map