@ankhorage/doctor 0.7.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/analysis.d.ts +2 -0
  3. package/dist/analysis.d.ts.map +1 -1
  4. package/dist/analysis.js.map +1 -1
  5. package/dist/authReadinessAnalysis.d.ts +8 -0
  6. package/dist/authReadinessAnalysis.d.ts.map +1 -0
  7. package/dist/authReadinessAnalysis.js +38 -0
  8. package/dist/authReadinessAnalysis.js.map +1 -0
  9. package/dist/authReadinessDiagnostic.d.ts +9 -0
  10. package/dist/authReadinessDiagnostic.d.ts.map +1 -0
  11. package/dist/authReadinessDiagnostic.js +11 -0
  12. package/dist/authReadinessDiagnostic.js.map +1 -0
  13. package/dist/authReadinessEnvironment.d.ts +16 -0
  14. package/dist/authReadinessEnvironment.d.ts.map +1 -0
  15. package/dist/authReadinessEnvironment.js +29 -0
  16. package/dist/authReadinessEnvironment.js.map +1 -0
  17. package/dist/authReadinessFileAnalysis.d.ts +3 -0
  18. package/dist/authReadinessFileAnalysis.d.ts.map +1 -0
  19. package/dist/authReadinessFileAnalysis.js +12 -0
  20. package/dist/authReadinessFileAnalysis.js.map +1 -0
  21. package/dist/authReadinessNativeDiagnostic.d.ts +4 -0
  22. package/dist/authReadinessNativeDiagnostic.d.ts.map +1 -0
  23. package/dist/authReadinessNativeDiagnostic.js +11 -0
  24. package/dist/authReadinessNativeDiagnostic.js.map +1 -0
  25. package/dist/authReadinessProvider.d.ts +15 -0
  26. package/dist/authReadinessProvider.d.ts.map +1 -0
  27. package/dist/authReadinessProvider.js +44 -0
  28. package/dist/authReadinessProvider.js.map +1 -0
  29. package/dist/authReadinessProviderEnvironment.d.ts +15 -0
  30. package/dist/authReadinessProviderEnvironment.d.ts.map +1 -0
  31. package/dist/authReadinessProviderEnvironment.js +35 -0
  32. package/dist/authReadinessProviderEnvironment.js.map +1 -0
  33. package/dist/authReadinessRequirements.d.ts +10 -0
  34. package/dist/authReadinessRequirements.d.ts.map +1 -0
  35. package/dist/authReadinessRequirements.js +34 -0
  36. package/dist/authReadinessRequirements.js.map +1 -0
  37. package/dist/authReadinessTargetFallback.d.ts +3 -0
  38. package/dist/authReadinessTargetFallback.d.ts.map +1 -0
  39. package/dist/authReadinessTargetFallback.js +32 -0
  40. package/dist/authReadinessTargetFallback.js.map +1 -0
  41. package/dist/authReadinessTargetResolution.d.ts +8 -0
  42. package/dist/authReadinessTargetResolution.d.ts.map +1 -0
  43. package/dist/authReadinessTargetResolution.js +2 -0
  44. package/dist/authReadinessTargetResolution.js.map +1 -0
  45. package/dist/authReadinessTargets.d.ts +3 -0
  46. package/dist/authReadinessTargets.d.ts.map +1 -0
  47. package/dist/authReadinessTargets.js +26 -0
  48. package/dist/authReadinessTargets.js.map +1 -0
  49. package/dist/authReadinessUnsupported.d.ts +13 -0
  50. package/dist/authReadinessUnsupported.d.ts.map +1 -0
  51. package/dist/authReadinessUnsupported.js +22 -0
  52. package/dist/authReadinessUnsupported.js.map +1 -0
  53. package/dist/authReadinessUnsupportedBackend.d.ts +12 -0
  54. package/dist/authReadinessUnsupportedBackend.d.ts.map +1 -0
  55. package/dist/authReadinessUnsupportedBackend.js +18 -0
  56. package/dist/authReadinessUnsupportedBackend.js.map +1 -0
  57. package/dist/bunPolicyAnalysis.d.ts +3 -0
  58. package/dist/bunPolicyAnalysis.d.ts.map +1 -0
  59. package/dist/bunPolicyAnalysis.js +190 -0
  60. package/dist/bunPolicyAnalysis.js.map +1 -0
  61. package/dist/commands.d.ts.map +1 -1
  62. package/dist/commands.js +14 -0
  63. package/dist/commands.js.map +1 -1
  64. package/dist/dependencyPolicyAnalysis.d.ts.map +1 -1
  65. package/dist/dependencyPolicyAnalysis.js +6 -2
  66. package/dist/dependencyPolicyAnalysis.js.map +1 -1
  67. package/dist/diagnostics.d.ts +1 -1
  68. package/dist/diagnostics.d.ts.map +1 -1
  69. package/dist/diagnostics.js.map +1 -1
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +2 -0
  73. package/dist/index.js.map +1 -1
  74. package/dist/manifestAnalysis.d.ts.map +1 -1
  75. package/dist/manifestAnalysis.js +4 -1
  76. package/dist/manifestAnalysis.js.map +1 -1
  77. package/dist/readiness.d.ts +13 -0
  78. package/dist/readiness.d.ts.map +1 -0
  79. package/dist/readiness.js +2 -0
  80. package/dist/readiness.js.map +1 -0
  81. package/package.json +3 -2
  82. package/src/analysis.ts +2 -0
  83. package/src/authReadinessAnalysis.ts +50 -0
  84. package/src/authReadinessDiagnostic.ts +18 -0
  85. package/src/authReadinessEnvironment.ts +51 -0
  86. package/src/authReadinessFileAnalysis.ts +14 -0
  87. package/src/authReadinessNativeDiagnostic.ts +17 -0
  88. package/src/authReadinessProvider.ts +61 -0
  89. package/src/authReadinessProviderEnvironment.ts +54 -0
  90. package/src/authReadinessRequirements.ts +50 -0
  91. package/src/authReadinessTargetFallback.ts +38 -0
  92. package/src/authReadinessTargetResolution.ts +9 -0
  93. package/src/authReadinessTargets.ts +35 -0
  94. package/src/authReadinessUnsupported.ts +34 -0
  95. package/src/authReadinessUnsupportedBackend.ts +34 -0
  96. package/src/bunPolicyAnalysis.ts +261 -0
  97. package/src/commands.ts +16 -0
  98. package/src/dependencyPolicyAnalysis.ts +9 -4
  99. package/src/diagnostics.ts +9 -0
  100. package/src/index.ts +3 -0
  101. package/src/manifestAnalysis.ts +4 -1
  102. package/src/readiness.ts +14 -0
@@ -0,0 +1,15 @@
1
+ import type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';
2
+ import type { DoctorDiagnostic } from './diagnostics.js';
3
+ import type { DoctorReadiness } from './readiness.js';
4
+ export declare function analyzeAuthProviderReadiness(input: {
5
+ readonly authProvider: unknown;
6
+ readonly callbackRoute: unknown;
7
+ readonly enabledTargets: readonly AppDeployTargetId[];
8
+ readonly manifestPath: string;
9
+ readonly provider: Record<string, unknown>;
10
+ readonly targets: AppDeployTargets;
11
+ }): {
12
+ readonly diagnostics: DoctorDiagnostic[];
13
+ readonly readiness: DoctorReadiness[];
14
+ };
15
+ //# sourceMappingURL=authReadinessProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessProvider.d.ts","sourceRoot":"","sources":["../src/authReadinessProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAOvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;CACpC,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,eAAe,EAAE,CAAA;CAAE,CA2CtF"}
@@ -0,0 +1,44 @@
1
+ import { APP_DEPLOY_ENVIRONMENT_IDS } from '@ankhorage/contracts/deploy';
2
+ import { createNativeAuthCallbackDiagnostic } from './authReadinessNativeDiagnostic.js';
3
+ import { analyzeAuthProviderEnvironment } from './authReadinessProviderEnvironment.js';
4
+ import { createUnsupportedAuthDiagnostic } from './authReadinessUnsupported.js';
5
+ import { analyzeUnsupportedAuthBackend } from './authReadinessUnsupportedBackend.js';
6
+ export function analyzeAuthProviderReadiness(input) {
7
+ const providerId = typeof input.provider.id === 'string' ? input.provider.id : '';
8
+ if (providerId === '')
9
+ return { diagnostics: [], readiness: [] };
10
+ if (input.authProvider !== 'supabase') {
11
+ const result = analyzeUnsupportedAuthBackend({
12
+ enabledTargets: input.enabledTargets,
13
+ manifestPath: input.manifestPath,
14
+ provider: providerId,
15
+ });
16
+ return { diagnostics: [...result.diagnostics], readiness: [...result.readiness] };
17
+ }
18
+ const diagnostics = [];
19
+ const readiness = [];
20
+ const missingNativeTargets = new Set();
21
+ let unsupported = false;
22
+ for (const environment of APP_DEPLOY_ENVIRONMENT_IDS) {
23
+ const result = analyzeAuthProviderEnvironment({
24
+ callbackRoute: input.callbackRoute,
25
+ credentialsRef: input.provider.credentialsRef,
26
+ enabledTargets: input.enabledTargets,
27
+ environment,
28
+ provider: providerId,
29
+ targets: input.targets,
30
+ });
31
+ readiness.push(...result.readiness);
32
+ unsupported ||= result.unsupported;
33
+ result.missingNativeTargets.forEach((target) => missingNativeTargets.add(target));
34
+ }
35
+ if (unsupported) {
36
+ diagnostics.push(createUnsupportedAuthDiagnostic({
37
+ message: `OAuth provider "${providerId}" is not supported by the Supabase brokeredRedirect setup resolver.`,
38
+ path: input.manifestPath,
39
+ }));
40
+ }
41
+ missingNativeTargets.forEach((target) => diagnostics.push(createNativeAuthCallbackDiagnostic(target, input.manifestPath)));
42
+ return { diagnostics, readiness };
43
+ }
44
+ //# sourceMappingURL=authReadinessProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessProvider.js","sourceRoot":"","sources":["../src/authReadinessProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,EAAE,kCAAkC,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAIrF,MAAM,UAAU,4BAA4B,CAAC,KAO5C;IACC,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,IAAI,UAAU,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACjE,IAAI,KAAK,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,6BAA6B,CAAC;YAC3C,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE,UAAU;SACrB,CAAC,CAAC;QACH,OAAO,EAAE,WAAW,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;IACpF,CAAC;IAED,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAsB,EAAE,CAAC;IACxC,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1D,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,KAAK,MAAM,WAAW,IAAI,0BAA0B,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,8BAA8B,CAAC;YAC5C,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,cAAc;YAC7C,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,WAAW;YACX,QAAQ,EAAE,UAAU;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QACpC,WAAW,KAAK,MAAM,CAAC,WAAW,CAAC;QACnC,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,WAAW,CAAC,IAAI,CACd,+BAA+B,CAAC;YAC9B,OAAO,EAAE,mBAAmB,UAAU,qEAAqE;YAC3G,IAAI,EAAE,KAAK,CAAC,YAAY;SACzB,CAAC,CACH,CAAC;IACJ,CAAC;IACD,oBAAoB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CACtC,WAAW,CAAC,IAAI,CAAC,kCAAkC,CAAC,MAAM,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CACjF,CAAC;IACF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;AACpC,CAAC","sourcesContent":["import type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';\nimport { APP_DEPLOY_ENVIRONMENT_IDS } from '@ankhorage/contracts/deploy';\n\nimport { createNativeAuthCallbackDiagnostic } from './authReadinessNativeDiagnostic.js';\nimport { analyzeAuthProviderEnvironment } from './authReadinessProviderEnvironment.js';\nimport { createUnsupportedAuthDiagnostic } from './authReadinessUnsupported.js';\nimport { analyzeUnsupportedAuthBackend } from './authReadinessUnsupportedBackend.js';\nimport type { DoctorDiagnostic } from './diagnostics.js';\nimport type { DoctorReadiness } from './readiness.js';\n\nexport function analyzeAuthProviderReadiness(input: {\n readonly authProvider: unknown;\n readonly callbackRoute: unknown;\n readonly enabledTargets: readonly AppDeployTargetId[];\n readonly manifestPath: string;\n readonly provider: Record<string, unknown>;\n readonly targets: AppDeployTargets;\n}): { readonly diagnostics: DoctorDiagnostic[]; readonly readiness: DoctorReadiness[] } {\n const providerId = typeof input.provider.id === 'string' ? input.provider.id : '';\n if (providerId === '') return { diagnostics: [], readiness: [] };\n if (input.authProvider !== 'supabase') {\n const result = analyzeUnsupportedAuthBackend({\n enabledTargets: input.enabledTargets,\n manifestPath: input.manifestPath,\n provider: providerId,\n });\n return { diagnostics: [...result.diagnostics], readiness: [...result.readiness] };\n }\n\n const diagnostics: DoctorDiagnostic[] = [];\n const readiness: DoctorReadiness[] = [];\n const missingNativeTargets = new Set<AppDeployTargetId>();\n let unsupported = false;\n\n for (const environment of APP_DEPLOY_ENVIRONMENT_IDS) {\n const result = analyzeAuthProviderEnvironment({\n callbackRoute: input.callbackRoute,\n credentialsRef: input.provider.credentialsRef,\n enabledTargets: input.enabledTargets,\n environment,\n provider: providerId,\n targets: input.targets,\n });\n readiness.push(...result.readiness);\n unsupported ||= result.unsupported;\n result.missingNativeTargets.forEach((target) => missingNativeTargets.add(target));\n }\n\n if (unsupported) {\n diagnostics.push(\n createUnsupportedAuthDiagnostic({\n message: `OAuth provider \"${providerId}\" is not supported by the Supabase brokeredRedirect setup resolver.`,\n path: input.manifestPath,\n }),\n );\n }\n missingNativeTargets.forEach((target) =>\n diagnostics.push(createNativeAuthCallbackDiagnostic(target, input.manifestPath)),\n );\n return { diagnostics, readiness };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { AppDeployEnvironmentId, AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';
2
+ import type { DoctorReadiness } from './readiness.js';
3
+ export declare function analyzeAuthProviderEnvironment(input: {
4
+ readonly callbackRoute: unknown;
5
+ readonly credentialsRef: unknown;
6
+ readonly enabledTargets: readonly AppDeployTargetId[];
7
+ readonly environment: AppDeployEnvironmentId;
8
+ readonly provider: string;
9
+ readonly targets: AppDeployTargets;
10
+ }): {
11
+ readonly missingNativeTargets: readonly AppDeployTargetId[];
12
+ readonly readiness: readonly DoctorReadiness[];
13
+ readonly unsupported: boolean;
14
+ };
15
+ //# sourceMappingURL=authReadinessProviderEnvironment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessProviderEnvironment.d.ts","sourceRoot":"","sources":["../src/authReadinessProviderEnvironment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,6BAA6B,CAAC;AAKrC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtD,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;CACpC,GAAG;IACF,QAAQ,CAAC,oBAAoB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5D,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B,CA+BA"}
@@ -0,0 +1,35 @@
1
+ import { resolveSupabaseOAuthSetupPlan } from '@ankhorage/supabase-auth';
2
+ import { analyzeAuthReadinessEnvironment } from './authReadinessEnvironment.js';
3
+ import { createUnsupportedAuthReadiness } from './authReadinessUnsupported.js';
4
+ export function analyzeAuthProviderEnvironment(input) {
5
+ const plan = resolveSupabaseOAuthSetupPlan({
6
+ provider: input.provider,
7
+ transport: 'brokeredRedirect',
8
+ environment: input.environment,
9
+ targets: input.enabledTargets,
10
+ });
11
+ if (plan === null) {
12
+ return {
13
+ missingNativeTargets: [],
14
+ readiness: createUnsupportedAuthReadiness({
15
+ environment: input.environment,
16
+ provider: input.provider,
17
+ targets: input.enabledTargets,
18
+ }),
19
+ unsupported: true,
20
+ };
21
+ }
22
+ return {
23
+ ...analyzeAuthReadinessEnvironment({
24
+ callbackRoute: input.callbackRoute,
25
+ credentialsRef: input.credentialsRef,
26
+ enabledTargets: input.enabledTargets,
27
+ environment: input.environment,
28
+ plan,
29
+ provider: input.provider,
30
+ targets: input.targets,
31
+ }),
32
+ unsupported: false,
33
+ };
34
+ }
35
+ //# sourceMappingURL=authReadinessProviderEnvironment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessProviderEnvironment.js","sourceRoot":"","sources":["../src/authReadinessProviderEnvironment.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAG/E,MAAM,UAAU,8BAA8B,CAAC,KAO9C;IAKC,MAAM,IAAI,GAAG,6BAA6B,CAAC;QACzC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,kBAAkB;QAC7B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,KAAK,CAAC,cAAc;KAC9B,CAAC,CAAC;IACH,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO;YACL,oBAAoB,EAAE,EAAE;YACxB,SAAS,EAAE,8BAA8B,CAAC;gBACxC,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,OAAO,EAAE,KAAK,CAAC,cAAc;aAC9B,CAAC;YACF,WAAW,EAAE,IAAI;SAClB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,+BAA+B,CAAC;YACjC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,IAAI;YACJ,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;QACF,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AppDeployEnvironmentId,\n AppDeployTargetId,\n AppDeployTargets,\n} from '@ankhorage/contracts/deploy';\nimport { resolveSupabaseOAuthSetupPlan } from '@ankhorage/supabase-auth';\n\nimport { analyzeAuthReadinessEnvironment } from './authReadinessEnvironment.js';\nimport { createUnsupportedAuthReadiness } from './authReadinessUnsupported.js';\nimport type { DoctorReadiness } from './readiness.js';\n\nexport function analyzeAuthProviderEnvironment(input: {\n readonly callbackRoute: unknown;\n readonly credentialsRef: unknown;\n readonly enabledTargets: readonly AppDeployTargetId[];\n readonly environment: AppDeployEnvironmentId;\n readonly provider: string;\n readonly targets: AppDeployTargets;\n}): {\n readonly missingNativeTargets: readonly AppDeployTargetId[];\n readonly readiness: readonly DoctorReadiness[];\n readonly unsupported: boolean;\n} {\n const plan = resolveSupabaseOAuthSetupPlan({\n provider: input.provider,\n transport: 'brokeredRedirect',\n environment: input.environment,\n targets: input.enabledTargets,\n });\n if (plan === null) {\n return {\n missingNativeTargets: [],\n readiness: createUnsupportedAuthReadiness({\n environment: input.environment,\n provider: input.provider,\n targets: input.enabledTargets,\n }),\n unsupported: true,\n };\n }\n\n return {\n ...analyzeAuthReadinessEnvironment({\n callbackRoute: input.callbackRoute,\n credentialsRef: input.credentialsRef,\n enabledTargets: input.enabledTargets,\n environment: input.environment,\n plan,\n provider: input.provider,\n targets: input.targets,\n }),\n unsupported: false,\n };\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { AuthOAuthSetupPlan } from '@ankhorage/contracts/auth';
2
+ import type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';
3
+ export declare function collectMissingAuthReadinessRequirements(input: {
4
+ readonly callbackRoute: unknown;
5
+ readonly credentialsRef: unknown;
6
+ readonly plan: AuthOAuthSetupPlan;
7
+ readonly target: AppDeployTargetId;
8
+ readonly targets: AppDeployTargets;
9
+ }): readonly string[];
10
+ //# sourceMappingURL=authReadinessRequirements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessRequirements.d.ts","sourceRoot":"","sources":["../src/authReadinessRequirements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGvF,wBAAgB,uCAAuC,CAAC,KAAK,EAAE;IAC7D,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;CACpC,GAAG,SAAS,MAAM,EAAE,CAoBpB"}
@@ -0,0 +1,34 @@
1
+ import { normalizeSecretRef } from '@ankhorage/contracts/secrets';
2
+ export function collectMissingAuthReadinessRequirements(input) {
3
+ const missing = [];
4
+ if (requiresTrustedCredential(input.plan) && !hasCanonicalCredentialRef(input.credentialsRef)) {
5
+ missing.push('credential reference');
6
+ }
7
+ const callbackRequired = input.plan.requirements.some((requirement) => requirement.kind === 'callback' &&
8
+ requirement.role === 'app' &&
9
+ requirement.required &&
10
+ requirement.target === input.target);
11
+ if (!callbackRequired)
12
+ return missing;
13
+ if (!isAbsoluteRoute(input.callbackRoute))
14
+ missing.push('callback route');
15
+ if (input.target !== 'web' && input.targets[input.target]?.scheme === undefined) {
16
+ missing.push(`${input.target} deep-link scheme`);
17
+ }
18
+ return missing;
19
+ }
20
+ function requiresTrustedCredential(plan) {
21
+ return plan.requirements.some((requirement) => requirement.kind === 'field' &&
22
+ requirement.required &&
23
+ requirement.persistence === 'trustedCredential');
24
+ }
25
+ function hasCanonicalCredentialRef(value) {
26
+ if (typeof value !== 'string')
27
+ return false;
28
+ const result = normalizeSecretRef(value);
29
+ return result.ok && result.data === value;
30
+ }
31
+ function isAbsoluteRoute(value) {
32
+ return typeof value === 'string' && value.trim().startsWith('/') && value.trim().length > 0;
33
+ }
34
+ //# sourceMappingURL=authReadinessRequirements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessRequirements.js","sourceRoot":"","sources":["../src/authReadinessRequirements.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,uCAAuC,CAAC,KAMvD;IACC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,yBAAyB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CACnD,CAAC,WAAW,EAAE,EAAE,CACd,WAAW,CAAC,IAAI,KAAK,UAAU;QAC/B,WAAW,CAAC,IAAI,KAAK,KAAK;QAC1B,WAAW,CAAC,QAAQ;QACpB,WAAW,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CACtC,CAAC;IACF,IAAI,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC;IAEtC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,mBAAmB,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,yBAAyB,CAAC,IAAwB;IACzD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAC3B,CAAC,WAAW,EAAE,EAAE,CACd,WAAW,CAAC,IAAI,KAAK,OAAO;QAC5B,WAAW,CAAC,QAAQ;QACpB,WAAW,CAAC,WAAW,KAAK,mBAAmB,CAClD,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAc;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;AAC5C,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9F,CAAC","sourcesContent":["import type { AuthOAuthSetupPlan } from '@ankhorage/contracts/auth';\nimport type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';\nimport { normalizeSecretRef } from '@ankhorage/contracts/secrets';\n\nexport function collectMissingAuthReadinessRequirements(input: {\n readonly callbackRoute: unknown;\n readonly credentialsRef: unknown;\n readonly plan: AuthOAuthSetupPlan;\n readonly target: AppDeployTargetId;\n readonly targets: AppDeployTargets;\n}): readonly string[] {\n const missing: string[] = [];\n if (requiresTrustedCredential(input.plan) && !hasCanonicalCredentialRef(input.credentialsRef)) {\n missing.push('credential reference');\n }\n\n const callbackRequired = input.plan.requirements.some(\n (requirement) =>\n requirement.kind === 'callback' &&\n requirement.role === 'app' &&\n requirement.required &&\n requirement.target === input.target,\n );\n if (!callbackRequired) return missing;\n\n if (!isAbsoluteRoute(input.callbackRoute)) missing.push('callback route');\n if (input.target !== 'web' && input.targets[input.target]?.scheme === undefined) {\n missing.push(`${input.target} deep-link scheme`);\n }\n return missing;\n}\n\nfunction requiresTrustedCredential(plan: AuthOAuthSetupPlan): boolean {\n return plan.requirements.some(\n (requirement) =>\n requirement.kind === 'field' &&\n requirement.required &&\n requirement.persistence === 'trustedCredential',\n );\n}\n\nfunction hasCanonicalCredentialRef(value: unknown): boolean {\n if (typeof value !== 'string') return false;\n const result = normalizeSecretRef(value);\n return result.ok && result.data === value;\n}\n\nfunction isAbsoluteRoute(value: unknown): boolean {\n return typeof value === 'string' && value.trim().startsWith('/') && value.trim().length > 0;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { AuthReadinessTargetResolution } from './authReadinessTargetResolution.js';
2
+ export declare function resolveAuthReadinessTargetFallback(deploy: unknown, manifestPath: string): AuthReadinessTargetResolution;
3
+ //# sourceMappingURL=authReadinessTargetFallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargetFallback.d.ts","sourceRoot":"","sources":["../src/authReadinessTargetFallback.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AAExF,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,MAAM,GACnB,6BAA6B,CA+B/B"}
@@ -0,0 +1,32 @@
1
+ import { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';
2
+ export function resolveAuthReadinessTargetFallback(deploy, manifestPath) {
3
+ if (deploy === undefined) {
4
+ return {
5
+ diagnostics: [
6
+ createAuthReadinessDiagnostic({
7
+ code: 'field-missing',
8
+ message: 'deploy.targets is missing; Doctor evaluates legacy Web-only readiness until canonical targets are persisted.',
9
+ path: manifestPath,
10
+ ruleId: 'manifest.deploy.targets.legacy-web',
11
+ severity: 'warning',
12
+ }),
13
+ ],
14
+ enabledTargets: ['web'],
15
+ targets: { web: { enabled: true } },
16
+ };
17
+ }
18
+ return {
19
+ diagnostics: [
20
+ createAuthReadinessDiagnostic({
21
+ code: 'field-invalid',
22
+ message: 'manifest.deploy must match the canonical Contracts deploy target model.',
23
+ path: manifestPath,
24
+ ruleId: 'manifest.deploy.valid-shape',
25
+ severity: 'error',
26
+ }),
27
+ ],
28
+ enabledTargets: [],
29
+ targets: null,
30
+ };
31
+ }
32
+ //# sourceMappingURL=authReadinessTargetFallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargetFallback.js","sourceRoot":"","sources":["../src/authReadinessTargetFallback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAG7E,MAAM,UAAU,kCAAkC,CAChD,MAAe,EACf,YAAoB;IAEpB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO;YACL,WAAW,EAAE;gBACX,6BAA6B,CAAC;oBAC5B,IAAI,EAAE,eAAe;oBACrB,OAAO,EACL,8GAA8G;oBAChH,IAAI,EAAE,YAAY;oBAClB,MAAM,EAAE,oCAAoC;oBAC5C,QAAQ,EAAE,SAAS;iBACpB,CAAC;aACH;YACD,cAAc,EAAE,CAAC,KAAK,CAAC;YACvB,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE;YACX,6BAA6B,CAAC;gBAC5B,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,yEAAyE;gBAClF,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,6BAA6B;gBACrC,QAAQ,EAAE,OAAO;aAClB,CAAC;SACH;QACD,cAAc,EAAE,EAAE;QAClB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC","sourcesContent":["import { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';\nimport type { AuthReadinessTargetResolution } from './authReadinessTargetResolution.js';\n\nexport function resolveAuthReadinessTargetFallback(\n deploy: unknown,\n manifestPath: string,\n): AuthReadinessTargetResolution {\n if (deploy === undefined) {\n return {\n diagnostics: [\n createAuthReadinessDiagnostic({\n code: 'field-missing',\n message:\n 'deploy.targets is missing; Doctor evaluates legacy Web-only readiness until canonical targets are persisted.',\n path: manifestPath,\n ruleId: 'manifest.deploy.targets.legacy-web',\n severity: 'warning',\n }),\n ],\n enabledTargets: ['web'],\n targets: { web: { enabled: true } },\n };\n }\n\n return {\n diagnostics: [\n createAuthReadinessDiagnostic({\n code: 'field-invalid',\n message: 'manifest.deploy must match the canonical Contracts deploy target model.',\n path: manifestPath,\n ruleId: 'manifest.deploy.valid-shape',\n severity: 'error',\n }),\n ],\n enabledTargets: [],\n targets: null,\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';
2
+ import type { DoctorDiagnostic } from './diagnostics.js';
3
+ export interface AuthReadinessTargetResolution {
4
+ readonly diagnostics: readonly DoctorDiagnostic[];
5
+ readonly enabledTargets: readonly AppDeployTargetId[];
6
+ readonly targets: AppDeployTargets | null;
7
+ }
8
+ //# sourceMappingURL=authReadinessTargetResolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargetResolution.d.ts","sourceRoot":"","sources":["../src/authReadinessTargetResolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,cAAc,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtD,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC3C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=authReadinessTargetResolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargetResolution.js","sourceRoot":"","sources":["../src/authReadinessTargetResolution.ts"],"names":[],"mappings":"","sourcesContent":["import type { AppDeployTargetId, AppDeployTargets } from '@ankhorage/contracts/deploy';\n\nimport type { DoctorDiagnostic } from './diagnostics.js';\n\nexport interface AuthReadinessTargetResolution {\n readonly diagnostics: readonly DoctorDiagnostic[];\n readonly enabledTargets: readonly AppDeployTargetId[];\n readonly targets: AppDeployTargets | null;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { AuthReadinessTargetResolution } from './authReadinessTargetResolution.js';
2
+ export declare function resolveAuthReadinessTargets(deploy: unknown, manifestPath: string): AuthReadinessTargetResolution;
3
+ //# sourceMappingURL=authReadinessTargets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargets.d.ts","sourceRoot":"","sources":["../src/authReadinessTargets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AAExF,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,MAAM,GACnB,6BAA6B,CAyB/B"}
@@ -0,0 +1,26 @@
1
+ import { APP_DEPLOY_TARGET_IDS, isAppDeployManifest } from '@ankhorage/contracts/deploy';
2
+ import { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';
3
+ import { resolveAuthReadinessTargetFallback } from './authReadinessTargetFallback.js';
4
+ export function resolveAuthReadinessTargets(deploy, manifestPath) {
5
+ if (!isAppDeployManifest(deploy)) {
6
+ return resolveAuthReadinessTargetFallback(deploy, manifestPath);
7
+ }
8
+ const enabledTargets = APP_DEPLOY_TARGET_IDS.filter((target) => deploy.targets[target]?.enabled === true);
9
+ if (enabledTargets.length > 0) {
10
+ return { diagnostics: [], enabledTargets, targets: deploy.targets };
11
+ }
12
+ return {
13
+ diagnostics: [
14
+ createAuthReadinessDiagnostic({
15
+ code: 'field-missing',
16
+ message: 'manifest.deploy.targets must enable at least one application target.',
17
+ path: manifestPath,
18
+ ruleId: 'manifest.deploy.targets.enabled',
19
+ severity: 'error',
20
+ }),
21
+ ],
22
+ enabledTargets,
23
+ targets: deploy.targets,
24
+ };
25
+ }
26
+ //# sourceMappingURL=authReadinessTargets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessTargets.js","sourceRoot":"","sources":["../src/authReadinessTargets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEzF,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AAGtF,MAAM,UAAU,2BAA2B,CACzC,MAAe,EACf,YAAoB;IAEpB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,kCAAkC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CACjD,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CACrD,CAAC;IACF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACtE,CAAC;IAED,OAAO;QACL,WAAW,EAAE;YACX,6BAA6B,CAAC;gBAC5B,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,sEAAsE;gBAC/E,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,iCAAiC;gBACzC,QAAQ,EAAE,OAAO;aAClB,CAAC;SACH;QACD,cAAc;QACd,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;AACJ,CAAC","sourcesContent":["import { APP_DEPLOY_TARGET_IDS, isAppDeployManifest } from '@ankhorage/contracts/deploy';\n\nimport { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';\nimport { resolveAuthReadinessTargetFallback } from './authReadinessTargetFallback.js';\nimport type { AuthReadinessTargetResolution } from './authReadinessTargetResolution.js';\n\nexport function resolveAuthReadinessTargets(\n deploy: unknown,\n manifestPath: string,\n): AuthReadinessTargetResolution {\n if (!isAppDeployManifest(deploy)) {\n return resolveAuthReadinessTargetFallback(deploy, manifestPath);\n }\n\n const enabledTargets = APP_DEPLOY_TARGET_IDS.filter(\n (target) => deploy.targets[target]?.enabled === true,\n );\n if (enabledTargets.length > 0) {\n return { diagnostics: [], enabledTargets, targets: deploy.targets };\n }\n\n return {\n diagnostics: [\n createAuthReadinessDiagnostic({\n code: 'field-missing',\n message: 'manifest.deploy.targets must enable at least one application target.',\n path: manifestPath,\n ruleId: 'manifest.deploy.targets.enabled',\n severity: 'error',\n }),\n ],\n enabledTargets,\n targets: deploy.targets,\n };\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import type { AppDeployEnvironmentId, AppDeployTargetId } from '@ankhorage/contracts/deploy';
2
+ import type { DoctorDiagnostic } from './diagnostics.js';
3
+ import type { DoctorReadiness } from './readiness.js';
4
+ export declare function createUnsupportedAuthReadiness(input: {
5
+ readonly environment: AppDeployEnvironmentId;
6
+ readonly provider: string;
7
+ readonly targets: readonly AppDeployTargetId[];
8
+ }): DoctorReadiness[];
9
+ export declare function createUnsupportedAuthDiagnostic(input: {
10
+ readonly message: string;
11
+ readonly path: string;
12
+ }): DoctorDiagnostic;
13
+ //# sourceMappingURL=authReadinessUnsupported.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessUnsupported.d.ts","sourceRoot":"","sources":["../src/authReadinessUnsupported.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAG7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAChD,GAAG,eAAe,EAAE,CAUpB;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GAAG,gBAAgB,CAQnB"}
@@ -0,0 +1,22 @@
1
+ import { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';
2
+ export function createUnsupportedAuthReadiness(input) {
3
+ return input.targets.map((target) => ({
4
+ category: 'auth-oauth',
5
+ environment: input.environment,
6
+ message: 'The selected backend/provider/transport combination has no setup capability.',
7
+ provider: input.provider,
8
+ status: 'unsupported',
9
+ target,
10
+ transport: 'brokeredRedirect',
11
+ }));
12
+ }
13
+ export function createUnsupportedAuthDiagnostic(input) {
14
+ return createAuthReadinessDiagnostic({
15
+ code: 'field-invalid',
16
+ message: input.message,
17
+ path: input.path,
18
+ ruleId: 'manifest.auth.oauth.setup.supported',
19
+ severity: 'error',
20
+ });
21
+ }
22
+ //# sourceMappingURL=authReadinessUnsupported.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessUnsupported.js","sourceRoot":"","sources":["../src/authReadinessUnsupported.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAI7E,MAAM,UAAU,8BAA8B,CAAC,KAI9C;IACC,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACpC,QAAQ,EAAE,YAAY;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,8EAA8E;QACvF,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,aAAa;QACrB,MAAM;QACN,SAAS,EAAE,kBAAkB;KAC9B,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,KAG/C;IACC,OAAO,6BAA6B,CAAC;QACnC,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,qCAAqC;QAC7C,QAAQ,EAAE,OAAO;KAClB,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { AppDeployEnvironmentId, AppDeployTargetId } from '@ankhorage/contracts/deploy';\n\nimport { createAuthReadinessDiagnostic } from './authReadinessDiagnostic.js';\nimport type { DoctorDiagnostic } from './diagnostics.js';\nimport type { DoctorReadiness } from './readiness.js';\n\nexport function createUnsupportedAuthReadiness(input: {\n readonly environment: AppDeployEnvironmentId;\n readonly provider: string;\n readonly targets: readonly AppDeployTargetId[];\n}): DoctorReadiness[] {\n return input.targets.map((target) => ({\n category: 'auth-oauth',\n environment: input.environment,\n message: 'The selected backend/provider/transport combination has no setup capability.',\n provider: input.provider,\n status: 'unsupported',\n target,\n transport: 'brokeredRedirect',\n }));\n}\n\nexport function createUnsupportedAuthDiagnostic(input: {\n readonly message: string;\n readonly path: string;\n}): DoctorDiagnostic {\n return createAuthReadinessDiagnostic({\n code: 'field-invalid',\n message: input.message,\n path: input.path,\n ruleId: 'manifest.auth.oauth.setup.supported',\n severity: 'error',\n });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { AppDeployTargetId } from '@ankhorage/contracts/deploy';
2
+ import type { DoctorDiagnostic } from './diagnostics.js';
3
+ import type { DoctorReadiness } from './readiness.js';
4
+ export declare function analyzeUnsupportedAuthBackend(input: {
5
+ readonly enabledTargets: readonly AppDeployTargetId[];
6
+ readonly manifestPath: string;
7
+ readonly provider: string;
8
+ }): {
9
+ readonly diagnostics: readonly DoctorDiagnostic[];
10
+ readonly readiness: readonly DoctorReadiness[];
11
+ };
12
+ //# sourceMappingURL=authReadinessUnsupportedBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessUnsupportedBackend.d.ts","sourceRoot":"","sources":["../src/authReadinessUnsupportedBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAOrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,QAAQ,CAAC,cAAc,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,GAAG;IACF,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;CAChD,CAgBA"}
@@ -0,0 +1,18 @@
1
+ import { APP_DEPLOY_ENVIRONMENT_IDS } from '@ankhorage/contracts/deploy';
2
+ import { createUnsupportedAuthDiagnostic, createUnsupportedAuthReadiness, } from './authReadinessUnsupported.js';
3
+ export function analyzeUnsupportedAuthBackend(input) {
4
+ return {
5
+ diagnostics: [
6
+ createUnsupportedAuthDiagnostic({
7
+ message: 'Configured OAuth backend has no Doctor setup resolver.',
8
+ path: input.manifestPath,
9
+ }),
10
+ ],
11
+ readiness: APP_DEPLOY_ENVIRONMENT_IDS.flatMap((environment) => createUnsupportedAuthReadiness({
12
+ environment,
13
+ provider: input.provider,
14
+ targets: input.enabledTargets,
15
+ })),
16
+ };
17
+ }
18
+ //# sourceMappingURL=authReadinessUnsupportedBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authReadinessUnsupportedBackend.js","sourceRoot":"","sources":["../src/authReadinessUnsupportedBackend.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,+BAA+B,CAAC;AAIvC,MAAM,UAAU,6BAA6B,CAAC,KAI7C;IAIC,OAAO;QACL,WAAW,EAAE;YACX,+BAA+B,CAAC;gBAC9B,OAAO,EAAE,wDAAwD;gBACjE,IAAI,EAAE,KAAK,CAAC,YAAY;aACzB,CAAC;SACH;QACD,SAAS,EAAE,0BAA0B,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAC5D,8BAA8B,CAAC;YAC7B,WAAW;YACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,cAAc;SAC9B,CAAC,CACH;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { AppDeployTargetId } from '@ankhorage/contracts/deploy';\nimport { APP_DEPLOY_ENVIRONMENT_IDS } from '@ankhorage/contracts/deploy';\n\nimport {\n createUnsupportedAuthDiagnostic,\n createUnsupportedAuthReadiness,\n} from './authReadinessUnsupported.js';\nimport type { DoctorDiagnostic } from './diagnostics.js';\nimport type { DoctorReadiness } from './readiness.js';\n\nexport function analyzeUnsupportedAuthBackend(input: {\n readonly enabledTargets: readonly AppDeployTargetId[];\n readonly manifestPath: string;\n readonly provider: string;\n}): {\n readonly diagnostics: readonly DoctorDiagnostic[];\n readonly readiness: readonly DoctorReadiness[];\n} {\n return {\n diagnostics: [\n createUnsupportedAuthDiagnostic({\n message: 'Configured OAuth backend has no Doctor setup resolver.',\n path: input.manifestPath,\n }),\n ],\n readiness: APP_DEPLOY_ENVIRONMENT_IDS.flatMap((environment) =>\n createUnsupportedAuthReadiness({\n environment,\n provider: input.provider,\n targets: input.enabledTargets,\n }),\n ),\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { DoctorAnalysisResult } from './analysis.js';
2
+ export declare function applyBunRuntimePolicy(result: DoctorAnalysisResult): Promise<DoctorAnalysisResult>;
3
+ //# sourceMappingURL=bunPolicyAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bunPolicyAnalysis.d.ts","sourceRoot":"","sources":["../src/bunPolicyAnalysis.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAuB1D,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAmB/B"}
@@ -0,0 +1,190 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ const DEVTOOLS_POLICY_SPECIFIER = '@ankhorage/devtools/policy';
6
+ const REPAIR_HINT = 'Run "ankh devtools sync" to repair the managed Bun state.';
7
+ const BUN_VERSION_PATTERN = /^\s*bun-version:\s*['"]?([^'"\s#]+)['"]?\s*(?:#.*)?$/mu;
8
+ const WORKFLOWS = [
9
+ {
10
+ relativePath: path.join('.github', 'workflows', 'ci.yml'),
11
+ ruleId: 'repo.workflows.ci.bun-policy',
12
+ },
13
+ {
14
+ relativePath: path.join('.github', 'workflows', 'release.yml'),
15
+ ruleId: 'repo.workflows.release.bun-policy',
16
+ },
17
+ ];
18
+ export async function applyBunRuntimePolicy(result) {
19
+ if (result.profile !== 'public-package' || !result.hasPackageJson) {
20
+ return result;
21
+ }
22
+ const policy = await loadTargetBunRuntimePolicy(result.targetPath);
23
+ const packageJsonPath = path.join(result.targetPath, 'package.json');
24
+ const packageJson = await readPackageJson(packageJsonPath);
25
+ if (policy === null || packageJson === null) {
26
+ return result;
27
+ }
28
+ const diagnostics = [
29
+ ...result.diagnostics,
30
+ ...analyzePackageBunPolicy(packageJson, packageJsonPath, result, policy),
31
+ ...(await analyzeWorkflowBunPolicy(result, policy)),
32
+ ];
33
+ return withDiagnostics(result, diagnostics);
34
+ }
35
+ async function loadTargetBunRuntimePolicy(targetPath) {
36
+ const requireFromTarget = createRequire(path.join(targetPath, 'package.json'));
37
+ try {
38
+ const modulePath = requireFromTarget.resolve(DEVTOOLS_POLICY_SPECIFIER);
39
+ const importedModule = (await import(pathToFileURL(modulePath).href));
40
+ return parseBunRuntimePolicy(importedModule);
41
+ }
42
+ catch (error) {
43
+ if (isUnavailablePolicyError(error)) {
44
+ return null;
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ function analyzePackageBunPolicy(packageJson, packageJsonPath, result, policy) {
50
+ const diagnostics = [];
51
+ const { packageManager } = packageJson;
52
+ if (isNonEmptyString(packageManager) && packageManager.startsWith('bun@')) {
53
+ pushMismatch(diagnostics, {
54
+ actual: packageManager,
55
+ expected: policy.packageManager,
56
+ location: 'package.json#packageManager',
57
+ path: packageJsonPath,
58
+ profile: result.profile,
59
+ ruleId: 'package.json.package-manager.policy',
60
+ });
61
+ }
62
+ const devDependencies = isRecord(packageJson.devDependencies)
63
+ ? packageJson.devDependencies
64
+ : null;
65
+ const bunTypes = devDependencies?.['@types/bun'];
66
+ if (isNonEmptyString(bunTypes)) {
67
+ pushMismatch(diagnostics, {
68
+ actual: bunTypes,
69
+ expected: policy.typesRange,
70
+ location: 'package.json#devDependencies.@types/bun',
71
+ path: packageJsonPath,
72
+ profile: result.profile,
73
+ ruleId: 'package.dependencies.types-bun.policy',
74
+ });
75
+ }
76
+ return diagnostics;
77
+ }
78
+ async function analyzeWorkflowBunPolicy(result, policy) {
79
+ const diagnostics = await Promise.all(WORKFLOWS.map(async (workflow) => await analyzeWorkflow(result, workflow, policy)));
80
+ return diagnostics.flat();
81
+ }
82
+ async function analyzeWorkflow(result, workflow, policy) {
83
+ const workflowPath = path.join(result.targetPath, workflow.relativePath);
84
+ const contents = await readTextOrNull(workflowPath);
85
+ if (contents === null) {
86
+ return [createWorkflowDiagnostic(result, workflow, policy, workflowPath, 'missing-path')];
87
+ }
88
+ const match = BUN_VERSION_PATTERN.exec(contents);
89
+ const actual = match?.[1];
90
+ if (!isNonEmptyString(actual)) {
91
+ return [createWorkflowDiagnostic(result, workflow, policy, workflowPath, 'field-missing')];
92
+ }
93
+ const diagnostics = [];
94
+ pushMismatch(diagnostics, {
95
+ actual,
96
+ expected: policy.version,
97
+ location: `${workflow.relativePath}#bun-version`,
98
+ path: workflowPath,
99
+ profile: result.profile,
100
+ ruleId: workflow.ruleId,
101
+ });
102
+ return diagnostics;
103
+ }
104
+ function createWorkflowDiagnostic(result, workflow, policy, workflowPath, code) {
105
+ const detail = code === 'missing-path'
106
+ ? `Managed workflow is missing: ${workflow.relativePath}.`
107
+ : `${workflow.relativePath} does not define bun-version.`;
108
+ return {
109
+ code,
110
+ message: `${detail} Expected Bun ${policy.version}. ${REPAIR_HINT}`,
111
+ path: workflowPath,
112
+ profile: result.profile,
113
+ ruleId: workflow.ruleId,
114
+ severity: 'error',
115
+ };
116
+ }
117
+ function pushMismatch(diagnostics, input) {
118
+ if (input.actual === input.expected) {
119
+ return;
120
+ }
121
+ diagnostics.push({
122
+ code: 'field-invalid',
123
+ message: `Bun policy drift at ${input.location}: expected "${input.expected}", found "${input.actual}". ${REPAIR_HINT}`,
124
+ path: input.path,
125
+ profile: input.profile,
126
+ ruleId: input.ruleId,
127
+ severity: 'error',
128
+ });
129
+ }
130
+ function parseBunRuntimePolicy(importedModule) {
131
+ if (!isRecord(importedModule) || !isRecord(importedModule.bunRuntimePolicy)) {
132
+ return null;
133
+ }
134
+ const { packageManager, typesRange, version } = importedModule.bunRuntimePolicy;
135
+ return isNonEmptyString(packageManager) &&
136
+ isNonEmptyString(typesRange) &&
137
+ isNonEmptyString(version)
138
+ ? { packageManager, typesRange, version }
139
+ : null;
140
+ }
141
+ function withDiagnostics(result, diagnostics) {
142
+ return {
143
+ ...result,
144
+ diagnostics,
145
+ fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },
146
+ };
147
+ }
148
+ async function readPackageJson(packageJsonPath) {
149
+ try {
150
+ const parsed = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
151
+ return isRecord(parsed) ? parsed : null;
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ async function readTextOrNull(filePath) {
158
+ try {
159
+ return await fs.readFile(filePath, 'utf8');
160
+ }
161
+ catch (error) {
162
+ if (isNodeError(error) && error.code === 'ENOENT') {
163
+ return null;
164
+ }
165
+ throw error;
166
+ }
167
+ }
168
+ function isUnavailablePolicyError(error) {
169
+ if (isNodeError(error) &&
170
+ (error.code === 'MODULE_NOT_FOUND' ||
171
+ error.code === 'ERR_MODULE_NOT_FOUND' ||
172
+ error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')) {
173
+ return true;
174
+ }
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ return (message.includes(DEVTOOLS_POLICY_SPECIFIER) &&
177
+ (message.includes('Cannot find module') ||
178
+ message.includes('not exported') ||
179
+ message.includes('Package subpath')));
180
+ }
181
+ function isNonEmptyString(value) {
182
+ return typeof value === 'string' && value.trim() !== '';
183
+ }
184
+ function isRecord(value) {
185
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
186
+ }
187
+ function isNodeError(error) {
188
+ return error instanceof Error && 'code' in error;
189
+ }
190
+ //# sourceMappingURL=bunPolicyAnalysis.js.map