@feltdb/core 0.6.9 → 0.6.10

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.
Files changed (98) hide show
  1. package/dist/cli/commands.js +189 -71
  2. package/dist/cli/index.js +1 -1
  3. package/dist/collection.d.ts +110 -2
  4. package/dist/collection.d.ts.map +1 -1
  5. package/dist/collection.js +228 -3
  6. package/dist/create/package-versions.js +1 -1
  7. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +408 -178
  8. package/dist/create/server-source/crates/feltdb/src/lib.rs +49 -5
  9. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +659 -0
  10. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +285 -0
  11. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +582 -0
  12. package/dist/create/server-source/crates/feltdb-server/src/main.rs +141 -0
  13. package/dist/db.d.ts +59 -0
  14. package/dist/db.d.ts.map +1 -1
  15. package/dist/db.js +94 -2
  16. package/dist/embedded-transaction.d.ts +77 -0
  17. package/dist/embedded-transaction.d.ts.map +1 -0
  18. package/dist/embedded-transaction.js +102 -0
  19. package/dist/feltdb.d.ts +49 -1
  20. package/dist/feltdb.d.ts.map +1 -1
  21. package/dist/file-db.d.ts +33 -0
  22. package/dist/file-db.d.ts.map +1 -1
  23. package/dist/file-db.js +128 -4
  24. package/dist/freshness.d.ts +119 -0
  25. package/dist/freshness.d.ts.map +1 -0
  26. package/dist/freshness.js +115 -0
  27. package/dist/http-db.d.ts +48 -0
  28. package/dist/http-db.d.ts.map +1 -1
  29. package/dist/http-db.js +77 -1
  30. package/dist/index-backend.d.ts +8 -0
  31. package/dist/index-backend.d.ts.map +1 -1
  32. package/dist/index-backend.js +13 -0
  33. package/dist/index-core.d.ts +78 -0
  34. package/dist/index-core.d.ts.map +1 -0
  35. package/dist/index-core.js +72 -0
  36. package/dist/index-manager.d.ts +11 -0
  37. package/dist/index-manager.d.ts.map +1 -1
  38. package/dist/index-manager.js +30 -13
  39. package/dist/index-types.d.ts +17 -0
  40. package/dist/index-types.d.ts.map +1 -1
  41. package/dist/index.browser.d.ts +14 -0
  42. package/dist/index.browser.d.ts.map +1 -0
  43. package/dist/index.browser.js +13 -0
  44. package/dist/index.d.ts +8 -59
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +11 -54
  47. package/dist/indexeddb-db.d.ts +32 -0
  48. package/dist/indexeddb-db.d.ts.map +1 -1
  49. package/dist/indexeddb-db.js +151 -1
  50. package/dist/memory-db.d.ts +26 -0
  51. package/dist/memory-db.d.ts.map +1 -1
  52. package/dist/memory-db.js +86 -0
  53. package/dist/runtime-registry.d.ts +32 -0
  54. package/dist/runtime-registry.d.ts.map +1 -0
  55. package/dist/runtime-registry.js +38 -0
  56. package/dist/studio-app/assets/{feltdb_wasm-B4wq4mqp.js → feltdb_wasm-CJv3wHzi.js} +1 -1
  57. package/dist/studio-app/assets/feltdb_wasm_bg-C8TG8r2n.wasm +0 -0
  58. package/dist/studio-app/assets/index-D3rT0SJi.js +28 -0
  59. package/dist/studio-app/index.html +1 -1
  60. package/dist/transaction.d.ts +98 -0
  61. package/dist/transaction.d.ts.map +1 -0
  62. package/dist/transaction.js +86 -0
  63. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  64. package/dist/workspace/browser.d.ts +22 -0
  65. package/dist/workspace/browser.d.ts.map +1 -0
  66. package/dist/workspace/browser.js +17 -0
  67. package/dist/workspace/git-identity.d.ts +35 -0
  68. package/dist/workspace/git-identity.d.ts.map +1 -0
  69. package/dist/workspace/git-identity.js +81 -0
  70. package/dist/workspace/index.d.ts +11 -1
  71. package/dist/workspace/index.d.ts.map +1 -1
  72. package/dist/workspace/index.js +6 -0
  73. package/dist/workspace/investigation-analysis.d.ts +47 -0
  74. package/dist/workspace/investigation-analysis.d.ts.map +1 -0
  75. package/dist/workspace/investigation-analysis.js +181 -0
  76. package/dist/workspace/investigation-lifecycle-manager.d.ts +86 -0
  77. package/dist/workspace/investigation-lifecycle-manager.d.ts.map +1 -0
  78. package/dist/workspace/investigation-lifecycle-manager.js +229 -0
  79. package/dist/workspace/investigation-supervisor.d.ts +100 -0
  80. package/dist/workspace/investigation-supervisor.d.ts.map +1 -0
  81. package/dist/workspace/investigation-supervisor.js +236 -0
  82. package/dist/workspace/runtime-investigation.d.ts +1 -1
  83. package/dist/workspace/runtime-investigation.d.ts.map +1 -1
  84. package/dist/workspace/runtime-investigation.js +46 -21
  85. package/dist/workspace/runtime-observation.d.ts +79 -0
  86. package/dist/workspace/runtime-observation.d.ts.map +1 -0
  87. package/dist/workspace/runtime-observation.js +152 -0
  88. package/dist/workspace/runtime-observer.d.ts +51 -0
  89. package/dist/workspace/runtime-observer.d.ts.map +1 -0
  90. package/dist/workspace/runtime-observer.js +268 -0
  91. package/dist/workspace/workspace-connection.d.ts.map +1 -1
  92. package/dist/workspace/workspace-connection.js +14 -5
  93. package/dist/workspace/workspace-types.d.ts +113 -0
  94. package/dist/workspace/workspace-types.d.ts.map +1 -1
  95. package/package.json +12 -4
  96. package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +0 -523
  97. package/dist/studio-app/assets/feltdb_wasm_bg-Ceyi7l21.wasm +0 -0
  98. package/dist/studio-app/assets/index-BF45M757.js +0 -28
@@ -7,7 +7,7 @@ import http from 'http';
7
7
  import net from 'net';
8
8
  import { createRequire } from 'module';
9
9
  import { spawn, spawnSync } from 'child_process';
10
- import { createFeltDB, diffFlowSpec, formatFlowSpec, parseFlowSpec, planFlowSpecMigration, startLocalDevelopmentAuthority, validateFlowSpec } from '@feltdb/core';
10
+ import { createFeltDB, diffFlowSpec, formatFlowSpec, InvestigationLifecycleManager, parseFlowSpec, planFlowSpecMigration, startLocalDevelopmentAuthority, validateFlowSpec } from '@feltdb/core';
11
11
  import { discoverWorkspace, ensureWorkspaceGitIgnored, generatePairingToken, persistPairingToken, displayWorkspaceStatus, initializeWorkspace, startPairingDiscoveryServer } from './workspace-integration.js';
12
12
  import { detectApplication, discoverApplicationUrl } from './application.js';
13
13
  function loadProjectEnvironment(file = path.resolve('.env.local')) {
@@ -55,6 +55,8 @@ export async function handleCommand(command, args) {
55
55
  return handleWorkspace(args);
56
56
  case 'dev':
57
57
  return handleDev(args);
58
+ case 'investigations':
59
+ return handleInvestigations(args);
58
60
  case 'build':
59
61
  return handleBuild(args);
60
62
  case 'check':
@@ -76,6 +78,92 @@ export async function handleCommand(command, args) {
76
78
  return handleHelp();
77
79
  }
78
80
  }
81
+ /**
82
+ * Inspect the durable investigation store.
83
+ *
84
+ * The evidence chain is only useful if a developer can get back to it after
85
+ * the browser is closed, so it is queryable from the command line.
86
+ */
87
+ function handleInvestigations(args) {
88
+ if (args.includes('--help')) {
89
+ console.log('Usage: feltdb investigations [<investigation-id>] [--json]\n');
90
+ console.log('List durable runtime investigations, or show one in full.\n');
91
+ console.log('Options:');
92
+ console.log(' --json Emit machine-readable JSON');
93
+ return;
94
+ }
95
+ const store = new InvestigationLifecycleManager(process.cwd());
96
+ const json = args.includes('--json');
97
+ const id = args.find(value => !value.startsWith('--'));
98
+ if (id) {
99
+ const investigation = store.loadInvestigation(id);
100
+ if (!investigation)
101
+ throw new Error(`Investigation not found: ${id}`);
102
+ if (json) {
103
+ console.log(JSON.stringify(investigation, null, 2));
104
+ return;
105
+ }
106
+ const observation = investigation.originalObservation;
107
+ console.log(`\nInvestigation ${investigation.id}`);
108
+ console.log(` Workspace: ${investigation.workspaceId}`);
109
+ console.log(` Investigation ${investigation.investigationState}`);
110
+ console.log(` Remediation: ${investigation.remediationState}`);
111
+ console.log(` Verification: ${investigation.verificationState}\n`);
112
+ if (observation) {
113
+ console.log('Observation');
114
+ console.log(` ${observation.method} ${observation.url} -> HTTP ${observation.status}`);
115
+ console.log(` ${observation.browser || 'unknown'} / ${observation.runtime || 'unknown'}`
116
+ + `${observation.durationMs !== undefined ? ` / ${observation.durationMs}ms` : ''}\n`);
117
+ }
118
+ if (investigation.evidence?.length) {
119
+ console.log('Evidence (observed by the runtime)');
120
+ for (const item of investigation.evidence)
121
+ console.log(` [${item.kind}] ${item.statement}`);
122
+ console.log();
123
+ }
124
+ if (investigation.finding) {
125
+ console.log('Finding (FeltDB analysis, not an observation)');
126
+ console.log(` ${investigation.finding.statement}`);
127
+ console.log(` confidence: ${investigation.finding.confidence}\n`);
128
+ }
129
+ if (investigation.remediation?.changeIdentity) {
130
+ console.log('Remediation');
131
+ console.log(` ${investigation.remediation.changeKind}: ${investigation.remediation.changeIdentity}`);
132
+ if (investigation.remediation.changedPaths.length) {
133
+ console.log(` changed: ${investigation.remediation.changedPaths.join(', ')}`);
134
+ }
135
+ console.log();
136
+ }
137
+ if (investigation.verificationAttempt) {
138
+ const attempt = investigation.verificationAttempt;
139
+ console.log('Verification');
140
+ console.log(` ${attempt.result}: ${attempt.summary}`);
141
+ console.log(` ${attempt.originalStatus} -> ${attempt.observedStatus ?? 'no matching observation'}\n`);
142
+ }
143
+ return;
144
+ }
145
+ const investigations = store.listInvestigations();
146
+ if (json) {
147
+ console.log(JSON.stringify(investigations, null, 2));
148
+ return;
149
+ }
150
+ if (investigations.length === 0) {
151
+ console.log('\nNo investigations recorded.');
152
+ console.log('Run "feltdb dev", exercise the application, and a runtime defect will open one.\n');
153
+ return;
154
+ }
155
+ console.log(`\n${investigations.length} investigation${investigations.length === 1 ? '' : 's'}\n`);
156
+ for (const investigation of investigations) {
157
+ const observation = investigation.originalObservation;
158
+ const summary = observation
159
+ ? `${observation.method} ${observation.url} -> ${observation.status}`
160
+ : investigation.observationId;
161
+ console.log(` ${investigation.id} ${investigation.verificationState.padEnd(12)} ${summary}`);
162
+ }
163
+ const metrics = store.metrics();
164
+ console.log(`\n ${metrics.observations} observations, ${metrics.evidenceRecords} evidence records, `
165
+ + `${metrics.serializedBytes} bytes, loaded in ${metrics.loadMilliseconds}ms\n`);
166
+ }
79
167
  function flowFile(args) {
80
168
  const candidate = args.find(value => !value.startsWith('--')) || 'feltdb.flow';
81
169
  return path.resolve(candidate);
@@ -414,37 +502,29 @@ async function handleWorkspaceConnect(args) {
414
502
  console.log(' This feature will be implemented in the next phase');
415
503
  console.log(' (when @feltdb/client workspace APIs are available)\n');
416
504
  }
417
- function runLocalVite(args, waitForExit) {
418
- const executable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
419
- const child = spawn(executable, ['exec', '--', 'vite', ...args], {
420
- cwd: process.cwd(),
421
- stdio: 'inherit',
422
- env: process.env,
423
- });
424
- if (!waitForExit)
425
- return child;
426
- return new Promise((resolve, reject) => {
427
- child.once('error', reject);
428
- child.once('exit', code => code === 0 ? resolve() : reject(new Error(`Vite exited with status ${code ?? 'unknown'}`)));
429
- });
430
- }
431
505
  async function handleDev(args) {
432
506
  var _a, _b, _c;
507
+ const projectDir = process.cwd();
433
508
  if (args.includes('--help')) {
434
- console.log('Usage: feltdb dev [--app-url URL | --app-port PORT] [--studio-port 7701] [--authority-port 7700] [--discovery-port 7799] [--no-open]');
509
+ console.log('Usage: feltdb dev [--app-url URL] [--studio-port 7701] [--authority-port 7700] [--discovery-port 7799] [--no-open]');
510
+ console.log('\nOptions:');
511
+ console.log(' --app-url <url> Application URL (e.g., http://127.0.0.1:3000)');
512
+ console.log(' --studio-port <port> FeltDB Studio port (default: 7701)');
513
+ console.log(' --authority-port <port> Authority port (default: 7700)');
514
+ console.log(' --discovery-port <port> Pairing discovery port (default: 7799)');
515
+ console.log(' --no-open Do not open Studio in browser');
435
516
  return;
436
517
  }
437
518
  loadProjectEnvironment();
438
519
  console.log('🚀 Starting FeltDB development server...\n');
439
- const projectDir = process.cwd();
440
- const configPath = path.join(projectDir, 'feltdb.config.json');
441
520
  // .feltdb/ is reserved local runtime state. Protect it before discovery,
442
521
  // initialization, the authority, or pairing can persist anything there.
522
+ // This runs after `--help` returns, so asking for help never writes anything.
443
523
  ensureWorkspaceGitIgnored(projectDir);
524
+ const configPath = path.join(projectDir, 'feltdb.config.json');
444
525
  // Initialize workspace if needed
445
526
  let workspace = discoverWorkspace(projectDir);
446
527
  if (!workspace) {
447
- // Get project name from package.json
448
528
  const packageJsonPath = path.join(projectDir, 'package.json');
449
529
  let projectId = path.basename(projectDir);
450
530
  if (fs.existsSync(packageJsonPath)) {
@@ -460,6 +540,8 @@ async function handleDev(args) {
460
540
  console.log(`✨ Initialized Development Workspace`);
461
541
  console.log(` Workspace ID: ${workspace.workspaceId}\n`);
462
542
  }
543
+ // Investigation lifecycle manager will be initialized when needed
544
+ // const investigationManager = new InvestigationLifecycleManager(projectDir);
463
545
  // Create feltdb.config.json if it doesn't exist
464
546
  if (!fs.existsSync(configPath)) {
465
547
  const packageJsonPath = path.join(projectDir, 'package.json');
@@ -478,11 +560,10 @@ async function handleDev(args) {
478
560
  runtime: 'browser',
479
561
  storage: 'indexeddb',
480
562
  distributed: true,
481
- agents: { enabled: false },
482
- capabilities: { search: true },
563
+ applicationUrl: null,
483
564
  };
484
565
  fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2) + '\n');
485
- console.log(`✨ Created feltdb.config.json with default configuration\n`);
566
+ console.log(`✨ Created feltdb.config.json\n`);
486
567
  }
487
568
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
488
569
  if (config.runtime === 'managed') {
@@ -495,17 +576,15 @@ async function handleDev(args) {
495
576
  const runtimeNamespace = config.runtime === 'managed'
496
577
  ? process.env.VITE_FELTDB_MANAGED_NAMESPACE || config.namespace
497
578
  : config.namespace;
498
- const hasAppUrl = args.includes('--app-url');
499
- const appUrlArgument = hasAppUrl ? args[args.indexOf('--app-url') + 1] : undefined;
500
- if (hasAppUrl && !appUrlArgument)
579
+ // Application URL precedence:
580
+ // 1. --app-url (highest priority)
581
+ // 2. feltdb.config.json applicationUrl
582
+ // 3. Deterministically discovered running application
583
+ // 4. No application (lowest priority - allowed)
584
+ const hasAppUrlArg = args.includes('--app-url');
585
+ const appUrlArgument = hasAppUrlArg ? args[args.indexOf('--app-url') + 1] : undefined;
586
+ if (hasAppUrlArg && !appUrlArgument)
501
587
  throw new Error('--app-url requires a URL');
502
- const hasAppPort = args.includes('--app-port') || args.includes('--port');
503
- const appPortValue = args.includes('--app-port')
504
- ? args[args.indexOf('--app-port') + 1]
505
- : args.includes('--port') ? args[args.indexOf('--port') + 1] : undefined;
506
- if (!hasAppUrl && hasAppPort && !appPortValue)
507
- throw new Error('--app-port requires a port');
508
- const appPort = appPortValue ? Number(appPortValue) : undefined;
509
588
  if (appUrlArgument) {
510
589
  try {
511
590
  const parsed = new URL(appUrlArgument);
@@ -516,28 +595,40 @@ async function handleDev(args) {
516
595
  throw new Error(`Invalid --app-url: ${appUrlArgument}`);
517
596
  }
518
597
  }
519
- if (!hasAppUrl && appPortValue && (!Number.isInteger(appPort) || appPort < 1 || appPort > 65535))
520
- throw new Error(`Invalid --app-port: ${appPortValue}`);
521
- let discoveredApplication;
522
- if (!hasAppUrl && !appPort) {
523
- discoveredApplication = await discoverApplicationUrl(projectDir);
524
- }
525
- else {
598
+ let appUrl;
599
+ let detectedApplication;
600
+ // Priority 1: --app-url takes highest priority
601
+ if (appUrlArgument) {
602
+ appUrl = appUrlArgument;
526
603
  try {
527
- discoveredApplication = { project: detectApplication(projectDir) };
604
+ detectedApplication = detectApplication(projectDir);
528
605
  }
529
606
  catch {
530
- discoveredApplication = { project: { packageManager: 'npm', framework: 'External' } };
607
+ detectedApplication = { packageManager: 'npm', framework: 'External' };
531
608
  }
532
609
  }
533
- const appUrl = appUrlArgument || (appPort ? `http://127.0.0.1:${appPort}` : discoveredApplication.url);
534
- if (!appUrl) {
535
- throw new Error('No application URL was detected.\nStart your application and run:\n feltdb dev --app-url http://127.0.0.1:<port>\nOr configure applicationUrl in feltdb.config.json.');
610
+ else {
611
+ // Priority 2: Check feltdb.config.json applicationUrl
612
+ if (config.applicationUrl) {
613
+ appUrl = config.applicationUrl;
614
+ try {
615
+ detectedApplication = detectApplication(projectDir);
616
+ }
617
+ catch {
618
+ detectedApplication = { packageManager: 'npm', framework: 'External' };
619
+ }
620
+ }
621
+ else {
622
+ // Priority 3: Try to discover an existing running application
623
+ const discovered = await discoverApplicationUrl(projectDir);
624
+ detectedApplication = discovered.project;
625
+ appUrl = discovered.url;
626
+ }
536
627
  }
537
628
  const requestedStudioPort = Number(args.includes('--studio-port') ? args[args.indexOf('--studio-port') + 1] || '7701' : '7701');
538
629
  const studioPort = String(await availablePort(requestedStudioPort));
539
630
  if (studioPort !== String(requestedStudioPort))
540
- console.log(`Port ${requestedStudioPort} is busy; using ${studioPort} for Studio.`);
631
+ console.log(`⚠ Port ${requestedStudioPort} is busy; using ${studioPort} for Studio.\n`);
541
632
  process.env.STUDIO_PORT = studioPort;
542
633
  let selfHostedStarted = false;
543
634
  let localAuthority = null;
@@ -588,45 +679,69 @@ async function handleDev(args) {
588
679
  pairingDiscoveryServer = await startPairingDiscoveryServer(token, discoveryPort);
589
680
  pairingToken = token.token;
590
681
  }
591
- console.log('FeltDB Dev Server');
592
- console.log(` Authority: ${process.env.VITE_FELTDB_URL}`);
593
- console.log(` Studio: http://127.0.0.1:${studioPort}`);
594
- console.log(` Pairing: http://127.0.0.1:${(pairingDiscoveryServer?.address()).port}`);
595
- console.log('Application');
596
- console.log(` Framework: ${discoveredApplication.project.framework}`);
597
- console.log(' Dev command: (managed externally)');
598
- console.log(` URL: ${appUrl}`);
599
- console.log(` Namespace: ${config.namespace}`);
600
- console.log(` Runtime: ${config.runtime}`);
601
- console.log(` Storage: ${config.storage}`);
602
- console.log(` Distributed: ${config.distributed}`);
682
+ // Output startup information
683
+ console.log('✨ Development Workspace');
603
684
  if (workspace) {
604
- console.log(` Workspace: ${workspace.workspaceId}\n`);
605
- console.log(`🔗 Development Workspace`);
606
- if (pairingToken) {
607
- console.log(` Pairing Code: ${pairingToken}`);
608
- console.log(` Pairing discovery: http://127.0.0.1:${(pairingDiscoveryServer?.address()).port}`);
609
- console.log(` Clients can use this code to auto-discover the workspace`);
610
- }
685
+ console.log(` Workspace ID: ${workspace.workspaceId}`);
611
686
  }
612
687
  console.log();
613
- const open = !args.includes('--no-open');
614
- console.log(`Application: ${appUrl}`);
615
- console.log(`Studio: http://127.0.0.1:${studioPort}\n`);
616
- console.log(`Using existing application at ${appUrl}\n`);
688
+ console.log('🔗 Development Workspace');
689
+ if (pairingToken) {
690
+ console.log(` Pairing Code: ${pairingToken}`);
691
+ console.log(` Pairing discovery: http://127.0.0.1:${(pairingDiscoveryServer?.address()).port}`);
692
+ }
693
+ console.log();
694
+ console.log('FeltDB Dev Server');
695
+ console.log(` Namespace: ${config.namespace}`);
696
+ console.log(` Runtime: ${config.runtime}`);
697
+ console.log(` Storage: ${config.storage}`);
698
+ console.log(` Distributed: ${config.distributed}`);
699
+ console.log();
700
+ if (appUrl) {
701
+ console.log(`Application: ${appUrl}`);
702
+ console.log(`Authority: ${process.env.VITE_FELTDB_URL}`);
703
+ console.log();
704
+ console.log(`Using existing application at ${appUrl}`);
705
+ console.log(`app=${encodeURIComponent(appUrl)}\n`);
706
+ }
707
+ else {
708
+ console.log('❌ No application URL is configured.\n');
709
+ console.log('Start your application, then run:\n');
710
+ console.log(' feltdb dev --app-url http://127.0.0.1:<port>\n');
711
+ console.log('Or set applicationUrl in feltdb.config.json\n');
712
+ console.log('FeltDB workspace is ready at:');
713
+ console.log('Authority: ' + process.env.VITE_FELTDB_URL);
714
+ console.log('Studio: http://127.0.0.1:' + studioPort);
715
+ console.log();
716
+ }
617
717
  const stopAll = () => { pairingDiscoveryServer?.close(); void localAuthority?.close(); stopSelfHosted(); };
618
718
  process.once('exit', stopAll);
619
719
  process.once('SIGINT', () => { stopAll(); process.exit(130); });
620
720
  process.once('SIGTERM', () => { stopAll(); process.exit(143); });
721
+ const open = !args.includes('--no-open');
621
722
  await handleStudio([
622
723
  '--port', studioPort,
623
724
  '--namespace', runtimeNamespace || 'default',
624
725
  '--runtime', config.runtime || 'browser',
625
- '--app-url', appUrl,
726
+ ...(appUrl ? ['--app-url', appUrl] : []),
626
727
  ...((config.runtime === 'self-hosted' || config.runtime === 'managed') && process.env.VITE_FELTDB_URL ? ['--connect', process.env.VITE_FELTDB_URL] : []),
627
728
  ...(open ? [] : ['--no-open']),
628
729
  ]);
629
730
  }
731
+ function runLocalVite(args, waitForExit) {
732
+ const executable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
733
+ const child = spawn(executable, ['exec', '--', 'vite', ...args], {
734
+ cwd: process.cwd(),
735
+ stdio: 'inherit',
736
+ env: process.env,
737
+ });
738
+ if (!waitForExit)
739
+ return child;
740
+ return new Promise((resolve, reject) => {
741
+ child.once('error', reject);
742
+ child.once('exit', code => code === 0 ? resolve() : reject(new Error(`Vite exited with status ${code ?? 'unknown'}`)));
743
+ });
744
+ }
630
745
  async function handleBuild(args) {
631
746
  console.log('🔨 Building FeltDB application...\n');
632
747
  const configPath = path.join(process.cwd(), 'feltdb.config.json');
@@ -897,11 +1012,13 @@ async function handleStudio(args) {
897
1012
  const require = createRequire(import.meta.url);
898
1013
  const packageFile = require.resolve('@feltdb/core/package.json');
899
1014
  const root = path.join(path.dirname(packageFile), 'dist', 'studio-app');
1015
+ if (!fs.existsSync(path.join(root, 'index.html'))) {
1016
+ console.log('⚠️ Studio application artifacts not found.');
1017
+ return;
1018
+ }
900
1019
  const projectFlow = ['feltdb.flow', ...fs.readdirSync(process.cwd()).filter(value => value.endsWith('.flow'))]
901
1020
  .map(value => path.resolve(process.cwd(), value))
902
1021
  .find((value, index, values) => values.indexOf(value) === index && fs.existsSync(value));
903
- if (!fs.existsSync(path.join(root, 'index.html')))
904
- throw new Error('Studio application artifact is missing; reinstall @feltdb/core');
905
1022
  const mime = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.svg': 'image/svg+xml', '.json': 'application/json' };
906
1023
  const server = http.createServer((request, response) => {
907
1024
  const pathname = decodeURIComponent(new URL(request.url || '/', 'http://localhost').pathname);
@@ -964,6 +1081,7 @@ Commands:
964
1081
  connect Connect to remote FeltDB
965
1082
  status Show connection status
966
1083
  dev Start development server
1084
+ investigations List or show durable runtime investigations
967
1085
  build Build FeltDB application
968
1086
  check Validate configuration
969
1087
  inspect Inspect runtime state
package/dist/cli/index.js CHANGED
@@ -23,7 +23,7 @@ import * as path from 'path';
23
23
  import * as readline from 'readline';
24
24
  import { getClient } from './api-client.js';
25
25
  import { loadFeltDBConfig, createDefaultConfig, validateModel, } from './config.js';
26
- const VERSION = '0.6.9';
26
+ const VERSION = '0.6.10';
27
27
  function prompt(question) {
28
28
  const rl = readline.createInterface({
29
29
  input: process.stdin,
@@ -8,9 +8,27 @@
8
8
  * for efficient, real-time state propagation.
9
9
  */
10
10
  import type { JsDb } from './feltdb.js';
11
- import type { IndexConfig } from './index-types.js';
11
+ import { type FreshnessCapability, type Revision } from './freshness.js';
12
+ import type { IndexConfig, CollectionQueryPlan } from './index-types.js';
12
13
  export type Predicate<T> = (item: T) => boolean;
13
14
  export type Subscriber<T> = (items: T[]) => void;
15
+ /**
16
+ * How a refresh decided whether the local cache could be reused.
17
+ *
18
+ * Reporting only, and deliberately explicit about *why* the runtime was
19
+ * queried, so a benchmark or a caller can tell a validated cache hit from a
20
+ * fallback that happens to be fast.
21
+ */
22
+ export interface FreshnessCheck {
23
+ /** `revision` when a revision decided it; `refresh` when the runtime was asked for the data. */
24
+ validation: 'revision' | 'refresh';
25
+ /** True only when the runtime was not queried for the collection at all. */
26
+ servedFromCache: boolean;
27
+ /** The revision the cache now corresponds to, when there is one. */
28
+ revision?: Revision;
29
+ /** Why a revision was not used. */
30
+ reason?: string;
31
+ }
14
32
  /**
15
33
  * Result of an atomic version-checked update operation.
16
34
  * Represents either a successful commit or a version conflict.
@@ -49,6 +67,26 @@ export declare class Collection<T> {
49
67
  private indexBackend;
50
68
  private indexStore;
51
69
  private indexesLoaded;
70
+ /** Incremented whenever `cache` is replaced, so the index can tell it is stale. */
71
+ private cacheGeneration;
72
+ /** The cache generation the index entries currently reflect, or -1 for none. */
73
+ private indexedGeneration;
74
+ private lastPlan;
75
+ /** Cache records addressed by id, valid for `indexedGeneration`. */
76
+ private recordsById;
77
+ /** Raw payload the cache was parsed from, used to detect that nothing changed. */
78
+ private lastRawSnapshot;
79
+ /**
80
+ * The runtime revision the cache was built from, when the runtime offers one.
81
+ *
82
+ * Captured *before* the query that produced the cache, never after. A write
83
+ * landing between the two then makes this older than the data it labels,
84
+ * which costs one unnecessary refresh. Capturing it after would make it
85
+ * newer than the data, and the cache would look current forever.
86
+ */
87
+ private cachedRevision;
88
+ /** How the last refresh decided the cache was usable. Reporting only. */
89
+ private lastFreshness;
52
90
  constructor(db: JsDb, name: string, predicate?: Predicate<T>, parent?: Collection<T>, loadIndexes?: boolean);
53
91
  /**
54
92
  * Load indexes that were persisted from a previous session.
@@ -59,8 +97,46 @@ export declare class Collection<T> {
59
97
  * Returns cached results (live-updated).
60
98
  */
61
99
  all(): Promise<T[]>;
62
- /** Find records whose fields match the supplied query. */
100
+ /**
101
+ * Find records whose fields match the supplied query.
102
+ *
103
+ * When a hash index covers one of the queried fields, the index supplies the
104
+ * candidate records and the remaining fields are checked on those candidates
105
+ * only. Otherwise every record is examined.
106
+ *
107
+ * The result is identical either way. The index is a projection of the same
108
+ * cached array a scan would walk, rebuilt whenever that array is replaced,
109
+ * so an indexed lookup cannot return a record a scan would miss or resolve
110
+ * an id the cache no longer holds.
111
+ *
112
+ * `lastQueryPlan()` reports which path ran.
113
+ */
63
114
  find(query?: Partial<T>): Promise<T[]>;
115
+ /**
116
+ * How the most recent `find` was answered.
117
+ *
118
+ * Exposed so an application — and the benchmark — can confirm that the index
119
+ * was actually consulted rather than inferring it from timing.
120
+ */
121
+ lastQueryPlan(): CollectionQueryPlan | null;
122
+ /** A hash index covering one of the queried fields, if there is one. */
123
+ private indexFor;
124
+ /**
125
+ * Candidate records from an index, or null when the index cannot be trusted.
126
+ *
127
+ * Returning null makes the caller fall back to a scan, which is always
128
+ * correct. That is the safe direction: a wrong answer is far worse than a
129
+ * slow one.
130
+ */
131
+ private indexCandidates;
132
+ /**
133
+ * Rebuild the index from the current cache when the cache has moved on.
134
+ *
135
+ * The index is only ever a projection of `this.cache`. Deriving it from the
136
+ * same array a scan walks is what makes the two paths agree by construction,
137
+ * rather than by hoping every write path remembered to update the index.
138
+ */
139
+ private ensureIndexReflectsCache;
64
140
  /**
65
141
  * Create an index on this collection for faster queries.
66
142
  * @example
@@ -159,6 +235,38 @@ export declare class Collection<T> {
159
235
  subscribe(subscriber: Subscriber<T>, _pollInterval?: number): () => void;
160
236
  /** Release runtime subscriptions owned by this live collection. */
161
237
  close(): void;
238
+ /**
239
+ * What this collection's runtime can tell it about staleness.
240
+ *
241
+ * This is a *validation mechanism*, not a guarantee that the cache is fresh.
242
+ * `validation: 'revision'` means a cheap staleness check exists; it says
243
+ * nothing about whether this collection's cache currently passes it.
244
+ *
245
+ * @example
246
+ * const capability = await people.freshness();
247
+ * // 'revision' -> a cheap staleness check exists
248
+ * // 'refresh' -> re-read is the only honest answer, and `reason` says why
249
+ */
250
+ freshness(): Promise<FreshnessCapability>;
251
+ /**
252
+ * How the last refresh decided the cache was usable.
253
+ *
254
+ * `servedFromCache` is true only when the runtime was never asked for this
255
+ * collection's data. Reporting only; it exists so a benchmark can tell a
256
+ * validated cache hit from a fallback that merely happened to be fast.
257
+ */
258
+ lastFreshnessCheck(): FreshnessCheck | null;
259
+ /**
260
+ * Read the runtime's current revision, or explain why there isn't one.
261
+ *
262
+ * The capability is re-checked on every call rather than remembered, because
263
+ * a deployment can change underneath a live collection: switching on
264
+ * replication revokes revision authority, and a collection holding a cached
265
+ * capability would keep trusting a number that stopped meaning anything.
266
+ * Any refusal — no capability, a topology change, a transport failure —
267
+ * lands here as a reason, and the caller falls back to a full refresh.
268
+ */
269
+ private currentRevision;
162
270
  /**
163
271
  * Refresh data from the database and notify subscribers.
164
272
  */
@@ -1 +1 @@
1
- {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}