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 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
- // This would be replaced at build time with the actual version
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 0.4.2\n\nUsage: create-feltdb [project-name] [options]\n\nOptions:\n --runtime <browser|node|self-hosted>\n --framework <react|vanilla>\n --no-distributed\n --no-agents\n --capabilities <list>\n --no-install\n --no-start\n -y, --yes\n -h, --help\n --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`);
128
227
  return;
129
228
  }
130
229
  if (args.includes('--version')) {
131
- console.log('0.4.2');
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');