@edge-base/cli 0.1.1
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 +182 -0
- package/dist/commands/admin.d.ts +10 -0
- package/dist/commands/admin.d.ts.map +1 -0
- package/dist/commands/admin.js +307 -0
- package/dist/commands/admin.js.map +1 -0
- package/dist/commands/backup.d.ts +148 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +1247 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/completion.d.ts +3 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +168 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/create-plugin.d.ts +3 -0
- package/dist/commands/create-plugin.d.ts.map +1 -0
- package/dist/commands/create-plugin.js +208 -0
- package/dist/commands/create-plugin.js.map +1 -0
- package/dist/commands/deploy.d.ts +146 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +1823 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/describe.d.ts +45 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/describe.js +114 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/destroy.d.ts +13 -0
- package/dist/commands/destroy.d.ts.map +1 -0
- package/dist/commands/destroy.js +642 -0
- package/dist/commands/destroy.js.map +1 -0
- package/dist/commands/dev.d.ts +80 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +1131 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/docker.d.ts +22 -0
- package/dist/commands/docker.d.ts.map +1 -0
- package/dist/commands/docker.js +373 -0
- package/dist/commands/docker.js.map +1 -0
- package/dist/commands/export.d.ts +15 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +142 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +506 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/keys.d.ts +23 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +347 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +104 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/migrate.d.ts +29 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +302 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/migration.d.ts +18 -0
- package/dist/commands/migration.d.ts.map +1 -0
- package/dist/commands/migration.js +114 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/neon.d.ts +66 -0
- package/dist/commands/neon.d.ts.map +1 -0
- package/dist/commands/neon.js +600 -0
- package/dist/commands/neon.js.map +1 -0
- package/dist/commands/plugins.d.ts +9 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +295 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/realtime.d.ts +3 -0
- package/dist/commands/realtime.d.ts.map +1 -0
- package/dist/commands/realtime.js +71 -0
- package/dist/commands/realtime.js.map +1 -0
- package/dist/commands/secret.d.ts +7 -0
- package/dist/commands/secret.d.ts.map +1 -0
- package/dist/commands/secret.js +180 -0
- package/dist/commands/secret.js.map +1 -0
- package/dist/commands/seed.d.ts +21 -0
- package/dist/commands/seed.d.ts.map +1 -0
- package/dist/commands/seed.js +325 -0
- package/dist/commands/seed.js.map +1 -0
- package/dist/commands/telemetry.d.ts +12 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +57 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/typegen.d.ts +26 -0
- package/dist/commands/typegen.d.ts.map +1 -0
- package/dist/commands/typegen.js +212 -0
- package/dist/commands/typegen.js.map +1 -0
- package/dist/commands/upgrade.d.ts +29 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +265 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/webhook-test.d.ts +3 -0
- package/dist/commands/webhook-test.d.ts.map +1 -0
- package/dist/commands/webhook-test.js +133 -0
- package/dist/commands/webhook-test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +183 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agent-contract.d.ts +36 -0
- package/dist/lib/agent-contract.d.ts.map +1 -0
- package/dist/lib/agent-contract.js +78 -0
- package/dist/lib/agent-contract.js.map +1 -0
- package/dist/lib/cf-auth.d.ts +76 -0
- package/dist/lib/cf-auth.d.ts.map +1 -0
- package/dist/lib/cf-auth.js +321 -0
- package/dist/lib/cf-auth.js.map +1 -0
- package/dist/lib/cli-context.d.ts +23 -0
- package/dist/lib/cli-context.d.ts.map +1 -0
- package/dist/lib/cli-context.js +40 -0
- package/dist/lib/cli-context.js.map +1 -0
- package/dist/lib/cloudflare-deploy-manifest.d.ts +26 -0
- package/dist/lib/cloudflare-deploy-manifest.d.ts.map +1 -0
- package/dist/lib/cloudflare-deploy-manifest.js +107 -0
- package/dist/lib/cloudflare-deploy-manifest.js.map +1 -0
- package/dist/lib/cloudflare-wrangler-resources.d.ts +32 -0
- package/dist/lib/cloudflare-wrangler-resources.d.ts.map +1 -0
- package/dist/lib/cloudflare-wrangler-resources.js +59 -0
- package/dist/lib/cloudflare-wrangler-resources.js.map +1 -0
- package/dist/lib/config-editor.d.ts +139 -0
- package/dist/lib/config-editor.d.ts.map +1 -0
- package/dist/lib/config-editor.js +1188 -0
- package/dist/lib/config-editor.js.map +1 -0
- package/dist/lib/deploy-shared.d.ts +55 -0
- package/dist/lib/deploy-shared.d.ts.map +1 -0
- package/dist/lib/deploy-shared.js +183 -0
- package/dist/lib/deploy-shared.js.map +1 -0
- package/dist/lib/dev-sidecar.d.ts +31 -0
- package/dist/lib/dev-sidecar.d.ts.map +1 -0
- package/dist/lib/dev-sidecar.js +1058 -0
- package/dist/lib/dev-sidecar.js.map +1 -0
- package/dist/lib/fetch-with-timeout.d.ts +14 -0
- package/dist/lib/fetch-with-timeout.d.ts.map +1 -0
- package/dist/lib/fetch-with-timeout.js +29 -0
- package/dist/lib/fetch-with-timeout.js.map +1 -0
- package/dist/lib/function-registry.d.ts +56 -0
- package/dist/lib/function-registry.d.ts.map +1 -0
- package/dist/lib/function-registry.js +210 -0
- package/dist/lib/function-registry.js.map +1 -0
- package/dist/lib/load-config.d.ts +24 -0
- package/dist/lib/load-config.d.ts.map +1 -0
- package/dist/lib/load-config.js +263 -0
- package/dist/lib/load-config.js.map +1 -0
- package/dist/lib/local-secrets.d.ts +2 -0
- package/dist/lib/local-secrets.d.ts.map +1 -0
- package/dist/lib/local-secrets.js +60 -0
- package/dist/lib/local-secrets.js.map +1 -0
- package/dist/lib/managed-resource-names.d.ts +4 -0
- package/dist/lib/managed-resource-names.d.ts.map +1 -0
- package/dist/lib/managed-resource-names.js +19 -0
- package/dist/lib/managed-resource-names.js.map +1 -0
- package/dist/lib/migrator.d.ts +57 -0
- package/dist/lib/migrator.d.ts.map +1 -0
- package/dist/lib/migrator.js +321 -0
- package/dist/lib/migrator.js.map +1 -0
- package/dist/lib/neon.d.ts +41 -0
- package/dist/lib/neon.d.ts.map +1 -0
- package/dist/lib/neon.js +325 -0
- package/dist/lib/neon.js.map +1 -0
- package/dist/lib/node-tools.d.ts +10 -0
- package/dist/lib/node-tools.d.ts.map +1 -0
- package/dist/lib/node-tools.js +32 -0
- package/dist/lib/node-tools.js.map +1 -0
- package/dist/lib/npm.d.ts +8 -0
- package/dist/lib/npm.d.ts.map +1 -0
- package/dist/lib/npm.js +10 -0
- package/dist/lib/npm.js.map +1 -0
- package/dist/lib/npx.d.ts +9 -0
- package/dist/lib/npx.d.ts.map +1 -0
- package/dist/lib/npx.js +11 -0
- package/dist/lib/npx.js.map +1 -0
- package/dist/lib/project-runtime.d.ts +38 -0
- package/dist/lib/project-runtime.d.ts.map +1 -0
- package/dist/lib/project-runtime.js +122 -0
- package/dist/lib/project-runtime.js.map +1 -0
- package/dist/lib/prompts.d.ts +28 -0
- package/dist/lib/prompts.d.ts.map +1 -0
- package/dist/lib/prompts.js +85 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/rate-limit-bindings.d.ts +11 -0
- package/dist/lib/rate-limit-bindings.d.ts.map +1 -0
- package/dist/lib/rate-limit-bindings.js +52 -0
- package/dist/lib/rate-limit-bindings.js.map +1 -0
- package/dist/lib/realtime-provision.d.ts +22 -0
- package/dist/lib/realtime-provision.d.ts.map +1 -0
- package/dist/lib/realtime-provision.js +246 -0
- package/dist/lib/realtime-provision.js.map +1 -0
- package/dist/lib/resolve-options.d.ts +42 -0
- package/dist/lib/resolve-options.d.ts.map +1 -0
- package/dist/lib/resolve-options.js +98 -0
- package/dist/lib/resolve-options.js.map +1 -0
- package/dist/lib/runtime-scaffold.d.ts +17 -0
- package/dist/lib/runtime-scaffold.d.ts.map +1 -0
- package/dist/lib/runtime-scaffold.js +366 -0
- package/dist/lib/runtime-scaffold.js.map +1 -0
- package/dist/lib/schema-check.d.ts +79 -0
- package/dist/lib/schema-check.d.ts.map +1 -0
- package/dist/lib/schema-check.js +347 -0
- package/dist/lib/schema-check.js.map +1 -0
- package/dist/lib/spinner.d.ts +20 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +42 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/telemetry.d.ts +37 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +98 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/turnstile-provision.d.ts +27 -0
- package/dist/lib/turnstile-provision.d.ts.map +1 -0
- package/dist/lib/turnstile-provision.js +144 -0
- package/dist/lib/turnstile-provision.js.map +1 -0
- package/dist/lib/update-check.d.ts +13 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +110 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/wrangler-secrets.d.ts +3 -0
- package/dist/lib/wrangler-secrets.d.ts.map +1 -0
- package/dist/lib/wrangler-secrets.js +32 -0
- package/dist/lib/wrangler-secrets.js.map +1 -0
- package/dist/lib/wrangler.d.ts +9 -0
- package/dist/lib/wrangler.d.ts.map +1 -0
- package/dist/lib/wrangler.js +84 -0
- package/dist/lib/wrangler.js.map +1 -0
- package/dist/templates/plugin/README.md.tmpl +91 -0
- package/dist/templates/plugin/client/js/package.json.tmpl +23 -0
- package/dist/templates/plugin/client/js/src/index.ts.tmpl +68 -0
- package/dist/templates/plugin/client/js/tsconfig.json.tmpl +14 -0
- package/dist/templates/plugin/server/package.json.tmpl +19 -0
- package/dist/templates/plugin/server/src/index.ts.tmpl +59 -0
- package/dist/templates/plugin/server/tsconfig.json.tmpl +14 -0
- package/llms.txt +94 -0
- package/package.json +60 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { resolve, dirname } from 'node:path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { isCliStructuredError, raiseCliError } from '../lib/agent-contract.js';
|
|
6
|
+
import { spin } from '../lib/spinner.js';
|
|
7
|
+
import { isJson, isQuiet } from '../lib/cli-context.js';
|
|
8
|
+
import { promptText } from '../lib/prompts.js';
|
|
9
|
+
import { fetchWithTimeout } from '../lib/fetch-with-timeout.js';
|
|
10
|
+
import { resolveServiceKey, resolveServerUrl } from '../lib/resolve-options.js';
|
|
11
|
+
/**
|
|
12
|
+
* `npx edgebase export` — Export table data as JSON.
|
|
13
|
+
*
|
|
14
|
+
* - `--format json` (only JSON supported)
|
|
15
|
+
* - `--table <name>` — Required: specific table to export
|
|
16
|
+
* - `--output <path>` — Output file path
|
|
17
|
+
* - `--url <url>` — Server URL (or EDGEBASE_URL env)
|
|
18
|
+
* - `--service-key <key>` — Service Key (or EDGEBASE_SERVICE_KEY env, or .edgebase/secrets.json)
|
|
19
|
+
*
|
|
20
|
+
* Uses Service Key authentication to call the backup export API endpoint.
|
|
21
|
+
* Authentication/URL resolution follows the same pattern as `backup` command.
|
|
22
|
+
*/
|
|
23
|
+
export const exportCommand = new Command('export')
|
|
24
|
+
.description('Export table data as JSON')
|
|
25
|
+
.option('--format <type>', 'Export format (only "json" supported)', 'json')
|
|
26
|
+
.option('--table <name>', 'Table to export')
|
|
27
|
+
.option('--output <path>', 'Output file path')
|
|
28
|
+
.option('--url <url>', 'Server URL (or EDGEBASE_URL env)')
|
|
29
|
+
.option('--service-key <key>', 'Service Key (or EDGEBASE_SERVICE_KEY env)')
|
|
30
|
+
.action(async (options) => {
|
|
31
|
+
const format = options.format.toLowerCase();
|
|
32
|
+
if (format !== 'json') {
|
|
33
|
+
raiseCliError({
|
|
34
|
+
code: 'export_format_unsupported',
|
|
35
|
+
field: 'format',
|
|
36
|
+
message: `Unsupported format: "${format}". Only "json" is currently supported.`,
|
|
37
|
+
hint: 'Rerun with --format json.',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Interactive prompt for --table if missing (TTY only)
|
|
41
|
+
if (!options.table) {
|
|
42
|
+
options.table = await promptText('Which table to export?', undefined, {
|
|
43
|
+
field: 'table',
|
|
44
|
+
hint: 'Rerun with --table <name>.',
|
|
45
|
+
message: 'A table name is required before export can continue.',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Resolve Service Key and URL via shared utilities
|
|
49
|
+
const serviceKey = resolveServiceKey(options);
|
|
50
|
+
const serverUrl = resolveServerUrl(options);
|
|
51
|
+
const tableName = options.table;
|
|
52
|
+
const defaultName = `${tableName}-export.json`;
|
|
53
|
+
const outputPath = resolve(options.output || `./${defaultName}`);
|
|
54
|
+
// Ensure output directory exists
|
|
55
|
+
const outputDir = dirname(outputPath);
|
|
56
|
+
if (!existsSync(outputDir)) {
|
|
57
|
+
mkdirSync(outputDir, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
if (!isQuiet()) {
|
|
60
|
+
console.log(chalk.blue('📦 Exporting table data...'));
|
|
61
|
+
console.log(chalk.dim(` Table: ${tableName}`));
|
|
62
|
+
console.log(chalk.dim(` Format: ${format}`));
|
|
63
|
+
console.log(chalk.dim(` Output: ${outputPath}`));
|
|
64
|
+
console.log();
|
|
65
|
+
}
|
|
66
|
+
// Call Export API endpoint (Service Key path)
|
|
67
|
+
const exportUrl = `${serverUrl.replace(/\/$/, '')}/admin/api/backup/export/${encodeURIComponent(tableName)}?format=json`;
|
|
68
|
+
const s = spin('Fetching data from server...');
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetchWithTimeout(exportUrl, {
|
|
71
|
+
headers: {
|
|
72
|
+
'X-EdgeBase-Service-Key': serviceKey,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const error = await response.text();
|
|
77
|
+
let message;
|
|
78
|
+
try {
|
|
79
|
+
const parsed = JSON.parse(error);
|
|
80
|
+
message = parsed.message || error;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
message = error;
|
|
84
|
+
}
|
|
85
|
+
s.fail(`Export failed (${response.status})`);
|
|
86
|
+
raiseCliError({
|
|
87
|
+
code: response.status === 404 ? 'export_table_not_found' : 'export_failed',
|
|
88
|
+
message,
|
|
89
|
+
hint: response.status === 401
|
|
90
|
+
? 'Check your Service Key. It may have been rotated.'
|
|
91
|
+
: response.status === 404
|
|
92
|
+
? `Table "${tableName}" not found. Check the table name and retry.`
|
|
93
|
+
: 'Check the server URL and ensure the server is running.',
|
|
94
|
+
details: {
|
|
95
|
+
table: tableName,
|
|
96
|
+
status: response.status,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const data = await response.text();
|
|
101
|
+
writeFileSync(outputPath, data, 'utf-8');
|
|
102
|
+
// Count records
|
|
103
|
+
let recordCount = 0;
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(data);
|
|
106
|
+
recordCount = Array.isArray(parsed) ? parsed.length : 0;
|
|
107
|
+
}
|
|
108
|
+
catch { /* ignore */ }
|
|
109
|
+
s.succeed(`Exported ${recordCount} record(s) from "${tableName}"`);
|
|
110
|
+
// Show server notice if present (e.g., View table warning)
|
|
111
|
+
const notice = response.headers.get('x-edgebase-notice');
|
|
112
|
+
if (notice) {
|
|
113
|
+
console.log(chalk.yellow('⚠'), chalk.yellow(notice));
|
|
114
|
+
}
|
|
115
|
+
if (isJson()) {
|
|
116
|
+
console.log(JSON.stringify({
|
|
117
|
+
status: 'success',
|
|
118
|
+
table: tableName,
|
|
119
|
+
records: recordCount,
|
|
120
|
+
output: outputPath,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
else if (!isQuiet()) {
|
|
124
|
+
console.log(chalk.dim(` → ${outputPath}`));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (isCliStructuredError(err))
|
|
129
|
+
throw err;
|
|
130
|
+
s.fail('Export failed');
|
|
131
|
+
raiseCliError({
|
|
132
|
+
code: 'export_failed',
|
|
133
|
+
message: err.message,
|
|
134
|
+
hint: 'Check the server URL and ensure the server is running.',
|
|
135
|
+
details: {
|
|
136
|
+
table: tableName,
|
|
137
|
+
output: outputPath,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC;;;GAGG;AACH,eAAO,MAAM,WAAW,SAqLpB,CAAC"}
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import { writeFileSync, mkdirSync, existsSync, chmodSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { deriveProjectSlug, ensureLocalWranglerToml, ensureRuntimeScaffold } from '../lib/runtime-scaffold.js';
|
|
8
|
+
/**
|
|
9
|
+
* `edgebase init [dir]` — Project scaffolding.
|
|
10
|
+
* Creates edgebase.config.ts, functions/ directory, env files, and .gitignore.
|
|
11
|
+
*/
|
|
12
|
+
export const initCommand = new Command('init')
|
|
13
|
+
.description('Initialize a new EdgeBase project')
|
|
14
|
+
.argument('[dir]', 'Project directory', '.')
|
|
15
|
+
.option('--no-dev', 'Skip automatically starting the dev server after scaffolding')
|
|
16
|
+
.option('--no-open', 'Do not open the Admin Dashboard when auto-starting the dev server')
|
|
17
|
+
.action(async (dir, options) => {
|
|
18
|
+
const projectDir = resolve(dir);
|
|
19
|
+
const localCliEntry = resolveLocalCliEntry(projectDir);
|
|
20
|
+
const edgebaseBin = localCliEntry ? `node ${localCliEntry}` : 'npx edgebase';
|
|
21
|
+
const needsPublishedPackages = localCliEntry === null;
|
|
22
|
+
console.log(chalk.blue('⚡ Initializing EdgeBase project...'));
|
|
23
|
+
console.log();
|
|
24
|
+
// Create project directory if needed
|
|
25
|
+
if (!existsSync(projectDir)) {
|
|
26
|
+
mkdirSync(projectDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
const configPath = join(projectDir, 'edgebase.config.ts');
|
|
29
|
+
// Create edgebase.config.ts template
|
|
30
|
+
if (!existsSync(configPath)) {
|
|
31
|
+
writeFileSync(configPath, CONFIG_TEMPLATE);
|
|
32
|
+
console.log(chalk.green(' ✓'), 'edgebase.config.ts');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log(chalk.yellow(' ⏭'), 'edgebase.config.ts (already exists)');
|
|
36
|
+
}
|
|
37
|
+
const configDir = join(projectDir, 'config');
|
|
38
|
+
const rateLimitsPath = join(configDir, 'rate-limits.ts');
|
|
39
|
+
if (!existsSync(rateLimitsPath)) {
|
|
40
|
+
mkdirSync(configDir, { recursive: true });
|
|
41
|
+
writeFileSync(rateLimitsPath, RATE_LIMITS_TEMPLATE);
|
|
42
|
+
console.log(chalk.green(' ✓'), 'config/rate-limits.ts');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(chalk.yellow(' ⏭'), 'config/rate-limits.ts (already exists)');
|
|
46
|
+
}
|
|
47
|
+
// Create functions/ directory
|
|
48
|
+
const functionsDir = join(projectDir, 'functions');
|
|
49
|
+
if (!existsSync(functionsDir)) {
|
|
50
|
+
mkdirSync(functionsDir, { recursive: true });
|
|
51
|
+
// Create example function
|
|
52
|
+
writeFileSync(join(functionsDir, 'health.ts'), EXAMPLE_FUNCTION_TEMPLATE);
|
|
53
|
+
console.log(chalk.green(' ✓'), 'functions/health.ts');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(chalk.yellow(' ⏭'), 'functions/ (already exists)');
|
|
57
|
+
}
|
|
58
|
+
// Create .env.development for local development secrets
|
|
59
|
+
const envDevPath = join(projectDir, '.env.development');
|
|
60
|
+
if (!existsSync(envDevPath)) {
|
|
61
|
+
const devUserSecret = generateDevSecret();
|
|
62
|
+
const devAdminSecret = generateDevSecret();
|
|
63
|
+
writeFileSync(envDevPath, ENV_DEVELOPMENT_TEMPLATE
|
|
64
|
+
.replace('JWT_USER_SECRET=', `JWT_USER_SECRET=${devUserSecret}`)
|
|
65
|
+
.replace('JWT_ADMIN_SECRET=', `JWT_ADMIN_SECRET=${devAdminSecret}`));
|
|
66
|
+
console.log(chalk.green(' ✓'), '.env.development (JWT secrets auto-generated)');
|
|
67
|
+
// Also save to .edgebase/secrets.json for local key management
|
|
68
|
+
const edgebaseDir = join(projectDir, '.edgebase');
|
|
69
|
+
const secretsJsonPath = join(edgebaseDir, 'secrets.json');
|
|
70
|
+
if (!existsSync(edgebaseDir))
|
|
71
|
+
mkdirSync(edgebaseDir, { recursive: true });
|
|
72
|
+
writeFileSync(secretsJsonPath, JSON.stringify({ JWT_USER_SECRET: devUserSecret, JWT_ADMIN_SECRET: devAdminSecret }, null, 2), 'utf-8');
|
|
73
|
+
chmodSync(secretsJsonPath, 0o600);
|
|
74
|
+
}
|
|
75
|
+
// Create example env files (committed to repo for onboarding)
|
|
76
|
+
const envDevExamplePath = join(projectDir, '.env.development.example');
|
|
77
|
+
if (!existsSync(envDevExamplePath)) {
|
|
78
|
+
writeFileSync(envDevExamplePath, ENV_DEVELOPMENT_TEMPLATE);
|
|
79
|
+
console.log(chalk.green(' ✓'), '.env.development.example');
|
|
80
|
+
}
|
|
81
|
+
const envReleaseExamplePath = join(projectDir, '.env.release.example');
|
|
82
|
+
if (!existsSync(envReleaseExamplePath)) {
|
|
83
|
+
writeFileSync(envReleaseExamplePath, ENV_RELEASE_TEMPLATE);
|
|
84
|
+
console.log(chalk.green(' ✓'), '.env.release.example');
|
|
85
|
+
}
|
|
86
|
+
const packageJsonPath = join(projectDir, 'package.json');
|
|
87
|
+
if (!existsSync(packageJsonPath)) {
|
|
88
|
+
writeFileSync(packageJsonPath, PACKAGE_JSON_TEMPLATE(deriveProjectSlug(projectDir), localCliEntry, needsPublishedPackages));
|
|
89
|
+
console.log(chalk.green(' ✓'), 'package.json');
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const packageJsonChanged = ensureScaffoldPackageJson(packageJsonPath, deriveProjectSlug(projectDir), localCliEntry, needsPublishedPackages);
|
|
93
|
+
console.log(packageJsonChanged ? chalk.green(' ✓') : chalk.yellow(' ⏭'), packageJsonChanged ? 'package.json (updated)' : 'package.json (already exists)');
|
|
94
|
+
}
|
|
95
|
+
const wranglerPath = join(projectDir, 'wrangler.toml');
|
|
96
|
+
if (!existsSync(wranglerPath)) {
|
|
97
|
+
ensureLocalWranglerToml(projectDir);
|
|
98
|
+
console.log(chalk.green(' ✓'), 'wrangler.toml');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log(chalk.yellow(' ⏭'), 'wrangler.toml (already exists)');
|
|
102
|
+
}
|
|
103
|
+
const gitignorePath = join(projectDir, '.gitignore');
|
|
104
|
+
const hadGitignore = existsSync(gitignorePath);
|
|
105
|
+
const gitignoreChanged = ensureScaffoldGitignore(gitignorePath);
|
|
106
|
+
console.log(gitignoreChanged ? chalk.green(' ✓') : chalk.yellow(' ⏭'), !hadGitignore
|
|
107
|
+
? '.gitignore'
|
|
108
|
+
: gitignoreChanged
|
|
109
|
+
? '.gitignore (updated)'
|
|
110
|
+
: '.gitignore (already exists)');
|
|
111
|
+
ensureRuntimeScaffold(projectDir);
|
|
112
|
+
console.log(chalk.green(' ✓'), '.edgebase/runtime scaffold');
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(chalk.green('✨'), 'Project initialized!');
|
|
115
|
+
console.log();
|
|
116
|
+
// Auto-start dev server with admin dashboard
|
|
117
|
+
if (!options.dev) {
|
|
118
|
+
console.log(chalk.bold('Next steps:'));
|
|
119
|
+
console.log(` 1. Edit ${chalk.cyan('edgebase.config.ts')} to define your schema and auth settings`);
|
|
120
|
+
if (needsPublishedPackages && shouldShowInstallStep()) {
|
|
121
|
+
console.log(` 2. Run ${chalk.cyan(`'npm install'`)} to install the local EdgeBase CLI`);
|
|
122
|
+
console.log(` 3. Run ${chalk.cyan(`'${edgebaseBin} dev'`)} to start the local development server`);
|
|
123
|
+
console.log(` 4. Open the Admin Dashboard to explore your API`);
|
|
124
|
+
console.log(` 5. Read the docs: ${chalk.cyan('https://edgebase.fun/docs/getting-started/quickstart')}`);
|
|
125
|
+
}
|
|
126
|
+
else if (needsPublishedPackages) {
|
|
127
|
+
console.log(` 2. Run ${chalk.cyan(`'${edgebaseBin} dev'`)} to start the local development server`);
|
|
128
|
+
console.log(` 3. Open the Admin Dashboard to explore your API`);
|
|
129
|
+
console.log(` 4. Read the docs: ${chalk.cyan('https://edgebase.fun/docs/getting-started/quickstart')}`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log(` 2. Run ${chalk.cyan(`'${edgebaseBin} dev'`)} to start the local development server`);
|
|
133
|
+
console.log(` 3. Open the Admin Dashboard to explore your API`);
|
|
134
|
+
console.log(` 4. Read the docs: ${chalk.cyan('https://edgebase.fun/docs/getting-started/quickstart')}`);
|
|
135
|
+
}
|
|
136
|
+
console.log();
|
|
137
|
+
console.log(chalk.dim('When you\'re ready for production:'));
|
|
138
|
+
const publishedInstallStep = needsPublishedPackages && shouldShowInstallStep();
|
|
139
|
+
console.log(` ${publishedInstallStep ? '6' : '5'}. Set ${chalk.cyan('release: true')} in edgebase.config.ts`);
|
|
140
|
+
console.log(` ${publishedInstallStep ? '7' : '6'}. Run ${chalk.cyan(`'${edgebaseBin} deploy'`)} to deploy to Cloudflare`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
console.log(chalk.bold('Next steps:'));
|
|
144
|
+
console.log(` 1. Edit ${chalk.cyan('edgebase.config.ts')} to define your schema and auth settings`);
|
|
145
|
+
console.log(` 2. Open the Admin Dashboard to explore your API`);
|
|
146
|
+
console.log(` 3. Read the docs: ${chalk.cyan('https://edgebase.fun/docs/getting-started/quickstart')}`);
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(chalk.dim('When you\'re ready for production:'));
|
|
149
|
+
console.log(` 4. Set ${chalk.cyan('release: true')} in edgebase.config.ts`);
|
|
150
|
+
console.log(` 5. Run ${chalk.cyan(`'${edgebaseBin} deploy'`)} to deploy to Cloudflare`);
|
|
151
|
+
console.log();
|
|
152
|
+
console.log(chalk.blue('⚡'), 'Starting dev server...');
|
|
153
|
+
console.log();
|
|
154
|
+
// Run dev in the project directory (same process, no redundant npx spawn)
|
|
155
|
+
process.chdir(projectDir);
|
|
156
|
+
const { devCommand } = await import('./dev.js');
|
|
157
|
+
const devArgs = options.open ? [] : ['--no-open'];
|
|
158
|
+
await devCommand.parseAsync(devArgs, { from: 'user' });
|
|
159
|
+
});
|
|
160
|
+
function generateDevSecret() {
|
|
161
|
+
return randomBytes(32).toString('hex');
|
|
162
|
+
}
|
|
163
|
+
// ─── Templates ───
|
|
164
|
+
const CONFIG_TEMPLATE = `import { defineConfig } from '@edge-base/shared';
|
|
165
|
+
import { rateLimiting } from './config/rate-limits';
|
|
166
|
+
|
|
167
|
+
export default defineConfig({
|
|
168
|
+
// release: false (default) — access policies are bypassed during development.
|
|
169
|
+
// Set release: true before production deployment to enable deny-by-default access.
|
|
170
|
+
|
|
171
|
+
databases: {
|
|
172
|
+
// Add your first DB block here, for example:
|
|
173
|
+
// app: {
|
|
174
|
+
// tables: {
|
|
175
|
+
// posts: {
|
|
176
|
+
// schema: {
|
|
177
|
+
// title: { type: 'string', required: true },
|
|
178
|
+
// content: { type: 'text' },
|
|
179
|
+
// },
|
|
180
|
+
// },
|
|
181
|
+
// },
|
|
182
|
+
// },
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// Optional rooms use handlers.lifecycle / handlers.actions / handlers.timers:
|
|
186
|
+
// rooms: {
|
|
187
|
+
// game: {
|
|
188
|
+
// maxPlayers: 8,
|
|
189
|
+
// handlers: {
|
|
190
|
+
// lifecycle: {
|
|
191
|
+
// onCreate(room) {
|
|
192
|
+
// room.setSharedState(() => ({ status: 'waiting' }));
|
|
193
|
+
// },
|
|
194
|
+
// },
|
|
195
|
+
// actions: {
|
|
196
|
+
// PING: (_payload, room) => {
|
|
197
|
+
// room.broadcast('PONG', { at: Date.now() });
|
|
198
|
+
// },
|
|
199
|
+
// },
|
|
200
|
+
// },
|
|
201
|
+
// },
|
|
202
|
+
// },
|
|
203
|
+
|
|
204
|
+
auth: {
|
|
205
|
+
emailAuth: true,
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
storage: {
|
|
209
|
+
buckets: {
|
|
210
|
+
uploads: {
|
|
211
|
+
// Uses the generated STORAGE R2 binding by default.
|
|
212
|
+
// Add access policies here when ready for production:
|
|
213
|
+
// access: {
|
|
214
|
+
// read: () => true,
|
|
215
|
+
// write: (auth) => auth !== null,
|
|
216
|
+
// delete: (auth) => auth !== null,
|
|
217
|
+
// },
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
serviceKeys: {
|
|
223
|
+
keys: [
|
|
224
|
+
{
|
|
225
|
+
kid: 'root',
|
|
226
|
+
tier: 'root',
|
|
227
|
+
scopes: ['*'],
|
|
228
|
+
secretSource: 'dashboard',
|
|
229
|
+
secretRef: 'SERVICE_KEY',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
rateLimiting,
|
|
235
|
+
|
|
236
|
+
cors: {
|
|
237
|
+
origin: '*',
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
`;
|
|
241
|
+
const RATE_LIMITS_TEMPLATE = `export const rateLimiting = {
|
|
242
|
+
global: {
|
|
243
|
+
requests: 10_000_000,
|
|
244
|
+
window: '60s',
|
|
245
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1001' },
|
|
246
|
+
},
|
|
247
|
+
db: {
|
|
248
|
+
requests: 100,
|
|
249
|
+
window: '60s',
|
|
250
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1002' },
|
|
251
|
+
},
|
|
252
|
+
storage: {
|
|
253
|
+
requests: 50,
|
|
254
|
+
window: '60s',
|
|
255
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1003' },
|
|
256
|
+
},
|
|
257
|
+
functions: {
|
|
258
|
+
requests: 50,
|
|
259
|
+
window: '60s',
|
|
260
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1004' },
|
|
261
|
+
},
|
|
262
|
+
auth: {
|
|
263
|
+
requests: 30,
|
|
264
|
+
window: '60s',
|
|
265
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1005' },
|
|
266
|
+
},
|
|
267
|
+
authSignin: {
|
|
268
|
+
requests: 10,
|
|
269
|
+
window: '60s',
|
|
270
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1006' },
|
|
271
|
+
},
|
|
272
|
+
authSignup: {
|
|
273
|
+
requests: 10,
|
|
274
|
+
window: '60s',
|
|
275
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1007' },
|
|
276
|
+
},
|
|
277
|
+
events: {
|
|
278
|
+
requests: 100,
|
|
279
|
+
window: '60s',
|
|
280
|
+
binding: { limit: 10_000_000, period: 60, namespaceId: '1008' },
|
|
281
|
+
},
|
|
282
|
+
} as const;
|
|
283
|
+
`;
|
|
284
|
+
const EXAMPLE_FUNCTION_TEMPLATE = `import { defineFunction } from '@edge-base/shared';
|
|
285
|
+
|
|
286
|
+
export const GET = defineFunction(async () => {
|
|
287
|
+
return Response.json({ ok: true });
|
|
288
|
+
});
|
|
289
|
+
`;
|
|
290
|
+
const GITIGNORE_RULES = [
|
|
291
|
+
'node_modules/',
|
|
292
|
+
'dist/',
|
|
293
|
+
'.wrangler/',
|
|
294
|
+
'.wrangler.generated.*',
|
|
295
|
+
'.dev.vars',
|
|
296
|
+
'.env.development',
|
|
297
|
+
'.env.release',
|
|
298
|
+
'.edgebase/',
|
|
299
|
+
'edgebase.d.ts',
|
|
300
|
+
'*.local',
|
|
301
|
+
];
|
|
302
|
+
const GITIGNORE_TEMPLATE = `${GITIGNORE_RULES.join('\n')}\n`;
|
|
303
|
+
function resolveLocalCliEntry(projectDir) {
|
|
304
|
+
let currentDir = resolve(projectDir);
|
|
305
|
+
while (true) {
|
|
306
|
+
const repoPackageJsonPath = join(currentDir, 'package.json');
|
|
307
|
+
const workspacePath = join(currentDir, 'pnpm-workspace.yaml');
|
|
308
|
+
const cliEntryPath = join(currentDir, 'packages', 'cli', 'dist', 'index.js');
|
|
309
|
+
if (existsSync(repoPackageJsonPath) && existsSync(workspacePath) && existsSync(cliEntryPath)) {
|
|
310
|
+
try {
|
|
311
|
+
const repoPackageJson = JSON.parse(readFileSync(repoPackageJsonPath, 'utf-8'));
|
|
312
|
+
if (repoPackageJson.name === 'edgebase') {
|
|
313
|
+
return toPosixPath(relative(projectDir, cliEntryPath));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// Ignore malformed repo metadata and keep walking upward.
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const parentDir = dirname(currentDir);
|
|
321
|
+
if (parentDir === currentDir) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
currentDir = parentDir;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function toPosixPath(path) {
|
|
328
|
+
return path.replace(/\\/g, '/');
|
|
329
|
+
}
|
|
330
|
+
function readPackageJsonFromUrl(relativePath) {
|
|
331
|
+
try {
|
|
332
|
+
const packageJsonPath = fileURLToPath(new URL(relativePath, import.meta.url));
|
|
333
|
+
return JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function resolveScaffoldDependencyVersion(packageName) {
|
|
340
|
+
const cliPackageJson = readPackageJsonFromUrl('../../package.json');
|
|
341
|
+
const cliVersion = typeof cliPackageJson?.version === 'string' ? cliPackageJson.version : '0.1.0';
|
|
342
|
+
const cliDependencies = typeof cliPackageJson?.dependencies === 'object' && cliPackageJson.dependencies !== null
|
|
343
|
+
? cliPackageJson.dependencies
|
|
344
|
+
: {};
|
|
345
|
+
const declaredVersion = cliDependencies[packageName];
|
|
346
|
+
if (typeof declaredVersion === 'string' && !declaredVersion.startsWith('workspace:')) {
|
|
347
|
+
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(declaredVersion)
|
|
348
|
+
? `^${declaredVersion}`
|
|
349
|
+
: declaredVersion;
|
|
350
|
+
}
|
|
351
|
+
if (packageName === '@edge-base/shared') {
|
|
352
|
+
const sharedPackageJson = readPackageJsonFromUrl('../../../shared/package.json');
|
|
353
|
+
if (typeof sharedPackageJson?.version === 'string') {
|
|
354
|
+
return `^${sharedPackageJson.version}`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return `^${cliVersion}`;
|
|
358
|
+
}
|
|
359
|
+
const PACKAGE_JSON_TEMPLATE = (name, localCliEntry, needsPublishedPackages) => {
|
|
360
|
+
return `${JSON.stringify(buildPackageJsonObject(name, localCliEntry, needsPublishedPackages), null, 2)}\n`;
|
|
361
|
+
};
|
|
362
|
+
function buildPackageJsonObject(name, localCliEntry, needsPublishedPackages) {
|
|
363
|
+
const scriptPrefix = localCliEntry ? `node ${localCliEntry}` : 'edgebase';
|
|
364
|
+
const packageJson = {
|
|
365
|
+
name,
|
|
366
|
+
private: true,
|
|
367
|
+
type: 'module',
|
|
368
|
+
scripts: {
|
|
369
|
+
dev: `${scriptPrefix} dev`,
|
|
370
|
+
deploy: `${scriptPrefix} deploy`,
|
|
371
|
+
typegen: `${scriptPrefix} typegen`,
|
|
372
|
+
},
|
|
373
|
+
engines: {
|
|
374
|
+
node: '^22.0.0 || ^24.0.0',
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
if (needsPublishedPackages) {
|
|
378
|
+
packageJson.devDependencies = {
|
|
379
|
+
'@edge-base/cli': resolveScaffoldDependencyVersion('@edge-base/cli'),
|
|
380
|
+
'@edge-base/shared': resolveScaffoldDependencyVersion('@edge-base/shared'),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return packageJson;
|
|
384
|
+
}
|
|
385
|
+
// ─── Env File Templates ───
|
|
386
|
+
function shouldShowInstallStep() {
|
|
387
|
+
return process.env.EDGEBASE_BOOTSTRAP_WRAPPER !== '1';
|
|
388
|
+
}
|
|
389
|
+
function ensureScaffoldPackageJson(packageJsonPath, name, localCliEntry, needsPublishedPackages) {
|
|
390
|
+
let existing;
|
|
391
|
+
try {
|
|
392
|
+
existing = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
const generated = buildPackageJsonObject(name, localCliEntry, needsPublishedPackages);
|
|
398
|
+
let changed = false;
|
|
399
|
+
if (existing.name === undefined) {
|
|
400
|
+
existing.name = generated.name;
|
|
401
|
+
changed = true;
|
|
402
|
+
}
|
|
403
|
+
if (existing.private === undefined) {
|
|
404
|
+
existing.private = generated.private;
|
|
405
|
+
changed = true;
|
|
406
|
+
}
|
|
407
|
+
if (existing.type === undefined) {
|
|
408
|
+
existing.type = generated.type;
|
|
409
|
+
changed = true;
|
|
410
|
+
}
|
|
411
|
+
const existingScripts = ensureStringMap(existing, 'scripts');
|
|
412
|
+
for (const [key, value] of Object.entries(generated.scripts ?? {})) {
|
|
413
|
+
if (existingScripts[key] === undefined) {
|
|
414
|
+
existingScripts[key] = value;
|
|
415
|
+
changed = true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const existingEngines = ensureStringMap(existing, 'engines');
|
|
419
|
+
if (generated.engines?.node && existingEngines.node === undefined) {
|
|
420
|
+
existingEngines.node = generated.engines.node;
|
|
421
|
+
changed = true;
|
|
422
|
+
}
|
|
423
|
+
if (needsPublishedPackages) {
|
|
424
|
+
const existingDependencies = ensureStringMap(existing, 'dependencies');
|
|
425
|
+
const existingDevDependencies = ensureStringMap(existing, 'devDependencies');
|
|
426
|
+
const existingPeerDependencies = ensureStringMap(existing, 'peerDependencies');
|
|
427
|
+
const existingOptionalDependencies = ensureStringMap(existing, 'optionalDependencies');
|
|
428
|
+
for (const [key, value] of Object.entries(generated.devDependencies ?? {})) {
|
|
429
|
+
if (existingDependencies[key] === undefined
|
|
430
|
+
&& existingDevDependencies[key] === undefined
|
|
431
|
+
&& existingPeerDependencies[key] === undefined
|
|
432
|
+
&& existingOptionalDependencies[key] === undefined) {
|
|
433
|
+
existingDevDependencies[key] = value;
|
|
434
|
+
changed = true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (!changed) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(existing, null, 2)}\n`, 'utf-8');
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
function ensureScaffoldGitignore(gitignorePath) {
|
|
445
|
+
if (!existsSync(gitignorePath)) {
|
|
446
|
+
writeFileSync(gitignorePath, GITIGNORE_TEMPLATE, 'utf-8');
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
const existing = readFileSync(gitignorePath, 'utf-8');
|
|
450
|
+
const existingRules = new Set(existing
|
|
451
|
+
.split(/\r?\n/)
|
|
452
|
+
.map((line) => line.trim())
|
|
453
|
+
.filter((line) => line.length > 0));
|
|
454
|
+
const missingRules = GITIGNORE_RULES.filter((rule) => !existingRules.has(rule));
|
|
455
|
+
if (missingRules.length === 0) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
const prefix = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
|
|
459
|
+
writeFileSync(gitignorePath, `${existing}${prefix}${missingRules.join('\n')}\n`, 'utf-8');
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
function ensureStringMap(target, key) {
|
|
463
|
+
const current = target[key];
|
|
464
|
+
if (current && typeof current === 'object' && !Array.isArray(current)) {
|
|
465
|
+
return current;
|
|
466
|
+
}
|
|
467
|
+
const next = {};
|
|
468
|
+
target[key] = next;
|
|
469
|
+
return next;
|
|
470
|
+
}
|
|
471
|
+
const ENV_DEVELOPMENT_TEMPLATE = `# EdgeBase Development Environment Variables
|
|
472
|
+
# This file is git-ignored. Copy from .env.development.example to get started.
|
|
473
|
+
#
|
|
474
|
+
# JWT secrets below are auto-generated by EdgeBase project scaffolding.
|
|
475
|
+
# Add any development/test API keys below.
|
|
476
|
+
|
|
477
|
+
JWT_USER_SECRET=
|
|
478
|
+
JWT_ADMIN_SECRET=
|
|
479
|
+
|
|
480
|
+
# Example: Stripe test keys
|
|
481
|
+
# STRIPE_SECRET_KEY=sk_test_...
|
|
482
|
+
# STRIPE_WEBHOOK_SECRET=whsec_...
|
|
483
|
+
|
|
484
|
+
# Example: Email provider (Resend, etc.)
|
|
485
|
+
# EMAIL_API_KEY=re_test_...
|
|
486
|
+
`;
|
|
487
|
+
const ENV_RELEASE_TEMPLATE = `# EdgeBase Production Environment Variables
|
|
488
|
+
# This file is git-ignored. Copy from .env.release.example to get started.
|
|
489
|
+
#
|
|
490
|
+
# On \`edgebase deploy\`, these are auto-synced to Cloudflare Secrets.
|
|
491
|
+
# SERVICE_KEY is auto-managed by the deploy pipeline — do not include it here.
|
|
492
|
+
|
|
493
|
+
JWT_USER_SECRET=
|
|
494
|
+
JWT_ADMIN_SECRET=
|
|
495
|
+
|
|
496
|
+
# Database provider connection strings (only if using provider: 'neon' or 'postgres')
|
|
497
|
+
# DB_POSTGRES_SHARED_URL=postgres://user:pass@host/db?sslmode=require
|
|
498
|
+
|
|
499
|
+
# Example: Stripe live keys
|
|
500
|
+
# STRIPE_SECRET_KEY=sk_live_...
|
|
501
|
+
# STRIPE_WEBHOOK_SECRET=whsec_...
|
|
502
|
+
|
|
503
|
+
# Example: Email provider (Resend, etc.)
|
|
504
|
+
# EMAIL_API_KEY=re_...
|
|
505
|
+
`;
|
|
506
|
+
//# sourceMappingURL=init.js.map
|