anhedral 0.8.5 → 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.
- package/README.md +140 -34
- package/assets/anhedral-cli-init-technical.svg +8 -8
- package/assets/anhedral-cli-init.svg +9 -9
- package/assets/security/LICENSES.txt +63 -0
- package/assets/security/audit-deps.mjs +295 -0
- package/assets/security/braces-regression.mjs +102 -0
- package/assets/security/braces@3.0.3.patch +285 -0
- package/assets/security/decode-uri-component@0.2.2.patch +149 -0
- package/assets/security/decoder-regression.mjs +37 -0
- package/assets/security/forge-regression.mjs +46 -0
- package/assets/security/manifest.json +53 -0
- package/assets/security/node-forge@1.4.0.patch +26 -0
- package/dist/access.d.ts +10 -0
- package/dist/access.js +93 -0
- package/dist/auth-schema-snapshot.d.ts +346 -0
- package/dist/auth-schema-snapshot.js +347 -0
- package/dist/auth-schema.d.ts +1 -0
- package/dist/auth-schema.js +57 -0
- package/dist/bin.js +353 -10
- package/dist/bounded-file.d.ts +2 -0
- package/dist/bounded-file.js +30 -0
- package/dist/capabilities.d.ts +19 -33
- package/dist/capabilities.js +73 -71
- package/dist/cloudflare.d.ts +14 -0
- package/dist/cloudflare.js +66 -0
- package/dist/command.js +12 -3
- package/dist/delivery.d.ts +118 -0
- package/dist/delivery.js +611 -0
- package/dist/dependencies.d.ts +22 -0
- package/dist/dependencies.js +109 -67
- package/dist/dependency-order.d.ts +2 -0
- package/dist/dependency-order.js +24 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.js +12 -1
- package/dist/managed-hosting.d.ts +49 -0
- package/dist/managed-hosting.js +373 -0
- package/dist/management.d.ts +3 -0
- package/dist/management.js +47 -0
- package/dist/platforms/desktop.d.ts +2 -2
- package/dist/platforms/desktop.js +22 -12
- package/dist/platforms/extension.d.ts +2 -2
- package/dist/platforms/extension.js +12 -4
- package/dist/platforms/mobile.d.ts +2 -2
- package/dist/platforms/mobile.js +13 -7
- package/dist/pnpm-policy.d.ts +4 -0
- package/dist/pnpm-policy.js +66 -0
- package/dist/project-state.d.ts +28 -0
- package/dist/project-state.js +226 -0
- package/dist/provider-readiness.d.ts +30 -0
- package/dist/provider-readiness.js +87 -0
- package/dist/provision.d.ts +46 -0
- package/dist/provision.js +197 -0
- package/dist/readiness.d.ts +4 -1
- package/dist/readiness.js +80 -8
- package/dist/registry/add.d.ts +22 -0
- package/dist/registry/add.js +198 -0
- package/dist/registry/bootstrap.d.ts +2 -0
- package/dist/registry/bootstrap.js +14 -0
- package/dist/registry/commands.d.ts +2 -0
- package/dist/registry/commands.js +99 -0
- package/dist/registry/context.d.ts +3 -0
- package/dist/registry/context.js +21 -0
- package/dist/registry/options.d.ts +2 -0
- package/dist/registry/options.js +65 -0
- package/dist/registry/receipt.d.ts +3 -0
- package/dist/registry/receipt.js +73 -0
- package/dist/registry/remote.d.ts +25 -0
- package/dist/registry/remote.js +168 -0
- package/dist/registry/resolve.d.ts +10 -0
- package/dist/registry/resolve.js +98 -0
- package/dist/registry/types.d.ts +64 -0
- package/dist/registry/usage.d.ts +1 -0
- package/dist/registry/usage.js +38 -0
- package/dist/render.js +3 -3
- package/dist/repository.d.ts +24 -0
- package/dist/repository.js +96 -0
- package/dist/scaffold/api.d.ts +2 -0
- package/dist/scaffold/api.js +13 -0
- package/dist/scaffold/auth.d.ts +3 -0
- package/dist/scaffold/auth.js +95 -0
- package/dist/scaffold/bootstrap.d.ts +2 -0
- package/dist/scaffold/bootstrap.js +34 -0
- package/dist/scaffold/compose.d.ts +4 -0
- package/dist/scaffold/compose.js +34 -0
- package/dist/scaffold/database.d.ts +2 -0
- package/dist/scaffold/database.js +43 -0
- package/dist/scaffold/documentation.d.ts +3 -0
- package/dist/scaffold/documentation.js +91 -0
- package/dist/scaffold/environment.d.ts +2 -0
- package/dist/scaffold/environment.js +5 -0
- package/dist/scaffold/files.d.ts +25 -0
- package/dist/scaffold/files.js +108 -0
- package/dist/scaffold/integrations.d.ts +3 -0
- package/dist/scaffold/integrations.js +7 -0
- package/dist/scaffold/services.d.ts +5 -0
- package/dist/scaffold/services.js +84 -0
- package/dist/scaffold/web.d.ts +2 -0
- package/dist/scaffold/web.js +102 -0
- package/dist/scaffold/workspace.d.ts +3 -0
- package/dist/scaffold/workspace.js +150 -0
- package/dist/security-backports.d.ts +3 -0
- package/dist/security-backports.js +26 -0
- package/dist/stack-registry.d.ts +80 -0
- package/dist/stack-registry.js +424 -0
- package/dist/standard.d.ts +6 -17
- package/dist/standard.js +41 -585
- package/dist/transaction.js +46 -26
- package/dist/util.js +12 -2
- package/dist/vercel.d.ts +98 -0
- package/dist/vercel.js +796 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/vinext.d.ts +1 -0
- package/dist/vinext.js +83 -0
- package/dist/workspace-graph.d.ts +7 -0
- package/dist/workspace-graph.js +73 -0
- package/docs/application-stack-standard.md +75 -674
- package/docs/delivery-workflow.md +83 -0
- package/docs/managed-hosting-architecture.md +87 -0
- package/docs/sponsorships.md +25 -0
- package/package.json +23 -28
- package/dist/project.d.ts +0 -4
- package/dist/standard-products.d.ts +0 -2
- package/dist/standard-products.js +0 -6
- /package/assets/{images/svg/logo-white-subtract.svg → anhedral-mark.svg} +0 -0
- /package/dist/{project.js → registry/types.js} +0 -0
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { runAdd, runRegistry } from './registry/commands.js';
|
|
3
|
+
import { registerManagedApplication, stageManagedVersion, saveManagedVersion, deployManagedVersion, managedApplicationStatus, } from './managed-hosting.js';
|
|
4
|
+
import { setupRepository } from './repository.js';
|
|
2
5
|
import path from 'node:path';
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { registerVercelApplication, connectVercelApplication, planVercelDelivery, shipVercelApplication, vercelApplicationStatus, verifyVercelApplication, rollbackVercelApplication, adoptVercelApplication, recoverVercelApplication, writeVercelOverview, } from './vercel.js';
|
|
8
|
+
import { registerApplication, connectApplication, planDelivery, shipApplication, applicationStatus, verifyApplication, rollbackApplication, recoverApplication, } from './delivery.js';
|
|
9
|
+
import { planProvisioning, provisionApplication } from './provision.js';
|
|
10
|
+
import { writeManagementOverview } from './management.js';
|
|
11
|
+
import { inspectProviderReadiness } from './provider-readiness.js';
|
|
3
12
|
import { inspectProject } from './readiness.js';
|
|
4
13
|
import { argv } from 'node:process';
|
|
5
14
|
import { STANDARD_USAGE, parseStandardOptions, scaffoldStandardProject } from './standard.js';
|
|
@@ -16,12 +25,92 @@ async function main() {
|
|
|
16
25
|
console.log(json ? JSON.stringify({ version: GENERATOR_VERSION }) : GENERATOR_VERSION);
|
|
17
26
|
return;
|
|
18
27
|
}
|
|
28
|
+
if (command === 'add') {
|
|
29
|
+
await runAdd(args);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (command === 'registry') {
|
|
33
|
+
await runRegistry(args, json);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (command === 'cloud') {
|
|
37
|
+
await runCloud(args);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (command === 'repository') {
|
|
41
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
42
|
+
console.log(STANDARD_USAGE);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let owner;
|
|
46
|
+
let name;
|
|
47
|
+
let visibility = 'private';
|
|
48
|
+
let create = false;
|
|
49
|
+
const directories = [];
|
|
50
|
+
for (let index = 0; index < args.length; index++) {
|
|
51
|
+
const flag = args[index];
|
|
52
|
+
if (flag === '--json')
|
|
53
|
+
continue;
|
|
54
|
+
if (flag === '--create') {
|
|
55
|
+
create = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (flag === '--owner' || flag === '--name' || flag === '--visibility') {
|
|
59
|
+
const value = args[++index];
|
|
60
|
+
if (!value || value.startsWith('-'))
|
|
61
|
+
throw new Error('Missing repository option value.');
|
|
62
|
+
if (flag === '--owner') {
|
|
63
|
+
if (owner)
|
|
64
|
+
throw new Error('Specify one GitHub owner.');
|
|
65
|
+
owner = value;
|
|
66
|
+
}
|
|
67
|
+
else if (flag === '--name') {
|
|
68
|
+
if (name)
|
|
69
|
+
throw new Error('Specify one repository name.');
|
|
70
|
+
name = value;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
if (!['private', 'public'].includes(value))
|
|
74
|
+
throw new Error('Visibility must be private or public.');
|
|
75
|
+
visibility = value;
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (flag.startsWith('-'))
|
|
80
|
+
throw new Error('Unknown repository option.');
|
|
81
|
+
directories.push(flag);
|
|
82
|
+
}
|
|
83
|
+
if (directories.length > 1)
|
|
84
|
+
throw new Error('Specify one application directory.');
|
|
85
|
+
console.log(JSON.stringify(await setupRepository(path.resolve(directories[0] ?? process.cwd()), {
|
|
86
|
+
owner,
|
|
87
|
+
name,
|
|
88
|
+
visibility,
|
|
89
|
+
create,
|
|
90
|
+
}), null, 2));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if ([
|
|
94
|
+
'register',
|
|
95
|
+
'connect',
|
|
96
|
+
'provision',
|
|
97
|
+
'ship',
|
|
98
|
+
'status',
|
|
99
|
+
'manage',
|
|
100
|
+
'verify',
|
|
101
|
+
'rollback',
|
|
102
|
+
'adopt',
|
|
103
|
+
'recover',
|
|
104
|
+
].includes(command ?? '')) {
|
|
105
|
+
await runDelivery(command, args);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
19
108
|
if (command === 'doctor') {
|
|
20
|
-
runDoctor(args);
|
|
109
|
+
await runDoctor(args);
|
|
21
110
|
return;
|
|
22
111
|
}
|
|
23
112
|
if (command !== 'new' && command !== 'init') {
|
|
24
|
-
throw new Error(`Unknown command: ${command}. Use new, init, doctor, --help, or --version.`);
|
|
113
|
+
throw new Error(`Unknown command: ${command}. Use new, init, registry, doctor, repository, cloud, register, connect, provision, ship, status, manage, verify, rollback, adopt, recover, --help, or --version.`);
|
|
25
114
|
}
|
|
26
115
|
if (args.some((arg) => ['--help', '-h'].includes(arg))) {
|
|
27
116
|
console.log(json ? JSON.stringify({ usage: STANDARD_USAGE }) : STANDARD_USAGE);
|
|
@@ -31,13 +120,247 @@ async function main() {
|
|
|
31
120
|
if (options)
|
|
32
121
|
await scaffoldStandardProject(options);
|
|
33
122
|
}
|
|
34
|
-
function
|
|
35
|
-
const
|
|
123
|
+
async function runCloud(args) {
|
|
124
|
+
const [action, ...flags] = args;
|
|
125
|
+
if (!action || flags.includes('--help') || action === '--help') {
|
|
126
|
+
console.log('anhedral cloud register|stage|save|deploy|status [directory] [--artifact directory] [--version stage-id] [--audience private|public] [--json]');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
let artifact;
|
|
130
|
+
let version;
|
|
131
|
+
let audience = 'private';
|
|
132
|
+
const directories = [];
|
|
133
|
+
for (let index = 0; index < flags.length; index++) {
|
|
134
|
+
const flag = flags[index];
|
|
135
|
+
if (flag === '--json')
|
|
136
|
+
continue;
|
|
137
|
+
if ((flag === '--artifact' && action === 'stage') ||
|
|
138
|
+
(flag === '--version' && ['save', 'deploy'].includes(action)) ||
|
|
139
|
+
(flag === '--audience' && action === 'register')) {
|
|
140
|
+
const value = flags[++index];
|
|
141
|
+
if (!value || value.startsWith('-'))
|
|
142
|
+
throw new Error('Missing cloud option value.');
|
|
143
|
+
if (flag === '--artifact') {
|
|
144
|
+
if (artifact)
|
|
145
|
+
throw new Error('Specify one artifact.');
|
|
146
|
+
artifact = value;
|
|
147
|
+
}
|
|
148
|
+
else if (flag === '--version') {
|
|
149
|
+
if (version)
|
|
150
|
+
throw new Error('Specify one version.');
|
|
151
|
+
version = value;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (value !== 'private' && value !== 'public')
|
|
155
|
+
throw new Error('Audience must be private or public.');
|
|
156
|
+
audience = value;
|
|
157
|
+
}
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (flag.startsWith('-'))
|
|
161
|
+
throw new Error('Unknown cloud option.');
|
|
162
|
+
directories.push(flag);
|
|
163
|
+
}
|
|
164
|
+
if (directories.length > 1)
|
|
165
|
+
throw new Error('Specify one application directory.');
|
|
166
|
+
const root = path.resolve(directories[0] ?? process.cwd());
|
|
167
|
+
let result;
|
|
168
|
+
if (action === 'register')
|
|
169
|
+
result = registerManagedApplication(root, audience);
|
|
170
|
+
else if (action === 'stage') {
|
|
171
|
+
if (!artifact)
|
|
172
|
+
throw new Error('Stage requires --artifact <complete-build-directory>.');
|
|
173
|
+
result = await stageManagedVersion(root, path.resolve(artifact));
|
|
174
|
+
}
|
|
175
|
+
else if (action === 'save' || action === 'deploy') {
|
|
176
|
+
if (!version)
|
|
177
|
+
throw new Error('Save/deploy requires --version <stage-id>.');
|
|
178
|
+
result = await (action === 'save'
|
|
179
|
+
? saveManagedVersion(root, version)
|
|
180
|
+
: deployManagedVersion(root, version));
|
|
181
|
+
}
|
|
182
|
+
else if (action === 'status')
|
|
183
|
+
result = await managedApplicationStatus(root);
|
|
184
|
+
else
|
|
185
|
+
throw new Error('Unknown cloud action.');
|
|
186
|
+
console.log(JSON.stringify(result, null, 2));
|
|
187
|
+
}
|
|
188
|
+
async function runDelivery(command, args) {
|
|
189
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
190
|
+
console.log(STANDARD_USAGE);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const positional = [];
|
|
194
|
+
let account;
|
|
195
|
+
let audience;
|
|
196
|
+
const emails = [];
|
|
197
|
+
let releaseId;
|
|
198
|
+
let provider;
|
|
199
|
+
let scope;
|
|
200
|
+
let use;
|
|
201
|
+
let create = false;
|
|
202
|
+
let git = false;
|
|
203
|
+
for (let index = 0; index < args.length; index++) {
|
|
204
|
+
const arg = args[index];
|
|
205
|
+
if (arg === '--provider') {
|
|
206
|
+
const value = args[++index];
|
|
207
|
+
if (!['vercel', 'cloudflare'].includes(value) || provider)
|
|
208
|
+
throw new Error('Specify one provider: vercel or cloudflare.');
|
|
209
|
+
provider = value;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (command === 'connect' && arg === '--scope') {
|
|
213
|
+
if (scope)
|
|
214
|
+
throw new Error('Specify one Vercel scope.');
|
|
215
|
+
scope = args[++index];
|
|
216
|
+
if (!scope || scope.startsWith('-'))
|
|
217
|
+
throw new Error('Missing Vercel scope.');
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (command === 'connect' && arg === '--use') {
|
|
221
|
+
const value = args[++index];
|
|
222
|
+
if (!['personal', 'commercial'].includes(value) || use)
|
|
223
|
+
throw new Error('Specify --use personal or commercial.');
|
|
224
|
+
use = value;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (command === 'connect' && arg === '--git') {
|
|
228
|
+
git = true;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (command === 'connect' && arg === '--create') {
|
|
232
|
+
create = true;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (command === 'rollback' && arg === '--release') {
|
|
236
|
+
releaseId = args[++index];
|
|
237
|
+
if (!releaseId || releaseId.startsWith('-'))
|
|
238
|
+
throw new Error('Missing release ID.');
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (command === 'rollback' && arg === '--data-compatible')
|
|
242
|
+
continue;
|
|
243
|
+
if (arg === '--json' ||
|
|
244
|
+
(['ship', 'provision'].includes(command) && arg === '--dry-run') ||
|
|
245
|
+
(['status', 'manage', 'verify', 'rollback', 'adopt', 'recover'].includes(command) &&
|
|
246
|
+
arg === '--refresh') ||
|
|
247
|
+
(command === 'manage' && arg === '--local'))
|
|
248
|
+
continue;
|
|
249
|
+
if (command === 'connect' && arg === '--account') {
|
|
250
|
+
if (account)
|
|
251
|
+
throw new Error('Specify one account.');
|
|
252
|
+
account = args[++index];
|
|
253
|
+
if (!account || account.startsWith('-'))
|
|
254
|
+
throw new Error('Missing account ID.');
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (command === 'connect' &&
|
|
258
|
+
arg === '--audience' &&
|
|
259
|
+
['public', 'private'].includes(args[index + 1])) {
|
|
260
|
+
audience = args[index + 1];
|
|
261
|
+
index++;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (command === 'connect' && arg === '--allow-email') {
|
|
265
|
+
const email = args[++index];
|
|
266
|
+
if (!email || email.startsWith('-'))
|
|
267
|
+
throw new Error('Missing allowed email address.');
|
|
268
|
+
emails.push(email);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (arg.startsWith('-'))
|
|
272
|
+
throw new Error(`Unknown ${command} option: ${arg}`);
|
|
273
|
+
positional.push(arg);
|
|
274
|
+
}
|
|
275
|
+
if (positional.length > 1)
|
|
276
|
+
throw new Error('Specify at most one application directory.');
|
|
277
|
+
const root = path.resolve(positional[0] ?? process.cwd());
|
|
278
|
+
let result;
|
|
279
|
+
const web = provider === 'vercel' ||
|
|
280
|
+
(provider !== 'cloudflare' &&
|
|
281
|
+
(existsSync(path.join(root, 'anhedral.web.json')) ||
|
|
282
|
+
(command === 'register' &&
|
|
283
|
+
existsSync(path.join(root, 'anhedral.setup.json')) &&
|
|
284
|
+
JSON.parse(readFileSync(path.join(root, 'anhedral.setup.json'), 'utf8')).hosting ===
|
|
285
|
+
'vercel')));
|
|
286
|
+
if (web) {
|
|
287
|
+
if (account || emails.length)
|
|
288
|
+
throw new Error('Cloudflare account/member flags require --provider cloudflare.');
|
|
289
|
+
if (command === 'register')
|
|
290
|
+
result = registerVercelApplication(root);
|
|
291
|
+
else if (command === 'connect') {
|
|
292
|
+
if (!audience || !use)
|
|
293
|
+
throw new Error('Vercel connect requires --audience public|private and --use personal|commercial.');
|
|
294
|
+
result = await connectVercelApplication(root, { scope, audience, use, create, git });
|
|
295
|
+
}
|
|
296
|
+
else if (command === 'ship')
|
|
297
|
+
result = args.includes('--dry-run')
|
|
298
|
+
? planVercelDelivery(root)
|
|
299
|
+
: await shipVercelApplication(root);
|
|
300
|
+
else if (command === 'adopt')
|
|
301
|
+
result = await adoptVercelApplication(root);
|
|
302
|
+
else if (command === 'recover')
|
|
303
|
+
result = await recoverVercelApplication(root);
|
|
304
|
+
else if (command === 'verify')
|
|
305
|
+
result = await verifyVercelApplication(root);
|
|
306
|
+
else if (command === 'rollback') {
|
|
307
|
+
if (!releaseId)
|
|
308
|
+
throw new Error('Rollback requires --release <recorded-id>.');
|
|
309
|
+
result = await rollbackVercelApplication(root, releaseId, args.includes('--data-compatible'));
|
|
310
|
+
}
|
|
311
|
+
else if (command === 'status')
|
|
312
|
+
result = await vercelApplicationStatus(root, args.includes('--refresh'));
|
|
313
|
+
else if (command === 'manage') {
|
|
314
|
+
const snapshot = await vercelApplicationStatus(root, !args.includes('--local'));
|
|
315
|
+
result = { file: writeVercelOverview(root, snapshot), evidence: snapshot.evidence };
|
|
316
|
+
}
|
|
317
|
+
else
|
|
318
|
+
throw new Error('Vercel project creation is handled by connect --create; Cloudflare resource provisioning requires --provider cloudflare.');
|
|
319
|
+
console.log(JSON.stringify(result, null, 2));
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (scope || use || create || git)
|
|
323
|
+
throw new Error('Vercel connect options require a Vercel web manifest or --provider vercel.');
|
|
324
|
+
if (command === 'register')
|
|
325
|
+
result = registerApplication(root);
|
|
326
|
+
else if (command === 'connect') {
|
|
327
|
+
result = await connectApplication(root, account, audience, undefined, emails);
|
|
328
|
+
}
|
|
329
|
+
else if (command === 'provision')
|
|
330
|
+
result = args.includes('--dry-run') ? planProvisioning(root) : await provisionApplication(root);
|
|
331
|
+
else if (command === 'ship')
|
|
332
|
+
result = args.includes('--dry-run') ? planDelivery(root) : await shipApplication(root);
|
|
333
|
+
else if (command === 'adopt')
|
|
334
|
+
throw new Error('Git deployment adoption requires --provider vercel.');
|
|
335
|
+
else if (command === 'recover')
|
|
336
|
+
result = await recoverApplication(root);
|
|
337
|
+
else if (command === 'verify')
|
|
338
|
+
result = await verifyApplication(root);
|
|
339
|
+
else if (command === 'rollback') {
|
|
340
|
+
if (!releaseId)
|
|
341
|
+
throw new Error('Rollback requires --release <recorded-id>.');
|
|
342
|
+
result = await rollbackApplication(root, releaseId, args.includes('--data-compatible'));
|
|
343
|
+
}
|
|
344
|
+
else if (command === 'manage') {
|
|
345
|
+
const snapshot = await applicationStatus(root, !args.includes('--local'));
|
|
346
|
+
result = { file: writeManagementOverview(root, snapshot), evidence: snapshot.evidence };
|
|
347
|
+
}
|
|
348
|
+
else
|
|
349
|
+
result = await applicationStatus(root, args.includes('--refresh'));
|
|
350
|
+
console.log(JSON.stringify(result, null, 2));
|
|
351
|
+
}
|
|
352
|
+
async function runDoctor(args) {
|
|
353
|
+
const positional = args.filter((arg) => arg !== '--json' && arg !== '--providers');
|
|
36
354
|
if (positional.length > 1 || positional.some((arg) => arg.startsWith('-')))
|
|
37
|
-
throw new Error('Usage: anhedral doctor [directory] [--json]');
|
|
38
|
-
const
|
|
355
|
+
throw new Error('Usage: anhedral doctor [directory] [--providers] [--json]');
|
|
356
|
+
const root = path.resolve(positional[0] ?? process.cwd());
|
|
357
|
+
const report = args.includes('--providers')
|
|
358
|
+
? await inspectProviderReadiness(root)
|
|
359
|
+
: inspectProject(root);
|
|
39
360
|
console.log(JSON.stringify(report, null, json ? 2 : undefined));
|
|
40
|
-
if (!report.localReady
|
|
361
|
+
if (!report.localReady ||
|
|
362
|
+
('prerequisitesReady' in report &&
|
|
363
|
+
(!report.prerequisitesReady || report.providerVerification !== 'verified-existing-context')))
|
|
41
364
|
process.exitCode = 1;
|
|
42
365
|
}
|
|
43
366
|
function readOptions(command, args) {
|
|
@@ -56,9 +379,29 @@ try {
|
|
|
56
379
|
}
|
|
57
380
|
catch (error) {
|
|
58
381
|
const message = error instanceof Error ? error.message : String(error);
|
|
59
|
-
const code = error instanceof PostCommitError
|
|
60
|
-
|
|
61
|
-
|
|
382
|
+
const code = error instanceof PostCommitError
|
|
383
|
+
? 'POST_COMMIT_FAILED'
|
|
384
|
+
: [
|
|
385
|
+
'repository',
|
|
386
|
+
'register',
|
|
387
|
+
'connect',
|
|
388
|
+
'provision',
|
|
389
|
+
'ship',
|
|
390
|
+
'status',
|
|
391
|
+
'manage',
|
|
392
|
+
'verify',
|
|
393
|
+
'rollback',
|
|
394
|
+
'adopt',
|
|
395
|
+
'recover',
|
|
396
|
+
].includes(command ?? '')
|
|
397
|
+
? 'DELIVERY_FAILED'
|
|
398
|
+
: command === 'cloud'
|
|
399
|
+
? 'HOSTING_FAILED'
|
|
400
|
+
: command === 'doctor'
|
|
401
|
+
? 'INVALID_ARGUMENT'
|
|
402
|
+
: command === 'new' || command === 'init'
|
|
403
|
+
? 'GENERATION_FAILED'
|
|
404
|
+
: 'UNKNOWN_COMMAND';
|
|
62
405
|
console.error(json ? JSON.stringify({ error: message, code }) : `Error: ${message}`);
|
|
63
406
|
process.exitCode = 1;
|
|
64
407
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from 'node:fs';
|
|
2
|
+
/** Reject devices, links and oversized or growing files before parsing local input. */
|
|
3
|
+
export function readBoundedFile(filePath, maximumBytes) {
|
|
4
|
+
const stat = lstatSync(filePath);
|
|
5
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
6
|
+
throw new Error(`Input file must be a regular file: ${filePath}`);
|
|
7
|
+
const descriptor = openSync(filePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
8
|
+
try {
|
|
9
|
+
const opened = fstatSync(descriptor);
|
|
10
|
+
if (!opened.isFile())
|
|
11
|
+
throw new Error(`Input file must be a regular file: ${filePath}`);
|
|
12
|
+
if (opened.size > maximumBytes)
|
|
13
|
+
throw new Error(`Input file exceeds size limit: ${filePath}`);
|
|
14
|
+
const chunks = [];
|
|
15
|
+
let total = 0;
|
|
16
|
+
for (;;) {
|
|
17
|
+
const chunk = Buffer.alloc(Math.min(8192, maximumBytes + 1 - total));
|
|
18
|
+
const length = readSync(descriptor, chunk, 0, chunk.length, null);
|
|
19
|
+
if (!length)
|
|
20
|
+
return Buffer.concat(chunks);
|
|
21
|
+
total += length;
|
|
22
|
+
if (total > maximumBytes)
|
|
23
|
+
throw new Error(`Input file exceeds size limit: ${filePath}`);
|
|
24
|
+
chunks.push(chunk.subarray(0, length));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
closeSync(descriptor);
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -1,52 +1,38 @@
|
|
|
1
|
-
import type { StandardProduct } from './
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
conflicts?: StandardProduct[];
|
|
6
|
-
requiresAny?: StandardProduct[];
|
|
7
|
-
requiresAll?: StandardProduct[];
|
|
8
|
-
workerBinding?: boolean;
|
|
9
|
-
}
|
|
10
|
-
export interface Capability {
|
|
11
|
-
purpose: string;
|
|
12
|
-
tools: string[];
|
|
13
|
-
access: string[];
|
|
14
|
-
credentials: string[];
|
|
15
|
-
resources: string[];
|
|
16
|
-
verify: string[];
|
|
17
|
-
selection: Selection;
|
|
18
|
-
}
|
|
19
|
-
/** Setup requirements describe unfinished starters; they never grant authority or claim readiness. */
|
|
1
|
+
import type { StandardOptions, StandardProduct, SetupRequirements, StackSelection } from './registry/types.js';
|
|
2
|
+
export type Capability = SetupRequirements & {
|
|
3
|
+
selection: StackSelection;
|
|
4
|
+
};
|
|
20
5
|
export declare const CAPABILITIES: Record<StandardProduct, Capability>;
|
|
21
|
-
export declare function resolveStandardProducts(selected: Set<StandardProduct>, hosting: StandardOptions['hosting'], hostingSpecified: boolean): void;
|
|
22
6
|
export declare const CAPABILITY_REGISTRY: {
|
|
23
7
|
schemaVersion: number;
|
|
24
8
|
cliVersion: string;
|
|
25
|
-
capabilities: Record<"
|
|
9
|
+
capabilities: Record<"realtime" | "electron" | "wxt" | "expo" | "next" | "vinext" | "hono" | "neon" | "better-auth" | "queues" | "workflows" | "d1" | "local-data" | "clerk" | "r2" | "kv" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog" | "styling", Capability>;
|
|
26
10
|
};
|
|
27
|
-
export declare function createSetupPlan(options: StandardOptions): {
|
|
11
|
+
export declare function createSetupPlan(options: StandardOptions, registry?: import("./registry/resolve.js").ResolvedStackRegistry): {
|
|
28
12
|
schemaVersion: number;
|
|
29
13
|
cliVersion: string;
|
|
30
14
|
registryVersion: number;
|
|
31
15
|
standard: string;
|
|
32
16
|
root: string;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
17
|
+
name: string;
|
|
18
|
+
products: ("realtime" | "electron" | "wxt" | "expo" | "next" | "vinext" | "hono" | "neon" | "better-auth" | "queues" | "workflows" | "d1" | "local-data" | "clerk" | "r2" | "kv" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog" | "styling")[];
|
|
19
|
+
hosting: import("./registry/types.js").Hosting;
|
|
20
|
+
registry: import("./registry/resolve.js").ResolvedStackRegistry;
|
|
21
|
+
bootstrap: ("pnpm" | "shadcn@4.21.4" | "dlx" | "init" | "--monorepo" | "--template" | "next")[];
|
|
36
22
|
dryRun: boolean;
|
|
37
23
|
setup: {
|
|
38
24
|
tools: string[];
|
|
39
25
|
access: string[];
|
|
40
26
|
capabilities: {
|
|
41
|
-
|
|
27
|
+
selection: StackSelection;
|
|
28
|
+
status: "planned" | "starter";
|
|
42
29
|
purpose: string;
|
|
43
|
-
tools: string[];
|
|
44
|
-
access: string[];
|
|
45
|
-
credentials: string[];
|
|
46
|
-
resources: string[];
|
|
47
|
-
verify: string[];
|
|
48
|
-
|
|
49
|
-
id: "next" | "expo" | "electron" | "wxt" | "hono" | "neon" | "d1" | "local-data" | "clerk" | "better-auth" | "r2" | "kv" | "realtime" | "queues" | "cron" | "workflows" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog" | "styling";
|
|
30
|
+
tools: readonly string[];
|
|
31
|
+
access: readonly string[];
|
|
32
|
+
credentials: readonly string[];
|
|
33
|
+
resources: readonly string[];
|
|
34
|
+
verify: readonly string[];
|
|
35
|
+
id: "realtime" | "electron" | "wxt" | "expo" | "next" | "vinext" | "hono" | "neon" | "better-auth" | "queues" | "workflows" | "d1" | "local-data" | "clerk" | "r2" | "kv" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog" | "styling";
|
|
50
36
|
}[];
|
|
51
37
|
completion: string[];
|
|
52
38
|
resourcesProvisioned: boolean;
|