create-feltdb 0.4.5 → 0.4.9
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 +2 -1
- package/dist/cli.js +131 -8
- package/dist/create.js +1309 -258
- package/dist/index.js +1 -0
- package/dist/managed-account.js +61 -0
- package/dist/package-versions.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -19,7 +19,8 @@ npx --yes create-feltdb@latest my-app --yes
|
|
|
19
19
|
|
|
20
20
|
### Options
|
|
21
21
|
|
|
22
|
-
- `--runtime <browser|node|self-hosted>`
|
|
22
|
+
- `--runtime <browser|node|self-hosted|managed>`
|
|
23
|
+
- `--managed` — connect the app and Studio to a managed FeltDB endpoint
|
|
23
24
|
- `--framework <react|vanilla>`
|
|
24
25
|
- `--no-distributed`
|
|
25
26
|
- `--no-agents`
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import readline from 'readline';
|
|
|
10
10
|
import { spawn } from 'child_process';
|
|
11
11
|
import { createProject } from './create.js';
|
|
12
12
|
import { FELTDB_PACKAGE_VERSION } from './package-versions.js';
|
|
13
|
+
import { configureManagedAccount } from './managed-account.js';
|
|
13
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
function parseArgs(args) {
|
|
15
16
|
const options = {
|
|
@@ -21,6 +22,18 @@ function parseArgs(args) {
|
|
|
21
22
|
};
|
|
22
23
|
for (let i = 0; i < args.length; i++) {
|
|
23
24
|
switch (args[i]) {
|
|
25
|
+
case '--browser':
|
|
26
|
+
options.runtime = 'browser';
|
|
27
|
+
break;
|
|
28
|
+
case '--server':
|
|
29
|
+
options.runtime = 'node';
|
|
30
|
+
break;
|
|
31
|
+
case '--self-host':
|
|
32
|
+
options.runtime = 'self-hosted';
|
|
33
|
+
break;
|
|
34
|
+
case '--managed':
|
|
35
|
+
options.runtime = 'managed';
|
|
36
|
+
break;
|
|
24
37
|
case '--runtime':
|
|
25
38
|
options.runtime = args[++i];
|
|
26
39
|
break;
|
|
@@ -49,6 +62,38 @@ function run(command, args, cwd) {
|
|
|
49
62
|
: reject(new Error(`${command} exited with status ${code ?? 'unknown'}`)));
|
|
50
63
|
});
|
|
51
64
|
}
|
|
65
|
+
async function prompt(message) {
|
|
66
|
+
const interface_ = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
67
|
+
return new Promise(resolve => interface_.question(message, value => { interface_.close(); resolve(value.trim()); }));
|
|
68
|
+
}
|
|
69
|
+
async function promptSecret(message) {
|
|
70
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
71
|
+
return '';
|
|
72
|
+
const input = process.stdin;
|
|
73
|
+
const output = process.stdout;
|
|
74
|
+
const wasRaw = input.isRaw;
|
|
75
|
+
readline.emitKeypressEvents(input);
|
|
76
|
+
input.setRawMode(true);
|
|
77
|
+
input.resume();
|
|
78
|
+
output.write(message);
|
|
79
|
+
return new Promise(resolve => {
|
|
80
|
+
let value = '';
|
|
81
|
+
const finish = () => { input.off('keypress', onKeypress); input.setRawMode(Boolean(wasRaw)); input.pause(); output.write('\n'); resolve(value); };
|
|
82
|
+
const onKeypress = (character, key) => {
|
|
83
|
+
if (key.ctrl && key.name === 'c')
|
|
84
|
+
process.exit(130);
|
|
85
|
+
if (key.name === 'return' || key.name === 'enter')
|
|
86
|
+
return finish();
|
|
87
|
+
if (key.name === 'backspace') {
|
|
88
|
+
value = value.slice(0, -1);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!key.ctrl && !key.meta && character)
|
|
92
|
+
value += character;
|
|
93
|
+
};
|
|
94
|
+
input.on('keypress', onKeypress);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
52
97
|
async function select(message, choices, initialValue) {
|
|
53
98
|
let selected = Math.max(0, choices.findIndex(choice => choice.value === initialValue));
|
|
54
99
|
const input = process.stdin;
|
|
@@ -108,6 +153,7 @@ async function promptForOptions(defaults) {
|
|
|
108
153
|
{ label: 'Browser', value: 'browser', description: 'local-first with durable browser storage' },
|
|
109
154
|
{ label: 'Node.js', value: 'node', description: 'application server or worker' },
|
|
110
155
|
{ label: 'Self-hosted', value: 'self-hosted', description: 'dedicated FeltDB server' },
|
|
156
|
+
{ label: 'Managed', value: 'managed', description: 'FeltDB-hosted persistence, sync, and workloads' },
|
|
111
157
|
], defaults.runtime),
|
|
112
158
|
framework: await select('Choose an application framework:', [
|
|
113
159
|
{ label: 'React', value: 'react' },
|
|
@@ -125,7 +171,59 @@ async function promptForOptions(defaults) {
|
|
|
125
171
|
async function main() {
|
|
126
172
|
const args = process.argv.slice(2);
|
|
127
173
|
if (args.includes('--help') || args.includes('-h')) {
|
|
128
|
-
console.log(`create-feltdb ${FELTDB_PACKAGE_VERSION}
|
|
174
|
+
console.log(`create-feltdb ${FELTDB_PACKAGE_VERSION}
|
|
175
|
+
|
|
176
|
+
Create a new FeltDB application with one command.
|
|
177
|
+
|
|
178
|
+
Usage:
|
|
179
|
+
create-feltdb [project-name] [options]
|
|
180
|
+
|
|
181
|
+
Examples:
|
|
182
|
+
create-feltdb my-app
|
|
183
|
+
create-feltdb my-app --browser
|
|
184
|
+
create-feltdb my-app --server
|
|
185
|
+
create-feltdb my-app --self-host
|
|
186
|
+
create-feltdb my-app --managed
|
|
187
|
+
create-feltdb my-app --framework react --yes
|
|
188
|
+
|
|
189
|
+
Deployment Target (Explicit):
|
|
190
|
+
--browser Local-first with durable browser storage (IndexedDB)
|
|
191
|
+
Best for: Client-side apps, offline-first experiences
|
|
192
|
+
No server required, full offline capability
|
|
193
|
+
|
|
194
|
+
--server Node.js server runtime with server-side FeltDB authority
|
|
195
|
+
Best for: Server-side applications, API servers
|
|
196
|
+
Requires production FeltDB instance or self-host
|
|
197
|
+
|
|
198
|
+
--self-host Dedicated FeltDB server with Docker Compose
|
|
199
|
+
Best for: Production deployments, multi-user systems
|
|
200
|
+
Generates Docker Compose with persistent /data volume
|
|
201
|
+
|
|
202
|
+
--managed Managed FeltDB runtime
|
|
203
|
+
Best for: Production without operating servers
|
|
204
|
+
Requires VITE_FELTDB_URL and VITE_FELTDB_API_KEY
|
|
205
|
+
|
|
206
|
+
Options:
|
|
207
|
+
--browser Explicit: Browser runtime with IndexedDB
|
|
208
|
+
--server Explicit: Node.js server runtime
|
|
209
|
+
--self-host Explicit: Self-hosted with Docker Compose
|
|
210
|
+
--managed Explicit: Managed FeltDB service
|
|
211
|
+
--runtime <runtime> Alternative: Set runtime (browser, node, self-hosted, managed)
|
|
212
|
+
--framework <framework> Choose framework: react or vanilla (default: react)
|
|
213
|
+
--no-distributed Disable distributed operation
|
|
214
|
+
--no-agents Exclude agent examples
|
|
215
|
+
--capabilities <list> Choose capabilities: search, vector, or search,vector
|
|
216
|
+
--no-install Skip npm install
|
|
217
|
+
--no-start Skip npm run dev
|
|
218
|
+
-y, --yes Use all defaults (non-interactive mode)
|
|
219
|
+
-h, --help Show this help message
|
|
220
|
+
--version Show version number
|
|
221
|
+
|
|
222
|
+
Environment Variables:
|
|
223
|
+
FELTDB_IMAGE Override the default self-hosted container image
|
|
224
|
+
NODE_ENV Set to 'development' or 'production'
|
|
225
|
+
|
|
226
|
+
Learn more: https://github.com/rkendel1/feltdb`);
|
|
129
227
|
return;
|
|
130
228
|
}
|
|
131
229
|
if (args.includes('--version')) {
|
|
@@ -149,16 +247,31 @@ async function main() {
|
|
|
149
247
|
const shouldInstall = !args.includes('--no-install');
|
|
150
248
|
const shouldStart = !args.includes('--no-start');
|
|
151
249
|
let options = parseArgs(args);
|
|
250
|
+
const runtimeDescriptions = {
|
|
251
|
+
'browser': 'Browser with IndexedDB (local-first, no server)',
|
|
252
|
+
'node': 'Node.js server (server-side authority)',
|
|
253
|
+
'self-hosted': 'Self-hosted with Docker Compose (production)',
|
|
254
|
+
'managed': 'Managed FeltDB service (hosted persistence, sync, and workloads)',
|
|
255
|
+
};
|
|
256
|
+
if (!runtimeDescriptions[options.runtime]) {
|
|
257
|
+
throw new Error(`Unsupported runtime "${options.runtime}". Choose browser, node, self-hosted, or managed.`);
|
|
258
|
+
}
|
|
152
259
|
console.log('\n✨ Creating FeltDB Application\n');
|
|
153
260
|
if (!shouldAutoYes) {
|
|
154
261
|
options = await promptForOptions(options);
|
|
155
|
-
console.log('\nConfiguration:');
|
|
156
|
-
console.log(` Runtime: ${options.runtime}`);
|
|
157
|
-
console.log(` Framework: ${options.framework}`);
|
|
158
|
-
console.log(` Distributed: ${options.distributed ? 'yes' : 'no'}`);
|
|
159
|
-
console.log(` Agents: ${options.agents ? 'yes' : 'no'}`);
|
|
160
|
-
console.log(` Capabilities: ${options.capabilities}\n`);
|
|
161
262
|
}
|
|
263
|
+
// Display the deployment target explicitly
|
|
264
|
+
console.log('\n═══════════════════════════════════════════════');
|
|
265
|
+
console.log('📦 DEPLOYMENT TARGET');
|
|
266
|
+
console.log('═══════════════════════════════════════════════');
|
|
267
|
+
console.log(`\nRuntime: ${options.runtime.toUpperCase()}`);
|
|
268
|
+
console.log(`Description: ${runtimeDescriptions[options.runtime]}`);
|
|
269
|
+
console.log(`Framework: ${options.framework}`);
|
|
270
|
+
console.log(`Distributed: ${options.distributed ? 'yes' : 'no'}`);
|
|
271
|
+
console.log(`Agents: ${options.agents ? 'yes' : 'no'}`);
|
|
272
|
+
console.log(`Capabilities: ${options.capabilities}`);
|
|
273
|
+
console.log('\n═══════════════════════════════════════════════\n');
|
|
274
|
+
const projectDir = path.resolve(process.cwd(), projectName);
|
|
162
275
|
try {
|
|
163
276
|
await createProject({
|
|
164
277
|
projectName,
|
|
@@ -170,8 +283,18 @@ async function main() {
|
|
|
170
283
|
agents: options.agents,
|
|
171
284
|
capabilities: options.capabilities,
|
|
172
285
|
});
|
|
286
|
+
if (options.runtime === 'managed') {
|
|
287
|
+
console.log('\n☁️ Setting up your managed FeltDB account...\n');
|
|
288
|
+
const email = process.env.FELTDB_MANAGED_EMAIL || (shouldAutoYes ? '' : await prompt('Email: '));
|
|
289
|
+
const password = process.env.FELTDB_MANAGED_PASSWORD || (shouldAutoYes ? '' : await promptSecret('Password (8+ characters): '));
|
|
290
|
+
if (!email || password.length < 8) {
|
|
291
|
+
throw new Error('Managed setup needs an email and an 8+ character password. In non-interactive mode set FELTDB_MANAGED_EMAIL and FELTDB_MANAGED_PASSWORD.');
|
|
292
|
+
}
|
|
293
|
+
const managed = await configureManagedAccount({ projectDir, applicationName: projectName, namespace: projectName, email, password });
|
|
294
|
+
console.log(`✓ Managed application: ${managed.application.name}`);
|
|
295
|
+
console.log(`✓ Managed environment written to ${projectName}/.env.local`);
|
|
296
|
+
}
|
|
173
297
|
console.log('\n✅ FeltDB application created successfully!\n');
|
|
174
|
-
const projectDir = path.resolve(process.cwd(), projectName);
|
|
175
298
|
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
176
299
|
if (shouldInstall) {
|
|
177
300
|
console.log('📦 Installing application, Studio, and local AI dependencies...\n');
|