@ankhorage/infra 0.4.0 → 0.4.2
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.
- package/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/dist/adapters/minikube/base/index.d.ts +1 -0
- package/dist/adapters/minikube/base/index.d.ts.map +1 -1
- package/dist/adapters/minikube/base/index.js +245 -26
- package/dist/adapters/minikube/base/index.js.map +1 -1
- package/dist/adapters/minikube/index.d.ts.map +1 -1
- package/dist/adapters/minikube/index.js +26 -0
- package/dist/adapters/minikube/index.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/minikube/auth/supabase/profile.integration.test.ts +170 -2
- package/src/adapters/minikube/base/index.test.ts +552 -0
- package/src/adapters/minikube/base/index.ts +249 -25
- package/src/adapters/minikube/index.ts +37 -0
- package/src/adapters/minikube/secrets/index.test.ts +37 -1
- package/src/index.test.ts +151 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst DEFAULT_NAMESPACE = 'ankh-app';\n\nexport function generateMinikubeInfra(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions = {},\n): InfrastructureGenerationResult {\n if (manifest.deployment?.target !== 'minikube') {\n throw new Error(\n `Minikube adapter only supports deployment target \"minikube\" (received \"${manifest.deployment?.target ?? 'undefined'}\").`,\n );\n }\n\n if (manifest.database?.provider && manifest.database.provider !== 'supabase') {\n throw new Error(\n `Unsupported database provider for minikube adapter: \"${manifest.database.provider}\". Only \"supabase\" is implemented.`,\n );\n }\n\n const namespace = resolveNamespace(manifest, options);\n\n const authArtifacts = generateAuthProviderArtifacts({ manifest, namespace });\n const authzArtifacts = generateAuthorizationArtifacts({\n manifest,\n namespace,\n appManifest: options.appManifest,\n });\n const storageArtifacts = generateStorageArtifacts({ manifest, namespace });\n const secretStoreArtifacts = generateSecretStoreArtifacts({ manifest, namespace });\n const apiArtifacts = generateApiInfrastructureArtifacts({\n data: options.appManifest?.data,\n databaseProvider: manifest.database?.provider,\n });\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const extraEnvEntries = unique([\n ...authArtifacts.envEntries,\n ...authzArtifacts.envEntries,\n ...storageArtifacts.envEntries,\n ...secretStoreArtifacts.envEntries,\n ]);\n\n const baseFiles = generateMinikubeBaseArtifacts({\n manifest,\n namespace,\n extraResources,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...apiArtifacts.warnings,\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...apiArtifacts.files,\n ],\n warnings,\n meta: {\n target: 'minikube',\n providers: collectProviders(manifest),\n },\n dependencies: collectDependencies(manifest),\n };\n}\n\nfunction collectProviders(manifest: InfraManifestInput): string[] {\n const providers = new Set<string>();\n\n if (manifest.auth?.provider) providers.add(manifest.auth.provider);\n if (manifest.auth?.authorization?.engine) {\n providers.add(manifest.auth.authorization.engine);\n }\n if (manifest.database?.provider) providers.add(manifest.database.provider);\n if (manifest.storage?.provider) providers.add(manifest.storage.provider);\n if (manifest.secretStore?.provider) providers.add(manifest.secretStore.provider);\n if (manifest.state?.provider) providers.add(manifest.state.provider);\n\n return [...providers].sort();\n}\n\nfunction collectDependencies(manifest: InfraManifestInput): readonly GeneratedPackageDependency[] {\n if (manifest.state?.provider !== 'legend') {\n return [];\n }\n\n return [\n {\n name: '@ankhorage/state-legend',\n version: '^0.1.0',\n reason: 'Selected by infra.state.provider=legend.',\n },\n ];\n}\n\nfunction collectWarnings(manifest: InfraManifestInput): string[] {\n const warnings: string[] = [];\n\n if (manifest.deployment?.monitoring) {\n warnings.push(\n 'Monitoring is enabled in manifest, but monitoring stack resources are not generated yet.',\n );\n }\n\n if (manifest.networking?.cdn) {\n warnings.push('CDN is enabled in manifest, but CDN resources are not generated for minikube.');\n }\n\n return warnings;\n}\n\nfunction resolveNamespace(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions,\n): string {\n const source =\n manifest.networking?.domain?.trim() ?? options.namespaceHint?.trim() ?? DEFAULT_NAMESPACE;\n\n const normalized = source\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n\n const safe = normalized.slice(0, 63).replace(/-+$/g, '');\n return safe || DEFAULT_NAMESPACE;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,oBAAoB,CAAC;AAOxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,6BAA6B,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,iBAAiB,GAAG,UAAU,CAAC;AACrC,MAAM,yBAAyB,GAAG,wCAAwC,CAAC;AAE3E,MAAM,UAAU,qBAAqB,CACnC,QAA4B,EAC5B,UAA2C,EAAE;IAE7C,IAAI,QAAQ,CAAC,UAAU,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,0EAA0E,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,WAAW,KAAK,CAC1H,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,EAAE,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC7E,MAAM,IAAI,KAAK,CACb,wDAAwD,QAAQ,CAAC,QAAQ,CAAC,QAAQ,oCAAoC,CACvH,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,QAAQ,CAAC;QACxD,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC;QAClE,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,aAAa,GAAG,6BAA6B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7E,MAAM,cAAc,GAAG,8BAA8B,CAAC;QACpD,QAAQ;QACR,SAAS;QACT,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC,CAAC;IACH,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,MAAM,oBAAoB,GAAG,4BAA4B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IACnF,MAAM,YAAY,GAAG,kCAAkC,CAAC;QACtD,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI;QAC/B,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ;KAC9C,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,MAAM,CAAC;QAC5B,GAAG,aAAa,CAAC,SAAS;QAC1B,GAAG,cAAc,CAAC,SAAS;QAC3B,GAAG,gBAAgB,CAAC,SAAS;QAC7B,GAAG,oBAAoB,CAAC,SAAS;KAClC,CAAC,CAAC;IACH,MAAM,eAAe,GAAG,MAAM,CAAC;QAC7B,GAAG,aAAa,CAAC,UAAU;QAC3B,GAAG,cAAc,CAAC,UAAU;QAC5B,GAAG,gBAAgB,CAAC,UAAU;QAC9B,GAAG,oBAAoB,CAAC,UAAU;KACnC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,6BAA6B,CAAC;QAC9C,QAAQ;QACR,SAAS;QACT,iBAAiB;QACjB,cAAc;QACd,eAAe;KAChB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,CAAC;QACtB,GAAG,eAAe,CAAC,QAAQ,CAAC;QAC5B,GAAG,aAAa,CAAC,QAAQ;QACzB,GAAG,cAAc,CAAC,QAAQ;QAC1B,GAAG,gBAAgB,CAAC,QAAQ;QAC5B,GAAG,oBAAoB,CAAC,QAAQ;QAChC,GAAG,YAAY,CAAC,QAAQ;KACzB,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE;YACL,GAAG,SAAS;YACZ,GAAG,aAAa,CAAC,KAAK;YACtB,GAAG,cAAc,CAAC,KAAK;YACvB,GAAG,gBAAgB,CAAC,KAAK;YACzB,GAAG,oBAAoB,CAAC,KAAK;YAC7B,GAAG,YAAY,CAAC,KAAK;SACtB;QACD,QAAQ;QACR,IAAI,EAAE;YACJ,MAAM,EAAE,UAAU;YAClB,SAAS,EAAE,gBAAgB,CAAC,QAAQ,CAAC;SACtC;QACD,YAAY,EAAE,mBAAmB,CAAC,QAAQ,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,QAA4B;IACpD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,IAAI,QAAQ,CAAC,IAAI,EAAE,QAAQ;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;QACzC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,EAAE,QAAQ;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,OAAO,EAAE,QAAQ;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzE,IAAI,QAAQ,CAAC,WAAW,EAAE,QAAQ;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACjF,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAErE,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,mBAAmB,CAAC,QAA4B;IACvD,IAAI,QAAQ,CAAC,KAAK,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO;QACL;YACE,IAAI,EAAE,yBAAyB;YAC/B,OAAO,EAAE,QAAQ;YACjB,MAAM,EAAE,0CAA0C;SACnD;KACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,QAA4B;IACnD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,CACX,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IACjG,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,sBAAsB,CAAC,QAA4B;IAC1D,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAC7C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IACrD,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IACnD,MAAM,mBAAmB,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAE3D,OAAO,CACL,YAAY,KAAK,UAAU;QAC3B,gBAAgB,KAAK,UAAU;QAC/B,eAAe,KAAK,UAAU;QAC9B,CAAC,eAAe,KAAK,MAAM;YACzB,CAAC,YAAY,KAAK,UAAU,IAAI,gBAAgB,KAAK,UAAU,CAAC,CAAC;QACnE,mBAAmB,KAAK,gBAAgB,CACzC,CAAC;AACJ,CAAC;AAED,SAAS,4BAA4B,CAAC,IAAwB;IAC5D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CACb,wMAAwM,CACzM,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CACvB,QAA4B,EAC5B,OAAwC;IAExC,MAAM,MAAM,GACV,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,iBAAiB,CAAC;IAE5F,MAAM,UAAU,GAAG,MAAM;SACtB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,IAAI,IAAI,iBAAiB,CAAC;AACnC,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst DEFAULT_NAMESPACE = 'ankh-app';\nconst CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;\n\nexport function generateMinikubeInfra(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions = {},\n): InfrastructureGenerationResult {\n if (manifest.deployment?.target !== 'minikube') {\n throw new Error(\n `Minikube adapter only supports deployment target \"minikube\" (received \"${manifest.deployment?.target ?? 'undefined'}\").`,\n );\n }\n\n if (manifest.database?.provider && manifest.database.provider !== 'supabase') {\n throw new Error(\n `Unsupported database provider for minikube adapter: \"${manifest.database.provider}\". Only \"supabase\" is implemented.`,\n );\n }\n\n const namespace = resolveNamespace(manifest, options);\n const supabaseProjectId = isSupabaseLocalEnabled(manifest)\n ? validateCanonicalProjectSlug(options.appManifest?.metadata.slug)\n : null;\n\n const authArtifacts = generateAuthProviderArtifacts({ manifest, namespace });\n const authzArtifacts = generateAuthorizationArtifacts({\n manifest,\n namespace,\n appManifest: options.appManifest,\n });\n const storageArtifacts = generateStorageArtifacts({ manifest, namespace });\n const secretStoreArtifacts = generateSecretStoreArtifacts({ manifest, namespace });\n const apiArtifacts = generateApiInfrastructureArtifacts({\n data: options.appManifest?.data,\n databaseProvider: manifest.database?.provider,\n });\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const extraEnvEntries = unique([\n ...authArtifacts.envEntries,\n ...authzArtifacts.envEntries,\n ...storageArtifacts.envEntries,\n ...secretStoreArtifacts.envEntries,\n ]);\n\n const baseFiles = generateMinikubeBaseArtifacts({\n manifest,\n namespace,\n supabaseProjectId,\n extraResources,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...apiArtifacts.warnings,\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...apiArtifacts.files,\n ],\n warnings,\n meta: {\n target: 'minikube',\n providers: collectProviders(manifest),\n },\n dependencies: collectDependencies(manifest),\n };\n}\n\nfunction collectProviders(manifest: InfraManifestInput): string[] {\n const providers = new Set<string>();\n\n if (manifest.auth?.provider) providers.add(manifest.auth.provider);\n if (manifest.auth?.authorization?.engine) {\n providers.add(manifest.auth.authorization.engine);\n }\n if (manifest.database?.provider) providers.add(manifest.database.provider);\n if (manifest.storage?.provider) providers.add(manifest.storage.provider);\n if (manifest.secretStore?.provider) providers.add(manifest.secretStore.provider);\n if (manifest.state?.provider) providers.add(manifest.state.provider);\n\n return [...providers].sort();\n}\n\nfunction collectDependencies(manifest: InfraManifestInput): readonly GeneratedPackageDependency[] {\n if (manifest.state?.provider !== 'legend') {\n return [];\n }\n\n return [\n {\n name: '@ankhorage/state-legend',\n version: '^0.1.0',\n reason: 'Selected by infra.state.provider=legend.',\n },\n ];\n}\n\nfunction collectWarnings(manifest: InfraManifestInput): string[] {\n const warnings: string[] = [];\n\n if (manifest.deployment?.monitoring) {\n warnings.push(\n 'Monitoring is enabled in manifest, but monitoring stack resources are not generated yet.',\n );\n }\n\n if (manifest.networking?.cdn) {\n warnings.push('CDN is enabled in manifest, but CDN resources are not generated for minikube.');\n }\n\n return warnings;\n}\n\nfunction isSupabaseLocalEnabled(manifest: InfraManifestInput): boolean {\n const authProvider = manifest.auth?.provider;\n const databaseProvider = manifest.database?.provider;\n const storageProvider = manifest.storage?.provider;\n const secretStoreProvider = manifest.secretStore?.provider;\n\n return (\n authProvider === 'supabase' ||\n databaseProvider === 'supabase' ||\n storageProvider === 'supabase' ||\n (storageProvider === 'auto' &&\n (authProvider === 'supabase' || databaseProvider === 'supabase')) ||\n secretStoreProvider === 'supabase-vault'\n );\n}\n\nfunction validateCanonicalProjectSlug(slug: string | undefined): string {\n if (!slug) {\n throw new Error(\n 'Cannot generate local Supabase infrastructure: appManifest.metadata.slug is required.',\n );\n }\n\n if (slug.trim() !== slug || !CANONICAL_PROJECT_SLUG_RE.test(slug)) {\n throw new Error(\n 'Cannot generate local Supabase infrastructure: appManifest.metadata.slug must be a canonical lowercase slug up to 40 characters using only a-z, 0-9, and hyphens, without leading or trailing hyphens.',\n );\n }\n\n return slug;\n}\n\nfunction resolveNamespace(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions,\n): string {\n const source =\n manifest.networking?.domain?.trim() ?? options.namespaceHint?.trim() ?? DEFAULT_NAMESPACE;\n\n const normalized = source\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n\n const safe = normalized.slice(0, 63).replace(/-+$/g, '');\n return safe || DEFAULT_NAMESPACE;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/infra",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.2",
|
|
5
5
|
"description": "Project-aware infrastructure generation library and executable Ankh provider for Ankhorage.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/infra#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import { execFile as execFileCallback } from 'node:child_process';
|
|
2
|
-
import { chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
6
|
|
|
7
7
|
import { describe, expect, test } from 'bun:test';
|
|
8
8
|
|
|
9
|
-
import { generateInfrastructure } from '../../../../index';
|
|
9
|
+
import { generateInfrastructure as generateRawInfrastructure } from '../../../../index';
|
|
10
|
+
import { createAppManifest } from '../../../../testSupport';
|
|
10
11
|
import type { GeneratedInfrastructureFile, InfraManifestInput } from '../../../../types';
|
|
11
12
|
|
|
12
13
|
const execFile = promisify(execFileCallback);
|
|
13
14
|
const INTEGRATION_TIMEOUT_MS = 300_000;
|
|
14
15
|
const integrationTest = process.env.ANKH_SUPABASE_INTEGRATION === '1' ? test : test.skip;
|
|
15
16
|
|
|
17
|
+
function generateInfrastructure(
|
|
18
|
+
manifest: InfraManifestInput,
|
|
19
|
+
options: { namespaceHint?: string } = {},
|
|
20
|
+
): ReturnType<typeof generateRawInfrastructure> {
|
|
21
|
+
const slug = options.namespaceHint ?? 'profile-integration';
|
|
22
|
+
return generateRawInfrastructure(manifest, {
|
|
23
|
+
...options,
|
|
24
|
+
appManifest: createAppManifest(slug),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
describe('generated Supabase profile reconciliation integration', () => {
|
|
17
29
|
integrationTest(
|
|
18
30
|
'drops stale managed columns while preserving custom columns',
|
|
@@ -132,6 +144,109 @@ $$;`,
|
|
|
132
144
|
INTEGRATION_TIMEOUT_MS,
|
|
133
145
|
);
|
|
134
146
|
|
|
147
|
+
integrationTest(
|
|
148
|
+
'boots clean disabled profile and writes client env idempotently',
|
|
149
|
+
async () => {
|
|
150
|
+
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
await writeGeneratedFiles(
|
|
154
|
+
appRoot,
|
|
155
|
+
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
156
|
+
namespaceHint,
|
|
157
|
+
}).files,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
await runLocalSupabaseEnv(minikubeRoot);
|
|
161
|
+
await runLocalSupabaseEnv(minikubeRoot);
|
|
162
|
+
|
|
163
|
+
const { stdout: statusEnv } = await execFile('supabase', [
|
|
164
|
+
'--workdir',
|
|
165
|
+
minikubeRoot,
|
|
166
|
+
'status',
|
|
167
|
+
'-o',
|
|
168
|
+
'env',
|
|
169
|
+
]);
|
|
170
|
+
const expectedUrl = readStatusEnv(statusEnv, 'API_URL');
|
|
171
|
+
const expectedAnonKey = readStatusEnv(statusEnv, 'ANON_KEY');
|
|
172
|
+
const appEnv = await readFile(path.join(appRoot, '.env.local'), 'utf8');
|
|
173
|
+
|
|
174
|
+
expect(readStatusEnv(appEnv, 'EXPO_PUBLIC_SUPABASE_URL')).toBe(expectedUrl);
|
|
175
|
+
expect(readStatusEnv(appEnv, 'EXPO_PUBLIC_SUPABASE_ANON_KEY')).toBe(expectedAnonKey);
|
|
176
|
+
} finally {
|
|
177
|
+
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
INTEGRATION_TIMEOUT_MS,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
integrationTest(
|
|
184
|
+
'accepts disabled profile when state table exists without auth profile state',
|
|
185
|
+
async () => {
|
|
186
|
+
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
await writeGeneratedFiles(
|
|
190
|
+
appRoot,
|
|
191
|
+
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
192
|
+
namespaceHint,
|
|
193
|
+
}).files,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
await runLocalSupabaseEnv(minikubeRoot);
|
|
197
|
+
await runSupabaseSql(
|
|
198
|
+
minikubeRoot,
|
|
199
|
+
`create schema if not exists ankhorage_internal;
|
|
200
|
+
create table if not exists ankhorage_internal.generated_schema_state (
|
|
201
|
+
artifact_key text primary key,
|
|
202
|
+
table_name text,
|
|
203
|
+
content_hash text,
|
|
204
|
+
updated_at timestamptz not null default now()
|
|
205
|
+
);
|
|
206
|
+
insert into ankhorage_internal.generated_schema_state (
|
|
207
|
+
artifact_key,
|
|
208
|
+
table_name,
|
|
209
|
+
content_hash
|
|
210
|
+
)
|
|
211
|
+
values ('storage.bucket', 'objects', repeat('1', 64))
|
|
212
|
+
on conflict (artifact_key) do update
|
|
213
|
+
set table_name = excluded.table_name,
|
|
214
|
+
content_hash = excluded.content_hash,
|
|
215
|
+
updated_at = now();`,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
await runLocalSupabaseEnv(minikubeRoot);
|
|
219
|
+
} finally {
|
|
220
|
+
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
INTEGRATION_TIMEOUT_MS,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
integrationTest(
|
|
227
|
+
'status reports clean disabled profile as skipped',
|
|
228
|
+
async () => {
|
|
229
|
+
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
await writeGeneratedFiles(
|
|
233
|
+
appRoot,
|
|
234
|
+
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
235
|
+
namespaceHint,
|
|
236
|
+
}).files,
|
|
237
|
+
);
|
|
238
|
+
await runLocalSupabaseEnv(minikubeRoot);
|
|
239
|
+
|
|
240
|
+
const output = await runGeneratedStatus(minikubeRoot);
|
|
241
|
+
expect(output).toContain('- profile reconciliation: skipped (no profile table configured)');
|
|
242
|
+
expect(output).toContain('- profile schema: skipped (no profile table configured)');
|
|
243
|
+
} finally {
|
|
244
|
+
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
INTEGRATION_TIMEOUT_MS,
|
|
248
|
+
);
|
|
249
|
+
|
|
135
250
|
integrationTest(
|
|
136
251
|
'rejects profile table rename once generated state exists',
|
|
137
252
|
async () => {
|
|
@@ -789,6 +904,59 @@ exit 0
|
|
|
789
904
|
throw new Error('Expected generated status script to fail');
|
|
790
905
|
}
|
|
791
906
|
|
|
907
|
+
async function runGeneratedStatus(minikubeRoot: string): Promise<string> {
|
|
908
|
+
const fakeBin = path.join(minikubeRoot, 'fake-status-bin');
|
|
909
|
+
const fakeKubectl = path.join(fakeBin, 'kubectl');
|
|
910
|
+
await mkdir(fakeBin, { recursive: true });
|
|
911
|
+
await writeFile(
|
|
912
|
+
fakeKubectl,
|
|
913
|
+
`#!/usr/bin/env bash
|
|
914
|
+
set -euo pipefail
|
|
915
|
+
|
|
916
|
+
if [[ "\${1:-}" == "config" && "\${2:-}" == "current-context" ]]; then
|
|
917
|
+
echo fake-context
|
|
918
|
+
exit 0
|
|
919
|
+
fi
|
|
920
|
+
|
|
921
|
+
if [[ "\${1:-}" == "cluster-info" ]]; then
|
|
922
|
+
echo "Kubernetes control plane is running"
|
|
923
|
+
exit 0
|
|
924
|
+
fi
|
|
925
|
+
|
|
926
|
+
if [[ "\${1:-}" == "get" && "\${2:-}" == "namespace" ]]; then
|
|
927
|
+
exit 0
|
|
928
|
+
fi
|
|
929
|
+
|
|
930
|
+
if [[ "\${1:-}" == "get" && "\${2:-}" == "all" ]]; then
|
|
931
|
+
exit 0
|
|
932
|
+
fi
|
|
933
|
+
|
|
934
|
+
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "configmap" ]]; then
|
|
935
|
+
exit 0
|
|
936
|
+
fi
|
|
937
|
+
|
|
938
|
+
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "secret" ]]; then
|
|
939
|
+
exit 1
|
|
940
|
+
fi
|
|
941
|
+
|
|
942
|
+
exit 0
|
|
943
|
+
`,
|
|
944
|
+
'utf8',
|
|
945
|
+
);
|
|
946
|
+
await chmod(fakeKubectl, 0o755);
|
|
947
|
+
|
|
948
|
+
const result = await execFile(path.join(minikubeRoot, 'scripts/status.sh'), {
|
|
949
|
+
cwd: minikubeRoot,
|
|
950
|
+
env: {
|
|
951
|
+
...process.env,
|
|
952
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
953
|
+
SUPABASE_PROJECT_DIR: minikubeRoot,
|
|
954
|
+
},
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
return `${result.stdout}\n${result.stderr}`;
|
|
958
|
+
}
|
|
959
|
+
|
|
792
960
|
async function runSupabaseSql(minikubeRoot: string, sql: string): Promise<void> {
|
|
793
961
|
const { stdout } = await execFile('supabase', ['--workdir', minikubeRoot, 'status', '-o', 'env']);
|
|
794
962
|
const dbUrl = readStatusEnv(stdout, 'DB_URL');
|