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 +11 -3
- package/dist/create.js +91 -31
- package/dist/docker-compose-generator.js +11 -45
- package/dist/package-versions.js +1 -1
- package/package.json +1 -1
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
|
-
|
|
309
|
-
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
collection Project {
|
|
93
|
+
name: text
|
|
94
|
+
description: text
|
|
95
|
+
status: text
|
|
94
96
|
createdAt: datetime
|
|
95
|
-
|
|
97
|
+
updatedAt: datetime
|
|
98
|
+
index status using hash(status)
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
collection
|
|
101
|
+
collection Task {
|
|
102
|
+
projectId: text
|
|
99
103
|
title: text
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
115
|
-
step
|
|
116
|
-
input
|
|
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
|
|
124
|
-
workflow
|
|
140
|
+
trigger on Task.created {
|
|
141
|
+
workflow TrackTask(task)
|
|
125
142
|
}
|
|
126
143
|
|
|
127
|
-
policy
|
|
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('
|
|
170
|
-
export const tasks = db.collection('
|
|
171
|
-
export const activity = db.collection('
|
|
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
|
-
'
|
|
523
|
+
'workspace-read': {
|
|
497
524
|
enabled: true,
|
|
498
|
-
scope: ['
|
|
525
|
+
scope: ['projects:read', 'tasks:read', 'activity:read'],
|
|
499
526
|
},
|
|
500
527
|
'vector-search': {
|
|
501
528
|
enabled: ${capabilities.includes('vector')},
|
|
502
|
-
scope: ['
|
|
529
|
+
scope: ['projects:read', 'tasks:read', 'capabilities:execute'],
|
|
503
530
|
},
|
|
504
|
-
'
|
|
531
|
+
'workspace-write': {
|
|
505
532
|
enabled: true,
|
|
506
|
-
scope: ['
|
|
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 `
|
|
12
|
-
|
|
13
|
-
services:
|
|
11
|
+
return `services:
|
|
14
12
|
feltdb:
|
|
15
|
-
image: rkendel1/feltdb
|
|
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:-
|
|
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", "
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
-
|
|
126
|
-
|
|
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() {
|
package/dist/package-versions.js
CHANGED
|
@@ -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.
|
|
3
|
+
export const FELTDB_PACKAGE_VERSION = '0.4.11';
|
|
4
4
|
export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
|