@feltdb/core 0.4.9 → 0.4.11

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/bin/feltdb.js CHANGED
File without changes
@@ -7,7 +7,7 @@ import http from 'http';
7
7
  import { createRequire } from 'module';
8
8
  import { spawn, spawnSync } from 'child_process';
9
9
  import { createFeltDB, diffFlowSpec, formatFlowSpec, parseFlowSpec, planFlowSpecMigration, validateFlowSpec } from '@feltdb/core';
10
- const RELEASE_VERSION = '0.4.9';
10
+ const RELEASE_VERSION = '0.4.11';
11
11
  function loadProjectEnvironment(file = path.resolve('.env.local')) {
12
12
  if (!fs.existsSync(file))
13
13
  return;
@@ -428,9 +428,18 @@ async function handleDev(args) {
428
428
  console.log(`Studio: http://127.0.0.1:${studioPort}\n`);
429
429
  const viteArgs = ['--host', '127.0.0.1', '--port', appPort, ...(open ? ['--open'] : [])];
430
430
  const vite = runLocalVite(viteArgs, false);
431
+ let shuttingDown = false;
431
432
  const stopVite = () => { if (!vite.killed)
432
433
  vite.kill('SIGTERM'); };
433
- const stopAll = () => { stopVite(); stopSelfHosted(); };
434
+ const stopAll = () => { shuttingDown = true; stopVite(); stopSelfHosted(); };
435
+ // In an inherited terminal Ctrl-C can reach Vite before this parent process.
436
+ // Never leave Studio (or its port) running after the application exits.
437
+ vite.once('exit', code => {
438
+ if (shuttingDown)
439
+ return;
440
+ stopSelfHosted();
441
+ process.exit(code ?? 0);
442
+ });
434
443
  process.once('exit', stopAll);
435
444
  process.once('SIGINT', () => { stopAll(); process.exit(130); });
436
445
  process.once('SIGTERM', () => { stopAll(); process.exit(143); });
@@ -438,6 +447,7 @@ async function handleDev(args) {
438
447
  '--port', studioPort,
439
448
  '--namespace', runtimeNamespace || 'default',
440
449
  '--runtime', config.runtime || 'browser',
450
+ '--app-url', `http://127.0.0.1:${appPort}`,
441
451
  ...((config.runtime === 'self-hosted' || config.runtime === 'managed') && process.env.VITE_FELTDB_URL ? ['--connect', process.env.VITE_FELTDB_URL] : []),
442
452
  ...(open ? [] : ['--no-open']),
443
453
  ]);
@@ -696,6 +706,9 @@ async function handleStudio(args) {
696
706
  const runtime = args.includes('--runtime')
697
707
  ? args[args.indexOf('--runtime') + 1] || 'browser'
698
708
  : connectUrl ? 'remote' : 'browser';
709
+ const appUrl = args.includes('--app-url')
710
+ ? args[args.indexOf('--app-url') + 1]
711
+ : undefined;
699
712
  if (connectUrl) {
700
713
  console.log(`Connecting to: ${connectUrl}`);
701
714
  console.log(`Remote Studio: http://localhost:${port}\n`);
@@ -736,6 +749,8 @@ async function handleStudio(args) {
736
749
  const parameters = new URLSearchParams({ namespace, runtime });
737
750
  if (connectUrl)
738
751
  parameters.set('connect', connectUrl);
752
+ if (appUrl)
753
+ parameters.set('app', appUrl);
739
754
  const query = `?${parameters.toString()}`;
740
755
  const studioUrl = `http://127.0.0.1:${port}/${query}`;
741
756
  console.log(`FeltDB Studio ready at ${studioUrl}`);
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.4.9';
26
+ const VERSION = '0.4.11';
27
27
  function prompt(question) {
28
28
  const rl = readline.createInterface({
29
29
  input: process.stdin,
@@ -7,7 +7,7 @@
7
7
  import path from 'path';
8
8
  import { fileURLToPath } from 'url';
9
9
  import readline from 'readline';
10
- import { spawn } from 'child_process';
10
+ import { spawn, spawnSync } from 'child_process';
11
11
  import { createProject } from './create.js';
12
12
  import { FELTDB_PACKAGE_VERSION } from './package-versions.js';
13
13
  import { configureManagedAccount } from './managed-account.js';
@@ -305,8 +305,16 @@ Learn more: https://github.com/rkendel1/feltdb`);
305
305
  console.log(`Start after installing dependencies:\n cd ${projectName}\n npm install\n npm run dev\n`);
306
306
  }
307
307
  else {
308
- console.log('\n🚀 Starting the application and FeltDB Studio...\n');
309
- await run(npm, ['run', 'dev'], projectDir);
308
+ if (options.runtime === 'self-hosted' && spawnSync('docker', ['version'], { stdio: 'ignore' }).status !== 0) {
309
+ console.log('\n✅ Project and Docker image definition are ready.');
310
+ console.log('Docker is not currently running, so startup was skipped.');
311
+ console.log(`Start Docker Desktop, then run:\n cd ${projectName}\n npm run dev`);
312
+ console.log('Build the production application image with: docker compose build app');
313
+ }
314
+ else {
315
+ console.log('\n🚀 Starting the application and FeltDB Studio...\n');
316
+ await run(npm, ['run', 'dev'], projectDir);
317
+ }
310
318
  }
311
319
  }
312
320
  else {
@@ -4,6 +4,7 @@
4
4
  import fs from 'fs';
5
5
  import path from 'path';
6
6
  import { feltdbPackageRange } from './package-versions.js';
7
+ import { generateDockerCompose, generateDockerfile, generateDockerIgnore, generateDotEnvLocal, } from './docker-compose-generator.js';
7
8
  export async function createProject(options) {
8
9
  const { projectName, templatesDir } = options;
9
10
  const projectDir = path.resolve(process.cwd(), projectName);
@@ -88,47 +89,73 @@ export async function createProject(options) {
88
89
  fs.writeFileSync(path.join(projectDir, 'feltdb.config.json'), JSON.stringify(feltdbConfig, null, 2));
89
90
  const appName = applicationName.replace(/[^A-Za-z0-9_]/g, '_').replace(/^[^A-Za-z_]/, 'App_');
90
91
  const flowSpec = `app ${appName} {
91
- collection Document {
92
- title: text
93
- content: text
92
+ collection Project {
93
+ name: text
94
+ description: text
95
+ status: text
94
96
  createdAt: datetime
95
- index search using fulltext(content)
97
+ updatedAt: datetime
98
+ index status using hash(status)
96
99
  }
97
100
 
98
- collection Report {
101
+ collection Task {
102
+ projectId: text
99
103
  title: text
100
- content: text
101
- document: ref Document
104
+ description: text
105
+ status: text
106
+ priority: text
107
+ assignee: text
108
+ createdAt: datetime
109
+ updatedAt: datetime
110
+ index project using hash(projectId)
111
+ index status using hash(status)
112
+ index priority using hash(priority)
102
113
  }
103
114
 
104
- capability Research {
105
- read Document
106
- write Report
115
+ collection Activity {
116
+ timestamp: datetime
117
+ type: text
118
+ entityType: text
119
+ entityId: text
120
+ entityName: text
121
+ userId: text
122
+ index timestamp using sorted(timestamp)
107
123
  }
108
124
 
109
- agent Researcher {
110
- capability Research
111
- workflow ResearchDocument
125
+ capability Workspace {
126
+ read Project
127
+ write Project
128
+ read Task
129
+ write Task
130
+ read Activity
131
+ write Activity
112
132
  }
113
133
 
114
- workflow ResearchDocument(document: Document) {
115
- step search {
116
- input document.content
117
- }
118
- step identity {
119
- input search.output
134
+ workflow TrackTask(task: Task) {
135
+ step record {
136
+ input task.title
120
137
  }
121
138
  }
122
139
 
123
- trigger on Document.created {
124
- workflow ResearchDocument(document)
140
+ trigger on Task.created {
141
+ workflow TrackTask(task)
125
142
  }
126
143
 
127
- policy Document {
144
+ policy Project {
128
145
  read: authenticated
129
146
  write: authenticated
130
147
  }
131
- }
148
+
149
+ policy Task {
150
+ read: authenticated
151
+ write: authenticated
152
+ }
153
+
154
+ ${hasAgents ? ` agent WorkspaceAssistant {
155
+ capability Workspace
156
+ workflow TrackTask
157
+ }
158
+ ` : ''}}
132
159
  `;
133
160
  fs.writeFileSync(path.join(projectDir, 'feltdb.flow'), flowSpec);
134
161
  // Create tsconfig.json
@@ -166,9 +193,9 @@ export async function createProject(options) {
166
193
  export const db = createFeltDB(${runtimeOptions});
167
194
 
168
195
  // Collections
169
- export const projects = db.collection('projects');
170
- export const tasks = db.collection('tasks');
171
- export const activity = db.collection('activity');
196
+ export const projects = db.collection('Project');
197
+ export const tasks = db.collection('Task');
198
+ export const activity = db.collection('Activity');
172
199
 
173
200
  // Types
174
201
  export interface Project {
@@ -205,11 +232,11 @@ export interface ActivityEvent {
205
232
  }
206
233
 
207
234
  // Indexes
208
- projects.createIndex('status');
209
- tasks.createIndex('projectId');
210
- tasks.createIndex('status');
211
- tasks.createIndex('priority');
212
- activity.createIndex('timestamp');
235
+ projects.createIndex({ name: 'projects_status', type: 'hash', field: 'status' });
236
+ tasks.createIndex({ name: 'tasks_project', type: 'hash', field: 'projectId' });
237
+ tasks.createIndex({ name: 'tasks_status', type: 'hash', field: 'status' });
238
+ tasks.createIndex({ name: 'tasks_priority', type: 'hash', field: 'priority' });
239
+ activity.createIndex({ name: 'activity_timestamp', type: 'sorted', field: 'timestamp' });
213
240
 
214
241
  // Operations
215
242
  export async function createProject(data: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>): Promise<Project> {
@@ -493,17 +520,17 @@ Make it production-ready.\`;
493
520
  */
494
521
 
495
522
  export const capabilities = {
496
- 'document-read': {
523
+ 'workspace-read': {
497
524
  enabled: true,
498
- scope: ['documents:read'],
525
+ scope: ['projects:read', 'tasks:read', 'activity:read'],
499
526
  },
500
527
  'vector-search': {
501
528
  enabled: ${capabilities.includes('vector')},
502
- scope: ['documents:read', 'capabilities:execute'],
529
+ scope: ['projects:read', 'tasks:read', 'capabilities:execute'],
503
530
  },
504
- 'report-write': {
531
+ 'workspace-write': {
505
532
  enabled: true,
506
- scope: ['reports:write'],
533
+ scope: ['projects:write', 'tasks:write', 'activity:write'],
507
534
  },
508
535
  };
509
536
  `;
@@ -751,6 +778,24 @@ export function App() {
751
778
  getDashboardStats().then(setDashboardStats);
752
779
  }, [projectsList, tasksList]);
753
780
 
781
+ useEffect(() => {
782
+ const handleStudioRequest = async (event: MessageEvent) => {
783
+ if (event.data?.type !== 'feltdb:studio:read' || !event.source) return;
784
+ let hostname = '';
785
+ try { hostname = new URL(event.origin).hostname; } catch { return; }
786
+ if (hostname !== '127.0.0.1' && hostname !== 'localhost') return;
787
+ const records = {
788
+ Project: await projects.all(),
789
+ Task: await tasks.all(),
790
+ Activity: await activity.all(),
791
+ };
792
+ (event.source as Window).postMessage({ type: 'feltdb:studio:data', requestId: event.data.requestId, records }, event.origin);
793
+ };
794
+ window.addEventListener('message', handleStudioRequest);
795
+ if (window.parent !== window) window.parent.postMessage({ type: 'feltdb:studio:ready' }, '*');
796
+ return () => window.removeEventListener('message', handleStudioRequest);
797
+ }, []);
798
+
754
799
  const handleCreateProject = async (e: React.FormEvent) => {
755
800
  e.preventDefault();
756
801
  if (!newProjectName.trim()) return;
@@ -1173,6 +1218,21 @@ FELTDB_IMAGE=
1173
1218
  NODE_ENV=development
1174
1219
  `;
1175
1220
  fs.writeFileSync(path.join(projectDir, '.env.example'), envExample);
1221
+ if (runtime === 'self-hosted') {
1222
+ const dockerConfig = {
1223
+ appName: applicationName,
1224
+ appId: applicationName,
1225
+ version: feltdbPackageRange.replace(/^\^/, ''),
1226
+ framework,
1227
+ port: 7700,
1228
+ replicationPort: 7701,
1229
+ studioPort: 3000,
1230
+ };
1231
+ fs.writeFileSync(path.join(projectDir, 'docker-compose.yml'), generateDockerCompose(dockerConfig));
1232
+ fs.writeFileSync(path.join(projectDir, 'Dockerfile'), generateDockerfile(dockerConfig, framework));
1233
+ fs.writeFileSync(path.join(projectDir, '.dockerignore'), generateDockerIgnore());
1234
+ fs.writeFileSync(path.join(projectDir, '.env.docker'), generateDotEnvLocal(dockerConfig));
1235
+ }
1176
1236
  // Create RUNTIME_GUIDE.md
1177
1237
  const runtimeGuide = `# Runtime Configuration Guide
1178
1238
 
@@ -8,11 +8,9 @@
8
8
  * - Environment configuration
9
9
  */
10
10
  export function generateDockerCompose(config) {
11
- return `version: '3.9'
12
-
13
- services:
11
+ return `services:
14
12
  feltdb:
15
- image: rkendel1/feltdb:latest
13
+ image: \${FELTDB_IMAGE:-ghcr.io/rkendel1/feltdb:${config.version}}
16
14
  container_name: \${COMPOSE_PROJECT_NAME}-feltdb
17
15
  environment:
18
16
  FELTDB_APP_NAME: \${FELTDB_APP_NAME:-${config.appName}}
@@ -41,6 +39,7 @@ services:
41
39
  app.feltdb/version: "${config.version}"
42
40
 
43
41
  app:
42
+ image: \${APP_IMAGE:-${config.appName.toLowerCase().replace(/[^a-z0-9]/g, '-')}:latest}
44
43
  build:
45
44
  context: .
46
45
  dockerfile: Dockerfile
@@ -52,15 +51,12 @@ services:
52
51
  FELTDB_APP_NAME: \${FELTDB_APP_NAME:-${config.appName}}
53
52
  NODE_ENV: \${NODE_ENV:-production}
54
53
  ports:
55
- - "\${APP_PORT:-3000}:3000"
54
+ - "\${APP_PORT:-5173}:80"
56
55
  depends_on:
57
56
  feltdb:
58
57
  condition: service_healthy
59
- volumes:
60
- - ./src:/app/src
61
- - app_node_modules:/app/node_modules
62
58
  healthcheck:
63
- test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
59
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost/"]
64
60
  interval: 10s
65
61
  timeout: 5s
66
62
  retries: 3
@@ -99,22 +95,20 @@ volumes:
99
95
  driver: local
100
96
  labels:
101
97
  app.feltdb/data: "durable-operations-log"
102
- app_node_modules:
103
- driver: local
104
98
  `;
105
99
  }
106
100
  export function generateDockerfile(config, framework) {
107
- const buildCommand = framework === 'react' ? 'npm run build' : 'npm run build';
101
+ const buildCommand = 'npm run build';
108
102
  return `# FeltDB Application Container
109
103
  # Multi-stage build for optimized production image
110
104
 
111
- FROM node:18-alpine AS builder
105
+ FROM node:20-alpine AS builder
112
106
 
113
107
  WORKDIR /app
114
108
 
115
109
  # Install dependencies
116
110
  COPY package.json package-lock.json ./
117
- RUN npm ci --only=production && npm cache clean --force
111
+ RUN npm ci && npm cache clean --force
118
112
 
119
113
  # Copy source
120
114
  COPY . .
@@ -122,37 +116,9 @@ COPY . .
122
116
  # Build application
123
117
  RUN ${buildCommand}
124
118
 
125
- # Final stage
126
- FROM node:18-alpine
127
-
128
- WORKDIR /app
129
-
130
- # Install health check utility
131
- RUN apk add --no-cache curl
132
-
133
- # Copy built application
134
- COPY --from=builder /app/node_modules ./node_modules
135
- COPY --from=builder /app/dist ./dist
136
- COPY --from=builder /app/package.json ./package.json
137
- COPY --from=builder /app/feltdb.flow ./feltdb.flow
138
-
139
- # Create data directory for Node runtime
140
- RUN mkdir -p /data && chmod 755 /data
141
-
142
- # Non-root user for security
143
- RUN addgroup -g 1001 -S nodejs
144
- RUN adduser -S nodejs -u 1001
145
- USER nodejs
146
-
147
- # Health check
148
- HEALTHCHECK --interval=10s --timeout=5s --retries=3 --start-period=30s \\
149
- CMD curl -f http://localhost:3000/health || exit 1
150
-
151
- # Startup
152
- ENV NODE_ENV=production
153
- EXPOSE 3000
154
-
155
- CMD ["node", "dist/index.js"]
119
+ FROM nginx:1.27-alpine
120
+ COPY --from=builder /app/dist /usr/share/nginx/html
121
+ EXPOSE 80
156
122
  `;
157
123
  }
158
124
  export function generateDockerIgnore() {
@@ -1,4 +1,4 @@
1
1
  // One release train keeps generated applications installable. The repository
2
2
  // validation script checks these values against every workspace manifest.
3
- export const FELTDB_PACKAGE_VERSION = '0.4.9';
3
+ export const FELTDB_PACKAGE_VERSION = '0.4.11';
4
4
  export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
@@ -6,8 +6,9 @@ export interface StudioAppProps {
6
6
  token?: string;
7
7
  namespace?: string;
8
8
  deploymentRuntime?: string;
9
+ applicationUrl?: string;
9
10
  onConnect?: (url: string, token: string) => void;
10
11
  }
11
- export declare function StudioApp({ db, remoteUrl, token, namespace, deploymentRuntime, onConnect }: StudioAppProps): React.JSX.Element;
12
+ export declare function StudioApp({ db, remoteUrl, token, namespace, deploymentRuntime, applicationUrl, onConnect }: StudioAppProps): React.JSX.Element;
12
13
  export default StudioApp;
13
14
  //# sourceMappingURL=app.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAmBnD,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,WAAW,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,SAAc,EAAE,KAAU,EAAE,SAAqB,EAAE,iBAA6B,EAAE,SAAS,EAAE,EAAE,cAAc,qBAmG5I;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAmBnD,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,WAAW,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,SAAc,EAAE,KAAU,EAAE,SAAqB,EAAE,iBAA6B,EAAE,cAAmB,EAAE,SAAS,EAAE,EAAE,cAAc,qBAgGjK;AAED,eAAe,SAAS,CAAC"}
@@ -4,7 +4,8 @@ export interface StateExplorerProps {
4
4
  db?: StateFirstDB;
5
5
  model?: FlowSpec | null;
6
6
  namespace?: string;
7
+ applicationUrl?: string;
7
8
  }
8
- export declare function StateExplorer({ db, model, namespace }: StateExplorerProps): React.JSX.Element;
9
+ export declare function StateExplorer({ db, model, namespace, applicationUrl }: StateExplorerProps): React.JSX.Element;
9
10
  export default StateExplorer;
10
11
  //# sourceMappingURL=StateExplorer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateExplorer.d.ts","sourceRoot":"","sources":["../../src/components/StateExplorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAkB,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG3E,MAAM,WAAW,kBAAkB;IAAG,EAAE,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AAmBtG,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAqB,EAAE,EAAE,kBAAkB,qBAOrF;AACD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"StateExplorer.d.ts","sourceRoot":"","sources":["../../src/components/StateExplorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAkB,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG3E,MAAM,WAAW,kBAAkB;IAAG,EAAE,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE;AAoB/H,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAqB,EAAE,cAAmB,EAAE,EAAE,kBAAkB,qBAuB1G;AACD,eAAe,aAAa,CAAC"}
@@ -1,4 +1,4 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f, u as p, x as m } from "../components-gmwCs-Pb.js";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f, u as p, x as m } from "../components-q43NSTTH.js";
2
2
  import { t as h } from "../KeyManagementPanel-DZuSeWBK.js";
3
3
  import { ManagedInstancePanel as g } from "./ManagedInstancePanel.js";
4
4
  export { c as AgentExplorer, f as ApplicationDesigner, p as CapabilityExplorer, t as ConflictExplorer, a as ExecutionViewer, s as GlobalSearch, i as HealthCenter, h as KeyManagementPanel, g as ManagedInstancePanel, r as OperationsExplorer, m as OverviewDashboard, n as PeerMap, e as ProvenanceViewer, l as ReferenceExplorer, u as SettingsPanel, o as StateExplorer, d as WorkflowVisualizer };
@@ -242,28 +242,28 @@ function S(e, t) {
242
242
  }
243
243
  //#endregion
244
244
  //#region src/components/StateExplorer.tsx
245
- function C({ db: e, definition: t, namespace: n }) {
246
- let { items: r, loading: i, error: o } = b(e, t.name), [l, u] = a(null);
245
+ function C({ db: e, definition: t, namespace: n, bridgedItems: r }) {
246
+ let { items: i, loading: o, error: l } = b(e, t.name), u = r ?? i, [d, f] = a(null);
247
247
  return /* @__PURE__ */ c("article", {
248
248
  className: "state-collection studio-card",
249
249
  children: [
250
250
  /* @__PURE__ */ c("header", { children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("span", {
251
251
  className: "card-kind",
252
252
  children: "collection"
253
- }), /* @__PURE__ */ s("h2", { children: t.name })] }), /* @__PURE__ */ s("strong", { children: i ? "…" : r.length })] }),
254
- o && /* @__PURE__ */ s("p", {
253
+ }), /* @__PURE__ */ s("h2", { children: t.name })] }), /* @__PURE__ */ s("strong", { children: r ? r.length : o ? "…" : i.length })] }),
254
+ l && /* @__PURE__ */ s("p", {
255
255
  className: "runtime-error",
256
- children: o
256
+ children: l
257
257
  }),
258
- !i && !r.length && /* @__PURE__ */ s("div", {
258
+ (!o || r) && !u.length && /* @__PURE__ */ s("div", {
259
259
  className: "model-empty compact",
260
- children: "No materialized state yet. Mutations will appear here live."
260
+ children: "No records yet. Mutations will appear here live."
261
261
  }),
262
- r.map((e, r) => {
262
+ u.map((e, r) => {
263
263
  let i = String(e.id ?? e.key ?? r);
264
264
  return /* @__PURE__ */ c("button", {
265
265
  className: "state-row",
266
- onClick: () => u(l === r ? null : r),
266
+ onClick: () => f(d === r ? null : r),
267
267
  children: [
268
268
  /* @__PURE__ */ c("span", { children: [/* @__PURE__ */ s("b", { children: i }), /* @__PURE__ */ c("small", { children: [
269
269
  "flow://",
@@ -273,16 +273,30 @@ function C({ db: e, definition: t, namespace: n }) {
273
273
  "/",
274
274
  i
275
275
  ] })] }),
276
- /* @__PURE__ */ s("span", { children: l === r ? "−" : "+" }),
277
- l === r && /* @__PURE__ */ s("pre", { children: JSON.stringify(e, null, 2) })
276
+ /* @__PURE__ */ s("span", { children: d === r ? "−" : "+" }),
277
+ d === r && /* @__PURE__ */ s("pre", { children: JSON.stringify(e, null, 2) })
278
278
  ]
279
279
  }, i);
280
280
  })
281
281
  ]
282
282
  });
283
283
  }
284
- function w({ db: e, model: t, namespace: n = "default" }) {
285
- return /* @__PURE__ */ c("div", {
284
+ function w({ db: e, model: t, namespace: r = "default", applicationUrl: o = "" }) {
285
+ let l = i(null), [u, d] = a(null);
286
+ return n(() => {
287
+ if (!o) return;
288
+ let e = new URL(o).origin, t = () => l.current?.contentWindow?.postMessage({
289
+ type: "feltdb:studio:read",
290
+ requestId: "live"
291
+ }, e), n = (n) => {
292
+ n.origin === e && (n.data?.type === "feltdb:studio:ready" && t(), n.data?.type === "feltdb:studio:data" && d(n.data.records));
293
+ };
294
+ window.addEventListener("message", n);
295
+ let r = window.setInterval(t, 1500);
296
+ return () => {
297
+ window.removeEventListener("message", n), window.clearInterval(r);
298
+ };
299
+ }, [o]), /* @__PURE__ */ c("div", {
286
300
  className: "studio-model-page",
287
301
  children: [
288
302
  /* @__PURE__ */ c("header", { children: [
@@ -290,14 +304,24 @@ function w({ db: e, model: t, namespace: n = "default" }) {
290
304
  className: "eyebrow",
291
305
  children: "Observe"
292
306
  }),
293
- /* @__PURE__ */ s("h1", { children: "State" }),
294
- /* @__PURE__ */ s("p", { children: "Live, materialized application state. Every object is addressable and reactive." })
307
+ /* @__PURE__ */ s("h1", { children: "Data" }),
308
+ /* @__PURE__ */ s("p", { children: "Live application records grouped by collection. Select a record to inspect every field." })
295
309
  ] }),
310
+ o && /* @__PURE__ */ s("iframe", {
311
+ ref: l,
312
+ className: "studio-data-bridge",
313
+ src: o,
314
+ title: "FeltDB application data bridge",
315
+ onLoad: () => l.current?.contentWindow?.postMessage({
316
+ type: "feltdb:studio:read",
317
+ requestId: "initial"
318
+ }, new URL(o).origin)
319
+ }),
296
320
  /* @__PURE__ */ c("div", {
297
321
  className: "model-summary",
298
322
  children: [
299
323
  /* @__PURE__ */ c("span", { children: [t?.collections.length ?? 0, " collections"] }),
300
- /* @__PURE__ */ c("span", { children: [n, " namespace"] }),
324
+ /* @__PURE__ */ c("span", { children: [r, " namespace"] }),
301
325
  /* @__PURE__ */ s("span", { children: e ? "runtime connected" : "runtime unavailable" })
302
326
  ]
303
327
  }),
@@ -306,7 +330,8 @@ function w({ db: e, model: t, namespace: n = "default" }) {
306
330
  children: [t?.collections.map((t) => /* @__PURE__ */ s(C, {
307
331
  db: e ?? null,
308
332
  definition: t,
309
- namespace: n
333
+ namespace: r,
334
+ bridgedItems: u?.[t.name]
310
335
  }, t.name)), !t?.collections.length && /* @__PURE__ */ c("div", {
311
336
  className: "model-empty",
312
337
  children: [