@feltdb/core 0.4.4 → 0.4.6

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 (143) hide show
  1. package/README.md +22 -0
  2. package/bin/create-feltdb.js +3 -0
  3. package/bin/feltdb.js +3 -0
  4. package/dist/analytics-backend.js +1 -1
  5. package/dist/cli/api-client.js +236 -0
  6. package/dist/cli/cli.js +18 -0
  7. package/dist/cli/commands.js +795 -0
  8. package/dist/cli/config.js +66 -0
  9. package/dist/cli/index.js +399 -0
  10. package/dist/create/application-identity.js +132 -0
  11. package/dist/create/cli-scripts-generator.js +211 -0
  12. package/dist/create/cli.js +202 -0
  13. package/dist/create/create.js +638 -0
  14. package/dist/create/docker-compose-generator.js +258 -0
  15. package/dist/create/index.js +4 -0
  16. package/dist/create/package-versions.js +4 -0
  17. package/dist/create/runtime-templates.js +272 -0
  18. package/dist/index-backend.js +1 -1
  19. package/dist/migrate/analyzer/index.d.ts +2 -0
  20. package/dist/migrate/analyzer/index.js +34 -0
  21. package/dist/migrate/benchmark/index.d.ts +13 -0
  22. package/dist/migrate/benchmark/index.js +8 -0
  23. package/dist/migrate/capability-gate/index.d.ts +3 -0
  24. package/dist/migrate/capability-gate/index.js +3 -0
  25. package/dist/migrate/classifier/index.d.ts +3 -0
  26. package/dist/migrate/classifier/index.js +53 -0
  27. package/dist/migrate/cli/index.d.ts +2 -0
  28. package/dist/migrate/cli/index.js +201 -0
  29. package/dist/migrate/domain-model/index.d.ts +2 -0
  30. package/dist/migrate/domain-model/index.js +4 -0
  31. package/dist/migrate/generator/index.d.ts +2 -0
  32. package/dist/migrate/generator/index.js +21 -0
  33. package/dist/migrate/index.d.ts +16 -0
  34. package/dist/migrate/index.js +16 -0
  35. package/dist/migrate/measurement/index.d.ts +7 -0
  36. package/dist/migrate/measurement/index.js +1 -0
  37. package/dist/migrate/migrator/index.d.ts +2 -0
  38. package/dist/migrate/migrator/index.js +35 -0
  39. package/dist/migrate/planner/index.d.ts +2 -0
  40. package/dist/migrate/planner/index.js +12 -0
  41. package/dist/migrate/prover/index.d.ts +9 -0
  42. package/dist/migrate/prover/index.js +3 -0
  43. package/dist/migrate/reporter/index.d.ts +4 -0
  44. package/dist/migrate/reporter/index.js +1 -0
  45. package/dist/migrate/runtime-dependencies/index.d.ts +13 -0
  46. package/dist/migrate/runtime-dependencies/index.js +112 -0
  47. package/dist/migrate/state-contract/index.d.ts +13 -0
  48. package/dist/migrate/state-contract/index.js +49 -0
  49. package/dist/migrate/types/index.d.ts +228 -0
  50. package/dist/migrate/types/index.js +1 -0
  51. package/dist/migrate/ui-wiring/index.d.ts +18 -0
  52. package/dist/migrate/ui-wiring/index.js +2 -0
  53. package/dist/migrate/util.d.ts +5 -0
  54. package/dist/migrate/util.js +10 -0
  55. package/dist/react/index.d.ts +7 -0
  56. package/dist/react/index.d.ts.map +1 -0
  57. package/dist/react/index.js +6 -0
  58. package/dist/react/useCapability.d.ts +11 -0
  59. package/dist/react/useCapability.d.ts.map +1 -0
  60. package/dist/react/useCapability.js +30 -0
  61. package/dist/react/useCollection.d.ts +17 -0
  62. package/dist/react/useCollection.d.ts.map +1 -0
  63. package/dist/react/useCollection.js +69 -0
  64. package/dist/react/useFeltDB.d.ts +136 -0
  65. package/dist/react/useFeltDB.d.ts.map +1 -0
  66. package/dist/react/useFeltDB.js +350 -0
  67. package/dist/studio/.gitkeep +1 -0
  68. package/dist/studio/KeyManagementPanel-BOvWTRyH.js +246 -0
  69. package/dist/studio/app.d.ts +10 -0
  70. package/dist/studio/app.d.ts.map +1 -0
  71. package/dist/studio/components/AgentExplorer.d.ts +9 -0
  72. package/dist/studio/components/AgentExplorer.d.ts.map +1 -0
  73. package/dist/studio/components/ApplicationDesigner.d.ts +11 -0
  74. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -0
  75. package/dist/studio/components/CapabilityExplorer.d.ts +9 -0
  76. package/dist/studio/components/CapabilityExplorer.d.ts.map +1 -0
  77. package/dist/studio/components/ConflictExplorer.d.ts +9 -0
  78. package/dist/studio/components/ConflictExplorer.d.ts.map +1 -0
  79. package/dist/studio/components/ExecutionViewer.d.ts +9 -0
  80. package/dist/studio/components/ExecutionViewer.d.ts.map +1 -0
  81. package/dist/studio/components/GlobalSearch.d.ts +10 -0
  82. package/dist/studio/components/GlobalSearch.d.ts.map +1 -0
  83. package/dist/studio/components/HealthCenter.d.ts +9 -0
  84. package/dist/studio/components/HealthCenter.d.ts.map +1 -0
  85. package/dist/studio/components/KeyManagementPanel.d.ts +9 -0
  86. package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -0
  87. package/dist/studio/components/KeyManagementPanel.js +2 -0
  88. package/dist/studio/components/ManagedInstancePanel.d.ts +4 -0
  89. package/dist/studio/components/ManagedInstancePanel.d.ts.map +1 -0
  90. package/dist/studio/components/ManagedInstancePanel.js +281 -0
  91. package/dist/studio/components/OperationsExplorer.d.ts +10 -0
  92. package/dist/studio/components/OperationsExplorer.d.ts.map +1 -0
  93. package/dist/studio/components/OverviewDashboard.d.ts +8 -0
  94. package/dist/studio/components/OverviewDashboard.d.ts.map +1 -0
  95. package/dist/studio/components/PeerMap.d.ts +8 -0
  96. package/dist/studio/components/PeerMap.d.ts.map +1 -0
  97. package/dist/studio/components/ProvenanceViewer.d.ts +11 -0
  98. package/dist/studio/components/ProvenanceViewer.d.ts.map +1 -0
  99. package/dist/studio/components/ReferenceExplorer.d.ts +10 -0
  100. package/dist/studio/components/ReferenceExplorer.d.ts.map +1 -0
  101. package/dist/studio/components/SettingsPanel.d.ts +7 -0
  102. package/dist/studio/components/SettingsPanel.d.ts.map +1 -0
  103. package/dist/studio/components/StateExplorer.d.ts +10 -0
  104. package/dist/studio/components/StateExplorer.d.ts.map +1 -0
  105. package/dist/studio/components/WorkflowVisualizer.d.ts +9 -0
  106. package/dist/studio/components/WorkflowVisualizer.d.ts.map +1 -0
  107. package/dist/studio/components/index.d.ts +24 -0
  108. package/dist/studio/components/index.d.ts.map +1 -0
  109. package/dist/studio/components/index.js +4 -0
  110. package/dist/studio/components-BRYUceo9.js +1711 -0
  111. package/dist/studio/hooks/index.d.ts +37 -0
  112. package/dist/studio/hooks/index.d.ts.map +1 -0
  113. package/dist/studio/index.d.ts +27 -0
  114. package/dist/studio/index.d.ts.map +1 -0
  115. package/dist/studio/index.html +30 -0
  116. package/dist/studio/index.js +236 -0
  117. package/dist/studio/main.d.ts +1 -0
  118. package/dist/studio/main.d.ts.map +1 -0
  119. package/dist/studio/studio.css +2 -0
  120. package/dist/studio/types/index.d.ts +133 -0
  121. package/dist/studio/types/index.d.ts.map +1 -0
  122. package/dist/studio/utils/api.d.ts +27 -0
  123. package/dist/studio/utils/api.d.ts.map +1 -0
  124. package/dist/studio/utils/format.d.ts +24 -0
  125. package/dist/studio/utils/format.d.ts.map +1 -0
  126. package/dist/studio/utils/index.d.ts +7 -0
  127. package/dist/studio/utils/index.d.ts.map +1 -0
  128. package/dist/studio/utils/index.js +75 -0
  129. package/dist/studio/utils/managed-instance.d.ts +40 -0
  130. package/dist/studio/utils/managed-instance.d.ts.map +1 -0
  131. package/dist/studio/utils/managed-instance.js +51 -0
  132. package/dist/studio-app/.gitkeep +1 -0
  133. package/dist/studio-app/assets/feltdb_wasm-BXMn9UxO.js +1 -0
  134. package/dist/studio-app/assets/feltdb_wasm_bg-bYYbZeRM.wasm +0 -0
  135. package/dist/studio-app/assets/index-B-lZjdtI.js +28 -0
  136. package/dist/studio-app/assets/index-CB-Eed9V.css +1 -0
  137. package/dist/studio-app/index.html +3 -0
  138. package/dist/wasm/feltdb_wasm.d.ts +461 -0
  139. package/dist/wasm/feltdb_wasm.js +1690 -0
  140. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  141. package/dist/wasm/feltdb_wasm_bg.wasm.d.ts +84 -0
  142. package/dist/wasm/package.json +16 -0
  143. package/package.json +40 -5
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Docker Compose generator for self-hosted FeltDB deployments
3
+ *
4
+ * Generates:
5
+ * - docker-compose.yml with three services (FeltDB, App, Studio)
6
+ * - Dockerfile for application container
7
+ * - .dockerignore for optimized builds
8
+ * - Environment configuration
9
+ */
10
+ export function generateDockerCompose(config) {
11
+ return `version: '3.9'
12
+
13
+ services:
14
+ feltdb:
15
+ image: rkendel1/feltdb:latest
16
+ container_name: \${COMPOSE_PROJECT_NAME}-feltdb
17
+ environment:
18
+ FELTDB_APP_NAME: \${FELTDB_APP_NAME:-${config.appName}}
19
+ FELTDB_APP_ID: \${FELTDB_APP_ID:-${config.appId}}
20
+ FELTDB_VERSION: \${FELTDB_VERSION:-${config.version}}
21
+ FELTDB_PEERS: \${FELTDB_PEERS:-}
22
+ FELTDB_REPLICATION_PORT: ${config.replicationPort}
23
+ NODE_ENV: \${NODE_ENV:-production}
24
+ ports:
25
+ - "\${FELTDB_API_PORT:-${config.port}}:7700"
26
+ - "\${FELTDB_REPLICATION_PORT:-${config.replicationPort}}:${config.replicationPort}"
27
+ volumes:
28
+ - feltdb_data:/data
29
+ - ./feltdb.flow:/app/feltdb.flow:ro
30
+ healthcheck:
31
+ test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
32
+ interval: 10s
33
+ timeout: 5s
34
+ retries: 3
35
+ start_period: 30s
36
+ restart: unless-stopped
37
+ networks:
38
+ - feltdb_network
39
+ labels:
40
+ app.feltdb/component: "database"
41
+ app.feltdb/version: "${config.version}"
42
+
43
+ app:
44
+ build:
45
+ context: .
46
+ dockerfile: Dockerfile
47
+ args:
48
+ NODE_ENV: production
49
+ container_name: \${COMPOSE_PROJECT_NAME}-app
50
+ environment:
51
+ FELTDB_API_URL: http://feltdb:7700
52
+ FELTDB_APP_NAME: \${FELTDB_APP_NAME:-${config.appName}}
53
+ NODE_ENV: \${NODE_ENV:-production}
54
+ ports:
55
+ - "\${APP_PORT:-3000}:3000"
56
+ depends_on:
57
+ feltdb:
58
+ condition: service_healthy
59
+ volumes:
60
+ - ./src:/app/src
61
+ - app_node_modules:/app/node_modules
62
+ healthcheck:
63
+ test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
64
+ interval: 10s
65
+ timeout: 5s
66
+ retries: 3
67
+ start_period: 30s
68
+ restart: unless-stopped
69
+ networks:
70
+ - feltdb_network
71
+ labels:
72
+ app.feltdb/component: "application"
73
+ app.feltdb/version: "${config.version}"
74
+
75
+ studio:
76
+ image: rkendel1/feltdb-studio:latest
77
+ container_name: \${COMPOSE_PROJECT_NAME}-studio
78
+ environment:
79
+ FELTDB_API_URL: http://feltdb:7700
80
+ APP_URL: http://app:3000
81
+ ports:
82
+ - "\${STUDIO_PORT:-${config.studioPort}}:8000"
83
+ depends_on:
84
+ - feltdb
85
+ - app
86
+ networks:
87
+ - feltdb_network
88
+ labels:
89
+ app.feltdb/component: "studio"
90
+
91
+ networks:
92
+ feltdb_network:
93
+ driver: bridge
94
+ labels:
95
+ app.feltdb/network: "internal"
96
+
97
+ volumes:
98
+ feltdb_data:
99
+ driver: local
100
+ labels:
101
+ app.feltdb/data: "durable-operations-log"
102
+ app_node_modules:
103
+ driver: local
104
+ `;
105
+ }
106
+ export function generateDockerfile(config, framework) {
107
+ const buildCommand = framework === 'react' ? 'npm run build' : 'npm run build';
108
+ return `# FeltDB Application Container
109
+ # Multi-stage build for optimized production image
110
+
111
+ FROM node:18-alpine AS builder
112
+
113
+ WORKDIR /app
114
+
115
+ # Install dependencies
116
+ COPY package.json package-lock.json ./
117
+ RUN npm ci --only=production && npm cache clean --force
118
+
119
+ # Copy source
120
+ COPY . .
121
+
122
+ # Build application
123
+ RUN ${buildCommand}
124
+
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"]
156
+ `;
157
+ }
158
+ export function generateDockerIgnore() {
159
+ return `node_modules
160
+ npm-debug.log
161
+ dist
162
+ build
163
+ .git
164
+ .gitignore
165
+ .env
166
+ .env.local
167
+ .env.*.local
168
+ .DS_Store
169
+ *.log
170
+ .feltdb/keys.json
171
+ .feltdb/connection.json
172
+ .nextc
173
+ .next
174
+ coverage
175
+ .nyc_output
176
+ .cache
177
+ .turbo
178
+ `;
179
+ }
180
+ export function generateDotEnvLocal(config) {
181
+ return `# Docker Compose Environment
182
+ # Generated by create-feltdb for \${config.appName}
183
+
184
+ COMPOSE_PROJECT_NAME=${config.appName.toLowerCase().replace(/[^a-z0-9]/g, '-')}
185
+
186
+ # FeltDB Configuration
187
+ FELTDB_APP_NAME=${config.appName}
188
+ FELTDB_APP_ID=${config.appId}
189
+ FELTDB_VERSION=${config.version}
190
+ FELTDB_API_PORT=${config.port}
191
+ FELTDB_REPLICATION_PORT=${config.replicationPort}
192
+ FELTDB_PEERS=
193
+
194
+ # Application Configuration
195
+ APP_PORT=3000
196
+ FELTDB_API_URL=http://feltdb:7700
197
+
198
+ # Studio Configuration
199
+ STUDIO_PORT=${config.studioPort}
200
+
201
+ # Runtime
202
+ NODE_ENV=production
203
+ `;
204
+ }
205
+ export function generateHealthCheckScript() {
206
+ return `#!/bin/bash
207
+
208
+ # Multi-service health check orchestration
209
+ # Ensures all services are ready before marking deployment as healthy
210
+
211
+ set -e
212
+
213
+ TIMEOUT=60
214
+ ELAPSED=0
215
+ INTERVAL=2
216
+
217
+ echo "[Health Check] Starting orchestration check (timeout: \${TIMEOUT}s)"
218
+
219
+ # Wait for FeltDB
220
+ echo "[Health Check] Checking FeltDB service..."
221
+ while [ \$ELAPSED -lt \$TIMEOUT ]; do
222
+ if curl -s -f http://feltdb:7700/health > /dev/null 2>&1; then
223
+ STATE=\$(curl -s http://feltdb:7700/health | grep -o '"state":"[^"]*' | cut -d'"' -f4)
224
+ if [ "\$STATE" = "ready" ] || [ "\$STATE" = "recovering" ]; then
225
+ echo "[Health Check] FeltDB is \$STATE"
226
+ break
227
+ fi
228
+ fi
229
+ sleep \$INTERVAL
230
+ ELAPSED=\$((ELAPSED + INTERVAL))
231
+ done
232
+
233
+ if [ \$ELAPSED -ge \$TIMEOUT ]; then
234
+ echo "[Health Check] FAILED: FeltDB did not respond within timeout"
235
+ exit 1
236
+ fi
237
+
238
+ # Wait for application
239
+ echo "[Health Check] Checking application service..."
240
+ ELAPSED=0
241
+ while [ \$ELAPSED -lt \$TIMEOUT ]; do
242
+ if curl -s -f http://app:3000/health > /dev/null 2>&1; then
243
+ echo "[Health Check] Application is ready"
244
+ break
245
+ fi
246
+ sleep \$INTERVAL
247
+ ELAPSED=\$((ELAPSED + INTERVAL))
248
+ done
249
+
250
+ if [ \$ELAPSED -ge \$TIMEOUT ]; then
251
+ echo "[Health Check] FAILED: Application did not respond within timeout"
252
+ exit 1
253
+ fi
254
+
255
+ echo "[Health Check] All services healthy - deployment ready"
256
+ exit 0
257
+ `;
258
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * create-feltdb - Main exports
3
+ */
4
+ export * from './create.js';
@@ -0,0 +1,4 @@
1
+ // One release train keeps generated applications installable. The repository
2
+ // validation script checks these values against every workspace manifest.
3
+ export const FELTDB_PACKAGE_VERSION = '0.4.6';
4
+ export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Runtime-specific templates and configuration
3
+ *
4
+ * Generates runtime-appropriate file structure and configuration
5
+ * for Browser, Node, and Self-hosted deployment modes.
6
+ */
7
+ export function generateBrowserRuntime(config) {
8
+ return {
9
+ feltdbInit: `import { createFeltDB } from '@feltdb/core';
10
+
11
+ /**
12
+ * Browser Runtime
13
+ *
14
+ * Local-first FeltDB with durable IndexedDB storage.
15
+ * No server required. Full offline capability.
16
+ *
17
+ * AppID: ${config.appId}
18
+ */
19
+ export const db = createFeltDB({
20
+ namespace: '${config.appName}',
21
+ runtime: 'browser',
22
+ storage: {
23
+ type: 'indexeddb',
24
+ durable: true,
25
+ },
26
+ ${config.distributed ? `
27
+ replication: {
28
+ enabled: false, // Browser cannot initiate replication
29
+ },` : ''}
30
+ health: {
31
+ onStateChange: (state: 'starting' | 'recovering' | 'ready' | 'failed') => {
32
+ console.log(\`[FeltDB Health] Browser state changed: \${state}\`);
33
+ window.dispatchEvent(new CustomEvent('feltdb:health', { detail: { state } }));
34
+ },
35
+ },
36
+ });
37
+
38
+ // Collections
39
+ export const documents = db.collection('documents');
40
+ export const reports = db.collection('reports');
41
+ `,
42
+ envExample: `# Browser Runtime
43
+ # No environment configuration needed.
44
+ # Data persists locally in IndexedDB.
45
+ NODE_ENV=development
46
+ `,
47
+ };
48
+ }
49
+ export function generateNodeRuntime(config) {
50
+ return {
51
+ feltdbInit: `import { createFeltDB } from '@feltdb/core';
52
+ import path from 'path';
53
+ import { fileURLToPath } from 'url';
54
+ import fs from 'fs';
55
+
56
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
57
+
58
+ /**
59
+ * Node Runtime
60
+ *
61
+ * Server-side FeltDB with durable file-based storage.
62
+ * Can participate in distributed replication.
63
+ * Persistent operation log to /data directory.
64
+ *
65
+ * AppID: ${config.appId}
66
+ */
67
+
68
+ const dataDir = process.env.FELTDB_DATA_DIR || path.join(__dirname, '..', 'data');
69
+ if (!fs.existsSync(dataDir)) {
70
+ fs.mkdirSync(dataDir, { recursive: true });
71
+ }
72
+
73
+ export const db = createFeltDB({
74
+ namespace: '${config.appName}',
75
+ runtime: 'node',
76
+ storage: {
77
+ type: 'file',
78
+ path: dataDir,
79
+ durable: true,
80
+ fsync: true,
81
+ },
82
+ ${config.distributed ? `
83
+ replication: {
84
+ enabled: true,
85
+ port: parseInt(process.env.FELTDB_REPLICATION_PORT || '9000'),
86
+ },` : ''}
87
+ health: {
88
+ onStateChange: (state: 'starting' | 'recovering' | 'ready' | 'failed') => {
89
+ console.log(\`[FeltDB Health] Node state changed: \${state}\`);
90
+ // Emit to monitoring system
91
+ process.emit('feltdb:health', { state, timestamp: Date.now() });
92
+ },
93
+ },
94
+ });
95
+
96
+ // Collections
97
+ export const documents = db.collection('documents');
98
+ export const reports = db.collection('reports');
99
+
100
+ // Startup hook
101
+ export async function startup() {
102
+ console.log(\`[FeltDB] Starting Node runtime\`);
103
+ console.log(\`[FeltDB] App: ${config.appName} (${config.appId})\`);
104
+ console.log(\`[FeltDB] Version: ${config.version}\`);
105
+ console.log(\`[FeltDB] Data directory: \${dataDir}\`);
106
+ ${config.distributed ? `console.log(\`[FeltDB] Replication enabled on port \${process.env.FELTDB_REPLICATION_PORT || 9000}\`);` : ''}
107
+ await db.ready();
108
+ console.log(\`[FeltDB] Ready\`);
109
+ }
110
+ `,
111
+ envExample: `# Node Runtime
112
+ FELTDB_DATA_DIR=./data
113
+ FELTDB_REPLICATION_PORT=9000
114
+ NODE_ENV=development
115
+ `,
116
+ startupScript: `#!/usr/bin/env node
117
+
118
+ /**
119
+ * Node runtime startup orchestration
120
+ */
121
+
122
+ import { db, startup } from './feltdb.js';
123
+
124
+ async function main() {
125
+ try {
126
+ await startup();
127
+
128
+ // Start HTTP server for API
129
+ const { createServer } = await import('./server.js');
130
+ const server = createServer(db);
131
+ const port = process.env.FELTDB_API_PORT || 7700;
132
+ server.listen(port, () => {
133
+ console.log(\`[HTTP] API server listening on port \${port}\`);
134
+ });
135
+ } catch (err) {
136
+ console.error('[FeltDB] Startup failed:', err);
137
+ process.exit(1);
138
+ }
139
+ }
140
+
141
+ main();
142
+ `,
143
+ };
144
+ }
145
+ export function generateSelfHostedRuntime(config) {
146
+ return {
147
+ feltdbInit: `import { createFeltDB } from '@feltdb/core';
148
+ import path from 'path';
149
+ import { fileURLToPath } from 'url';
150
+ import fs from 'fs';
151
+
152
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
153
+
154
+ /**
155
+ * Self-hosted Runtime
156
+ *
157
+ * Containerized FeltDB with Docker Compose orchestration.
158
+ * Durable file-based storage with persistent volumes.
159
+ * Full replication topology with multi-node support.
160
+ *
161
+ * AppID: ${config.appId}
162
+ * Version: ${config.version}
163
+ */
164
+
165
+ const dataDir = process.env.FELTDB_DATA_DIR || '/data';
166
+ if (!fs.existsSync(dataDir)) {
167
+ fs.mkdirSync(dataDir, { recursive: true });
168
+ }
169
+
170
+ export const db = createFeltDB({
171
+ namespace: '${config.appName}',
172
+ runtime: 'self-hosted',
173
+ storage: {
174
+ type: 'file',
175
+ path: dataDir,
176
+ durable: true,
177
+ fsync: true,
178
+ },
179
+ replication: {
180
+ enabled: true,
181
+ port: 9000,
182
+ peers: (process.env.FELTDB_PEERS || '').split(',').filter(Boolean),
183
+ },
184
+ health: {
185
+ onStateChange: (state: 'starting' | 'recovering' | 'ready' | 'failed') => {
186
+ console.log(\`[\${new Date().toISOString()}] [FeltDB] \${state.toUpperCase()}\`);
187
+ // Structured logging for container orchestration
188
+ process.emit('feltdb:health', { state, timestamp: Date.now() });
189
+ },
190
+ },
191
+ });
192
+
193
+ // Collections
194
+ export const documents = db.collection('documents');
195
+ export const reports = db.collection('reports');
196
+
197
+ // Startup with health check loop
198
+ export async function startup() {
199
+ console.log(\`[\${new Date().toISOString()}] [FeltDB] Container starting\`);
200
+ console.log(\`[FeltDB] App: ${config.appName} (${config.appId})\`);
201
+ console.log(\`[FeltDB] Version: ${config.version}\`);
202
+ console.log(\`[FeltDB] Runtime: self-hosted\`);
203
+ console.log(\`[FeltDB] Data directory: \${dataDir}\`);
204
+
205
+ await db.ready();
206
+ console.log(\`[\${new Date().toISOString()}] [FeltDB] READY\`);
207
+ }
208
+ `,
209
+ envExample: `# Self-hosted Docker Runtime
210
+ FELTDB_DATA_DIR=/data
211
+ FELTDB_APP_NAME=${config.appName}
212
+ FELTDB_APP_ID=${config.appId}
213
+ FELTDB_VERSION=${config.version}
214
+ FELTDB_REPLICATION_PORT=9000
215
+ FELTDB_PEERS=
216
+ NODE_ENV=production
217
+ `,
218
+ healthCheck: `#!/bin/sh
219
+
220
+ # Health check for Docker container
221
+ # Verifies FeltDB is responding and not in RECOVERING state
222
+
223
+ HEALTH_URL="http://localhost:7700/health"
224
+ TIMEOUT=5
225
+
226
+ # Query health endpoint
227
+ RESPONSE=\$(curl -s -m \${TIMEOUT} \${HEALTH_URL} 2>/dev/null)
228
+
229
+ if [ -z "\$RESPONSE" ]; then
230
+ echo "UNHEALTHY: No response from health endpoint"
231
+ exit 1
232
+ fi
233
+
234
+ STATE=\$(echo \$RESPONSE | grep -o '"state":"[^"]*' | cut -d'"' -f4)
235
+
236
+ case "\$STATE" in
237
+ ready)
238
+ echo "HEALTHY: State is ready"
239
+ exit 0
240
+ ;;
241
+ recovering)
242
+ echo "STARTING: Recovering from disk"
243
+ exit 0
244
+ ;;
245
+ starting)
246
+ echo "STARTING: Initializing"
247
+ exit 0
248
+ ;;
249
+ failed)
250
+ echo "UNHEALTHY: State is failed"
251
+ exit 1
252
+ ;;
253
+ *)
254
+ echo "UNKNOWN: State is \$STATE"
255
+ exit 2
256
+ ;;
257
+ esac
258
+ `,
259
+ };
260
+ }
261
+ export function getTemplate(config) {
262
+ switch (config.runtime) {
263
+ case 'browser':
264
+ return generateBrowserRuntime(config);
265
+ case 'node':
266
+ return generateNodeRuntime(config);
267
+ case 'self-hosted':
268
+ return generateSelfHostedRuntime(config);
269
+ default:
270
+ throw new Error(`Unknown runtime: ${config.runtime}`);
271
+ }
272
+ }
@@ -11,7 +11,7 @@ async function loadWasm() {
11
11
  try {
12
12
  // Try to import WASM module
13
13
  // @ts-ignore - WASM module is optional and built separately
14
- const wasmModule = await import('@feltdb/wasm');
14
+ const wasmModule = await import('./wasm/feltdb_wasm.js');
15
15
  wasmIndexModule = wasmModule;
16
16
  wasmAvailable = true;
17
17
  return wasmModule;
@@ -0,0 +1,2 @@
1
+ import type { Analysis } from '../types/index.js';
2
+ export declare function analyze(sourceRoot: string, schemaFile: string): Promise<Analysis>;
@@ -0,0 +1,34 @@
1
+ import { readFile, readdir, stat } from 'node:fs/promises';
2
+ import { join, relative } from 'node:path';
3
+ import { hash, json } from '../util.js';
4
+ const CODE = /\.(?:[cm]?[jt]sx?|sql|prisma|py|rb|go)$/;
5
+ const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'target', '.feltdb']);
6
+ async function files(root, dir = root, out = []) { for (const n of await readdir(dir)) {
7
+ if (SKIP.has(n))
8
+ continue;
9
+ const p = join(dir, n), s = await stat(p);
10
+ if (s.isDirectory())
11
+ await files(root, p, out);
12
+ else if (CODE.test(n))
13
+ out.push(p);
14
+ } return out.sort(); }
15
+ export async function analyze(sourceRoot, schemaFile) {
16
+ const raw = await json(schemaFile);
17
+ const entities = (raw.entities ?? raw.tables ?? []).map(e => ({ ...e, kind: e.kind ?? 'table' })).sort((a, b) => a.name.localeCompare(b.name));
18
+ if (!entities.length)
19
+ throw new Error('Schema contains no entities');
20
+ const names = new Set(entities.map(e => e.name)), findings = [];
21
+ for (const file of await files(sourceRoot)) {
22
+ const text = await readFile(file, 'utf8');
23
+ for (const [i, line] of text.split(/\r?\n/).entries()) {
24
+ const hit = [...names].filter(n => line.includes(n));
25
+ if (!hit.length)
26
+ continue;
27
+ const kind = /\b(SELECT|INSERT|UPDATE|DELETE|JOIN)\b/i.test(line) ? 'sql' : /fetch\(|axios|useQuery|poll|subscribe/i.test(line) ? 'consumer' : 'reference';
28
+ findings.push({ file: relative(sourceRoot, file), line: i + 1, kind, value: line.trim().slice(0, 300), entities: hit });
29
+ }
30
+ }
31
+ const dependencies = entities.flatMap(e => (e.foreignKeys ?? []).map(f => ({ from: e.name, to: f.referencedTable }))).sort((a, b) => `${a.from}:${a.to}`.localeCompare(`${b.from}:${b.to}`));
32
+ const core = { version: 1, sourceRoot, entities, findings, dependencies };
33
+ return { ...core, generatedAt: new Date().toISOString(), schemaHash: hash({ entities, dependencies }) };
34
+ }
@@ -0,0 +1,13 @@
1
+ export interface BenchmarkWorkload {
2
+ name: string;
3
+ iterations?: number;
4
+ run(): Promise<void>;
5
+ }
6
+ export interface BenchmarkResult {
7
+ name: string;
8
+ iterations: number;
9
+ totalMs: number;
10
+ meanMs: number;
11
+ operationsPerSecond: number;
12
+ }
13
+ export declare function benchmark(workloads: BenchmarkWorkload[]): Promise<BenchmarkResult[]>;
@@ -0,0 +1,8 @@
1
+ import { performance } from 'node:perf_hooks';
2
+ export async function benchmark(workloads) { const results = []; for (const w of workloads) {
3
+ const iterations = w.iterations ?? 100, start = performance.now();
4
+ for (let i = 0; i < iterations; i++)
5
+ await w.run();
6
+ const totalMs = performance.now() - start;
7
+ results.push({ name: w.name, iterations, totalMs, meanMs: totalMs / iterations, operationsPerSecond: iterations / (totalMs / 1000) });
8
+ } return results; }
@@ -0,0 +1,3 @@
1
+ import type { Capabilities } from '../types/index.js';
2
+ export declare const REQUIRED: string[];
3
+ export declare function gate(capabilities: Capabilities, required?: string[]): void;
@@ -0,0 +1,3 @@
1
+ export const REQUIRED = ['atomicTransactions', 'immutableHistory', 'deterministicOrdering', 'durablePersistence', 'indexedQueries', 'tenantIsolation', 'idempotentWrites', 'concurrencySafety', 'reconstruction', 'versionConflicts', 'canonicalStateRefresh', 'stateHistorySeparation', 'uiStateContract'];
2
+ export function gate(capabilities, required = REQUIRED) { const missing = required.filter(x => capabilities[x] !== true); if (missing.length)
3
+ throw new Error(`Missing FeltDB platform capabilities: ${missing.join(', ')}`); }
@@ -0,0 +1,3 @@
1
+ import type { Analysis, Classification, ClassificationResult } from '../types/index.js';
2
+ export declare function classify(a: Analysis, threshold?: number, overrides?: Record<string, Classification>, blobLimit?: number): ClassificationResult;
3
+ export declare function approve(result: ClassificationResult): ClassificationResult;
@@ -0,0 +1,53 @@
1
+ import { hash } from '../util.js';
2
+ const secret = /(password|secret|token|credential|private_key|certificate|api_key)/i, blob = /(bytea|blob|binary|image|wasm|archive)/i;
3
+ export function classify(a, threshold = .8, overrides = {}, blobLimit = 262144) {
4
+ const entities = a.entities.map(e => {
5
+ let classification, confidence = .72, reasons = [];
6
+ const cols = e.columns;
7
+ if (overrides[e.name]) {
8
+ classification = overrides[e.name];
9
+ confidence = 1;
10
+ reasons = ['configuration override'];
11
+ }
12
+ else if (cols.some(c => secret.test(c.name))) {
13
+ classification = 'SECRET_REFERENCE';
14
+ confidence = .98;
15
+ reasons = ['security-sensitive column'];
16
+ }
17
+ else if (cols.some(c => blob.test(c.type) || blob.test(c.name) || (c.sizeBytes ?? 0) > blobLimit)) {
18
+ classification = 'BLOB_REFERENCE';
19
+ confidence = .95;
20
+ reasons = ['binary or large payload'];
21
+ }
22
+ else if ((e.foreignKeys?.length ?? 0) >= 2 && cols.filter(c => c.primaryKey).length >= 2) {
23
+ classification = 'RELATIONSHIP';
24
+ confidence = .9;
25
+ reasons = ['junction-table shape'];
26
+ }
27
+ else if (/(_events?|_history|_audit|_logs?)$/i.test(e.name)) {
28
+ classification = 'HISTORY';
29
+ confidence = .92;
30
+ reasons = ['event/history naming', 'timestamp ordering likely'];
31
+ }
32
+ else if (e.kind === 'view') {
33
+ classification = 'MATERIALIZED';
34
+ confidence = .9;
35
+ reasons = ['database view'];
36
+ }
37
+ else if (/(_cache|_jobs?|_locks?|_sessions?)$/i.test(e.name)) {
38
+ classification = 'OPERATIONAL';
39
+ confidence = .82;
40
+ reasons = ['operational naming'];
41
+ }
42
+ else {
43
+ classification = 'STATE';
44
+ confidence = .78;
45
+ reasons = ['mutable entity shape'];
46
+ }
47
+ return { entity: e.name, classification, confidence, reasons, requiresApproval: confidence < threshold };
48
+ });
49
+ const payload = { version: 1, threshold, entities };
50
+ return { ...payload, classificationHash: hash(payload), approved: false };
51
+ }
52
+ export function approve(result) { if (result.entities.some(e => e.requiresApproval))
53
+ throw new Error('Low-confidence classifications require explicit overrides before approval'); return { ...result, approved: true }; }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};