@embeddables/cli 0.6.10 → 0.7.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/.prompts/custom/build-funnel.md +1 -1
- package/dist/cli.js +7 -10
- package/dist/commands/branch.d.ts.map +1 -1
- package/dist/commands/branch.js +20 -15
- package/dist/commands/build-workbench.d.ts.map +1 -1
- package/dist/commands/build-workbench.js +37 -31
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +12 -3
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +34 -21
- package/dist/commands/experiments-connect.d.ts.map +1 -1
- package/dist/commands/experiments-connect.js +43 -30
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +49 -48
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +35 -25
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +10 -6
- package/dist/commands/pull.d.ts +2 -0
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +53 -40
- package/dist/commands/save.d.ts.map +1 -1
- package/dist/commands/save.js +79 -53
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/index.js +10 -9
- package/dist/compiler/reverse.d.ts.map +1 -1
- package/dist/compiler/reverse.js +18 -17
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -0
- package/dist/prompts/branches.d.ts.map +1 -1
- package/dist/prompts/branches.js +3 -2
- package/dist/prompts/embeddables.d.ts.map +1 -1
- package/dist/prompts/embeddables.js +8 -7
- package/dist/prompts/experiments.d.ts.map +1 -1
- package/dist/prompts/experiments.js +5 -4
- package/dist/prompts/projects.d.ts.map +1 -1
- package/dist/prompts/projects.js +4 -3
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/server.js +33 -32
- package/package.json +2 -1
package/dist/commands/save.js
CHANGED
|
@@ -8,6 +8,8 @@ import { compileAllPages } from '../compiler/index.js';
|
|
|
8
8
|
import { formatError } from '../compiler/errors.js';
|
|
9
9
|
import { promptForLocalEmbeddable, promptForProject } from '../prompts/index.js';
|
|
10
10
|
import { WEB_APP_BASE_URL } from '../constants.js';
|
|
11
|
+
import { captureException, createLogger, exit } from '../logger.js';
|
|
12
|
+
import * as stdout from '../stdout.js';
|
|
11
13
|
import { translateJsonDiffToEditCommands } from '../helpers/json.js';
|
|
12
14
|
import { generateId, inferEmbeddableFromCwd } from '../helpers/utils.js';
|
|
13
15
|
/** Error with optional gray detail line (hint/next step) for the user. */
|
|
@@ -188,42 +190,48 @@ async function fetchOtherUsersDrafts(supabase, flowId, versionNumber, branchId,
|
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
192
|
export async function runSave(opts) {
|
|
193
|
+
const logger = createLogger('runSave');
|
|
191
194
|
try {
|
|
192
195
|
await runSaveInner(opts);
|
|
193
196
|
}
|
|
194
197
|
catch (error) {
|
|
198
|
+
captureException(error);
|
|
195
199
|
if (error instanceof SaveError) {
|
|
196
|
-
|
|
200
|
+
stdout.error(pc.red(`Save failed: ${error.message}`));
|
|
197
201
|
if (error.detail) {
|
|
198
|
-
|
|
202
|
+
stdout.print(pc.gray(error.detail));
|
|
199
203
|
}
|
|
200
204
|
}
|
|
201
205
|
else if (error instanceof Error) {
|
|
202
|
-
|
|
206
|
+
stdout.error(pc.red(`Save failed: ${error.message}`));
|
|
203
207
|
}
|
|
204
208
|
else {
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
process.exit(1);
|
|
208
|
-
// Rethrow only when exit was mocked to throw (e.g. in tests expecting rejection)
|
|
209
|
-
if (error instanceof Error && error.message === 'exit') {
|
|
210
|
-
throw error;
|
|
209
|
+
stdout.error(pc.red('Save failed with an unexpected error.'));
|
|
211
210
|
}
|
|
211
|
+
logger.error('save failed', {
|
|
212
|
+
message: error instanceof Error ? error.message : 'unexpected error',
|
|
213
|
+
});
|
|
214
|
+
await exit(1);
|
|
212
215
|
}
|
|
213
216
|
}
|
|
214
217
|
async function runSaveInner(opts) {
|
|
218
|
+
const logger = createLogger('runSave');
|
|
215
219
|
// 1. Check login
|
|
216
220
|
if (!isLoggedIn()) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
stdout.error(pc.red('Not logged in.'));
|
|
222
|
+
stdout.print(pc.gray('Run "embeddables login" first.'));
|
|
223
|
+
logger.error('not logged in');
|
|
224
|
+
await exit(1);
|
|
225
|
+
return;
|
|
220
226
|
}
|
|
221
227
|
// 2. Get access token
|
|
222
228
|
const accessToken = getAccessToken();
|
|
223
229
|
if (!accessToken) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
230
|
+
stdout.error(pc.red('Could not retrieve access token.'));
|
|
231
|
+
stdout.print(pc.gray('Run "embeddables login" to re-authenticate.'));
|
|
232
|
+
logger.error('no access token');
|
|
233
|
+
await exit(1);
|
|
234
|
+
return;
|
|
227
235
|
}
|
|
228
236
|
// 3. Get embeddable ID (from option, cwd inference, or interactive prompt)
|
|
229
237
|
const inferred = inferEmbeddableFromCwd();
|
|
@@ -236,20 +244,23 @@ async function runSaveInner(opts) {
|
|
|
236
244
|
message: 'Select an embeddable to save:',
|
|
237
245
|
});
|
|
238
246
|
if (!selected) {
|
|
239
|
-
|
|
247
|
+
await exit(1);
|
|
248
|
+
return;
|
|
240
249
|
}
|
|
241
250
|
embeddableId = selected;
|
|
242
|
-
|
|
251
|
+
stdout.print('');
|
|
243
252
|
}
|
|
244
253
|
// Resolve branch: explicit -b flag wins, otherwise use current branch from config (set by `embeddables branch`)
|
|
245
254
|
const effectiveBranch = opts.branch ?? getBranchFromConfig(embeddableId) ?? undefined;
|
|
255
|
+
logger.info('save started', { embeddableId, branch: effectiveBranch, fromVersion: opts.fromVersion });
|
|
246
256
|
// 4. Get project ID (from config or interactive prompt)
|
|
247
257
|
let projectId = getProjectId();
|
|
248
258
|
if (!projectId) {
|
|
249
|
-
|
|
259
|
+
stdout.print(pc.cyan('No project configured. Fetching projects...'));
|
|
250
260
|
const selectedProject = await promptForProject();
|
|
251
261
|
if (!selectedProject) {
|
|
252
|
-
|
|
262
|
+
await exit(1);
|
|
263
|
+
return;
|
|
253
264
|
}
|
|
254
265
|
projectId = selectedProject.id;
|
|
255
266
|
writeProjectConfig({
|
|
@@ -258,8 +269,8 @@ async function runSaveInner(opts) {
|
|
|
258
269
|
project_id: projectId,
|
|
259
270
|
project_name: selectedProject.title || undefined,
|
|
260
271
|
});
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
stdout.print(pc.green('✓ Saved project to embeddables.json'));
|
|
273
|
+
stdout.print('');
|
|
263
274
|
}
|
|
264
275
|
// 5. Build (compile TSX → JSON) unless --skip-build is set
|
|
265
276
|
const generatedDir = path.join('embeddables', embeddableId, '.generated');
|
|
@@ -268,7 +279,7 @@ async function runSaveInner(opts) {
|
|
|
268
279
|
const pagesGlob = `embeddables/${embeddableId}/pages/**/*.page.tsx`;
|
|
269
280
|
const stylesDir = path.join('embeddables', embeddableId, 'styles');
|
|
270
281
|
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
271
|
-
|
|
282
|
+
stdout.print(pc.cyan('Building embeddable...'));
|
|
272
283
|
try {
|
|
273
284
|
await compileAllPages({
|
|
274
285
|
pagesGlob,
|
|
@@ -280,17 +291,22 @@ async function runSaveInner(opts) {
|
|
|
280
291
|
});
|
|
281
292
|
}
|
|
282
293
|
catch (e) {
|
|
283
|
-
|
|
284
|
-
|
|
294
|
+
captureException(e);
|
|
295
|
+
stdout.error(formatError(e));
|
|
296
|
+
logger.error('build failed', { embeddableId });
|
|
297
|
+
await exit(1);
|
|
298
|
+
return;
|
|
285
299
|
}
|
|
286
|
-
|
|
287
|
-
|
|
300
|
+
stdout.print(pc.green('✓ Build successful'));
|
|
301
|
+
stdout.print('');
|
|
288
302
|
}
|
|
289
303
|
// 6. Read the compiled JSON
|
|
290
304
|
if (!fs.existsSync(outPath)) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
305
|
+
stdout.error(pc.red(`No compiled embeddable found at ${outPath}`));
|
|
306
|
+
stdout.print(pc.gray('Run "embeddables build" or "embeddables pull" first.'));
|
|
307
|
+
logger.error('compiled json not found', { outPath });
|
|
308
|
+
await exit(1);
|
|
309
|
+
return;
|
|
294
310
|
}
|
|
295
311
|
const jsonContent = fs.readFileSync(outPath, 'utf8');
|
|
296
312
|
let embeddableJson;
|
|
@@ -298,32 +314,40 @@ async function runSaveInner(opts) {
|
|
|
298
314
|
embeddableJson = JSON.parse(jsonContent);
|
|
299
315
|
}
|
|
300
316
|
catch {
|
|
301
|
-
|
|
302
|
-
|
|
317
|
+
stdout.error(pc.red('Failed to parse embeddable JSON.'));
|
|
318
|
+
logger.error('failed to parse compiled json');
|
|
319
|
+
await exit(1);
|
|
320
|
+
return;
|
|
303
321
|
}
|
|
304
322
|
// Validate that pages array exists and is non-empty
|
|
305
323
|
if (!embeddableJson.pages ||
|
|
306
324
|
!Array.isArray(embeddableJson.pages) ||
|
|
307
325
|
embeddableJson.pages.length === 0) {
|
|
308
|
-
|
|
309
|
-
|
|
326
|
+
stdout.error(pc.red('Embeddable JSON must contain a non-empty pages array.'));
|
|
327
|
+
logger.error('empty pages array');
|
|
328
|
+
await exit(1);
|
|
329
|
+
return;
|
|
310
330
|
}
|
|
311
331
|
// 7. Determine fromVersionNumber
|
|
312
332
|
let fromVersionNumber;
|
|
313
333
|
if (opts.fromVersion) {
|
|
314
334
|
fromVersionNumber = parseInt(opts.fromVersion, 10);
|
|
315
335
|
if (isNaN(fromVersionNumber)) {
|
|
316
|
-
|
|
317
|
-
|
|
336
|
+
stdout.error(pc.red(`Invalid --from-version value: ${opts.fromVersion}`));
|
|
337
|
+
logger.error('invalid from-version', { fromVersion: opts.fromVersion });
|
|
338
|
+
await exit(1);
|
|
339
|
+
return;
|
|
318
340
|
}
|
|
319
341
|
}
|
|
320
342
|
else {
|
|
321
343
|
// Primary: read _version from config.json; fallback: scan .generated/ for versioned files
|
|
322
344
|
const detectedVersion = getVersionFromConfig(embeddableId) ?? getLatestVersionFromFiles(generatedDir);
|
|
323
345
|
if (detectedVersion === null) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
346
|
+
stdout.error(pc.red('Could not determine the current version number.'));
|
|
347
|
+
stdout.print(pc.gray('Make sure you have pulled the embeddable first (embeddables pull), or specify --from-version <number>.'));
|
|
348
|
+
logger.error('could not determine version');
|
|
349
|
+
await exit(1);
|
|
350
|
+
return;
|
|
327
351
|
}
|
|
328
352
|
fromVersionNumber = detectedVersion;
|
|
329
353
|
}
|
|
@@ -343,8 +367,8 @@ async function runSaveInner(opts) {
|
|
|
343
367
|
const namesText = names.length === 1
|
|
344
368
|
? names[0]
|
|
345
369
|
: `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
|
|
346
|
-
|
|
347
|
-
|
|
370
|
+
stdout.print('');
|
|
371
|
+
stdout.warn(pc.yellow(`⚠ ${namesText} ${names.length === 1 ? 'has' : 'have'} unsaved edits on version ${fromVersionNumber}. Saving may cause conflicts.`));
|
|
348
372
|
const { proceed } = await prompts({
|
|
349
373
|
type: 'confirm',
|
|
350
374
|
name: 'proceed',
|
|
@@ -356,15 +380,15 @@ async function runSaveInner(opts) {
|
|
|
356
380
|
},
|
|
357
381
|
});
|
|
358
382
|
if (!proceed) {
|
|
359
|
-
|
|
360
|
-
|
|
383
|
+
stdout.print(pc.gray('Save cancelled.'));
|
|
384
|
+
await exit(0);
|
|
361
385
|
}
|
|
362
|
-
|
|
386
|
+
stdout.print('');
|
|
363
387
|
}
|
|
364
388
|
}
|
|
365
389
|
}
|
|
366
390
|
// 8. POST to save-version API
|
|
367
|
-
|
|
391
|
+
stdout.print(pc.cyan(`Saving embeddable (based on v${fromVersionNumber})...`));
|
|
368
392
|
// Resolve current user id (required by API)
|
|
369
393
|
if (!currentUserId && supabase) {
|
|
370
394
|
const { data: { user }, } = await supabase.auth.getUser();
|
|
@@ -448,8 +472,8 @@ async function runSaveInner(opts) {
|
|
|
448
472
|
if (!conflictResult || !isSaveConflictResponse(conflictResult)) {
|
|
449
473
|
throw new SaveError(`Version conflict but invalid response (HTTP ${response.status}).`, 'Try saving again; if it persists, the server may be misconfigured.');
|
|
450
474
|
}
|
|
451
|
-
|
|
452
|
-
|
|
475
|
+
stdout.print('');
|
|
476
|
+
stdout.warn(pc.yellow(`⚠ Version conflict: the server has version ${conflictResult.latestVersionNumber}, but you are saving from version ${conflictResult.yourVersionNumber}.`));
|
|
453
477
|
const { forceSave } = await prompts({
|
|
454
478
|
type: 'confirm',
|
|
455
479
|
name: 'forceSave',
|
|
@@ -461,11 +485,11 @@ async function runSaveInner(opts) {
|
|
|
461
485
|
},
|
|
462
486
|
});
|
|
463
487
|
if (!forceSave) {
|
|
464
|
-
|
|
465
|
-
|
|
488
|
+
stdout.print(pc.gray('Save cancelled.'));
|
|
489
|
+
await exit(0);
|
|
466
490
|
}
|
|
467
491
|
// Retry with force flag
|
|
468
|
-
|
|
492
|
+
stdout.print(pc.cyan('Retrying save with force...'));
|
|
469
493
|
let forceResponse;
|
|
470
494
|
try {
|
|
471
495
|
forceResponse = await fetch(url, {
|
|
@@ -492,13 +516,14 @@ async function runSaveInner(opts) {
|
|
|
492
516
|
throw new SaveError(`Invalid response from server (HTTP ${forceResponse.status}).`, 'The server returned an unexpected format. Try again or contact support if it persists.');
|
|
493
517
|
}
|
|
494
518
|
const { newVersionNumber } = forceResult.data;
|
|
495
|
-
|
|
519
|
+
stdout.print(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
520
|
+
logger.info('save complete', { embeddableId, newVersionNumber, forced: true });
|
|
496
521
|
setVersionInConfig(embeddableId, newVersionNumber);
|
|
497
522
|
const branchSlug = getBranchSlugFromConfig(embeddableId);
|
|
498
523
|
const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
|
|
499
524
|
fs.mkdirSync(generatedDir, { recursive: true });
|
|
500
525
|
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
501
|
-
|
|
526
|
+
stdout.print(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
502
527
|
return;
|
|
503
528
|
}
|
|
504
529
|
const result = await safeParseJson(response);
|
|
@@ -510,7 +535,8 @@ async function runSaveInner(opts) {
|
|
|
510
535
|
throw new SaveError(`Invalid response from server (HTTP ${response.status}).`, 'The server returned an unexpected format. Try again or contact support if it persists.');
|
|
511
536
|
}
|
|
512
537
|
const { newVersionNumber } = result.data;
|
|
513
|
-
|
|
538
|
+
stdout.print(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
539
|
+
logger.info('save complete', { embeddableId, newVersionNumber });
|
|
514
540
|
// Update _version in config.json so future saves know the base version
|
|
515
541
|
setVersionInConfig(embeddableId, newVersionNumber);
|
|
516
542
|
// Also save the versioned file to .generated/ as a snapshot (embeddable-{branch}@{version}.json)
|
|
@@ -518,7 +544,7 @@ async function runSaveInner(opts) {
|
|
|
518
544
|
const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
|
|
519
545
|
fs.mkdirSync(generatedDir, { recursive: true });
|
|
520
546
|
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
521
|
-
|
|
547
|
+
stdout.print(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
522
548
|
}
|
|
523
549
|
function setMultipleFlowUpdates({ commands, metadata, }) {
|
|
524
550
|
const type = 'set_multiple_embeddable_updates';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AAoDA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA2DlF;AA6BD,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;IACnB,mHAAmH;IACnH,OAAO,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAA;CAC1B,iBAoeA"}
|
package/dist/compiler/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fg from 'fast-glob';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import * as stdout from '../stdout.js';
|
|
4
5
|
import { parsePageFromFile } from './parsePage.js';
|
|
5
6
|
import { CompileError } from './errors.js';
|
|
6
7
|
import CSSJSON from 'cssjson';
|
|
@@ -263,23 +264,23 @@ export async function compileAllPages(opts) {
|
|
|
263
264
|
if (totalLintIssues > 0) {
|
|
264
265
|
// Report all issues
|
|
265
266
|
if (idFixes.size > 0) {
|
|
266
|
-
|
|
267
|
+
stdout.warn(`Found ${idFixes.size} duplicate ID(s). Keys and IDs must be unique across the embeddable.`);
|
|
267
268
|
for (const [fixKey, newId] of idFixes) {
|
|
268
269
|
const parts = fixKey.split(':');
|
|
269
270
|
const file = parts[0];
|
|
270
271
|
const compIdx = parts[1];
|
|
271
272
|
const btnIdx = parts[2];
|
|
272
273
|
const loc = btnIdx !== undefined ? `component ${compIdx}, button ${btnIdx}` : `component ${compIdx}`;
|
|
273
|
-
|
|
274
|
+
stdout.warn(` → ${file}: ${loc} → "${newId}"`);
|
|
274
275
|
}
|
|
275
276
|
}
|
|
276
277
|
if (numericLeadingFixes.length > 0) {
|
|
277
|
-
|
|
278
|
+
stdout.warn(`Found ${numericLeadingFixes.length} key(s)/ID(s) that start with a number. Use a prefix (e.g. range_1_to_2_weeks).`);
|
|
278
279
|
for (const f of numericLeadingFixes) {
|
|
279
280
|
const loc = f.buttonIndex !== undefined
|
|
280
281
|
? `component ${f.componentIndex}, button ${f.buttonIndex} (${f.kind})`
|
|
281
282
|
: `component ${f.componentIndex} (${f.kind})`;
|
|
282
|
-
|
|
283
|
+
stdout.warn(` → ${f.file}: "${f.oldValue}" → "${f.newValue}" (${loc})`);
|
|
283
284
|
}
|
|
284
285
|
}
|
|
285
286
|
if (opts.fixLint === true) {
|
|
@@ -311,7 +312,7 @@ export async function compileAllPages(opts) {
|
|
|
311
312
|
code = fixNumericLeadingInSourceFile(code, file, numericForFile);
|
|
312
313
|
}
|
|
313
314
|
fs.writeFileSync(file, code, 'utf8');
|
|
314
|
-
|
|
315
|
+
stdout.print(` ✓ Updated ${file}`);
|
|
315
316
|
}
|
|
316
317
|
}
|
|
317
318
|
// Re-parse after fixes
|
|
@@ -348,7 +349,7 @@ export async function compileAllPages(opts) {
|
|
|
348
349
|
config = JSON.parse(configContent);
|
|
349
350
|
}
|
|
350
351
|
catch (error) {
|
|
351
|
-
|
|
352
|
+
stdout.warn(`Failed to parse config.json: ${error}`);
|
|
352
353
|
}
|
|
353
354
|
}
|
|
354
355
|
else if (opts.embeddableId) {
|
|
@@ -360,7 +361,7 @@ export async function compileAllPages(opts) {
|
|
|
360
361
|
config = JSON.parse(configContent);
|
|
361
362
|
}
|
|
362
363
|
catch (error) {
|
|
363
|
-
|
|
364
|
+
stdout.warn(`Failed to parse config.json: ${error}`);
|
|
364
365
|
}
|
|
365
366
|
}
|
|
366
367
|
}
|
|
@@ -548,7 +549,7 @@ export async function compileAllPages(opts) {
|
|
|
548
549
|
}
|
|
549
550
|
}
|
|
550
551
|
writeAtomic(opts.outPath, JSON.stringify(toWrite, null, 2));
|
|
551
|
-
|
|
552
|
+
stdout.print(`Wrote ${opts.outPath} (${orderedPages.length} pages, ${Object.keys(styles).length > 0 ? 'with styles' : 'no styles'})`);
|
|
552
553
|
}
|
|
553
554
|
function derivePageKey(file, mode) {
|
|
554
555
|
if (mode === 'filename') {
|
|
@@ -1191,7 +1192,7 @@ async function loadGlobalComponents(embeddableId, _config = null // config.compo
|
|
|
1191
1192
|
// Extract location from filename (e.g., "before_page.location.tsx" -> "before_page")
|
|
1192
1193
|
const locationMatch = tsxFile.match(/^(.+)\.location\.tsx$/);
|
|
1193
1194
|
if (!locationMatch) {
|
|
1194
|
-
|
|
1195
|
+
stdout.warn(`Global component file "${tsxFile}" doesn't match expected pattern <location>.location.tsx`);
|
|
1195
1196
|
continue;
|
|
1196
1197
|
}
|
|
1197
1198
|
const fileLocation = locationMatch[1];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAA;AAqlBzD,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;IACL,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5E,iBAoFF;AAgiDD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD"}
|
package/dist/compiler/reverse.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import CSSJSON from 'cssjson';
|
|
4
4
|
import pc from 'picocolors';
|
|
5
|
+
import * as stdout from '../stdout.js';
|
|
5
6
|
import { TYPE_MAP } from './registry.js';
|
|
6
7
|
import { generateRandomIdByType } from './helpers/duplicateIds.js';
|
|
7
8
|
/**
|
|
@@ -262,7 +263,7 @@ function hasRequiredProps(component, fix) {
|
|
|
262
263
|
}
|
|
263
264
|
if (missingProps.length > 0) {
|
|
264
265
|
if (fix) {
|
|
265
|
-
|
|
266
|
+
stdout.warn(`Removed ${component.type} component (id: ${component.id}, key: ${component.key}) missing required props: ${missingProps.join(', ')}.`);
|
|
266
267
|
return false;
|
|
267
268
|
}
|
|
268
269
|
throw new Error(`${component.type} component (id: ${component.id}, key: ${component.key}) missing required props: ${missingProps.join(', ')}.`);
|
|
@@ -400,13 +401,13 @@ function checkAndFixDuplicateIds(pages, fix) {
|
|
|
400
401
|
// This ID is duplicated
|
|
401
402
|
const isButton = occurrences[0].buttonIndex !== undefined;
|
|
402
403
|
const suffix = isButton ? ' (OptionSelector button)' : '';
|
|
403
|
-
|
|
404
|
+
stdout.warn(`Found duplicate ID "${id}"${suffix} used ${occurrences.length} times:`);
|
|
404
405
|
for (let i = 0; i < occurrences.length; i++) {
|
|
405
406
|
const occ = occurrences[i];
|
|
406
407
|
const location = occ.buttonIndex !== undefined
|
|
407
408
|
? `button at index ${occ.buttonIndex}`
|
|
408
409
|
: `component at index ${occ.componentIndex}`;
|
|
409
|
-
|
|
410
|
+
stdout.print(` - Page "${occ.pageKey}": ${occ.type} (${location}) with ID "${occ.id}"`);
|
|
410
411
|
}
|
|
411
412
|
// Create unique IDs for all but the first occurrence (type-based: plaintext_xxx, button_xxx, option_xxx)
|
|
412
413
|
for (let i = 1; i < occurrences.length; i++) {
|
|
@@ -419,7 +420,7 @@ function checkAndFixDuplicateIds(pages, fix) {
|
|
|
419
420
|
const location = occ.buttonIndex !== undefined
|
|
420
421
|
? `button at index ${occ.buttonIndex}`
|
|
421
422
|
: `component at index ${occ.componentIndex}`;
|
|
422
|
-
|
|
423
|
+
stdout.print(` → Renamed duplicate ID "${occ.id}" to "${newId}" in page "${occ.pageKey}" (${location})`);
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
426
|
}
|
|
@@ -454,14 +455,14 @@ function fixParentKeyDeprecation(components, fix) {
|
|
|
454
455
|
const resolvedId = keyToId.get(parentKey);
|
|
455
456
|
if (resolvedId) {
|
|
456
457
|
comp.parent_id = resolvedId;
|
|
457
|
-
|
|
458
|
+
stdout.warn(`Fixed parent_key on component (id: ${comp.id}, key: ${comp.key}) – resolved parent_key "${parentKey}" to parent_id.`);
|
|
458
459
|
}
|
|
459
460
|
else {
|
|
460
461
|
toRemove.set(comp.id, parentKey);
|
|
461
462
|
}
|
|
462
463
|
}
|
|
463
464
|
else {
|
|
464
|
-
|
|
465
|
+
stdout.warn(`Fixed parent_key on component (id: ${comp.id}, key: ${comp.key}) – removed deprecated parent_key (already has parent_id).`);
|
|
465
466
|
}
|
|
466
467
|
delete comp.parent_key;
|
|
467
468
|
}
|
|
@@ -471,7 +472,7 @@ function fixParentKeyDeprecation(components, fix) {
|
|
|
471
472
|
while (i < components.length) {
|
|
472
473
|
const comp = components[i];
|
|
473
474
|
if (toRemove.has(comp.id)) {
|
|
474
|
-
|
|
475
|
+
stdout.warn(`Removed component (id: ${comp.id}, key: ${comp.key}) – parent_key "${toRemove.get(comp.id)}" not found, no parent_id.`);
|
|
475
476
|
components.splice(i, 1);
|
|
476
477
|
}
|
|
477
478
|
else {
|
|
@@ -579,7 +580,7 @@ export async function reverseCompile(embeddable, embeddableId, opts) {
|
|
|
579
580
|
embeddable.components.length > 0) {
|
|
580
581
|
await extractGlobalComponents(embeddable.components, embeddableId, fix);
|
|
581
582
|
}
|
|
582
|
-
|
|
583
|
+
stdout.print(`${pc.cyan(`✓ Generated ${embeddable.pages.length} page(s) and ${embeddable.styles && Object.keys(embeddable.styles).length > 0 ? 'styles' : 'no styles'}`)}`);
|
|
583
584
|
}
|
|
584
585
|
async function generatePageFile(page, embeddableId, fix) {
|
|
585
586
|
const pageKey = page.key;
|
|
@@ -592,7 +593,7 @@ async function generatePageFile(page, embeddableId, fix) {
|
|
|
592
593
|
// Write to embeddables/<id>/pages/<pageKey>.page.tsx
|
|
593
594
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
594
595
|
fs.writeFileSync(filePath, tsx, 'utf8');
|
|
595
|
-
|
|
596
|
+
stdout.print(`${pc.gray(`Generated ${filePath}`)}`);
|
|
596
597
|
}
|
|
597
598
|
catch (error) {
|
|
598
599
|
if (error instanceof Error) {
|
|
@@ -606,7 +607,7 @@ function buildTree(components, pageKey, fix) {
|
|
|
606
607
|
let filteredComponents = components.filter((comp) => {
|
|
607
608
|
if (!comp.type) {
|
|
608
609
|
if (fix) {
|
|
609
|
-
|
|
610
|
+
stdout.warn(`Removed component (id: ${comp.id}, key: ${comp.key}) – missing type property.`);
|
|
610
611
|
return false;
|
|
611
612
|
}
|
|
612
613
|
throw new Error(`Component (id: ${comp.id}, key: ${comp.key}) is missing required type property.`);
|
|
@@ -1066,7 +1067,7 @@ async function generateStylesFile(styles, embeddableId) {
|
|
|
1066
1067
|
const filePath = path.join('embeddables', embeddableId, 'styles', 'index.css');
|
|
1067
1068
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
1068
1069
|
fs.writeFileSync(filePath, css, 'utf8');
|
|
1069
|
-
|
|
1070
|
+
stdout.print(`${pc.gray(`Generated ${filePath}`)}`);
|
|
1070
1071
|
}
|
|
1071
1072
|
catch (error) {
|
|
1072
1073
|
if (error instanceof Error) {
|
|
@@ -1698,7 +1699,7 @@ async function generateConfigFile(embeddable, embeddableId, opts) {
|
|
|
1698
1699
|
}
|
|
1699
1700
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1700
1701
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
1701
|
-
|
|
1702
|
+
stdout.print(`${pc.gray(`Generated ${configPath}`)}`);
|
|
1702
1703
|
}
|
|
1703
1704
|
catch (error) {
|
|
1704
1705
|
if (error instanceof Error) {
|
|
@@ -1727,7 +1728,7 @@ async function extractComputedFields(computedFields, embeddableId) {
|
|
|
1727
1728
|
const filePath = path.join(computedFieldsDir, fileName);
|
|
1728
1729
|
// Write the code as-is (it should be valid JavaScript)
|
|
1729
1730
|
fs.writeFileSync(filePath, field.code, 'utf8');
|
|
1730
|
-
|
|
1731
|
+
stdout.print(`${pc.gray(`Generated ${filePath}`)}`);
|
|
1731
1732
|
}
|
|
1732
1733
|
}
|
|
1733
1734
|
/**
|
|
@@ -1750,7 +1751,7 @@ async function extractDataOutputs(dataOutputs, embeddableId) {
|
|
|
1750
1751
|
const filePath = path.join(actionsDir, fileName);
|
|
1751
1752
|
// Write the code as-is (it should be valid JavaScript)
|
|
1752
1753
|
fs.writeFileSync(filePath, action.code, 'utf8');
|
|
1753
|
-
|
|
1754
|
+
stdout.print(`${pc.gray(`Generated ${filePath}`)}`);
|
|
1754
1755
|
}
|
|
1755
1756
|
}
|
|
1756
1757
|
/**
|
|
@@ -1796,7 +1797,7 @@ async function extractGlobalComponents(components, embeddableId, fix) {
|
|
|
1796
1797
|
// Components without parent_id must have _location
|
|
1797
1798
|
if (!component.parent_id && !location) {
|
|
1798
1799
|
if (fix) {
|
|
1799
|
-
|
|
1800
|
+
stdout.warn(`Removed global component "${component.id}" (key: "${component.key}") – missing _location (no parent_id).`);
|
|
1800
1801
|
continue;
|
|
1801
1802
|
}
|
|
1802
1803
|
throw new Error(`Global component "${component.id}" (key: "${component.key}") must have _location since it has no parent_id.`);
|
|
@@ -1818,7 +1819,7 @@ async function extractGlobalComponents(components, embeddableId, fix) {
|
|
|
1818
1819
|
const tsx = generateGlobalComponentTSX(locationComponents, tree);
|
|
1819
1820
|
// Write to file
|
|
1820
1821
|
fs.writeFileSync(filePath, tsx, 'utf8');
|
|
1821
|
-
|
|
1822
|
+
stdout.print(`${pc.gray(`Generated ${filePath}`)}`);
|
|
1822
1823
|
}
|
|
1823
1824
|
}
|
|
1824
1825
|
/**
|
|
@@ -1829,7 +1830,7 @@ function buildTreeForGlobalComponents(components, fix) {
|
|
|
1829
1830
|
let filteredComponents = components.filter((comp) => {
|
|
1830
1831
|
if (!comp.type) {
|
|
1831
1832
|
if (fix) {
|
|
1832
|
-
|
|
1833
|
+
stdout.warn(`Removed global component (id: ${comp.id}, key: ${comp.key}) – missing type property.`);
|
|
1833
1834
|
return false;
|
|
1834
1835
|
}
|
|
1835
1836
|
throw new Error(`Global component (id: ${comp.id}, key: ${comp.key}) is missing required type property.`);
|
package/dist/logger.d.ts
CHANGED
|
@@ -6,5 +6,6 @@ export interface Logger {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function createLogger(fn: string): Logger;
|
|
8
8
|
export declare function captureException(error: unknown): void;
|
|
9
|
+
export declare function exit(code: number): Promise<never>;
|
|
9
10
|
export {};
|
|
10
11
|
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAE9E,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;CAC/C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAY/C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAErD"}
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAE9E,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;CAC/C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAY/C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAErD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAGvD"}
|
package/dist/logger.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branches.d.ts","sourceRoot":"","sources":["../../src/prompts/branches.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branches.d.ts","sourceRoot":"","sources":["../../src/prompts/branches.ts"],"names":[],"mappings":"AAIA,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"}
|
package/dist/prompts/branches.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import pc from 'picocolors';
|
|
2
2
|
import prompts from 'prompts';
|
|
3
3
|
import { getAuthenticatedSupabaseClient } from '../auth/index.js';
|
|
4
|
+
import * as stdout from '../stdout.js';
|
|
4
5
|
import { BranchStatus } from '../constants.js';
|
|
5
6
|
import { formatDate } from '../helpers/dates.js';
|
|
6
7
|
/**
|
|
@@ -18,7 +19,7 @@ export async function fetchBranches(flowId) {
|
|
|
18
19
|
.eq('flow_id', flowId)
|
|
19
20
|
.order('created_at', { ascending: false });
|
|
20
21
|
if (error) {
|
|
21
|
-
|
|
22
|
+
stdout.warn(pc.yellow(`Could not fetch branches: ${error.message}`));
|
|
22
23
|
return [];
|
|
23
24
|
}
|
|
24
25
|
return (data || []).map((row) => ({
|
|
@@ -31,7 +32,7 @@ export async function fetchBranches(flowId) {
|
|
|
31
32
|
}));
|
|
32
33
|
}
|
|
33
34
|
catch (err) {
|
|
34
|
-
|
|
35
|
+
stdout.warn(pc.yellow(`Could not fetch branches: ${err}`));
|
|
35
36
|
return [];
|
|
36
37
|
}
|
|
37
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddables.d.ts","sourceRoot":"","sources":["../../src/prompts/embeddables.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"embeddables.d.ts","sourceRoot":"","sources":["../../src/prompts/embeddables.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA0B1F;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA2BpC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuCxB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAqC3E;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuCxB"}
|