create-feltdb 0.4.10 → 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/dist/cli.js CHANGED
@@ -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 {
package/dist/create.js CHANGED
@@ -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 {
@@ -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.10';
3
+ export const FELTDB_PACKAGE_VERSION = '0.4.11';
4
4
  export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "create-feltdb",
3
3
  "private": false,
4
4
  "description": "Create a new FeltDB application with one command",
5
- "version": "0.4.10",
5
+ "version": "0.4.11",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "create-feltdb": "bin/create-feltdb.js"