@embeddables/cli 0.1.0 → 0.3.0
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/.cursor/rules/embeddables-cli.md +679 -0
- package/README.md +37 -7
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +5 -3
- package/dist/cli.js +42 -6
- package/dist/commands/branch.d.ts +4 -0
- package/dist/commands/branch.d.ts.map +1 -0
- package/dist/commands/branch.js +46 -0
- package/dist/commands/dev.d.ts +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +48 -9
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +245 -0
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +104 -3
- package/dist/commands/save.d.ts +8 -0
- package/dist/commands/save.d.ts.map +1 -0
- package/dist/commands/save.js +269 -0
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/index.js +4 -0
- package/dist/compiler/reverse.d.ts.map +1 -1
- package/dist/compiler/reverse.js +4 -10
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +42 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +6 -0
- package/dist/helpers/dates.d.ts +5 -0
- package/dist/helpers/dates.d.ts.map +1 -0
- package/dist/helpers/dates.js +7 -0
- package/dist/prompts/branches.d.ts +20 -0
- package/dist/prompts/branches.d.ts.map +1 -0
- package/dist/prompts/branches.js +89 -0
- package/dist/prompts/embeddables.d.ts +41 -0
- package/dist/prompts/embeddables.d.ts.map +1 -0
- package/dist/prompts/embeddables.js +161 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +4 -0
- package/dist/prompts/projects.d.ts +22 -0
- package/dist/prompts/projects.d.ts.map +1 -0
- package/dist/prompts/projects.js +85 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/server.js +10 -4
- package/package.json +6 -5
package/dist/commands/pull.js
CHANGED
|
@@ -1,10 +1,52 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
|
+
import prompts from 'prompts';
|
|
4
5
|
import { reverseCompile } from '../compiler/reverse.js';
|
|
5
|
-
import { getAccessToken } from '../auth/index.js';
|
|
6
|
+
import { getAccessToken, isLoggedIn } from '../auth/index.js';
|
|
7
|
+
import { getProjectId, writeProjectConfig } from '../config/index.js';
|
|
8
|
+
import { promptForProject, promptForEmbeddable, fetchEmbeddableMetadata } from '../prompts/index.js';
|
|
6
9
|
export async function runPull(opts) {
|
|
7
|
-
|
|
10
|
+
let embeddableId = opts.id;
|
|
11
|
+
// If no ID provided, try to get it interactively
|
|
12
|
+
if (!embeddableId) {
|
|
13
|
+
if (!isLoggedIn()) {
|
|
14
|
+
console.error(pc.red('No embeddable ID provided and not logged in.'));
|
|
15
|
+
console.log('');
|
|
16
|
+
console.log(pc.gray('Either:'));
|
|
17
|
+
console.log(pc.gray(' 1. Use --id <embeddable-id> to specify an embeddable'));
|
|
18
|
+
console.log(pc.gray(' 2. Run "embeddables login" first for interactive selection'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
let projectId = getProjectId();
|
|
22
|
+
// If no project ID configured, prompt for project selection
|
|
23
|
+
if (!projectId) {
|
|
24
|
+
console.log(pc.cyan('Fetching projects...'));
|
|
25
|
+
const selectedProject = await promptForProject();
|
|
26
|
+
if (!selectedProject) {
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
projectId = selectedProject.id;
|
|
30
|
+
// Save the selected project to config
|
|
31
|
+
writeProjectConfig({
|
|
32
|
+
org_id: selectedProject.org_id || undefined,
|
|
33
|
+
org_title: selectedProject.org_title || undefined,
|
|
34
|
+
project_id: projectId,
|
|
35
|
+
project_name: selectedProject.title || undefined,
|
|
36
|
+
});
|
|
37
|
+
console.log(pc.green(`✓ Saved project to embeddables.json`));
|
|
38
|
+
console.log('');
|
|
39
|
+
}
|
|
40
|
+
console.log(pc.cyan('Fetching embeddables from project...'));
|
|
41
|
+
const selected = await promptForEmbeddable(projectId, {
|
|
42
|
+
message: 'Select an embeddable to pull:',
|
|
43
|
+
});
|
|
44
|
+
if (!selected) {
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
embeddableId = selected;
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
8
50
|
let url = `https://engine.embeddables.com/${embeddableId}?version=latest`;
|
|
9
51
|
if (opts.branch) {
|
|
10
52
|
url += `&embeddable_branch=${opts.branch}`;
|
|
@@ -44,6 +86,14 @@ export async function runPull(opts) {
|
|
|
44
86
|
fs.writeFileSync(versionedPath, flowJson, 'utf8');
|
|
45
87
|
console.log(pc.cyan(`✓ Saved embeddable JSON to ${versionedPath}`));
|
|
46
88
|
}
|
|
89
|
+
// Fetch and save flow metadata from DB (title, archived, created_at)
|
|
90
|
+
const metadata = await fetchEmbeddableMetadata(embeddableId);
|
|
91
|
+
if (metadata) {
|
|
92
|
+
const metadataPath = path.join('embeddables', embeddableId, 'metadata.json');
|
|
93
|
+
fs.mkdirSync(path.dirname(metadataPath), { recursive: true });
|
|
94
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf8');
|
|
95
|
+
console.log(pc.cyan(`✓ Saved flow metadata to ${metadataPath}`));
|
|
96
|
+
}
|
|
47
97
|
// Clear existing pages, styles, computed-fields, actions, and global-components before generating new ones
|
|
48
98
|
const pagesDir = path.join('embeddables', embeddableId, 'pages');
|
|
49
99
|
const stylesDir = path.join('embeddables', embeddableId, 'styles');
|
|
@@ -88,7 +138,58 @@ export async function runPull(opts) {
|
|
|
88
138
|
console.log(`${pc.gray(`Cleared ${existingGlobalComponents.length} existing global component(s)`)}`);
|
|
89
139
|
}
|
|
90
140
|
// Run reverse compiler
|
|
91
|
-
|
|
141
|
+
try {
|
|
142
|
+
await reverseCompile(flow, embeddableId, { fix: opts.fix });
|
|
143
|
+
}
|
|
144
|
+
catch (compileError) {
|
|
145
|
+
// If fix mode wasn't already enabled, offer to retry with fix mode
|
|
146
|
+
if (!opts.fix && compileError instanceof Error) {
|
|
147
|
+
console.log('');
|
|
148
|
+
console.error(pc.red('Error during reverse compile:'));
|
|
149
|
+
console.error(pc.yellow(` ${compileError.message}`));
|
|
150
|
+
console.log('');
|
|
151
|
+
const response = await prompts({
|
|
152
|
+
type: 'confirm',
|
|
153
|
+
name: 'fix',
|
|
154
|
+
message: 'Would you like to retry with auto-fix enabled? (removes problematic components)',
|
|
155
|
+
initial: true,
|
|
156
|
+
}, {
|
|
157
|
+
onCancel: () => {
|
|
158
|
+
process.exit(1);
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
if (response.fix) {
|
|
162
|
+
console.log('');
|
|
163
|
+
console.log(pc.cyan('Retrying with auto-fix enabled...'));
|
|
164
|
+
console.log('');
|
|
165
|
+
await reverseCompile(flow, embeddableId, { fix: true });
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
throw compileError;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Store version number in config.json so save knows the base version
|
|
176
|
+
if (version != null) {
|
|
177
|
+
const versionNumber = typeof version === 'number' ? version : parseInt(String(version), 10);
|
|
178
|
+
if (!isNaN(versionNumber)) {
|
|
179
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
180
|
+
if (fs.existsSync(configPath)) {
|
|
181
|
+
try {
|
|
182
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
183
|
+
const config = JSON.parse(configContent);
|
|
184
|
+
config._version = versionNumber;
|
|
185
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Ignore errors updating config.json - versioned files are a fallback
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
92
193
|
}
|
|
93
194
|
catch (error) {
|
|
94
195
|
console.error('Error pulling embeddable:', error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"AA+FA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,iBAoPA"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import prompts from 'prompts';
|
|
5
|
+
import { getAccessToken, isLoggedIn } from '../auth/index.js';
|
|
6
|
+
import { getProjectId, writeProjectConfig } from '../config/index.js';
|
|
7
|
+
import { compileAllPages } from '../compiler/index.js';
|
|
8
|
+
import { formatError } from '../compiler/errors.js';
|
|
9
|
+
import { promptForLocalEmbeddable, promptForProject } from '../prompts/index.js';
|
|
10
|
+
import { WEB_APP_BASE_URL } from '../constants.js';
|
|
11
|
+
/**
|
|
12
|
+
* Read `_version` from config.json for the given embeddable.
|
|
13
|
+
*/
|
|
14
|
+
function getVersionFromConfig(embeddableId) {
|
|
15
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
16
|
+
if (!fs.existsSync(configPath)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
21
|
+
if (typeof config._version === 'number') {
|
|
22
|
+
return config._version;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Ignore parse errors
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Update `_version` in config.json for the given embeddable.
|
|
32
|
+
*/
|
|
33
|
+
function setVersionInConfig(embeddableId, version) {
|
|
34
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
35
|
+
if (!fs.existsSync(configPath)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
40
|
+
config._version = version;
|
|
41
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Ignore errors - versioned files are a fallback
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Scan the .generated/ directory for versioned files (embeddable-v*.json)
|
|
49
|
+
* and return the highest version number found.
|
|
50
|
+
*/
|
|
51
|
+
function getLatestVersionFromFiles(generatedDir) {
|
|
52
|
+
if (!fs.existsSync(generatedDir)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const files = fs.readdirSync(generatedDir);
|
|
56
|
+
const versionPattern = /^embeddable-v(\d+)\.json$/;
|
|
57
|
+
let maxVersion = null;
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
const match = file.match(versionPattern);
|
|
60
|
+
if (match) {
|
|
61
|
+
const version = parseInt(match[1], 10);
|
|
62
|
+
if (maxVersion === null || version > maxVersion) {
|
|
63
|
+
maxVersion = version;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return maxVersion;
|
|
68
|
+
}
|
|
69
|
+
export async function runSave(opts) {
|
|
70
|
+
// 1. Check login
|
|
71
|
+
if (!isLoggedIn()) {
|
|
72
|
+
console.error(pc.red('Not logged in.'));
|
|
73
|
+
console.log(pc.gray('Run "embeddables login" first.'));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
// 2. Get access token
|
|
77
|
+
const accessToken = getAccessToken();
|
|
78
|
+
if (!accessToken) {
|
|
79
|
+
console.error(pc.red('Could not retrieve access token.'));
|
|
80
|
+
console.log(pc.gray('Run "embeddables login" to re-authenticate.'));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
// 3. Get embeddable ID (from option or interactive prompt)
|
|
84
|
+
let embeddableId = opts.id;
|
|
85
|
+
if (!embeddableId) {
|
|
86
|
+
const selected = await promptForLocalEmbeddable({
|
|
87
|
+
message: 'Select an embeddable to save:',
|
|
88
|
+
});
|
|
89
|
+
if (!selected) {
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
embeddableId = selected;
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
// 4. Get project ID (from config or interactive prompt)
|
|
96
|
+
let projectId = getProjectId();
|
|
97
|
+
if (!projectId) {
|
|
98
|
+
console.log(pc.cyan('No project configured. Fetching projects...'));
|
|
99
|
+
const selectedProject = await promptForProject();
|
|
100
|
+
if (!selectedProject) {
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
projectId = selectedProject.id;
|
|
104
|
+
writeProjectConfig({
|
|
105
|
+
org_id: selectedProject.org_id || undefined,
|
|
106
|
+
org_title: selectedProject.org_title || undefined,
|
|
107
|
+
project_id: projectId,
|
|
108
|
+
project_name: selectedProject.title || undefined,
|
|
109
|
+
});
|
|
110
|
+
console.log(pc.green('✓ Saved project to embeddables.json'));
|
|
111
|
+
console.log('');
|
|
112
|
+
}
|
|
113
|
+
// 5. Build (compile TSX → JSON) unless --skip-build is set
|
|
114
|
+
const generatedDir = path.join('embeddables', embeddableId, '.generated');
|
|
115
|
+
const outPath = path.join(generatedDir, 'embeddable.json');
|
|
116
|
+
if (!opts.skipBuild) {
|
|
117
|
+
const pagesGlob = `embeddables/${embeddableId}/pages/**/*.page.tsx`;
|
|
118
|
+
const stylesDir = path.join('embeddables', embeddableId, 'styles');
|
|
119
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
120
|
+
console.log(pc.cyan('Building embeddable...'));
|
|
121
|
+
try {
|
|
122
|
+
await compileAllPages({
|
|
123
|
+
pagesGlob,
|
|
124
|
+
outPath,
|
|
125
|
+
pageKeyFrom: 'filename',
|
|
126
|
+
stylesDir,
|
|
127
|
+
embeddableId,
|
|
128
|
+
configPath,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
console.error(formatError(e));
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
console.log(pc.green('✓ Build successful'));
|
|
136
|
+
console.log('');
|
|
137
|
+
}
|
|
138
|
+
// 6. Read the compiled JSON
|
|
139
|
+
if (!fs.existsSync(outPath)) {
|
|
140
|
+
console.error(pc.red(`No compiled embeddable found at ${outPath}`));
|
|
141
|
+
console.log(pc.gray('Run "embeddables build" or "embeddables pull" first.'));
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
const jsonContent = fs.readFileSync(outPath, 'utf8');
|
|
145
|
+
let embeddableJson;
|
|
146
|
+
try {
|
|
147
|
+
embeddableJson = JSON.parse(jsonContent);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
console.error(pc.red('Failed to parse embeddable JSON.'));
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
// Validate that pages array exists and is non-empty
|
|
154
|
+
if (!embeddableJson.pages ||
|
|
155
|
+
!Array.isArray(embeddableJson.pages) ||
|
|
156
|
+
embeddableJson.pages.length === 0) {
|
|
157
|
+
console.error(pc.red('Embeddable JSON must contain a non-empty pages array.'));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
// 7. Determine fromVersionNumber
|
|
161
|
+
let fromVersionNumber;
|
|
162
|
+
if (opts.fromVersion) {
|
|
163
|
+
fromVersionNumber = parseInt(opts.fromVersion, 10);
|
|
164
|
+
if (isNaN(fromVersionNumber)) {
|
|
165
|
+
console.error(pc.red(`Invalid --from-version value: ${opts.fromVersion}`));
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Primary: read _version from config.json; fallback: scan .generated/ for versioned files
|
|
171
|
+
const detectedVersion = getVersionFromConfig(embeddableId) ?? getLatestVersionFromFiles(generatedDir);
|
|
172
|
+
if (detectedVersion === null) {
|
|
173
|
+
console.error(pc.red('Could not determine the current version number.'));
|
|
174
|
+
console.log(pc.gray('Make sure you have pulled the embeddable first (embeddables pull), or specify --from-version <number>.'));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
fromVersionNumber = detectedVersion;
|
|
178
|
+
}
|
|
179
|
+
// 8. POST to save-version API
|
|
180
|
+
console.log(pc.cyan(`Saving embeddable (based on v${fromVersionNumber})...`));
|
|
181
|
+
const body = {
|
|
182
|
+
embeddableId,
|
|
183
|
+
jsonString: JSON.stringify(embeddableJson),
|
|
184
|
+
projectId,
|
|
185
|
+
fromVersionNumber,
|
|
186
|
+
};
|
|
187
|
+
if (opts.label) {
|
|
188
|
+
body.label = opts.label;
|
|
189
|
+
}
|
|
190
|
+
if (opts.branch) {
|
|
191
|
+
body.branchId = opts.branch;
|
|
192
|
+
}
|
|
193
|
+
const url = `${WEB_APP_BASE_URL}/api/embeddables/save-version`;
|
|
194
|
+
const headers = {
|
|
195
|
+
Authorization: `Bearer ${accessToken}`,
|
|
196
|
+
'Content-Type': 'application/json',
|
|
197
|
+
};
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(url, {
|
|
200
|
+
method: 'POST',
|
|
201
|
+
headers,
|
|
202
|
+
body: JSON.stringify(body),
|
|
203
|
+
});
|
|
204
|
+
if (response.status === 409) {
|
|
205
|
+
const conflictResult = (await response.json());
|
|
206
|
+
console.log('');
|
|
207
|
+
console.warn(pc.yellow(`⚠ Version conflict: the server has version ${conflictResult.latestVersionNumber}, but you are saving from version ${conflictResult.yourVersionNumber}.`));
|
|
208
|
+
const { forceSave } = await prompts({
|
|
209
|
+
type: 'confirm',
|
|
210
|
+
name: 'forceSave',
|
|
211
|
+
message: 'A newer version exists on the server. Save anyway?',
|
|
212
|
+
initial: false,
|
|
213
|
+
}, {
|
|
214
|
+
onCancel: () => {
|
|
215
|
+
process.exit(1);
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
if (!forceSave) {
|
|
219
|
+
console.log(pc.gray('Save cancelled.'));
|
|
220
|
+
process.exit(0);
|
|
221
|
+
}
|
|
222
|
+
// Retry with force flag
|
|
223
|
+
console.log(pc.cyan('Retrying save with force...'));
|
|
224
|
+
const forceResponse = await fetch(url, {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers,
|
|
227
|
+
body: JSON.stringify({ ...body, force: true }),
|
|
228
|
+
});
|
|
229
|
+
const forceResult = (await forceResponse.json());
|
|
230
|
+
if (!forceResponse.ok) {
|
|
231
|
+
const errorResult = forceResult;
|
|
232
|
+
throw new Error(errorResult.error || `HTTP ${forceResponse.status}`);
|
|
233
|
+
}
|
|
234
|
+
const successResult = forceResult;
|
|
235
|
+
const { newVersionNumber } = successResult.data;
|
|
236
|
+
console.log(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
237
|
+
setVersionInConfig(embeddableId, newVersionNumber);
|
|
238
|
+
const versionedPath = path.join(generatedDir, `embeddable-v${newVersionNumber}.json`);
|
|
239
|
+
fs.mkdirSync(generatedDir, { recursive: true });
|
|
240
|
+
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
241
|
+
console.log(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const result = (await response.json());
|
|
245
|
+
if (!response.ok) {
|
|
246
|
+
const errorResult = result;
|
|
247
|
+
throw new Error(errorResult.error || `HTTP ${response.status}`);
|
|
248
|
+
}
|
|
249
|
+
const successResult = result;
|
|
250
|
+
const { newVersionNumber } = successResult.data;
|
|
251
|
+
console.log(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
252
|
+
// Update _version in config.json so future saves know the base version
|
|
253
|
+
setVersionInConfig(embeddableId, newVersionNumber);
|
|
254
|
+
// Also save the versioned file to .generated/ as a snapshot
|
|
255
|
+
const versionedPath = path.join(generatedDir, `embeddable-v${newVersionNumber}.json`);
|
|
256
|
+
fs.mkdirSync(generatedDir, { recursive: true });
|
|
257
|
+
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
258
|
+
console.log(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
if (error instanceof Error) {
|
|
262
|
+
console.error(pc.red(`Save failed: ${error.message}`));
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
console.error(pc.red('Save failed with an unexpected error.'));
|
|
266
|
+
}
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AA+CA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA2DlF;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AA+CA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA2DlF;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,iBAiXA"}
|
package/dist/compiler/index.js
CHANGED
|
@@ -329,6 +329,10 @@ export async function compileAllPages(opts) {
|
|
|
329
329
|
// Skip styles from config - they will be added from compiled CSS files later
|
|
330
330
|
continue;
|
|
331
331
|
}
|
|
332
|
+
else if (key === '_version') {
|
|
333
|
+
// Skip _version - this is CLI metadata (tracked version number), not part of the embeddable
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
332
336
|
else if (key === 'computedFields') {
|
|
333
337
|
// Replace computedFields with loaded computedFields (which include code)
|
|
334
338
|
if (computedFields.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAA;AAihBzD,wBAAsB,cAAc,CAClC,UAAU,EAAE;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,cAAc,CAAC,EAAE,GAAG,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,GAAG,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,EACD,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,iBAmDzB;
|
|
1
|
+
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAA;AAihBzD,wBAAsB,cAAc,CAClC,UAAU,EAAE;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,cAAc,CAAC,EAAE,GAAG,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,GAAG,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,EACD,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,iBAmDzB;AAoyCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD"}
|
package/dist/compiler/reverse.js
CHANGED
|
@@ -578,13 +578,10 @@ function generateTSX(page, tree) {
|
|
|
578
578
|
const jsx = generateJSXFromTree(tree, 4, pageKey, nameMap);
|
|
579
579
|
return `"use client";
|
|
580
580
|
|
|
581
|
-
import
|
|
582
|
-
${imports
|
|
583
|
-
.map((imp) => `import { ${imp} } from "../../../src/components/primitives/${imp}";`)
|
|
584
|
-
.join('\n')}
|
|
581
|
+
${imports.map((imp) => `import { ${imp} } from "@embeddables/cli/components";`).join('\n')}
|
|
585
582
|
${hasButtons
|
|
586
583
|
? `
|
|
587
|
-
import type { OptionSelectorButton } from "
|
|
584
|
+
import type { OptionSelectorButton } from "@embeddables/cli/types";`
|
|
588
585
|
: ''}
|
|
589
586
|
|
|
590
587
|
export default function ${pageName}() {
|
|
@@ -1604,13 +1601,10 @@ function generateGlobalComponentTSX(components, tree) {
|
|
|
1604
1601
|
const jsx = generateJSXFromTree(tree, 2, undefined, nameMap);
|
|
1605
1602
|
return `"use client";
|
|
1606
1603
|
|
|
1607
|
-
import
|
|
1608
|
-
${imports
|
|
1609
|
-
.map((imp) => `import { ${imp} } from "../../../src/components/primitives/${imp}";`)
|
|
1610
|
-
.join('\n')}
|
|
1604
|
+
${imports.map((imp) => `import { ${imp} } from "@embeddables/cli/components";`).join('\n')}
|
|
1611
1605
|
${hasButtons
|
|
1612
1606
|
? `
|
|
1613
|
-
import type { OptionSelectorButton } from "
|
|
1607
|
+
import type { OptionSelectorButton } from "@embeddables/cli/types";`
|
|
1614
1608
|
: ''}
|
|
1615
1609
|
|
|
1616
1610
|
export default function GlobalComponents() {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ProjectConfig {
|
|
2
|
+
org_id?: string;
|
|
3
|
+
org_title?: string;
|
|
4
|
+
project_id?: string;
|
|
5
|
+
project_name?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get the path to the project config file
|
|
9
|
+
*/
|
|
10
|
+
export declare function getConfigFilePath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Read project config from file
|
|
13
|
+
*/
|
|
14
|
+
export declare function readProjectConfig(): ProjectConfig | null;
|
|
15
|
+
/**
|
|
16
|
+
* Write project config to file
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeProjectConfig(config: ProjectConfig): void;
|
|
19
|
+
/**
|
|
20
|
+
* Get the project ID from config
|
|
21
|
+
*/
|
|
22
|
+
export declare function getProjectId(): string | null;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAID;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,aAAa,GAAG,IAAI,CAWxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAQ9D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAG5C"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const CONFIG_FILE = 'embeddables.json';
|
|
4
|
+
/**
|
|
5
|
+
* Get the path to the project config file
|
|
6
|
+
*/
|
|
7
|
+
export function getConfigFilePath() {
|
|
8
|
+
return path.join(process.cwd(), CONFIG_FILE);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Read project config from file
|
|
12
|
+
*/
|
|
13
|
+
export function readProjectConfig() {
|
|
14
|
+
const configPath = getConfigFilePath();
|
|
15
|
+
try {
|
|
16
|
+
if (!fs.existsSync(configPath)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Write project config to file
|
|
28
|
+
*/
|
|
29
|
+
export function writeProjectConfig(config) {
|
|
30
|
+
const configPath = getConfigFilePath();
|
|
31
|
+
// Merge with existing config
|
|
32
|
+
const existing = readProjectConfig() || {};
|
|
33
|
+
const merged = { ...existing, ...config };
|
|
34
|
+
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the project ID from config
|
|
38
|
+
*/
|
|
39
|
+
export function getProjectId() {
|
|
40
|
+
const config = readProjectConfig();
|
|
41
|
+
return config?.project_id || null;
|
|
42
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const BranchStatus: {
|
|
2
|
+
readonly ACTIVE: "ACTIVE";
|
|
3
|
+
readonly MERGED: "MERGED";
|
|
4
|
+
};
|
|
5
|
+
export type BranchStatus = (typeof BranchStatus)[keyof typeof BranchStatus];
|
|
6
|
+
export declare const WEB_APP_BASE_URL = "http://localhost:3000";
|
|
7
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY;;;CAGf,CAAA;AAEV,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAA;AAG3E,eAAO,MAAM,gBAAgB,0BAA0B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/helpers/dates.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGtD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BranchStatus } from '../constants.js';
|
|
2
|
+
export interface BranchInfo {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
status: BranchStatus;
|
|
6
|
+
created_at: string;
|
|
7
|
+
origin_version: number | null;
|
|
8
|
+
origin_branch: string | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Fetch all branches for an embeddable from Supabase
|
|
12
|
+
*/
|
|
13
|
+
export declare function fetchBranches(flowId: string): Promise<BranchInfo[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Prompt the user to select a branch
|
|
16
|
+
* Returns null if user selects "main" or cancels
|
|
17
|
+
* The "main" option is always included at the top
|
|
18
|
+
*/
|
|
19
|
+
export declare function promptForBranch(branches: BranchInfo[]): Promise<BranchInfo | null>;
|
|
20
|
+
//# sourceMappingURL=branches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branches.d.ts","sourceRoot":"","sources":["../../src/prompts/branches.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG9C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CA8BzE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA8DxF"}
|