@ankhorage/infra 3.2.0 → 3.3.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.
- package/CHANGELOG.md +6 -0
- package/README.md +14 -10
- package/dist/adapters/minikube/auth/index.d.ts +2 -1
- package/dist/adapters/minikube/auth/index.d.ts.map +1 -1
- package/dist/adapters/minikube/auth/index.js +6 -3
- package/dist/adapters/minikube/auth/index.js.map +1 -1
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts +7 -0
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts.map +1 -0
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js +104 -0
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js.map +1 -0
- package/dist/adapters/minikube/index.d.ts.map +1 -1
- package/dist/adapters/minikube/index.js +5 -1
- package/dist/adapters/minikube/index.js.map +1 -1
- package/dist/authTargetRedirects.d.ts +12 -0
- package/dist/authTargetRedirects.d.ts.map +1 -0
- package/dist/authTargetRedirects.js +32 -0
- package/dist/authTargetRedirects.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/minikube/auth/index.ts +8 -4
- package/src/adapters/minikube/auth/targetAwareOAuthRuntime.test.ts +83 -0
- package/src/adapters/minikube/auth/targetAwareOAuthRuntime.ts +136 -0
- package/src/adapters/minikube/index.ts +5 -1
- package/src/authTargetRedirects.test.ts +62 -0
- package/src/authTargetRedirects.ts +46 -0
- package/src/types.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @ankhorage/infra
|
|
2
2
|
|
|
3
|
+
## 3.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 716f678: Derive Supabase OAuth redirect allowlists from canonical app deployment targets, using enabled Web state and stable Android/iOS schemes instead of a separate native redirect environment variable.
|
|
8
|
+
|
|
3
9
|
## 3.2.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -3,17 +3,23 @@
|
|
|
3
3
|
|
|
4
4
|
# INFRA
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Executable infra provider and standalone CLI for Ankhorage project workflows.
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
### Provider and
|
|
12
|
+
### Provider, CLI, and project API surface
|
|
13
13
|
|
|
14
|
-
`@ankhorage/infra` owns
|
|
14
|
+
`@ankhorage/infra` owns infrastructure generation, project reconciliation,
|
|
15
|
+
and generated lifecycle execution.
|
|
15
16
|
|
|
16
|
-
The same
|
|
17
|
+
The same owner implementation backs CLI consumers and the public
|
|
18
|
+
`@ankhorage/infra/project` application-service boundary. Trusted hosts such
|
|
19
|
+
as Studio should call that subpath instead of reproducing ledger, generated
|
|
20
|
+
file, lifecycle-script, or port-forward configuration semantics.
|
|
21
|
+
|
|
22
|
+
CLI entrypoints:
|
|
17
23
|
|
|
18
24
|
- `ankh infra ...`
|
|
19
25
|
- `bunx @ankhorage/infra ...`
|
|
@@ -26,12 +32,10 @@ Current command surface:
|
|
|
26
32
|
- `up`
|
|
27
33
|
- `down`
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- pass `[project]`, or
|
|
34
|
-
- omit it when cwd is already inside `apps/<project>`
|
|
35
|
+
Project resolution for the CLI is workspace-aware: pass `[project]`, or
|
|
36
|
+
omit it when cwd is already inside `apps/<project>`. Programmatic project
|
|
37
|
+
operations accept an explicit project path and do not require Studio or a
|
|
38
|
+
particular workspace layout.
|
|
35
39
|
|
|
36
40
|
Source: `src/readme-usage.ts`
|
|
37
41
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { InfraManifestInput } from '../../../types';
|
|
1
|
+
import type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';
|
|
2
2
|
import { type MinikubeAdapterArtifacts } from '../contracts';
|
|
3
3
|
export declare function generateAuthProviderArtifacts(args: {
|
|
4
|
+
appManifest: InfrastructureGenerationOptions['appManifest'];
|
|
4
5
|
manifest: InfraManifestInput;
|
|
5
6
|
namespace: string;
|
|
6
7
|
}): MinikubeAdapterArtifacts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAA0B,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAIrF,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,WAAW,EAAE,+BAA+B,CAAC,aAAa,CAAC,CAAC;IAC5D,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,wBAAwB,CA8B3B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { emptyMinikubeArtifacts } from '../contracts';
|
|
2
|
-
import { generateSupabaseOAuthRuntimeArtifacts } from './oauthRuntime';
|
|
3
2
|
import { generateSupabaseAuthArtifacts } from './supabase';
|
|
3
|
+
import { generateTargetAwareSupabaseOAuthRuntimeArtifacts } from './targetAwareOAuthRuntime';
|
|
4
4
|
export function generateAuthProviderArtifacts(args) {
|
|
5
|
-
const { manifest, namespace } = args;
|
|
5
|
+
const { appManifest, manifest, namespace } = args;
|
|
6
6
|
const { auth } = manifest;
|
|
7
7
|
if (!auth) {
|
|
8
8
|
return emptyMinikubeArtifacts();
|
|
@@ -11,7 +11,10 @@ export function generateAuthProviderArtifacts(args) {
|
|
|
11
11
|
throw new Error(`Unsupported auth provider for minikube adapter: "${auth.provider}". Only "supabase" is currently supported.`);
|
|
12
12
|
}
|
|
13
13
|
const providerArtifacts = generateSupabaseAuthArtifacts({ manifest, namespace });
|
|
14
|
-
const oauthArtifacts =
|
|
14
|
+
const oauthArtifacts = generateTargetAwareSupabaseOAuthRuntimeArtifacts({
|
|
15
|
+
appManifest,
|
|
16
|
+
manifest,
|
|
17
|
+
});
|
|
15
18
|
return {
|
|
16
19
|
files: [...providerArtifacts.files, ...oauthArtifacts.files],
|
|
17
20
|
resources: [...providerArtifacts.resources, ...oauthArtifacts.resources],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAiC,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAiC,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,gDAAgD,EAAE,MAAM,2BAA2B,CAAC;AAE7F,MAAM,UAAU,6BAA6B,CAAC,IAI7C;IACC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAClD,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;IAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,sBAAsB,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,oDAAoD,IAAI,CAAC,QAAQ,4CAA4C,CAC9G,CAAC;IACJ,CAAC;IAED,MAAM,iBAAiB,GAAG,6BAA6B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IACjF,MAAM,cAAc,GAAG,gDAAgD,CAAC;QACtE,WAAW;QACX,QAAQ;KACT,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC;QAC5D,SAAS,EAAE,CAAC,GAAG,iBAAiB,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC,SAAS,CAAC;QACxE,iBAAiB,EAAE;YACjB,GAAG,iBAAiB,CAAC,iBAAiB;YACtC,GAAG,cAAc,CAAC,iBAAiB;SACpC;QACD,UAAU,EAAE,CAAC,GAAG,iBAAiB,CAAC,UAAU,EAAE,GAAG,cAAc,CAAC,UAAU,CAAC;QAC3E,QAAQ,EAAE,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC;KACtE,CAAC;AACJ,CAAC","sourcesContent":["import type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';\nimport { emptyMinikubeArtifacts, type MinikubeAdapterArtifacts } from '../contracts';\nimport { generateSupabaseAuthArtifacts } from './supabase';\nimport { generateTargetAwareSupabaseOAuthRuntimeArtifacts } from './targetAwareOAuthRuntime';\n\nexport function generateAuthProviderArtifacts(args: {\n appManifest: InfrastructureGenerationOptions['appManifest'];\n manifest: InfraManifestInput;\n namespace: string;\n}): MinikubeAdapterArtifacts {\n const { appManifest, manifest, namespace } = args;\n const { auth } = manifest;\n\n if (!auth) {\n return emptyMinikubeArtifacts();\n }\n\n if (auth.provider !== 'supabase') {\n throw new Error(\n `Unsupported auth provider for minikube adapter: \"${auth.provider}\". Only \"supabase\" is currently supported.`,\n );\n }\n\n const providerArtifacts = generateSupabaseAuthArtifacts({ manifest, namespace });\n const oauthArtifacts = generateTargetAwareSupabaseOAuthRuntimeArtifacts({\n appManifest,\n manifest,\n });\n\n return {\n files: [...providerArtifacts.files, ...oauthArtifacts.files],\n resources: [...providerArtifacts.resources, ...oauthArtifacts.resources],\n providerLifecycle: [\n ...providerArtifacts.providerLifecycle,\n ...oauthArtifacts.providerLifecycle,\n ],\n envEntries: [...providerArtifacts.envEntries, ...oauthArtifacts.envEntries],\n warnings: [...providerArtifacts.warnings, ...oauthArtifacts.warnings],\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';
|
|
2
|
+
import type { MinikubeAdapterArtifacts } from '../contracts';
|
|
3
|
+
export declare function generateTargetAwareSupabaseOAuthRuntimeArtifacts(args: {
|
|
4
|
+
readonly appManifest: InfrastructureGenerationOptions['appManifest'];
|
|
5
|
+
readonly manifest: InfraManifestInput;
|
|
6
|
+
}): MinikubeAdapterArtifacts;
|
|
7
|
+
//# sourceMappingURL=targetAwareOAuthRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targetAwareOAuthRuntime.d.ts","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/targetAwareOAuthRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,KAAK,EAAE,wBAAwB,EAA6B,MAAM,cAAc,CAAC;AAUxF,wBAAgB,gDAAgD,CAAC,IAAI,EAAE;IACrE,QAAQ,CAAC,WAAW,EAAE,+BAA+B,CAAC,aAAa,CAAC,CAAC;IACrE,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;CACvC,GAAG,wBAAwB,CA8B3B"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { getLocalAuthRedirectPatterns, normalizeAuthCallbackRoute } from '../../../authRedirects';
|
|
2
|
+
import { resolveAuthTargetRedirectModel } from '../../../authTargetRedirects';
|
|
3
|
+
import { generateSupabaseOAuthRuntimeArtifacts } from './oauthRuntime';
|
|
4
|
+
export function generateTargetAwareSupabaseOAuthRuntimeArtifacts(args) {
|
|
5
|
+
const baseArtifacts = generateSupabaseOAuthRuntimeArtifacts(args.manifest);
|
|
6
|
+
if (!baseArtifacts.providerLifecycle.some((lifecycle) => lifecycle.id === 'supabase-auth')) {
|
|
7
|
+
return baseArtifacts;
|
|
8
|
+
}
|
|
9
|
+
const callbackRoute = normalizeAuthCallbackRoute(args.manifest.auth?.oauth?.callbackRoute ?? '');
|
|
10
|
+
const targets = resolveAuthTargetRedirectModel({
|
|
11
|
+
callbackRoute,
|
|
12
|
+
targets: args.appManifest?.deploy?.targets,
|
|
13
|
+
});
|
|
14
|
+
const policy = {
|
|
15
|
+
callbackRoute,
|
|
16
|
+
localPatterns: targets.webEnabled ? getLocalAuthRedirectPatterns(callbackRoute) : [],
|
|
17
|
+
nativeRedirectUris: targets.nativeRedirectUris,
|
|
18
|
+
webEnabled: targets.webEnabled,
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
...baseArtifacts,
|
|
22
|
+
files: baseArtifacts.files.map((file) => file.path === 'infra/minikube/auth/oauth-runtime.md'
|
|
23
|
+
? { ...file, content: getTargetAwareGuide(policy) }
|
|
24
|
+
: file),
|
|
25
|
+
providerLifecycle: baseArtifacts.providerLifecycle.map((lifecycle) => lifecycle.id === 'supabase-auth' ? applyRedirectPolicy(lifecycle, policy) : lifecycle),
|
|
26
|
+
warnings: [...baseArtifacts.warnings, ...targets.warnings],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function applyRedirectPolicy(lifecycle, policy) {
|
|
30
|
+
return {
|
|
31
|
+
...lifecycle,
|
|
32
|
+
reconciliationCommands: lifecycle.reconciliationCommands.map((entry) => ({
|
|
33
|
+
...entry,
|
|
34
|
+
command: rewriteReconciliationCommand(entry.command, policy),
|
|
35
|
+
})),
|
|
36
|
+
statusChecks: lifecycle.statusChecks.map((entry) => ({
|
|
37
|
+
...entry,
|
|
38
|
+
command: getTargetAwareStatusCommand(policy),
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function rewriteReconciliationCommand(command, policy) {
|
|
43
|
+
const legacyPatterns = getLocalAuthRedirectPatterns(policy.callbackRoute).join(',');
|
|
44
|
+
const legacyPolicy = `oauth_redirect_allow_list="\${oauth_site_url},\${oauth_site_url}/\${oauth_callback_path},${legacyPatterns}"
|
|
45
|
+
if [[ -n "\${OAUTH_NATIVE_REDIRECT_URLS:-}" ]]; then
|
|
46
|
+
oauth_redirect_allow_list="\${oauth_redirect_allow_list},\${OAUTH_NATIVE_REDIRECT_URLS}"
|
|
47
|
+
fi`;
|
|
48
|
+
const staticRedirects = [...policy.localPatterns, ...policy.nativeRedirectUris].join(',');
|
|
49
|
+
const suffix = staticRedirects ? `,${staticRedirects}` : '';
|
|
50
|
+
const canonicalPolicy = policy.webEnabled
|
|
51
|
+
? `oauth_redirect_allow_list="\${oauth_site_url},\${oauth_site_url}/\${oauth_callback_path}${suffix}"`
|
|
52
|
+
: `oauth_redirect_allow_list='${staticRedirects}'`;
|
|
53
|
+
let rewritten = replaceOnce(command, legacyPolicy, canonicalPolicy);
|
|
54
|
+
if (!policy.webEnabled) {
|
|
55
|
+
rewritten = replaceOnce(rewritten, 'oauth_site_url="${SITE_URL%/}"\n', '');
|
|
56
|
+
}
|
|
57
|
+
return rewritten;
|
|
58
|
+
}
|
|
59
|
+
function getTargetAwareStatusCommand(policy) {
|
|
60
|
+
const appCallback = policy.webEnabled
|
|
61
|
+
? `if [[ -n "\${SITE_URL:-}" ]]; then
|
|
62
|
+
echo "- provider supabase-auth/app-callback: \${SITE_URL%/}/\${oauth_callback_path}"
|
|
63
|
+
else
|
|
64
|
+
echo "- provider supabase-auth/app-callback: unavailable"
|
|
65
|
+
fi`
|
|
66
|
+
: 'echo "- provider supabase-auth/app-callback: disabled (web target)"';
|
|
67
|
+
const localPatterns = policy.localPatterns.join(',') || 'none';
|
|
68
|
+
const nativeRedirects = policy.nativeRedirectUris.join(',') || 'none';
|
|
69
|
+
return `oauth_callback_route='${policy.callbackRoute}'
|
|
70
|
+
oauth_callback_path="\${oauth_callback_route#/}"
|
|
71
|
+
if [[ -n "\${API_EXTERNAL_URL:-}" ]]; then
|
|
72
|
+
echo "- provider supabase-auth/provider-callback: \${API_EXTERNAL_URL%/}/callback"
|
|
73
|
+
else
|
|
74
|
+
echo "- provider supabase-auth/provider-callback: unavailable"
|
|
75
|
+
fi
|
|
76
|
+
${appCallback}
|
|
77
|
+
echo "- provider supabase-auth/local-callback-patterns: ${localPatterns}"
|
|
78
|
+
echo "- provider supabase-auth/native-callbacks: ${nativeRedirects}"`;
|
|
79
|
+
}
|
|
80
|
+
function getTargetAwareGuide(policy) {
|
|
81
|
+
const nativeRedirects = policy.nativeRedirectUris.length
|
|
82
|
+
? policy.nativeRedirectUris.map((uri) => `- \`${uri}\``).join('\n')
|
|
83
|
+
: '- none';
|
|
84
|
+
return `# Supabase OAuth Runtime Reconciliation
|
|
85
|
+
|
|
86
|
+
The provider callback remains project-owned. GoTrue-to-app redirects use the configured callback
|
|
87
|
+
route \`${policy.callbackRoute}\` and are derived from \`AppManifest.deploy.targets\`.
|
|
88
|
+
|
|
89
|
+
- Web target: ${policy.webEnabled ? 'enabled' : 'disabled'}
|
|
90
|
+
- Native callbacks:
|
|
91
|
+
${nativeRedirects}
|
|
92
|
+
|
|
93
|
+
Local loopback patterns are emitted only for an enabled Web target. Native callbacks come only
|
|
94
|
+
from enabled Android/iOS target schemes; no environment variable or slug-derived identity can add
|
|
95
|
+
a native callback. Provider credential values remain sourced from trusted secret resolution.
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
function replaceOnce(value, search, replacement) {
|
|
99
|
+
if (!value.includes(search)) {
|
|
100
|
+
throw new Error('Supabase OAuth redirect reconciliation template drifted from its canonical form.');
|
|
101
|
+
}
|
|
102
|
+
return value.replace(search, replacement);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=targetAwareOAuthRuntime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targetAwareOAuthRuntime.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/targetAwareOAuthRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLocalAuthRedirectPatterns, normalizeAuthCallbackRoute } from '../../../authRedirects';\nimport { resolveAuthTargetRedirectModel } from '../../../authTargetRedirects';\nimport type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';\nimport type { MinikubeAdapterArtifacts, MinikubeProviderLifecycle } from '../contracts';\nimport { generateSupabaseOAuthRuntimeArtifacts } from './oauthRuntime';\n\ninterface RedirectPolicy {\n readonly callbackRoute: string;\n readonly localPatterns: readonly string[];\n readonly nativeRedirectUris: readonly string[];\n readonly webEnabled: boolean;\n}\n\nexport function generateTargetAwareSupabaseOAuthRuntimeArtifacts(args: {\n readonly appManifest: InfrastructureGenerationOptions['appManifest'];\n readonly manifest: InfraManifestInput;\n}): MinikubeAdapterArtifacts {\n const baseArtifacts = generateSupabaseOAuthRuntimeArtifacts(args.manifest);\n if (!baseArtifacts.providerLifecycle.some((lifecycle) => lifecycle.id === 'supabase-auth')) {\n return baseArtifacts;\n }\n\n const callbackRoute = normalizeAuthCallbackRoute(args.manifest.auth?.oauth?.callbackRoute ?? '');\n const targets = resolveAuthTargetRedirectModel({\n callbackRoute,\n targets: args.appManifest?.deploy?.targets,\n });\n const policy: RedirectPolicy = {\n callbackRoute,\n localPatterns: targets.webEnabled ? getLocalAuthRedirectPatterns(callbackRoute) : [],\n nativeRedirectUris: targets.nativeRedirectUris,\n webEnabled: targets.webEnabled,\n };\n\n return {\n ...baseArtifacts,\n files: baseArtifacts.files.map((file) =>\n file.path === 'infra/minikube/auth/oauth-runtime.md'\n ? { ...file, content: getTargetAwareGuide(policy) }\n : file,\n ),\n providerLifecycle: baseArtifacts.providerLifecycle.map((lifecycle) =>\n lifecycle.id === 'supabase-auth' ? applyRedirectPolicy(lifecycle, policy) : lifecycle,\n ),\n warnings: [...baseArtifacts.warnings, ...targets.warnings],\n };\n}\n\nfunction applyRedirectPolicy(\n lifecycle: MinikubeProviderLifecycle,\n policy: RedirectPolicy,\n): MinikubeProviderLifecycle {\n return {\n ...lifecycle,\n reconciliationCommands: lifecycle.reconciliationCommands.map((entry) => ({\n ...entry,\n command: rewriteReconciliationCommand(entry.command, policy),\n })),\n statusChecks: lifecycle.statusChecks.map((entry) => ({\n ...entry,\n command: getTargetAwareStatusCommand(policy),\n })),\n };\n}\n\nfunction rewriteReconciliationCommand(command: string, policy: RedirectPolicy): string {\n const legacyPatterns = getLocalAuthRedirectPatterns(policy.callbackRoute).join(',');\n const legacyPolicy = `oauth_redirect_allow_list=\"\\${oauth_site_url},\\${oauth_site_url}/\\${oauth_callback_path},${legacyPatterns}\"\nif [[ -n \"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\" ]]; then\n oauth_redirect_allow_list=\"\\${oauth_redirect_allow_list},\\${OAUTH_NATIVE_REDIRECT_URLS}\"\nfi`;\n const staticRedirects = [...policy.localPatterns, ...policy.nativeRedirectUris].join(',');\n const suffix = staticRedirects ? `,${staticRedirects}` : '';\n const canonicalPolicy = policy.webEnabled\n ? `oauth_redirect_allow_list=\"\\${oauth_site_url},\\${oauth_site_url}/\\${oauth_callback_path}${suffix}\"`\n : `oauth_redirect_allow_list='${staticRedirects}'`;\n let rewritten = replaceOnce(command, legacyPolicy, canonicalPolicy);\n\n if (!policy.webEnabled) {\n rewritten = replaceOnce(rewritten, 'oauth_site_url=\"${SITE_URL%/}\"\\n', '');\n }\n\n return rewritten;\n}\n\nfunction getTargetAwareStatusCommand(policy: RedirectPolicy): string {\n const appCallback = policy.webEnabled\n ? `if [[ -n \"\\${SITE_URL:-}\" ]]; then\n echo \"- provider supabase-auth/app-callback: \\${SITE_URL%/}/\\${oauth_callback_path}\"\nelse\n echo \"- provider supabase-auth/app-callback: unavailable\"\nfi`\n : 'echo \"- provider supabase-auth/app-callback: disabled (web target)\"';\n const localPatterns = policy.localPatterns.join(',') || 'none';\n const nativeRedirects = policy.nativeRedirectUris.join(',') || 'none';\n\n return `oauth_callback_route='${policy.callbackRoute}'\noauth_callback_path=\"\\${oauth_callback_route#/}\"\nif [[ -n \"\\${API_EXTERNAL_URL:-}\" ]]; then\n echo \"- provider supabase-auth/provider-callback: \\${API_EXTERNAL_URL%/}/callback\"\nelse\n echo \"- provider supabase-auth/provider-callback: unavailable\"\nfi\n${appCallback}\necho \"- provider supabase-auth/local-callback-patterns: ${localPatterns}\"\necho \"- provider supabase-auth/native-callbacks: ${nativeRedirects}\"`;\n}\n\nfunction getTargetAwareGuide(policy: RedirectPolicy): string {\n const nativeRedirects = policy.nativeRedirectUris.length\n ? policy.nativeRedirectUris.map((uri) => `- \\`${uri}\\``).join('\\n')\n : '- none';\n\n return `# Supabase OAuth Runtime Reconciliation\n\nThe provider callback remains project-owned. GoTrue-to-app redirects use the configured callback\nroute \\`${policy.callbackRoute}\\` and are derived from \\`AppManifest.deploy.targets\\`.\n\n- Web target: ${policy.webEnabled ? 'enabled' : 'disabled'}\n- Native callbacks:\n${nativeRedirects}\n\nLocal loopback patterns are emitted only for an enabled Web target. Native callbacks come only\nfrom enabled Android/iOS target schemes; no environment variable or slug-derived identity can add\na native callback. Provider credential values remain sourced from trusted secret resolution.\n`;\n}\n\nfunction replaceOnce(value: string, search: string, replacement: string): string {\n if (!value.includes(search)) {\n throw new Error(\n 'Supabase OAuth redirect reconciliation template drifted from its canonical form.',\n );\n }\n return value.replace(search, replacement);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,aAAa,CAAC;AAUrB,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,+BAAoC,GAC5C,8BAA8B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,aAAa,CAAC;AAUrB,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,+BAAoC,GAC5C,8BAA8B,CAsGhC"}
|
|
@@ -15,7 +15,11 @@ export function generateMinikubeInfra(manifest, options = {}) {
|
|
|
15
15
|
}
|
|
16
16
|
const appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);
|
|
17
17
|
const namespace = APP_NAMESPACE;
|
|
18
|
-
const authArtifacts = generateAuthProviderArtifacts({
|
|
18
|
+
const authArtifacts = generateAuthProviderArtifacts({
|
|
19
|
+
appManifest: options.appManifest,
|
|
20
|
+
manifest,
|
|
21
|
+
namespace,
|
|
22
|
+
});
|
|
19
23
|
const authzArtifacts = generateAuthorizationArtifacts({
|
|
20
24
|
manifest,
|
|
21
25
|
namespace,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { generateGeneratedApiDatabaseArtifacts } from '../../generatedApiDatabase';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { APP_NAMESPACE, generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;\nconst BUILT_IN_NAMESPACES = new Set([APP_NAMESPACE, 'supabase']);\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 appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);\n const namespace = APP_NAMESPACE;\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 generatedApiDatabaseArtifacts = generateGeneratedApiDatabaseArtifacts({\n generatedApis: options.appManifest?.generatedApis,\n databaseProvider: manifest.database?.provider,\n });\n const generatedApiErrors = generatedApiDatabaseArtifacts.diagnostics.filter(\n (diagnostic) => diagnostic.severity === 'error',\n );\n\n if (generatedApiErrors.length > 0) {\n throw new Error(\n `Generated API database definition is invalid:\\n${generatedApiErrors\n .map((diagnostic) => `- ${diagnostic.path ?? diagnostic.apiId}: ${diagnostic.message}`)\n .join('\\n')}`,\n );\n }\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const providerLifecycle = [\n ...authArtifacts.providerLifecycle,\n ...authzArtifacts.providerLifecycle,\n ...storageArtifacts.providerLifecycle,\n ...secretStoreArtifacts.providerLifecycle,\n ];\n const providerNamespaces = unique([\n ...providerLifecycle.map((contribution) => contribution.namespace),\n ]).filter((providerNamespace) => !BUILT_IN_NAMESPACES.has(providerNamespace));\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 appSlug,\n extraResources,\n providerNamespaces,\n providerLifecycle,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...generatedApiDatabaseArtifacts.diagnostics\n .filter((diagnostic) => diagnostic.severity === 'warning')\n .map((diagnostic) => diagnostic.message),\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...generatedApiDatabaseArtifacts.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 validateCanonicalAppSlug(slug: string | undefined): string {\n if (!slug) {\n throw new Error(\n 'Cannot generate Minikube 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 Minikube 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 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":"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","sourcesContent":["import { generateGeneratedApiDatabaseArtifacts } from '../../generatedApiDatabase';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { APP_NAMESPACE, generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;\nconst BUILT_IN_NAMESPACES = new Set([APP_NAMESPACE, 'supabase']);\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 appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);\n const namespace = APP_NAMESPACE;\n\n const authArtifacts = generateAuthProviderArtifacts({\n appManifest: options.appManifest,\n manifest,\n namespace,\n });\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 generatedApiDatabaseArtifacts = generateGeneratedApiDatabaseArtifacts({\n generatedApis: options.appManifest?.generatedApis,\n databaseProvider: manifest.database?.provider,\n });\n const generatedApiErrors = generatedApiDatabaseArtifacts.diagnostics.filter(\n (diagnostic) => diagnostic.severity === 'error',\n );\n\n if (generatedApiErrors.length > 0) {\n throw new Error(\n `Generated API database definition is invalid:\\n${generatedApiErrors\n .map((diagnostic) => `- ${diagnostic.path ?? diagnostic.apiId}: ${diagnostic.message}`)\n .join('\\n')}`,\n );\n }\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const providerLifecycle = [\n ...authArtifacts.providerLifecycle,\n ...authzArtifacts.providerLifecycle,\n ...storageArtifacts.providerLifecycle,\n ...secretStoreArtifacts.providerLifecycle,\n ];\n const providerNamespaces = unique([\n ...providerLifecycle.map((contribution) => contribution.namespace),\n ]).filter((providerNamespace) => !BUILT_IN_NAMESPACES.has(providerNamespace));\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 appSlug,\n extraResources,\n providerNamespaces,\n providerLifecycle,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...generatedApiDatabaseArtifacts.diagnostics\n .filter((diagnostic) => diagnostic.severity === 'warning')\n .map((diagnostic) => diagnostic.message),\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...generatedApiDatabaseArtifacts.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 validateCanonicalAppSlug(slug: string | undefined): string {\n if (!slug) {\n throw new Error(\n 'Cannot generate Minikube 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 Minikube 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 unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AppDeployTargets } from '@ankhorage/contracts/deploy';
|
|
2
|
+
interface AuthTargetRedirectModel {
|
|
3
|
+
readonly nativeRedirectUris: readonly string[];
|
|
4
|
+
readonly warnings: readonly string[];
|
|
5
|
+
readonly webEnabled: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveAuthTargetRedirectModel(args: {
|
|
8
|
+
readonly callbackRoute: string;
|
|
9
|
+
readonly targets: AppDeployTargets | undefined;
|
|
10
|
+
}): AuthTargetRedirectModel;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=authTargetRedirects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authTargetRedirects.d.ts","sourceRoot":"","sources":["../src/authTargetRedirects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD,GAAG,uBAAuB,CAkC1B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function resolveAuthTargetRedirectModel(args) {
|
|
2
|
+
if (args.targets === undefined) {
|
|
3
|
+
return {
|
|
4
|
+
nativeRedirectUris: [],
|
|
5
|
+
warnings: [
|
|
6
|
+
'OAuth deploy.targets is missing; Infra keeps Web-local redirects only until canonical targets are persisted.',
|
|
7
|
+
],
|
|
8
|
+
webEnabled: true,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const callbackPath = args.callbackRoute.replace(/^\/+/u, '');
|
|
12
|
+
const nativeRedirectUris = [];
|
|
13
|
+
const warnings = [];
|
|
14
|
+
for (const [targetId, target] of [
|
|
15
|
+
['android', args.targets.android],
|
|
16
|
+
['ios', args.targets.ios],
|
|
17
|
+
]) {
|
|
18
|
+
if (target?.enabled !== true)
|
|
19
|
+
continue;
|
|
20
|
+
if (target.scheme === undefined) {
|
|
21
|
+
warnings.push(`OAuth ${targetId} target is enabled but deploy.targets.${targetId}.scheme is missing; native callback omitted.`);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
nativeRedirectUris.push(`${target.scheme}://${callbackPath}`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
nativeRedirectUris: [...new Set(nativeRedirectUris)],
|
|
28
|
+
warnings,
|
|
29
|
+
webEnabled: args.targets.web?.enabled === true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=authTargetRedirects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authTargetRedirects.js","sourceRoot":"","sources":["../src/authTargetRedirects.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,8BAA8B,CAAC,IAG9C;IACC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO;YACL,kBAAkB,EAAE,EAAE;YACtB,QAAQ,EAAE;gBACR,8GAA8G;aAC/G;YACD,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI;QAC/B,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QACjC,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;KACjB,EAAE,CAAC;QACX,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI;YAAE,SAAS;QACvC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,QAAQ,CAAC,IAAI,CACX,SAAS,QAAQ,yCAAyC,QAAQ,8CAA8C,CACjH,CAAC;YACF,SAAS;QACX,CAAC;QACD,kBAAkB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,YAAY,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACpD,QAAQ;QACR,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI;KAC/C,CAAC;AACJ,CAAC","sourcesContent":["import type { AppDeployTargets } from '@ankhorage/contracts/deploy';\n\ninterface AuthTargetRedirectModel {\n readonly nativeRedirectUris: readonly string[];\n readonly warnings: readonly string[];\n readonly webEnabled: boolean;\n}\n\nexport function resolveAuthTargetRedirectModel(args: {\n readonly callbackRoute: string;\n readonly targets: AppDeployTargets | undefined;\n}): AuthTargetRedirectModel {\n if (args.targets === undefined) {\n return {\n nativeRedirectUris: [],\n warnings: [\n 'OAuth deploy.targets is missing; Infra keeps Web-local redirects only until canonical targets are persisted.',\n ],\n webEnabled: true,\n };\n }\n\n const callbackPath = args.callbackRoute.replace(/^\\/+/u, '');\n const nativeRedirectUris: string[] = [];\n const warnings: string[] = [];\n\n for (const [targetId, target] of [\n ['android', args.targets.android],\n ['ios', args.targets.ios],\n ] as const) {\n if (target?.enabled !== true) continue;\n if (target.scheme === undefined) {\n warnings.push(\n `OAuth ${targetId} target is enabled but deploy.targets.${targetId}.scheme is missing; native callback omitted.`,\n );\n continue;\n }\n nativeRedirectUris.push(`${target.scheme}://${callbackPath}`);\n }\n\n return {\n nativeRedirectUris: [...new Set(nativeRedirectUris)],\n warnings,\n webEnabled: args.targets.web?.enabled === true,\n };\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export interface InfrastructureGenerationOptions {
|
|
|
30
30
|
/**
|
|
31
31
|
* Optional app-level context used by provider/engine-specific generators.
|
|
32
32
|
*/
|
|
33
|
-
readonly appManifest?: Pick<AppManifest, 'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'>;
|
|
33
|
+
readonly appManifest?: Pick<AppManifest, 'deploy' | 'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'>;
|
|
34
34
|
}
|
|
35
35
|
export interface InfraGenerationInput {
|
|
36
36
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,2BAA2B,EAAE,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,SAAS,0BAA0B,EAAE,CAAC;CAC9D;AAED,MAAM,WAAW,+BAA+B;IAC9C;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CACzB,WAAW,EACX,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,2BAA2B,EAAE,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,SAAS,0BAA0B,EAAE,CAAC;CAC9D;AAED,MAAM,WAAW,+BAA+B;IAC9C;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CACzB,WAAW,EACX,QAAQ,GAAG,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CACzF,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,+BAA+B,CAAC;CACpD;AAED,MAAM,MAAM,sBAAsB,GAAG,+BAA+B,CAAC;AACrE,MAAM,MAAM,qBAAqB,GAAG,8BAA8B,CAAC;AACnE,MAAM,MAAM,aAAa,GAAG,2BAA2B,CAAC;AACxD,MAAM,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,KAAK,oBAAoB,GAAG,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;AAE3F,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAC1C,CAAC"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AppManifest, InfraManifest } from '@ankhorage/contracts';\n\nexport interface GeneratedInfrastructureFile {\n /**\n * Path relative to the target app root.\n */\n readonly path: string;\n readonly content: string;\n readonly executable?: boolean;\n}\n\nexport interface GeneratedPackageDependency {\n readonly name: string;\n readonly version: string;\n readonly reason: string;\n}\n\nexport interface InfrastructureGenerationMeta {\n readonly target: NonNullable<InfraManifest['deployment']>['target'];\n readonly providers: readonly string[];\n}\n\nexport interface InfrastructureGenerationResult {\n readonly files: readonly GeneratedInfrastructureFile[];\n readonly warnings: readonly string[];\n readonly meta: InfrastructureGenerationMeta;\n readonly dependencies: readonly GeneratedPackageDependency[];\n}\n\nexport interface InfrastructureGenerationOptions {\n /**\n * Optional namespace hint from caller context, such as app slug or project id.\n */\n readonly namespaceHint?: string;\n /**\n * Optional app-level context used by provider/engine-specific generators.\n */\n readonly appManifest?: Pick<\n AppManifest,\n 'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'\n >;\n}\n\nexport interface InfraGenerationInput {\n /**\n * Infra manifest section from an app manifest.\n */\n readonly manifest: InfraManifestInput;\n /**\n * Optional root used by callers that want to keep output intent alongside generation.\n * The generator itself still returns relative file paths and does not write to disk.\n */\n readonly outputRoot?: string;\n readonly options?: InfrastructureGenerationOptions;\n}\n\nexport type InfraGenerationOptions = InfrastructureGenerationOptions;\nexport type InfraGenerationResult = InfrastructureGenerationResult;\nexport type GeneratedFile = GeneratedInfrastructureFile;\nexport type PackageDependency = GeneratedPackageDependency;\n\nexport interface InfraDiagnostic {\n readonly severity: 'warning';\n readonly message: string;\n}\n\ntype InfraStorageProvider = NonNullable<InfraManifest['storage']>['provider'] | 'supabase';\n\ninterface InfraStorageSpecInput {\n readonly provider: InfraStorageProvider;\n readonly buckets: readonly string[];\n}\n\n/**\n * Infra-local manifest input type.\n *\n * This is intentionally broader than `@ankhorage/contracts` to allow adapters to support\n * additional providers before the shared contracts package officially includes them.\n */\nexport type InfraManifestInput = Omit<InfraManifest, 'storage'> & {\n readonly storage?: InfraStorageSpecInput;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AppManifest, InfraManifest } from '@ankhorage/contracts';\n\nexport interface GeneratedInfrastructureFile {\n /**\n * Path relative to the target app root.\n */\n readonly path: string;\n readonly content: string;\n readonly executable?: boolean;\n}\n\nexport interface GeneratedPackageDependency {\n readonly name: string;\n readonly version: string;\n readonly reason: string;\n}\n\nexport interface InfrastructureGenerationMeta {\n readonly target: NonNullable<InfraManifest['deployment']>['target'];\n readonly providers: readonly string[];\n}\n\nexport interface InfrastructureGenerationResult {\n readonly files: readonly GeneratedInfrastructureFile[];\n readonly warnings: readonly string[];\n readonly meta: InfrastructureGenerationMeta;\n readonly dependencies: readonly GeneratedPackageDependency[];\n}\n\nexport interface InfrastructureGenerationOptions {\n /**\n * Optional namespace hint from caller context, such as app slug or project id.\n */\n readonly namespaceHint?: string;\n /**\n * Optional app-level context used by provider/engine-specific generators.\n */\n readonly appManifest?: Pick<\n AppManifest,\n 'deploy' | 'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'\n >;\n}\n\nexport interface InfraGenerationInput {\n /**\n * Infra manifest section from an app manifest.\n */\n readonly manifest: InfraManifestInput;\n /**\n * Optional root used by callers that want to keep output intent alongside generation.\n * The generator itself still returns relative file paths and does not write to disk.\n */\n readonly outputRoot?: string;\n readonly options?: InfrastructureGenerationOptions;\n}\n\nexport type InfraGenerationOptions = InfrastructureGenerationOptions;\nexport type InfraGenerationResult = InfrastructureGenerationResult;\nexport type GeneratedFile = GeneratedInfrastructureFile;\nexport type PackageDependency = GeneratedPackageDependency;\n\nexport interface InfraDiagnostic {\n readonly severity: 'warning';\n readonly message: string;\n}\n\ntype InfraStorageProvider = NonNullable<InfraManifest['storage']>['provider'] | 'supabase';\n\ninterface InfraStorageSpecInput {\n readonly provider: InfraStorageProvider;\n readonly buckets: readonly string[];\n}\n\n/**\n * Infra-local manifest input type.\n *\n * This is intentionally broader than `@ankhorage/contracts` to allow adapters to support\n * additional providers before the shared contracts package officially includes them.\n */\nexport type InfraManifestInput = Omit<InfraManifest, 'storage'> & {\n readonly storage?: InfraStorageSpecInput;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/infra",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.3.0",
|
|
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": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"openapi"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@ankhorage/contracts": "^7.
|
|
38
|
+
"@ankhorage/contracts": "^7.7.0",
|
|
39
39
|
"@ankhorage/supabase-vault": "^0.2.4"
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type { InfraManifestInput } from '../../../types';
|
|
1
|
+
import type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';
|
|
2
2
|
import { emptyMinikubeArtifacts, type MinikubeAdapterArtifacts } from '../contracts';
|
|
3
|
-
import { generateSupabaseOAuthRuntimeArtifacts } from './oauthRuntime';
|
|
4
3
|
import { generateSupabaseAuthArtifacts } from './supabase';
|
|
4
|
+
import { generateTargetAwareSupabaseOAuthRuntimeArtifacts } from './targetAwareOAuthRuntime';
|
|
5
5
|
|
|
6
6
|
export function generateAuthProviderArtifacts(args: {
|
|
7
|
+
appManifest: InfrastructureGenerationOptions['appManifest'];
|
|
7
8
|
manifest: InfraManifestInput;
|
|
8
9
|
namespace: string;
|
|
9
10
|
}): MinikubeAdapterArtifacts {
|
|
10
|
-
const { manifest, namespace } = args;
|
|
11
|
+
const { appManifest, manifest, namespace } = args;
|
|
11
12
|
const { auth } = manifest;
|
|
12
13
|
|
|
13
14
|
if (!auth) {
|
|
@@ -21,7 +22,10 @@ export function generateAuthProviderArtifacts(args: {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const providerArtifacts = generateSupabaseAuthArtifacts({ manifest, namespace });
|
|
24
|
-
const oauthArtifacts =
|
|
25
|
+
const oauthArtifacts = generateTargetAwareSupabaseOAuthRuntimeArtifacts({
|
|
26
|
+
appManifest,
|
|
27
|
+
manifest,
|
|
28
|
+
});
|
|
25
29
|
|
|
26
30
|
return {
|
|
27
31
|
files: [...providerArtifacts.files, ...oauthArtifacts.files],
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { InfraManifest } from '@ankhorage/contracts';
|
|
2
|
+
import { describe, expect, test } from 'bun:test';
|
|
3
|
+
|
|
4
|
+
import { createAppManifest } from '../../../testSupport';
|
|
5
|
+
import { generateTargetAwareSupabaseOAuthRuntimeArtifacts } from './targetAwareOAuthRuntime';
|
|
6
|
+
|
|
7
|
+
describe('target-aware Supabase OAuth runtime', () => {
|
|
8
|
+
test('removes the legacy native redirect environment source', () => {
|
|
9
|
+
const artifacts = generateTargetAwareSupabaseOAuthRuntimeArtifacts({
|
|
10
|
+
appManifest: undefined,
|
|
11
|
+
manifest: createOAuthManifest(),
|
|
12
|
+
});
|
|
13
|
+
const [lifecycle] = artifacts.providerLifecycle;
|
|
14
|
+
const command = lifecycle?.reconciliationCommands[0]?.command ?? '';
|
|
15
|
+
|
|
16
|
+
expect(command).toContain('http://127.0.0.1:*/auth/callback');
|
|
17
|
+
expect(command).toContain('http://localhost:*/auth/callback');
|
|
18
|
+
expect(command).not.toContain('OAUTH_NATIVE_REDIRECT_URLS');
|
|
19
|
+
expect(artifacts.warnings).toEqual([
|
|
20
|
+
'OAuth deploy.targets is missing; Infra keeps Web-local redirects only until canonical targets are persisted.',
|
|
21
|
+
]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('emits only the enabled native callback for a native-only app', () => {
|
|
25
|
+
const appManifest = {
|
|
26
|
+
...createAppManifest('native-oauth'),
|
|
27
|
+
deploy: {
|
|
28
|
+
targets: {
|
|
29
|
+
web: { enabled: false },
|
|
30
|
+
android: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
package: 'com.ankh.native',
|
|
33
|
+
scheme: 'ankh-native',
|
|
34
|
+
},
|
|
35
|
+
ios: {
|
|
36
|
+
enabled: false,
|
|
37
|
+
bundleIdentifier: 'com.ankh.native',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const artifacts = generateTargetAwareSupabaseOAuthRuntimeArtifacts({
|
|
43
|
+
appManifest,
|
|
44
|
+
manifest: createOAuthManifest(),
|
|
45
|
+
});
|
|
46
|
+
const [lifecycle] = artifacts.providerLifecycle;
|
|
47
|
+
const command = lifecycle?.reconciliationCommands[0]?.command ?? '';
|
|
48
|
+
const status = lifecycle?.statusChecks[0]?.command ?? '';
|
|
49
|
+
|
|
50
|
+
expect(command).toContain("oauth_redirect_allow_list='ankh-native://auth/callback'");
|
|
51
|
+
expect(command).not.toContain('oauth_site_url');
|
|
52
|
+
expect(command).not.toContain('localhost:*');
|
|
53
|
+
expect(command).not.toContain('127.0.0.1:*');
|
|
54
|
+
expect(command).not.toContain('OAUTH_NATIVE_REDIRECT_URLS');
|
|
55
|
+
expect(status).toContain('app-callback: disabled (web target)');
|
|
56
|
+
expect(status).toContain('native-callbacks: ankh-native://auth/callback');
|
|
57
|
+
expect(artifacts.warnings).toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function createOAuthManifest(): InfraManifest {
|
|
62
|
+
return {
|
|
63
|
+
deployment: { target: 'minikube', monitoring: false },
|
|
64
|
+
auth: {
|
|
65
|
+
scope: 'global',
|
|
66
|
+
provider: 'supabase',
|
|
67
|
+
oauth: {
|
|
68
|
+
enabled: true,
|
|
69
|
+
callbackRoute: '/auth/callback',
|
|
70
|
+
providers: [
|
|
71
|
+
{
|
|
72
|
+
id: 'google',
|
|
73
|
+
enabled: true,
|
|
74
|
+
credentialsRef: 'auth/oauth/google',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
database: { provider: 'supabase', tier: 'dev' },
|
|
80
|
+
secretStore: { provider: 'supabase-vault' },
|
|
81
|
+
modules: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getLocalAuthRedirectPatterns, normalizeAuthCallbackRoute } from '../../../authRedirects';
|
|
2
|
+
import { resolveAuthTargetRedirectModel } from '../../../authTargetRedirects';
|
|
3
|
+
import type { InfraManifestInput, InfrastructureGenerationOptions } from '../../../types';
|
|
4
|
+
import type { MinikubeAdapterArtifacts, MinikubeProviderLifecycle } from '../contracts';
|
|
5
|
+
import { generateSupabaseOAuthRuntimeArtifacts } from './oauthRuntime';
|
|
6
|
+
|
|
7
|
+
interface RedirectPolicy {
|
|
8
|
+
readonly callbackRoute: string;
|
|
9
|
+
readonly localPatterns: readonly string[];
|
|
10
|
+
readonly nativeRedirectUris: readonly string[];
|
|
11
|
+
readonly webEnabled: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function generateTargetAwareSupabaseOAuthRuntimeArtifacts(args: {
|
|
15
|
+
readonly appManifest: InfrastructureGenerationOptions['appManifest'];
|
|
16
|
+
readonly manifest: InfraManifestInput;
|
|
17
|
+
}): MinikubeAdapterArtifacts {
|
|
18
|
+
const baseArtifacts = generateSupabaseOAuthRuntimeArtifacts(args.manifest);
|
|
19
|
+
if (!baseArtifacts.providerLifecycle.some((lifecycle) => lifecycle.id === 'supabase-auth')) {
|
|
20
|
+
return baseArtifacts;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const callbackRoute = normalizeAuthCallbackRoute(args.manifest.auth?.oauth?.callbackRoute ?? '');
|
|
24
|
+
const targets = resolveAuthTargetRedirectModel({
|
|
25
|
+
callbackRoute,
|
|
26
|
+
targets: args.appManifest?.deploy?.targets,
|
|
27
|
+
});
|
|
28
|
+
const policy: RedirectPolicy = {
|
|
29
|
+
callbackRoute,
|
|
30
|
+
localPatterns: targets.webEnabled ? getLocalAuthRedirectPatterns(callbackRoute) : [],
|
|
31
|
+
nativeRedirectUris: targets.nativeRedirectUris,
|
|
32
|
+
webEnabled: targets.webEnabled,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
...baseArtifacts,
|
|
37
|
+
files: baseArtifacts.files.map((file) =>
|
|
38
|
+
file.path === 'infra/minikube/auth/oauth-runtime.md'
|
|
39
|
+
? { ...file, content: getTargetAwareGuide(policy) }
|
|
40
|
+
: file,
|
|
41
|
+
),
|
|
42
|
+
providerLifecycle: baseArtifacts.providerLifecycle.map((lifecycle) =>
|
|
43
|
+
lifecycle.id === 'supabase-auth' ? applyRedirectPolicy(lifecycle, policy) : lifecycle,
|
|
44
|
+
),
|
|
45
|
+
warnings: [...baseArtifacts.warnings, ...targets.warnings],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function applyRedirectPolicy(
|
|
50
|
+
lifecycle: MinikubeProviderLifecycle,
|
|
51
|
+
policy: RedirectPolicy,
|
|
52
|
+
): MinikubeProviderLifecycle {
|
|
53
|
+
return {
|
|
54
|
+
...lifecycle,
|
|
55
|
+
reconciliationCommands: lifecycle.reconciliationCommands.map((entry) => ({
|
|
56
|
+
...entry,
|
|
57
|
+
command: rewriteReconciliationCommand(entry.command, policy),
|
|
58
|
+
})),
|
|
59
|
+
statusChecks: lifecycle.statusChecks.map((entry) => ({
|
|
60
|
+
...entry,
|
|
61
|
+
command: getTargetAwareStatusCommand(policy),
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function rewriteReconciliationCommand(command: string, policy: RedirectPolicy): string {
|
|
67
|
+
const legacyPatterns = getLocalAuthRedirectPatterns(policy.callbackRoute).join(',');
|
|
68
|
+
const legacyPolicy = `oauth_redirect_allow_list="\${oauth_site_url},\${oauth_site_url}/\${oauth_callback_path},${legacyPatterns}"
|
|
69
|
+
if [[ -n "\${OAUTH_NATIVE_REDIRECT_URLS:-}" ]]; then
|
|
70
|
+
oauth_redirect_allow_list="\${oauth_redirect_allow_list},\${OAUTH_NATIVE_REDIRECT_URLS}"
|
|
71
|
+
fi`;
|
|
72
|
+
const staticRedirects = [...policy.localPatterns, ...policy.nativeRedirectUris].join(',');
|
|
73
|
+
const suffix = staticRedirects ? `,${staticRedirects}` : '';
|
|
74
|
+
const canonicalPolicy = policy.webEnabled
|
|
75
|
+
? `oauth_redirect_allow_list="\${oauth_site_url},\${oauth_site_url}/\${oauth_callback_path}${suffix}"`
|
|
76
|
+
: `oauth_redirect_allow_list='${staticRedirects}'`;
|
|
77
|
+
let rewritten = replaceOnce(command, legacyPolicy, canonicalPolicy);
|
|
78
|
+
|
|
79
|
+
if (!policy.webEnabled) {
|
|
80
|
+
rewritten = replaceOnce(rewritten, 'oauth_site_url="${SITE_URL%/}"\n', '');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return rewritten;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getTargetAwareStatusCommand(policy: RedirectPolicy): string {
|
|
87
|
+
const appCallback = policy.webEnabled
|
|
88
|
+
? `if [[ -n "\${SITE_URL:-}" ]]; then
|
|
89
|
+
echo "- provider supabase-auth/app-callback: \${SITE_URL%/}/\${oauth_callback_path}"
|
|
90
|
+
else
|
|
91
|
+
echo "- provider supabase-auth/app-callback: unavailable"
|
|
92
|
+
fi`
|
|
93
|
+
: 'echo "- provider supabase-auth/app-callback: disabled (web target)"';
|
|
94
|
+
const localPatterns = policy.localPatterns.join(',') || 'none';
|
|
95
|
+
const nativeRedirects = policy.nativeRedirectUris.join(',') || 'none';
|
|
96
|
+
|
|
97
|
+
return `oauth_callback_route='${policy.callbackRoute}'
|
|
98
|
+
oauth_callback_path="\${oauth_callback_route#/}"
|
|
99
|
+
if [[ -n "\${API_EXTERNAL_URL:-}" ]]; then
|
|
100
|
+
echo "- provider supabase-auth/provider-callback: \${API_EXTERNAL_URL%/}/callback"
|
|
101
|
+
else
|
|
102
|
+
echo "- provider supabase-auth/provider-callback: unavailable"
|
|
103
|
+
fi
|
|
104
|
+
${appCallback}
|
|
105
|
+
echo "- provider supabase-auth/local-callback-patterns: ${localPatterns}"
|
|
106
|
+
echo "- provider supabase-auth/native-callbacks: ${nativeRedirects}"`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getTargetAwareGuide(policy: RedirectPolicy): string {
|
|
110
|
+
const nativeRedirects = policy.nativeRedirectUris.length
|
|
111
|
+
? policy.nativeRedirectUris.map((uri) => `- \`${uri}\``).join('\n')
|
|
112
|
+
: '- none';
|
|
113
|
+
|
|
114
|
+
return `# Supabase OAuth Runtime Reconciliation
|
|
115
|
+
|
|
116
|
+
The provider callback remains project-owned. GoTrue-to-app redirects use the configured callback
|
|
117
|
+
route \`${policy.callbackRoute}\` and are derived from \`AppManifest.deploy.targets\`.
|
|
118
|
+
|
|
119
|
+
- Web target: ${policy.webEnabled ? 'enabled' : 'disabled'}
|
|
120
|
+
- Native callbacks:
|
|
121
|
+
${nativeRedirects}
|
|
122
|
+
|
|
123
|
+
Local loopback patterns are emitted only for an enabled Web target. Native callbacks come only
|
|
124
|
+
from enabled Android/iOS target schemes; no environment variable or slug-derived identity can add
|
|
125
|
+
a native callback. Provider credential values remain sourced from trusted secret resolution.
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function replaceOnce(value: string, search: string, replacement: string): string {
|
|
130
|
+
if (!value.includes(search)) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
'Supabase OAuth redirect reconciliation template drifted from its canonical form.',
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return value.replace(search, replacement);
|
|
136
|
+
}
|
|
@@ -33,7 +33,11 @@ export function generateMinikubeInfra(
|
|
|
33
33
|
const appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);
|
|
34
34
|
const namespace = APP_NAMESPACE;
|
|
35
35
|
|
|
36
|
-
const authArtifacts = generateAuthProviderArtifacts({
|
|
36
|
+
const authArtifacts = generateAuthProviderArtifacts({
|
|
37
|
+
appManifest: options.appManifest,
|
|
38
|
+
manifest,
|
|
39
|
+
namespace,
|
|
40
|
+
});
|
|
37
41
|
const authzArtifacts = generateAuthorizationArtifacts({
|
|
38
42
|
manifest,
|
|
39
43
|
namespace,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { AppDeployTargets } from '@ankhorage/contracts/deploy';
|
|
2
|
+
import { describe, expect, test } from 'bun:test';
|
|
3
|
+
|
|
4
|
+
import { resolveAuthTargetRedirectModel } from './authTargetRedirects';
|
|
5
|
+
|
|
6
|
+
describe('resolveAuthTargetRedirectModel', () => {
|
|
7
|
+
test('derives enabled native callbacks and deduplicates shared schemes', () => {
|
|
8
|
+
const targets: AppDeployTargets = {
|
|
9
|
+
web: { enabled: true },
|
|
10
|
+
android: {
|
|
11
|
+
enabled: true,
|
|
12
|
+
package: 'com.ankh.demo',
|
|
13
|
+
scheme: 'ankh-demo',
|
|
14
|
+
},
|
|
15
|
+
ios: {
|
|
16
|
+
enabled: true,
|
|
17
|
+
bundleIdentifier: 'com.ankh.demo',
|
|
18
|
+
scheme: 'ankh-demo',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
expect(resolveAuthTargetRedirectModel({ callbackRoute: '/auth/callback', targets })).toEqual({
|
|
23
|
+
nativeRedirectUris: ['ankh-demo://auth/callback'],
|
|
24
|
+
warnings: [],
|
|
25
|
+
webEnabled: true,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('omits disabled targets and warns instead of guessing missing native schemes', () => {
|
|
30
|
+
const targets: AppDeployTargets = {
|
|
31
|
+
web: { enabled: false },
|
|
32
|
+
android: {
|
|
33
|
+
enabled: false,
|
|
34
|
+
package: 'com.ankh.demo',
|
|
35
|
+
},
|
|
36
|
+
ios: {
|
|
37
|
+
enabled: true,
|
|
38
|
+
bundleIdentifier: 'com.ankh.demo',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const result = resolveAuthTargetRedirectModel({ callbackRoute: '/auth/callback', targets });
|
|
43
|
+
|
|
44
|
+
expect(result.nativeRedirectUris).toEqual([]);
|
|
45
|
+
expect(result.webEnabled).toBe(false);
|
|
46
|
+
expect(result.warnings).toEqual([
|
|
47
|
+
'OAuth ios target is enabled but deploy.targets.ios.scheme is missing; native callback omitted.',
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('keeps the pre-target manifest path Web-only and explicit', () => {
|
|
52
|
+
expect(
|
|
53
|
+
resolveAuthTargetRedirectModel({ callbackRoute: '/auth/callback', targets: undefined }),
|
|
54
|
+
).toEqual({
|
|
55
|
+
nativeRedirectUris: [],
|
|
56
|
+
warnings: [
|
|
57
|
+
'OAuth deploy.targets is missing; Infra keeps Web-local redirects only until canonical targets are persisted.',
|
|
58
|
+
],
|
|
59
|
+
webEnabled: true,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AppDeployTargets } from '@ankhorage/contracts/deploy';
|
|
2
|
+
|
|
3
|
+
interface AuthTargetRedirectModel {
|
|
4
|
+
readonly nativeRedirectUris: readonly string[];
|
|
5
|
+
readonly warnings: readonly string[];
|
|
6
|
+
readonly webEnabled: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function resolveAuthTargetRedirectModel(args: {
|
|
10
|
+
readonly callbackRoute: string;
|
|
11
|
+
readonly targets: AppDeployTargets | undefined;
|
|
12
|
+
}): AuthTargetRedirectModel {
|
|
13
|
+
if (args.targets === undefined) {
|
|
14
|
+
return {
|
|
15
|
+
nativeRedirectUris: [],
|
|
16
|
+
warnings: [
|
|
17
|
+
'OAuth deploy.targets is missing; Infra keeps Web-local redirects only until canonical targets are persisted.',
|
|
18
|
+
],
|
|
19
|
+
webEnabled: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const callbackPath = args.callbackRoute.replace(/^\/+/u, '');
|
|
24
|
+
const nativeRedirectUris: string[] = [];
|
|
25
|
+
const warnings: string[] = [];
|
|
26
|
+
|
|
27
|
+
for (const [targetId, target] of [
|
|
28
|
+
['android', args.targets.android],
|
|
29
|
+
['ios', args.targets.ios],
|
|
30
|
+
] as const) {
|
|
31
|
+
if (target?.enabled !== true) continue;
|
|
32
|
+
if (target.scheme === undefined) {
|
|
33
|
+
warnings.push(
|
|
34
|
+
`OAuth ${targetId} target is enabled but deploy.targets.${targetId}.scheme is missing; native callback omitted.`,
|
|
35
|
+
);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
nativeRedirectUris.push(`${target.scheme}://${callbackPath}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
nativeRedirectUris: [...new Set(nativeRedirectUris)],
|
|
43
|
+
warnings,
|
|
44
|
+
webEnabled: args.targets.web?.enabled === true,
|
|
45
|
+
};
|
|
46
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface InfrastructureGenerationOptions {
|
|
|
37
37
|
*/
|
|
38
38
|
readonly appManifest?: Pick<
|
|
39
39
|
AppManifest,
|
|
40
|
-
'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'
|
|
40
|
+
'deploy' | 'generatedApis' | 'infra' | 'metadata' | 'navigator' | 'screens' | 'settings'
|
|
41
41
|
>;
|
|
42
42
|
}
|
|
43
43
|
|