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.
- package/README.md +78 -39
- package/assets/{anhedral-cli-init-technical.svg → anhedral-stack-technical.svg} +6 -6
- package/assets/{anhedral-cli-init.svg → anhedral-stack.svg} +7 -7
- package/assets/security/audit-deps.mjs +6 -1
- package/dist/bin.js +271 -154
- package/dist/bounded-file.d.ts +1 -0
- package/dist/bounded-file.js +1 -0
- package/dist/capabilities.d.ts +4 -4
- package/dist/capabilities.js +1 -1
- package/dist/capability-contract.d.ts +47 -0
- package/dist/capability-contract.js +136 -0
- package/dist/cli-arguments.d.ts +16 -0
- package/dist/cli-arguments.js +115 -0
- package/dist/cli-output.d.ts +8 -0
- package/dist/cli-output.js +211 -0
- package/dist/cloudflare.d.ts +7 -2
- package/dist/cloudflare.js +166 -36
- package/dist/command-schema.d.ts +21 -0
- package/dist/command-schema.js +374 -0
- package/dist/delivery.d.ts +2 -2
- package/dist/delivery.js +21 -4
- package/dist/dependencies.d.ts +32 -0
- package/dist/dependencies.js +47 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +15 -1
- package/dist/inspector-model.d.ts +115 -0
- package/dist/inspector-model.js +1 -0
- package/dist/lifecycle-model.d.ts +15 -0
- package/dist/lifecycle-model.js +20 -0
- package/dist/lifecycle.d.ts +12 -0
- package/dist/lifecycle.js +92 -0
- package/dist/mobile-delivery.d.ts +100 -0
- package/dist/mobile-delivery.js +319 -0
- package/dist/platforms/desktop.js +4 -5
- package/dist/platforms/extension.js +9 -73
- package/dist/platforms/mobile.js +14 -52
- package/dist/project-inspector.d.ts +4 -0
- package/dist/project-inspector.js +646 -0
- package/dist/project-state.d.ts +17 -0
- package/dist/project-state.js +239 -11
- package/dist/provider-auth.d.ts +41 -0
- package/dist/provider-auth.js +210 -0
- package/dist/providers/adapters.d.ts +17 -0
- package/dist/providers/adapters.js +269 -0
- package/dist/providers/api.d.ts +28 -0
- package/dist/providers/api.js +252 -0
- package/dist/providers/config.d.ts +15 -0
- package/dist/providers/config.js +184 -0
- package/dist/providers/definitions.d.ts +318 -0
- package/dist/providers/definitions.js +127 -0
- package/dist/providers/provision.d.ts +24 -0
- package/dist/providers/provision.js +76 -0
- package/dist/providers/receipts.d.ts +20 -0
- package/dist/providers/receipts.js +66 -0
- package/dist/providers/recovery-verification.d.ts +7 -0
- package/dist/providers/recovery-verification.js +112 -0
- package/dist/providers/recovery.d.ts +30 -0
- package/dist/providers/recovery.js +34 -0
- package/dist/providers/runtime.d.ts +10 -0
- package/dist/providers/runtime.js +231 -0
- package/dist/providers/schema.d.ts +28 -0
- package/dist/providers/schema.js +49 -0
- package/dist/providers/state.d.ts +56 -0
- package/dist/providers/state.js +329 -0
- package/dist/provision.d.ts +1 -1
- package/dist/provision.js +61 -3
- package/dist/readiness.js +11 -3
- package/dist/registry/add.d.ts +6 -0
- package/dist/registry/add.js +35 -4
- package/dist/registry/commands.d.ts +3 -2
- package/dist/registry/commands.js +53 -14
- package/dist/registry/options.js +3 -2
- package/dist/registry/preview.d.ts +11 -0
- package/dist/registry/preview.js +91 -0
- package/dist/registry/receipt.js +1 -0
- package/dist/registry/resolve.js +19 -13
- package/dist/registry/types.d.ts +1 -0
- package/dist/registry/usage.d.ts +10 -0
- package/dist/registry/usage.js +22 -37
- package/dist/render.d.ts +2 -0
- package/dist/render.js +10 -0
- package/dist/scaffold/api.js +20 -3
- package/dist/scaffold/auth.js +68 -28
- package/dist/scaffold/bootstrap.d.ts +2 -0
- package/dist/scaffold/bootstrap.js +9 -0
- package/dist/scaffold/database.js +12 -6
- package/dist/scaffold/documentation.js +11 -8
- package/dist/scaffold/environment.d.ts +2 -0
- package/dist/scaffold/environment.js +18 -1
- package/dist/scaffold/files.d.ts +1 -0
- package/dist/scaffold/files.js +15 -4
- package/dist/scaffold/services.js +37 -13
- package/dist/scaffold/stack-documentation.d.ts +3 -0
- package/dist/scaffold/stack-documentation.js +52 -0
- package/dist/scaffold/styling.d.ts +3 -0
- package/dist/scaffold/styling.js +84 -0
- package/dist/scaffold/web.js +31 -11
- package/dist/scaffold/workspace.js +49 -22
- package/dist/ship.d.ts +320 -0
- package/dist/ship.js +211 -0
- package/dist/stack-registry.d.ts +2 -2
- package/dist/stack-registry.js +44 -11
- package/dist/standard.d.ts +2 -1
- package/dist/standard.js +13 -12
- package/dist/vercel.d.ts +3 -3
- package/dist/vercel.js +27 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/vinext.js +9 -18
- package/dist/workspace-graph.js +3 -2
- package/docs/application-stack-standard.md +51 -80
- package/docs/cli-design.md +67 -0
- package/docs/delivery-workflow.md +29 -15
- package/docs/plugin-ui.md +61 -0
- package/docs/provider-configuration.md +117 -0
- package/package.json +16 -12
- package/dist/managed-hosting.d.ts +0 -49
- package/dist/managed-hosting.js +0 -373
- package/docs/managed-hosting-architecture.md +0 -87
- 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
|
-
|
|
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']],
|
package/dist/dependencies.d.ts
CHANGED
|
@@ -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
|
+
};
|
package/dist/dependencies.js
CHANGED
|
@@ -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:
|
|
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
|
+
}>;
|