anhedral 0.10.0 → 0.11.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 (120) hide show
  1. package/README.md +78 -39
  2. package/assets/{anhedral-cli-init-technical.svg → anhedral-stack-technical.svg} +6 -6
  3. package/assets/{anhedral-cli-init.svg → anhedral-stack.svg} +7 -7
  4. package/assets/security/audit-deps.mjs +6 -1
  5. package/dist/bin.js +271 -154
  6. package/dist/bounded-file.d.ts +1 -0
  7. package/dist/bounded-file.js +1 -0
  8. package/dist/capabilities.d.ts +4 -4
  9. package/dist/capabilities.js +1 -1
  10. package/dist/capability-contract.d.ts +47 -0
  11. package/dist/capability-contract.js +136 -0
  12. package/dist/cli-arguments.d.ts +16 -0
  13. package/dist/cli-arguments.js +115 -0
  14. package/dist/cli-output.d.ts +8 -0
  15. package/dist/cli-output.js +211 -0
  16. package/dist/cloudflare.d.ts +7 -2
  17. package/dist/cloudflare.js +166 -36
  18. package/dist/command-schema.d.ts +21 -0
  19. package/dist/command-schema.js +374 -0
  20. package/dist/delivery.d.ts +2 -2
  21. package/dist/delivery.js +21 -4
  22. package/dist/dependencies.d.ts +32 -0
  23. package/dist/dependencies.js +47 -1
  24. package/dist/index.d.ts +23 -1
  25. package/dist/index.js +15 -1
  26. package/dist/inspector-model.d.ts +115 -0
  27. package/dist/inspector-model.js +1 -0
  28. package/dist/lifecycle-model.d.ts +15 -0
  29. package/dist/lifecycle-model.js +20 -0
  30. package/dist/lifecycle.d.ts +12 -0
  31. package/dist/lifecycle.js +92 -0
  32. package/dist/mobile-delivery.d.ts +100 -0
  33. package/dist/mobile-delivery.js +319 -0
  34. package/dist/platforms/desktop.js +4 -5
  35. package/dist/platforms/extension.js +9 -73
  36. package/dist/platforms/mobile.js +14 -52
  37. package/dist/project-inspector.d.ts +4 -0
  38. package/dist/project-inspector.js +646 -0
  39. package/dist/project-state.d.ts +17 -0
  40. package/dist/project-state.js +239 -11
  41. package/dist/provider-auth.d.ts +41 -0
  42. package/dist/provider-auth.js +210 -0
  43. package/dist/providers/adapters.d.ts +17 -0
  44. package/dist/providers/adapters.js +269 -0
  45. package/dist/providers/api.d.ts +28 -0
  46. package/dist/providers/api.js +252 -0
  47. package/dist/providers/config.d.ts +15 -0
  48. package/dist/providers/config.js +184 -0
  49. package/dist/providers/definitions.d.ts +318 -0
  50. package/dist/providers/definitions.js +127 -0
  51. package/dist/providers/provision.d.ts +24 -0
  52. package/dist/providers/provision.js +76 -0
  53. package/dist/providers/receipts.d.ts +20 -0
  54. package/dist/providers/receipts.js +66 -0
  55. package/dist/providers/recovery-verification.d.ts +7 -0
  56. package/dist/providers/recovery-verification.js +112 -0
  57. package/dist/providers/recovery.d.ts +30 -0
  58. package/dist/providers/recovery.js +34 -0
  59. package/dist/providers/runtime.d.ts +10 -0
  60. package/dist/providers/runtime.js +231 -0
  61. package/dist/providers/schema.d.ts +28 -0
  62. package/dist/providers/schema.js +49 -0
  63. package/dist/providers/state.d.ts +56 -0
  64. package/dist/providers/state.js +329 -0
  65. package/dist/provision.d.ts +1 -1
  66. package/dist/provision.js +61 -3
  67. package/dist/readiness.js +11 -3
  68. package/dist/registry/add.d.ts +6 -0
  69. package/dist/registry/add.js +35 -4
  70. package/dist/registry/commands.d.ts +3 -2
  71. package/dist/registry/commands.js +53 -14
  72. package/dist/registry/options.js +3 -2
  73. package/dist/registry/preview.d.ts +11 -0
  74. package/dist/registry/preview.js +91 -0
  75. package/dist/registry/receipt.js +1 -0
  76. package/dist/registry/resolve.js +19 -13
  77. package/dist/registry/types.d.ts +1 -0
  78. package/dist/registry/usage.d.ts +10 -0
  79. package/dist/registry/usage.js +22 -37
  80. package/dist/render.d.ts +2 -0
  81. package/dist/render.js +10 -0
  82. package/dist/scaffold/api.js +20 -3
  83. package/dist/scaffold/auth.js +68 -28
  84. package/dist/scaffold/bootstrap.d.ts +2 -0
  85. package/dist/scaffold/bootstrap.js +9 -0
  86. package/dist/scaffold/database.js +12 -6
  87. package/dist/scaffold/documentation.js +11 -8
  88. package/dist/scaffold/environment.d.ts +2 -0
  89. package/dist/scaffold/environment.js +18 -1
  90. package/dist/scaffold/files.d.ts +1 -0
  91. package/dist/scaffold/files.js +15 -4
  92. package/dist/scaffold/services.js +37 -13
  93. package/dist/scaffold/stack-documentation.d.ts +3 -0
  94. package/dist/scaffold/stack-documentation.js +52 -0
  95. package/dist/scaffold/styling.d.ts +3 -0
  96. package/dist/scaffold/styling.js +84 -0
  97. package/dist/scaffold/web.js +31 -11
  98. package/dist/scaffold/workspace.js +49 -22
  99. package/dist/ship.d.ts +320 -0
  100. package/dist/ship.js +211 -0
  101. package/dist/stack-registry.d.ts +2 -2
  102. package/dist/stack-registry.js +44 -11
  103. package/dist/standard.d.ts +2 -1
  104. package/dist/standard.js +13 -12
  105. package/dist/vercel.d.ts +3 -3
  106. package/dist/vercel.js +27 -1
  107. package/dist/version.d.ts +1 -1
  108. package/dist/version.js +1 -1
  109. package/dist/vinext.js +9 -18
  110. package/dist/workspace-graph.js +3 -2
  111. package/docs/application-stack-standard.md +51 -80
  112. package/docs/cli-design.md +67 -0
  113. package/docs/delivery-workflow.md +29 -15
  114. package/docs/plugin-ui.md +61 -0
  115. package/docs/provider-configuration.md +117 -0
  116. package/package.json +16 -12
  117. package/dist/managed-hosting.d.ts +0 -49
  118. package/dist/managed-hosting.js +0 -373
  119. package/docs/managed-hosting-architecture.md +0 -87
  120. package/docs/sponsorships.md +0 -25
package/dist/delivery.js CHANGED
@@ -69,7 +69,7 @@ function history(root, project) {
69
69
  throw new Error('Release history belongs to a different or unsupported project.');
70
70
  return value;
71
71
  }
72
- function checkTargets(root, project) {
72
+ function checkTargets(root, project, allowResourcePlaceholders = false) {
73
73
  if (!project.targets.length)
74
74
  throw new Error('No Cloudflare targets; native applications require their platform delivery tools.');
75
75
  for (const target of project.targets) {
@@ -80,7 +80,24 @@ function checkTargets(root, project) {
80
80
  throw new Error('Worker name or environment changed; reconcile the application manifest before shipping.');
81
81
  if (config.account_id && config.account_id !== project.accountId)
82
82
  throw new Error('Wrangler configuration account conflicts with the registered account.');
83
- if (/REPLACE_WITH_|YOUR_[A-Z_]+/.test(readFileSync(path.join(directory, 'wrangler.jsonc'), 'utf8')))
83
+ const pending = structuredClone(config);
84
+ if (allowResourcePlaceholders) {
85
+ for (const [field, id] of [
86
+ ['d1_databases', 'database_id'],
87
+ ['kv_namespaces', 'id'],
88
+ ['pipelines', 'stream'],
89
+ ]) {
90
+ const entries = pending[field];
91
+ if (Array.isArray(entries))
92
+ for (const entry of entries) {
93
+ if (entry && typeof entry[id] === 'string' && entry[id].startsWith('REPLACE_WITH_'))
94
+ entry[id] = 'pending-resource';
95
+ }
96
+ }
97
+ }
98
+ if (/REPLACE_WITH_|YOUR_[A-Z_]+/.test(allowResourcePlaceholders
99
+ ? JSON.stringify(pending)
100
+ : readFileSync(path.join(directory, 'wrangler.jsonc'), 'utf8')))
84
101
  throw new Error('Configure selected resources before shipping; placeholder bindings remain.');
85
102
  const pkg = JSON.parse(readFileSync(path.join(directory, 'package.json'), 'utf8'));
86
103
  if (typeof pkg.scripts?.deploy !== 'string')
@@ -93,9 +110,9 @@ function configurationFingerprint(root, project) {
93
110
  hash.update(readFileSync(path.join(targetDirectory(root, target), 'wrangler.jsonc')));
94
111
  return hash.digest('hex');
95
112
  }
96
- export function planDelivery(root) {
113
+ export function planDelivery(root, allowResourcePlaceholders = false) {
97
114
  const project = readApplication(root);
98
- checkTargets(root, project);
115
+ checkTargets(root, project, allowResourcePlaceholders);
99
116
  return {
100
117
  project,
101
118
  checks: [['pnpm', 'run', 'check']],
@@ -2,14 +2,21 @@ export interface DependencyGroup {
2
2
  dependencies?: Record<string, string>;
3
3
  devDependencies?: Record<string, string>;
4
4
  }
5
+ export declare const NATIVE_ESLINT_VERSION = "10.0.3";
5
6
  export declare const DESKTOP_DEPENDENCIES: DependencyGroup;
6
7
  export declare const EXTENSION_DEPENDENCIES: DependencyGroup;
7
8
  export declare const MOBILE_APP_DEPENDENCIES: DependencyGroup;
8
9
  export declare const MOBILE_NATIVEWIND_DEPENDENCIES: DependencyGroup;
10
+ export declare const WORKSPACE_NODE_ENGINE = "^22.13.0 || >=24.0.0";
9
11
  export declare const PACKAGE_MANAGER = "pnpm@10.34.5";
10
12
  export declare const EAS_CLI_VERSION = "21.0.1";
11
13
  export declare const SHADCN_VERSION = "4.21.4";
14
+ export declare const NEXT_VERCEL_VERSION = "16.4.0";
15
+ export declare const NEXT_OPENNEXT_VERSION = "16.3.8";
12
16
  export declare const STACK_DEPENDENCIES: {
17
+ readonly 'better-auth': "1.7.7";
18
+ readonly '@better-auth/drizzle-adapter': "1.7.7";
19
+ readonly '@neondatabase/serverless': "1.2.0";
13
20
  readonly 'drizzle-orm': "0.45.4";
14
21
  readonly '@clerk/nextjs': "7.9.14";
15
22
  readonly '@clerk/backend': "3.23.2";
@@ -30,3 +37,28 @@ export declare const STACK_DEPENDENCIES: {
30
37
  readonly stripe: "20.4.1";
31
38
  readonly 'posthog-node': "5.55.2";
32
39
  };
40
+ /** Vinext's RSC/React versions form a separately verified compatibility group. */
41
+ export declare const VINEXT_DEPENDENCIES: DependencyGroup;
42
+ /** Separate HTTP and inspector ports let all selected Workers run together. */
43
+ export declare const WORKER_DEV_PORTS: {
44
+ readonly api: {
45
+ readonly http: 8787;
46
+ readonly inspector: 9231;
47
+ };
48
+ readonly realtime: {
49
+ readonly http: 8788;
50
+ readonly inspector: 9232;
51
+ };
52
+ readonly jobs: {
53
+ readonly http: 8789;
54
+ readonly inspector: 9233;
55
+ };
56
+ readonly scheduled: {
57
+ readonly http: 8790;
58
+ readonly inspector: 9234;
59
+ };
60
+ readonly workflows: {
61
+ readonly http: 8791;
62
+ readonly inspector: 9235;
63
+ };
64
+ };
@@ -1,3 +1,5 @@
1
+ // renovate: datasource=npm depName=eslint
2
+ export const NATIVE_ESLINT_VERSION = '10.0.3';
1
3
  export const DESKTOP_DEPENDENCIES = {
2
4
  dependencies: {
3
5
  // renovate: datasource=npm depName=react
@@ -24,7 +26,7 @@ export const DESKTOP_DEPENDENCIES = {
24
26
  electron: '43.7.8',
25
27
  // renovate: datasource=npm depName=electron-builder
26
28
  'electron-builder': '26.15.3',
27
- eslint: '10.0.3',
29
+ eslint: NATIVE_ESLINT_VERSION,
28
30
  // renovate: datasource=npm depName=tailwindcss
29
31
  tailwindcss: '4.1.18',
30
32
  // renovate: datasource=npm depName=postcss
@@ -129,12 +131,23 @@ export const MOBILE_NATIVEWIND_DEPENDENCIES = {
129
131
  tailwindcss: '3.4.19',
130
132
  },
131
133
  };
134
+ export const WORKSPACE_NODE_ENGINE = '^22.13.0 || >=24.0.0';
132
135
  export const PACKAGE_MANAGER = 'pnpm@10.34.5';
133
136
  // renovate: datasource=npm depName=eas-cli
134
137
  export const EAS_CLI_VERSION = '21.0.1';
135
138
  // renovate: datasource=npm depName=shadcn
136
139
  export const SHADCN_VERSION = '4.21.4';
140
+ // renovate: datasource=npm depName=next
141
+ export const NEXT_VERCEL_VERSION = '16.4.0';
142
+ // renovate: datasource=npm depName=next
143
+ export const NEXT_OPENNEXT_VERSION = '16.3.8';
137
144
  export const STACK_DEPENDENCIES = {
145
+ // renovate: datasource=npm depName=better-auth
146
+ 'better-auth': '1.7.7',
147
+ // renovate: datasource=npm depName=@better-auth/drizzle-adapter
148
+ '@better-auth/drizzle-adapter': '1.7.7',
149
+ // renovate: datasource=npm depName=@neondatabase/serverless
150
+ '@neondatabase/serverless': '1.2.0',
138
151
  // renovate: datasource=npm depName=drizzle-orm
139
152
  'drizzle-orm': '0.45.4',
140
153
  // renovate: datasource=npm depName=@clerk/nextjs
@@ -174,3 +187,36 @@ export const STACK_DEPENDENCIES = {
174
187
  // renovate: datasource=npm depName=posthog-node
175
188
  'posthog-node': '5.55.2',
176
189
  };
190
+ /** Vinext's RSC/React versions form a separately verified compatibility group. */
191
+ export const VINEXT_DEPENDENCIES = {
192
+ dependencies: {
193
+ // renovate: datasource=npm depName=vinext
194
+ vinext: '1.1.0',
195
+ next: NEXT_VERCEL_VERSION,
196
+ // renovate: datasource=npm depName=react
197
+ react: '19.2.8',
198
+ // renovate: datasource=npm depName=react-dom
199
+ 'react-dom': '19.2.8',
200
+ // renovate: datasource=npm depName=react-server-dom-webpack
201
+ 'react-server-dom-webpack': '19.2.8',
202
+ },
203
+ devDependencies: {
204
+ // renovate: datasource=npm depName=vite
205
+ vite: '8.3.4',
206
+ // renovate: datasource=npm depName=@cloudflare/vite-plugin
207
+ '@cloudflare/vite-plugin': '1.63.1',
208
+ // renovate: datasource=npm depName=@vitejs/plugin-rsc
209
+ '@vitejs/plugin-rsc': '0.5.36',
210
+ // renovate: datasource=npm depName=@vitejs/plugin-react
211
+ '@vitejs/plugin-react': '6.1.2',
212
+ wrangler: STACK_DEPENDENCIES.wrangler,
213
+ },
214
+ };
215
+ /** Separate HTTP and inspector ports let all selected Workers run together. */
216
+ export const WORKER_DEV_PORTS = {
217
+ api: { http: 8787, inspector: 9231 },
218
+ realtime: { http: 8788, inspector: 9232 },
219
+ jobs: { http: 8789, inspector: 9233 },
220
+ scheduled: { http: 8790, inspector: 9234 },
221
+ workflows: { http: 8791, inspector: 9235 },
222
+ };
package/dist/index.d.ts CHANGED
@@ -10,7 +10,6 @@ export { planProvisioning, provisionApplication } from './provision.js';
10
10
  export { registerVercelApplication, connectVercelApplication, planVercelDelivery, shipVercelApplication, vercelApplicationStatus, verifyVercelApplication, rollbackVercelApplication, adoptVercelApplication, recoverVercelApplication, } from './vercel.js';
11
11
  export { setupRepository, githubRepository } from './repository.js';
12
12
  export { inspectProviderReadiness } from './provider-readiness.js';
13
- export { registerManagedApplication, stageManagedVersion, saveManagedVersion, deployManagedVersion, managedApplicationStatus, } from './managed-hosting.js';
14
13
  export { STACK_REGISTRY, STACK_ITEMS, getStackItem } from './stack-registry.js';
15
14
  export type { StackItemId } from './stack-registry.js';
16
15
  export type { StackRegistryItem } from './registry/types.js';
@@ -19,3 +18,26 @@ export { resolveStackRegistry } from './registry/resolve.js';
19
18
  export type { ResolvedStackRegistry } from './registry/resolve.js';
20
19
  export { addStackItems } from './registry/add.js';
21
20
  export type { AddRequest } from './registry/add.js';
21
+ export { PROVIDER_AUTH, requiredProviders, authenticateProviders } from './provider-auth.js';
22
+ export type { ProviderAuth, AuthOptions, AuthCheck } from './provider-auth.js';
23
+ export { buildMobileApplication } from './mobile-delivery.js';
24
+ export type { MobileBuildOptions } from './mobile-delivery.js';
25
+ export { shipCloudflareApplication } from './ship.js';
26
+ export { shipSelectedStack, shipSelectedVercelApplication } from './ship.js';
27
+ export { planProviderProvisioning, provisionSelectedProviders } from './providers/provision.js';
28
+ export { providerConfigurationTemplate } from './providers/config.js';
29
+ export type { ProviderConfiguration, IntegrationProvider } from './providers/config.js';
30
+ export { validateProviderConfiguration } from './providers/config.js';
31
+ export { PROVIDER_CONFIGURATION_SCHEMA } from './providers/schema.js';
32
+ export { PROVIDER_DEFINITIONS } from './providers/definitions.js';
33
+ export type { ProviderSettingsById } from './providers/definitions.js';
34
+ export { applicationRuntime } from './providers/runtime.js';
35
+ export { readLifecycleOperation } from './lifecycle.js';
36
+ export type { LifecycleOperation, OperationState, PhaseState } from './lifecycle.js';
37
+ export { integrationStatus, recoverIntegrationResource } from './providers/recovery.js';
38
+ export type { IntegrationRecoveryRequest } from './providers/recovery.js';
39
+ export { CAPABILITY_CONTRACT, formatCapabilityContract } from './capability-contract.js';
40
+ export type { CapabilitySupport, CapabilityEvidence, CapabilityStage, ProductCapability, } from './capability-contract.js';
41
+ export { recoverDeliveryLock } from './project-state.js';
42
+ export { inspectApplication } from './project-inspector.js';
43
+ export type { ProjectInspection } from './inspector-model.js';
package/dist/index.js CHANGED
@@ -7,8 +7,22 @@ export { planProvisioning, provisionApplication } from './provision.js';
7
7
  export { registerVercelApplication, connectVercelApplication, planVercelDelivery, shipVercelApplication, vercelApplicationStatus, verifyVercelApplication, rollbackVercelApplication, adoptVercelApplication, recoverVercelApplication, } from './vercel.js';
8
8
  export { setupRepository, githubRepository } from './repository.js';
9
9
  export { inspectProviderReadiness } from './provider-readiness.js';
10
- export { registerManagedApplication, stageManagedVersion, saveManagedVersion, deployManagedVersion, managedApplicationStatus, } from './managed-hosting.js';
11
10
  export { STACK_REGISTRY, STACK_ITEMS, getStackItem } from './stack-registry.js';
12
11
  export { inspectWorkspaceGraph } from './workspace-graph.js';
13
12
  export { resolveStackRegistry } from './registry/resolve.js';
14
13
  export { addStackItems } from './registry/add.js';
14
+ export { PROVIDER_AUTH, requiredProviders, authenticateProviders } from './provider-auth.js';
15
+ export { buildMobileApplication } from './mobile-delivery.js';
16
+ export { shipCloudflareApplication } from './ship.js';
17
+ export { shipSelectedStack, shipSelectedVercelApplication } from './ship.js';
18
+ export { planProviderProvisioning, provisionSelectedProviders } from './providers/provision.js';
19
+ export { providerConfigurationTemplate } from './providers/config.js';
20
+ export { validateProviderConfiguration } from './providers/config.js';
21
+ export { PROVIDER_CONFIGURATION_SCHEMA } from './providers/schema.js';
22
+ export { PROVIDER_DEFINITIONS } from './providers/definitions.js';
23
+ export { applicationRuntime } from './providers/runtime.js';
24
+ export { readLifecycleOperation } from './lifecycle.js';
25
+ export { integrationStatus, recoverIntegrationResource } from './providers/recovery.js';
26
+ export { CAPABILITY_CONTRACT, formatCapabilityContract } from './capability-contract.js';
27
+ export { recoverDeliveryLock } from './project-state.js';
28
+ export { inspectApplication } from './project-inspector.js';
@@ -0,0 +1,115 @@
1
+ import type { LifecycleOperation } from './lifecycle-model.js';
2
+ export interface InspectionSection<T> {
3
+ state: 'available' | 'unavailable';
4
+ data: T;
5
+ error?: string;
6
+ }
7
+ export type DependencyField = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies';
8
+ export interface WorkspaceEvidence {
9
+ name: string;
10
+ directory: string;
11
+ dependencies: {
12
+ name: string;
13
+ kind: DependencyField;
14
+ }[];
15
+ }
16
+ export interface BindingEvidence {
17
+ application: string;
18
+ name: string;
19
+ kind: string;
20
+ configured: boolean;
21
+ identifierRequired: boolean;
22
+ resourceId: string | null;
23
+ }
24
+ export interface ReleaseEvidence {
25
+ id: string;
26
+ state: string;
27
+ commit: string;
28
+ recordedAt: string | null;
29
+ url: string | null;
30
+ kind: 'deployment' | 'build';
31
+ operationState?: string;
32
+ platform?: string;
33
+ profile?: string;
34
+ artifact?: string;
35
+ }
36
+ export interface TargetEvidence {
37
+ id: string;
38
+ provider: 'cloudflare' | 'vercel' | 'expo' | 'desktop' | 'extension';
39
+ application: string;
40
+ audience: 'public' | 'private' | 'unconfigured' | 'not-applicable';
41
+ accountReference: string | null;
42
+ latestAttempt: ReleaseEvidence | null;
43
+ lastSuccessful: ReleaseEvidence | null;
44
+ delivery: 'implemented' | 'artifact-only' | 'scaffold-only';
45
+ liveStatus: 'unknown';
46
+ error?: string;
47
+ }
48
+ export interface IntegrationEvidence {
49
+ provider: string;
50
+ operations: {
51
+ operation: string;
52
+ status: 'pending' | 'complete';
53
+ resources: Record<string, string>;
54
+ recovery: string;
55
+ kind: string | null;
56
+ }[];
57
+ }
58
+ export interface ResourceEvidence {
59
+ kind: string;
60
+ name: string;
61
+ id: string;
62
+ reused: boolean | null;
63
+ recordedAt: string | null;
64
+ }
65
+ /** Browser-safe projection. Read time never substitutes for provider evidence time. */
66
+ export interface ProjectInspection {
67
+ schemaVersion: 1;
68
+ name: string;
69
+ inspectedAt: string;
70
+ authentication: {
71
+ state: 'not-checked';
72
+ };
73
+ liveStatus: {
74
+ state: 'unknown';
75
+ };
76
+ limits: string[];
77
+ selection: InspectionSection<{
78
+ cliVersion: string | null;
79
+ products: string[];
80
+ hosting: 'cloudflare' | 'vercel' | null;
81
+ }>;
82
+ setupProviders: InspectionSection<{
83
+ id: string;
84
+ managementCredential: string | null;
85
+ ownerSteps: string[];
86
+ authentication: 'not-checked';
87
+ permissions: 'unknown';
88
+ billing: 'unknown';
89
+ }[]>;
90
+ workspaces: InspectionSection<WorkspaceEvidence[]>;
91
+ configuration: InspectionSection<{
92
+ bindings: BindingEvidence[];
93
+ schedules: {
94
+ application: string;
95
+ expression: string;
96
+ }[];
97
+ environment: {
98
+ application: string;
99
+ name: string;
100
+ }[];
101
+ }>;
102
+ targets: InspectionSection<TargetEvidence[]>;
103
+ integrations: InspectionSection<IntegrationEvidence[]>;
104
+ cloudflareResources: InspectionSection<ResourceEvidence[]>;
105
+ readiness: InspectionSection<{
106
+ localReady: boolean;
107
+ checks: {
108
+ id: string;
109
+ ok: boolean;
110
+ detail: string;
111
+ }[];
112
+ }>;
113
+ operation: InspectionSection<LifecycleOperation | null>;
114
+ }
115
+ export type ApplicationInspection = ProjectInspection;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ export type OperationState = 'running' | 'blocked' | 'completed' | 'failed';
2
+ export type PhaseState = 'running' | 'completed' | 'failed';
3
+ export interface LifecycleOperation {
4
+ schemaVersion: 1;
5
+ id: string;
6
+ target: 'cloudflare' | 'vercel' | 'mixed' | 'mobile';
7
+ state: OperationState;
8
+ startedAt: string;
9
+ updatedAt: string;
10
+ phases: {
11
+ name: string;
12
+ state: PhaseState;
13
+ }[];
14
+ }
15
+ export declare function isLifecycleOperation(value: unknown): value is LifecycleOperation;
@@ -0,0 +1,20 @@
1
+ export function isLifecycleOperation(value) {
2
+ if (!value || typeof value !== 'object' || Array.isArray(value))
3
+ return false;
4
+ const operation = value;
5
+ return (operation.schemaVersion === 1 &&
6
+ typeof operation.id === 'string' &&
7
+ /^[a-f0-9-]{36}$/.test(operation.id) &&
8
+ ['cloudflare', 'vercel', 'mixed', 'mobile'].includes(operation.target) &&
9
+ ['running', 'blocked', 'completed', 'failed'].includes(operation.state) &&
10
+ [operation.startedAt, operation.updatedAt].every((date) => typeof date === 'string' && Number.isFinite(Date.parse(date))) &&
11
+ Array.isArray(operation.phases) &&
12
+ operation.phases.length <= 100 &&
13
+ operation.phases.every((phase) => phase &&
14
+ typeof phase.name === 'string' &&
15
+ /^[a-z][a-z-]{0,63}$/.test(phase.name) &&
16
+ ['running', 'completed', 'failed'].includes(phase.state)) &&
17
+ new Set(operation.phases.map((phase) => phase.name)).size === operation.phases.length &&
18
+ Object.keys(operation).every((key) => ['schemaVersion', 'id', 'target', 'state', 'startedAt', 'updatedAt', 'phases'].includes(key)) &&
19
+ operation.phases.every((phase) => Object.keys(phase).every((key) => ['name', 'state'].includes(key))));
20
+ }
@@ -0,0 +1,12 @@
1
+ import { type DeliveryRunner } from './project-state.js';
2
+ import { type LifecycleOperation } from './lifecycle-model.js';
3
+ export type { LifecycleOperation, OperationState, PhaseState } from './lifecycle-model.js';
4
+ export { isLifecycleOperation } from './lifecycle-model.js';
5
+ export interface LifecycleSession {
6
+ phase<T>(name: string, action: () => Promise<T>): Promise<T>;
7
+ }
8
+ /** A nonsecret record of execution; a completed phase is not product acceptance. */
9
+ export declare function readLifecycleOperation(root: string): LifecycleOperation | null;
10
+ export declare function withLifecycleOperation<T>(root: string, target: LifecycleOperation['target'], run: DeliveryRunner, action: (session: LifecycleSession) => Promise<T>): Promise<T & {
11
+ operation: LifecycleOperation;
12
+ }>;
@@ -0,0 +1,92 @@
1
+ import path from 'node:path';
2
+ import { existsSync, lstatSync, realpathSync } from 'node:fs';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { readBoundedFile, MAX_PROJECT_JSON_BYTES } from './bounded-file.js';
5
+ import { atomicJson, withApplicationLock } from './project-state.js';
6
+ import { isLifecycleOperation } from './lifecycle-model.js';
7
+ export { isLifecycleOperation } from './lifecycle-model.js';
8
+ /** A nonsecret record of execution; a completed phase is not product acceptance. */
9
+ export function readLifecycleOperation(root) {
10
+ root = realpathSync(root);
11
+ const file = path.join(root, '.anhedral/operation.json');
12
+ if (!existsSync(file))
13
+ return null;
14
+ if (realpathSync(path.dirname(file)) !== path.join(root, '.anhedral') ||
15
+ lstatSync(file).isSymbolicLink())
16
+ throw new Error('Invalid lifecycle state location.');
17
+ let value;
18
+ try {
19
+ value = JSON.parse(readBoundedFile(file, MAX_PROJECT_JSON_BYTES).toString('utf8'));
20
+ }
21
+ catch {
22
+ throw new Error('Invalid lifecycle state.');
23
+ }
24
+ if (!isLifecycleOperation(value))
25
+ throw new Error('Invalid lifecycle state.');
26
+ return value;
27
+ }
28
+ export async function withLifecycleOperation(root, target, run, action) {
29
+ root = realpathSync(root);
30
+ const env = { ...process.env, CI: '1', NO_COLOR: '1' };
31
+ const relative = '.anhedral/operation.json';
32
+ if ((await run('git', ['ls-files', '--', relative], root, env)).trim() ||
33
+ (await run('git', ['check-ignore', '--no-index', '--', relative], root, env)).trim() !==
34
+ relative)
35
+ throw new Error('Ignore .anhedral/ before recording a shipping operation.');
36
+ return withApplicationLock(root, async () => {
37
+ readLifecycleOperation(root);
38
+ const now = new Date().toISOString();
39
+ const operation = {
40
+ schemaVersion: 1,
41
+ id: randomUUID(),
42
+ target,
43
+ state: 'running',
44
+ startedAt: now,
45
+ updatedAt: now,
46
+ phases: [],
47
+ };
48
+ const save = () => {
49
+ operation.updatedAt = new Date().toISOString();
50
+ atomicJson(path.join(root, relative), operation);
51
+ };
52
+ save();
53
+ const session = {
54
+ async phase(name, task) {
55
+ if (!/^[a-z][a-z-]{0,63}$/.test(name) ||
56
+ operation.phases.some((phase) => phase.name === name) ||
57
+ operation.phases.length >= 100)
58
+ throw new Error('Invalid or duplicate lifecycle phase.');
59
+ const phase = { name, state: 'running' };
60
+ operation.phases.push(phase);
61
+ save();
62
+ try {
63
+ const result = await task();
64
+ phase.state = 'completed';
65
+ save();
66
+ return result;
67
+ }
68
+ catch (error) {
69
+ phase.state = 'failed';
70
+ save();
71
+ throw error;
72
+ }
73
+ },
74
+ };
75
+ try {
76
+ const result = await action(session);
77
+ const state = result && typeof result === 'object' && 'state' in result ? result.state : undefined;
78
+ operation.state = ['partial', 'failed'].includes(String(state))
79
+ ? 'failed'
80
+ : ['configuration-required', 'provider-configuration-required', 'building'].includes(String(state))
81
+ ? 'blocked'
82
+ : 'completed';
83
+ save();
84
+ return Object.assign({}, result, { operation });
85
+ }
86
+ catch (error) {
87
+ operation.state = 'failed';
88
+ save();
89
+ throw error;
90
+ }
91
+ });
92
+ }
@@ -0,0 +1,100 @@
1
+ import { type DeliveryRunner } from './project-state.js';
2
+ export interface MobileBuildOptions {
3
+ platform: 'ios' | 'android';
4
+ profile: string;
5
+ dryRun?: boolean;
6
+ }
7
+ /** EAS builds produce artifacts; store submission is a separate user action. */
8
+ export declare function buildMobileApplication(root: string, options: MobileBuildOptions, run?: DeliveryRunner): Promise<{
9
+ commit: string;
10
+ platform: "android" | "ios";
11
+ profile: string;
12
+ buildId: any;
13
+ downloadUrl: string;
14
+ state: string;
15
+ storeSubmission: boolean;
16
+ artifact: string;
17
+ buildPageUrl?: string | undefined;
18
+ schemaVersion: number;
19
+ projectId: string;
20
+ owner: any;
21
+ slug: any;
22
+ recordedAt: string;
23
+ } | {
24
+ platform: "android" | "ios";
25
+ profile: string;
26
+ command: string[];
27
+ mutation: boolean;
28
+ storeSubmission: boolean;
29
+ integrations: {
30
+ schemaVersion: number;
31
+ providers: {
32
+ provider: keyof import("./index.js").ProviderSettingsById;
33
+ settings: import("./providers/definitions.js").NeonSettings | import("./providers/definitions.js").ClerkSettings | import("./providers/definitions.js").ResendSettings | import("./providers/definitions.js").StripeSettings | import("./providers/definitions.js").RevenueCatSettings | import("./providers/definitions.js").SentrySettings | import("./providers/definitions.js").PostHogSettings | import("./providers/definitions.js").OpenAISettings;
34
+ credential: string;
35
+ missing: string[];
36
+ }[];
37
+ configured: boolean;
38
+ mutation: boolean;
39
+ };
40
+ state?: undefined;
41
+ deployed?: undefined;
42
+ nextAction?: undefined;
43
+ schemaVersion?: undefined;
44
+ buildId?: undefined;
45
+ buildPageUrl?: undefined;
46
+ commit?: undefined;
47
+ } | {
48
+ state: string;
49
+ deployed: boolean;
50
+ integrations: {
51
+ schemaVersion: number;
52
+ results: {
53
+ provider: string;
54
+ resources: Record<string, string>;
55
+ ready: boolean;
56
+ nextActions: string[];
57
+ }[];
58
+ ready: boolean;
59
+ configuredFiles: string[];
60
+ mutation: boolean;
61
+ };
62
+ storeSubmission: boolean;
63
+ platform?: undefined;
64
+ profile?: undefined;
65
+ command?: undefined;
66
+ mutation?: undefined;
67
+ nextAction?: undefined;
68
+ schemaVersion?: undefined;
69
+ buildId?: undefined;
70
+ buildPageUrl?: undefined;
71
+ commit?: undefined;
72
+ } | {
73
+ state: string;
74
+ deployed: boolean;
75
+ storeSubmission: boolean;
76
+ nextAction: string;
77
+ platform?: undefined;
78
+ profile?: undefined;
79
+ command?: undefined;
80
+ mutation?: undefined;
81
+ integrations?: undefined;
82
+ schemaVersion?: undefined;
83
+ buildId?: undefined;
84
+ buildPageUrl?: undefined;
85
+ commit?: undefined;
86
+ } | {
87
+ schemaVersion: number;
88
+ state: string;
89
+ buildId: any;
90
+ buildPageUrl: string;
91
+ commit: string;
92
+ platform: "android" | "ios";
93
+ profile: string;
94
+ storeSubmission: boolean;
95
+ nextAction: string;
96
+ command?: undefined;
97
+ mutation?: undefined;
98
+ integrations?: undefined;
99
+ deployed?: undefined;
100
+ }>;