create-feltdb 0.4.4 → 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/application-identity.js +2 -2
- package/dist/cli.js +133 -9
- package/dist/create.js +1309 -260
- 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`
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* - Version matching between components
|
|
9
9
|
*/
|
|
10
10
|
import crypto from 'crypto';
|
|
11
|
+
import { FELTDB_PACKAGE_VERSION } from './package-versions.js';
|
|
11
12
|
/**
|
|
12
13
|
* Generate a stable UUID from application name
|
|
13
14
|
* Ensures same name always produces same ID
|
|
@@ -47,8 +48,7 @@ export function sanitizeAppName(name) {
|
|
|
47
48
|
* Get current FeltDB version from package.json
|
|
48
49
|
*/
|
|
49
50
|
export function getCurrentFeltDBVersion() {
|
|
50
|
-
|
|
51
|
-
return '0.4.2';
|
|
51
|
+
return FELTDB_PACKAGE_VERSION;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
54
|
* Create application identity manifest
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,8 @@ import { fileURLToPath } from 'url';
|
|
|
9
9
|
import readline from 'readline';
|
|
10
10
|
import { spawn } from 'child_process';
|
|
11
11
|
import { createProject } from './create.js';
|
|
12
|
+
import { FELTDB_PACKAGE_VERSION } from './package-versions.js';
|
|
13
|
+
import { configureManagedAccount } from './managed-account.js';
|
|
12
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
15
|
function parseArgs(args) {
|
|
14
16
|
const options = {
|
|
@@ -20,6 +22,18 @@ function parseArgs(args) {
|
|
|
20
22
|
};
|
|
21
23
|
for (let i = 0; i < args.length; i++) {
|
|
22
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;
|
|
23
37
|
case '--runtime':
|
|
24
38
|
options.runtime = args[++i];
|
|
25
39
|
break;
|
|
@@ -48,6 +62,38 @@ function run(command, args, cwd) {
|
|
|
48
62
|
: reject(new Error(`${command} exited with status ${code ?? 'unknown'}`)));
|
|
49
63
|
});
|
|
50
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
|
+
}
|
|
51
97
|
async function select(message, choices, initialValue) {
|
|
52
98
|
let selected = Math.max(0, choices.findIndex(choice => choice.value === initialValue));
|
|
53
99
|
const input = process.stdin;
|
|
@@ -107,6 +153,7 @@ async function promptForOptions(defaults) {
|
|
|
107
153
|
{ label: 'Browser', value: 'browser', description: 'local-first with durable browser storage' },
|
|
108
154
|
{ label: 'Node.js', value: 'node', description: 'application server or worker' },
|
|
109
155
|
{ label: 'Self-hosted', value: 'self-hosted', description: 'dedicated FeltDB server' },
|
|
156
|
+
{ label: 'Managed', value: 'managed', description: 'FeltDB-hosted persistence, sync, and workloads' },
|
|
110
157
|
], defaults.runtime),
|
|
111
158
|
framework: await select('Choose an application framework:', [
|
|
112
159
|
{ label: 'React', value: 'react' },
|
|
@@ -124,11 +171,63 @@ async function promptForOptions(defaults) {
|
|
|
124
171
|
async function main() {
|
|
125
172
|
const args = process.argv.slice(2);
|
|
126
173
|
if (args.includes('--help') || args.includes('-h')) {
|
|
127
|
-
console.log(`create-feltdb
|
|
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`);
|
|
128
227
|
return;
|
|
129
228
|
}
|
|
130
229
|
if (args.includes('--version')) {
|
|
131
|
-
console.log(
|
|
230
|
+
console.log(FELTDB_PACKAGE_VERSION);
|
|
132
231
|
return;
|
|
133
232
|
}
|
|
134
233
|
// Find project name (first non-flag argument)
|
|
@@ -148,16 +247,31 @@ async function main() {
|
|
|
148
247
|
const shouldInstall = !args.includes('--no-install');
|
|
149
248
|
const shouldStart = !args.includes('--no-start');
|
|
150
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
|
+
}
|
|
151
259
|
console.log('\n✨ Creating FeltDB Application\n');
|
|
152
260
|
if (!shouldAutoYes) {
|
|
153
261
|
options = await promptForOptions(options);
|
|
154
|
-
console.log('\nConfiguration:');
|
|
155
|
-
console.log(` Runtime: ${options.runtime}`);
|
|
156
|
-
console.log(` Framework: ${options.framework}`);
|
|
157
|
-
console.log(` Distributed: ${options.distributed ? 'yes' : 'no'}`);
|
|
158
|
-
console.log(` Agents: ${options.agents ? 'yes' : 'no'}`);
|
|
159
|
-
console.log(` Capabilities: ${options.capabilities}\n`);
|
|
160
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);
|
|
161
275
|
try {
|
|
162
276
|
await createProject({
|
|
163
277
|
projectName,
|
|
@@ -169,8 +283,18 @@ async function main() {
|
|
|
169
283
|
agents: options.agents,
|
|
170
284
|
capabilities: options.capabilities,
|
|
171
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
|
+
}
|
|
172
297
|
console.log('\n✅ FeltDB application created successfully!\n');
|
|
173
|
-
const projectDir = path.resolve(process.cwd(), projectName);
|
|
174
298
|
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
175
299
|
if (shouldInstall) {
|
|
176
300
|
console.log('📦 Installing application, Studio, and local AI dependencies...\n');
|