@embeddables/cli 0.6.11 → 0.7.1

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 (40) hide show
  1. package/.prompts/custom/build-funnel.md +1 -1
  2. package/dist/cli.js +7 -10
  3. package/dist/commands/branch.d.ts.map +1 -1
  4. package/dist/commands/branch.js +20 -15
  5. package/dist/commands/build-workbench.d.ts.map +1 -1
  6. package/dist/commands/build-workbench.js +37 -31
  7. package/dist/commands/build.d.ts.map +1 -1
  8. package/dist/commands/build.js +12 -3
  9. package/dist/commands/dev.d.ts.map +1 -1
  10. package/dist/commands/dev.js +34 -21
  11. package/dist/commands/experiments-connect.d.ts.map +1 -1
  12. package/dist/commands/experiments-connect.js +43 -30
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +49 -48
  15. package/dist/commands/login.d.ts.map +1 -1
  16. package/dist/commands/login.js +35 -25
  17. package/dist/commands/logout.d.ts.map +1 -1
  18. package/dist/commands/logout.js +10 -6
  19. package/dist/commands/pull.d.ts.map +1 -1
  20. package/dist/commands/pull.js +49 -36
  21. package/dist/commands/save.d.ts.map +1 -1
  22. package/dist/commands/save.js +79 -53
  23. package/dist/compiler/index.d.ts.map +1 -1
  24. package/dist/compiler/index.js +10 -9
  25. package/dist/compiler/reverse.d.ts.map +1 -1
  26. package/dist/compiler/reverse.js +18 -17
  27. package/dist/logger.d.ts +1 -0
  28. package/dist/logger.d.ts.map +1 -1
  29. package/dist/logger.js +4 -0
  30. package/dist/prompts/branches.d.ts.map +1 -1
  31. package/dist/prompts/branches.js +3 -2
  32. package/dist/prompts/embeddables.d.ts.map +1 -1
  33. package/dist/prompts/embeddables.js +8 -7
  34. package/dist/prompts/experiments.d.ts.map +1 -1
  35. package/dist/prompts/experiments.js +5 -4
  36. package/dist/prompts/projects.d.ts.map +1 -1
  37. package/dist/prompts/projects.js +4 -3
  38. package/dist/proxy/server.d.ts.map +1 -1
  39. package/dist/proxy/server.js +33 -32
  40. package/package.json +2 -1
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import pc from 'picocolors';
4
4
  import prompts from 'prompts';
5
5
  import { getAuthenticatedSupabaseClient } from '../auth/index.js';
6
+ import * as stdout from '../stdout.js';
6
7
  /**
7
8
  * Fetch all embeddables for a project from Supabase
8
9
  */
@@ -18,7 +19,7 @@ export async function fetchProjectEmbeddables(projectId) {
18
19
  .eq('project_id', projectId)
19
20
  .order('title', { ascending: true });
20
21
  if (error) {
21
- console.warn(pc.yellow(`Could not fetch embeddables: ${error.message}`));
22
+ stdout.warn(pc.yellow(`Could not fetch embeddables: ${error.message}`));
22
23
  return [];
23
24
  }
24
25
  return (data || []).map((row) => ({
@@ -27,7 +28,7 @@ export async function fetchProjectEmbeddables(projectId) {
27
28
  }));
28
29
  }
29
30
  catch (err) {
30
- console.warn(pc.yellow(`Could not fetch embeddables: ${err}`));
31
+ stdout.warn(pc.yellow(`Could not fetch embeddables: ${err}`));
31
32
  return [];
32
33
  }
33
34
  }
@@ -47,7 +48,7 @@ export async function fetchEmbeddableMetadata(embeddableId) {
47
48
  .eq('id', embeddableId)
48
49
  .single();
49
50
  if (error) {
50
- console.warn(pc.yellow(`Could not fetch embeddable metadata: ${error.message}`));
51
+ stdout.warn(pc.yellow(`Could not fetch embeddable metadata: ${error.message}`));
51
52
  return null;
52
53
  }
53
54
  return {
@@ -57,7 +58,7 @@ export async function fetchEmbeddableMetadata(embeddableId) {
57
58
  };
58
59
  }
59
60
  catch (err) {
60
- console.warn(pc.yellow(`Could not fetch embeddable metadata: ${err}`));
61
+ stdout.warn(pc.yellow(`Could not fetch embeddable metadata: ${err}`));
61
62
  return null;
62
63
  }
63
64
  }
@@ -69,7 +70,7 @@ export async function promptForEmbeddable(projectId, options = {}) {
69
70
  const { message = 'Select an embeddable:' } = options;
70
71
  const embeddables = await fetchProjectEmbeddables(projectId);
71
72
  if (embeddables.length === 0) {
72
- console.log(pc.yellow('No embeddables found in this project.'));
73
+ stdout.print(pc.yellow('No embeddables found in this project.'));
73
74
  return null;
74
75
  }
75
76
  const choices = embeddables.map((e) => ({
@@ -137,8 +138,8 @@ export async function promptForLocalEmbeddable(options = {}) {
137
138
  const { message = 'Select an embeddable:' } = options;
138
139
  const embeddables = await discoverLocalEmbeddables();
139
140
  if (embeddables.length === 0) {
140
- console.error(pc.red('No embeddables found in the embeddables/ directory.'));
141
- console.log(pc.gray('Run `embeddables pull` to pull an embeddable first.'));
141
+ stdout.error(pc.red('No embeddables found in the embeddables/ directory.'));
142
+ stdout.print(pc.gray('Run `embeddables pull` to pull an embeddable first.'));
142
143
  return null;
143
144
  }
144
145
  const choices = embeddables.map((e) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"experiments.d.ts","sourceRoot":"","sources":["../../src/prompts/experiments.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA+B1F;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4DnE"}
1
+ {"version":3,"file":"experiments.d.ts","sourceRoot":"","sources":["../../src/prompts/experiments.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA+B1F;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4DnE"}
@@ -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
  /**
5
6
  * Fetch experiments for a project from Supabase (using experiments_extended view)
6
7
  */
@@ -16,7 +17,7 @@ export async function fetchProjectExperiments(projectId) {
16
17
  .eq('project_id', projectId)
17
18
  .order('name', { ascending: true, nullsFirst: false });
18
19
  if (error) {
19
- console.warn(pc.yellow(`Could not fetch experiments: ${error.message}`));
20
+ stdout.warn(pc.yellow(`Could not fetch experiments: ${error.message}`));
20
21
  return [];
21
22
  }
22
23
  return (data || []).map((row) => ({
@@ -30,7 +31,7 @@ export async function fetchProjectExperiments(projectId) {
30
31
  }));
31
32
  }
32
33
  catch (err) {
33
- console.warn(pc.yellow(`Could not fetch experiments: ${err}`));
34
+ stdout.warn(pc.yellow(`Could not fetch experiments: ${err}`));
34
35
  return [];
35
36
  }
36
37
  }
@@ -50,10 +51,10 @@ export async function promptForExperiment(projectId, options = {}) {
50
51
  }
51
52
  if (filtered.length === 0) {
52
53
  if (excludeConnectedTo && experiments.length > 0) {
53
- console.log(pc.yellow('All experiments in this project are already connected to this embeddable.'));
54
+ stdout.print(pc.yellow('All experiments in this project are already connected to this embeddable.'));
54
55
  }
55
56
  else {
56
- console.log(pc.yellow('No experiments found in this project.'));
57
+ stdout.print(pc.yellow('No experiments found in this project.'));
57
58
  }
58
59
  return null;
59
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/prompts/projects.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAwC5D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqD7B"}
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/prompts/projects.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAwC5D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqD7B"}
@@ -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
  /**
5
6
  * Fetch all non-archived projects from Supabase
6
7
  */
@@ -23,7 +24,7 @@ export async function fetchProjects() {
23
24
  .not('archived', 'is', 'true')
24
25
  .order('title', { ascending: true });
25
26
  if (error) {
26
- console.warn(pc.yellow(`Could not fetch projects: ${error.message}`));
27
+ stdout.warn(pc.yellow(`Could not fetch projects: ${error.message}`));
27
28
  return [];
28
29
  }
29
30
  return (data || []).map((row) => ({
@@ -37,7 +38,7 @@ export async function fetchProjects() {
37
38
  }));
38
39
  }
39
40
  catch (err) {
40
- console.warn(pc.yellow(`Could not fetch projects: ${err}`));
41
+ stdout.warn(pc.yellow(`Could not fetch projects: ${err}`));
41
42
  return [];
42
43
  }
43
44
  }
@@ -49,7 +50,7 @@ export async function promptForProject(options = {}) {
49
50
  const { allowSkip = false, message = 'Select a project:' } = options;
50
51
  const projects = await fetchProjects();
51
52
  if (projects.length === 0) {
52
- console.log(pc.yellow('No projects found.'));
53
+ stdout.print(pc.yellow('No projects found.'));
53
54
  return null;
54
55
  }
55
56
  const choices = projects.map((p) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAmCA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;;GAyTA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAoCA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;;GAwTA"}
@@ -13,6 +13,7 @@ import { injectWorkbenchHtml } from './injectWorkbench.js';
13
13
  import { injectReloadScript } from './injectReload.js';
14
14
  import { injectApiInterceptor } from './injectApiInterceptor.js';
15
15
  import { WORKBENCH_CDN_ORIGIN } from '../constants.js';
16
+ import * as stdout from '../stdout.js';
16
17
  // Resolve the CLI package root so workbench paths work regardless of cwd.
17
18
  // This file lives at src/proxy/server.ts (or dist/proxy/server.js when compiled),
18
19
  // so the package root is two directories up.
@@ -45,10 +46,10 @@ export async function startProxyServer(opts) {
45
46
  // string → remote CDN origin (e.g. https://embeddables-workbench.heysavvy.workers.dev)
46
47
  const workbenchOrigin = localDev ? undefined : WORKBENCH_CDN_ORIGIN;
47
48
  if (localDev) {
48
- console.log('[Workbench] Local dev mode — building workbench from source');
49
+ stdout.print('[Workbench] Local dev mode — building workbench from source');
49
50
  }
50
51
  else {
51
- console.log(`[Workbench] Installed mode — loading workbench from CDN (${WORKBENCH_CDN_ORIGIN})`);
52
+ stdout.print(`[Workbench] Installed mode — loading workbench from CDN (${WORKBENCH_CDN_ORIGIN})`);
52
53
  }
53
54
  const buildWorkbench = async () => {
54
55
  try {
@@ -74,14 +75,14 @@ export async function startProxyServer(opts) {
74
75
  });
75
76
  workbenchCss = cssResult.css;
76
77
  if (workbenchBundle) {
77
- console.log('[Workbench] Bundle built successfully');
78
+ stdout.print('[Workbench] Bundle built successfully');
78
79
  return true;
79
80
  }
80
- console.warn('[Workbench] Bundle build completed but no output file found');
81
+ stdout.warn('[Workbench] Bundle build completed but no output file found');
81
82
  return false;
82
83
  }
83
84
  catch (err) {
84
- console.warn('[Workbench] Failed to build Workbench bundle. Workbench UI will be unavailable.', err);
85
+ stdout.warn(`[Workbench] Failed to build Workbench bundle. Workbench UI will be unavailable. ${err instanceof Error ? err.message : String(err)}`);
85
86
  workbenchCss = null;
86
87
  return false;
87
88
  }
@@ -104,15 +105,15 @@ export async function startProxyServer(opts) {
104
105
  watcher.on('all', async () => {
105
106
  clearTimeout(rebuildTimeout);
106
107
  rebuildTimeout = setTimeout(async () => {
107
- console.log('[Workbench] Files changed, rebuilding bundle...');
108
+ stdout.print('[Workbench] Files changed, rebuilding bundle...');
108
109
  const success = await buildWorkbench();
109
110
  if (success) {
110
111
  broadcastReload();
111
- console.log('[Workbench] Bundle rebuilt and reload broadcast');
112
+ stdout.print('[Workbench] Bundle rebuilt and reload broadcast');
112
113
  }
113
114
  }, 100);
114
115
  });
115
- console.log(`[Workbench] Watching ${workbenchGlob} for changes`);
116
+ stdout.print(`[Workbench] Watching ${workbenchGlob} for changes`);
116
117
  }
117
118
  // Serve the Workbench bundle as a static asset (local-dev mode only)
118
119
  if (localDev) {
@@ -143,13 +144,13 @@ export async function startProxyServer(opts) {
143
144
  }
144
145
  // Intercept GET requests to overrideRoute: convert to POST and add generated JSON to body
145
146
  app.get(opts.overrideRoute, async (req, res) => {
146
- console.log(`[/init] Intercepted GET ${opts.overrideRoute}, query:`, req.query);
147
+ stdout.print(`[/init] Intercepted GET ${opts.overrideRoute}, query: ${JSON.stringify(req.query)}`);
147
148
  try {
148
149
  // Load the generated JSON
149
150
  const raw = fs.readFileSync(opts.generatedJsonPath, 'utf8');
150
151
  const generatedJson = JSON.parse(raw);
151
152
  generatedJson.id = opts.embeddableId;
152
- console.log(`[/init] Loaded local JSON, pages: ${generatedJson.pages?.length ?? 0}`);
153
+ stdout.print(`[/init] Loaded local JSON, pages: ${generatedJson.pages?.length ?? 0}`);
153
154
  // Create POST request body with the JSON
154
155
  const postBody = {
155
156
  json: {
@@ -161,7 +162,7 @@ export async function startProxyServer(opts) {
161
162
  // Build the target URL with query parameters
162
163
  const queryString = new URLSearchParams(req.query).toString();
163
164
  const targetUrl = `${opts.engineOrigin}/init${queryString ? `?${queryString}` : ''}`;
164
- console.log(`[/init] Forwarding to engine: POST ${targetUrl}`);
165
+ stdout.print(`[/init] Forwarding to engine: POST ${targetUrl}`);
165
166
  // Forward headers from original request (excluding problematic ones)
166
167
  const headers = {};
167
168
  for (const [key, value] of Object.entries(req.headers)) {
@@ -183,13 +184,13 @@ export async function startProxyServer(opts) {
183
184
  });
184
185
  // Parse and forward the response
185
186
  const responseBody = await engineResponse.json();
186
- console.log(`[/init] Engine response: status=${engineResponse.status}, hasFlow=${!!responseBody?.flow}, flowPages=${responseBody?.flow?.pages?.length ?? 'N/A'}`);
187
+ stdout.print(`[/init] Engine response: status=${engineResponse.status}, hasFlow=${!!responseBody?.flow}, flowPages=${responseBody?.flow?.pages?.length ?? 'N/A'}`);
187
188
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
188
189
  res.setHeader('Cache-Control', 'no-store');
189
190
  return res.status(engineResponse.status).send(JSON.stringify(responseBody));
190
191
  }
191
192
  catch (err) {
192
- console.error('Failed to modify /init request', err);
193
+ stdout.error(`Failed to modify /init request: ${err instanceof Error ? err.message : String(err)}`);
193
194
  if (!res.headersSent) {
194
195
  res.status(500).json({
195
196
  error: 'Failed to modify /init request',
@@ -204,13 +205,13 @@ export async function startProxyServer(opts) {
204
205
  app.get('/', async (req, res, next) => {
205
206
  const host = (req.headers.host ?? '').toString();
206
207
  const isLocalhost = host.startsWith('localhost') || host.startsWith('127.0.0.1');
207
- console.log(`[Workbench] GET / handler: host=${host}, isLocalhost=${isLocalhost}, url=${req.url}`);
208
+ stdout.print(`[Workbench] GET / handler: host=${host}, isLocalhost=${isLocalhost}, url=${req.url}`);
208
209
  if (!isLocalhost) {
209
- console.log('[Workbench] Not localhost, skipping injection');
210
+ stdout.print('[Workbench] Not localhost, skipping injection');
210
211
  return next();
211
212
  }
212
213
  const targetUrl = `${opts.engineOrigin}${req.url}`;
213
- console.log(`[Workbench] Fetching from engine: ${targetUrl}`);
214
+ stdout.print(`[Workbench] Fetching from engine: ${targetUrl}`);
214
215
  try {
215
216
  const headers = {};
216
217
  for (const [key, value] of Object.entries(req.headers)) {
@@ -223,19 +224,19 @@ export async function startProxyServer(opts) {
223
224
  }
224
225
  const engineRes = await fetch(targetUrl, { method: 'GET', headers });
225
226
  const contentType = engineRes.headers.get('content-type') ?? '';
226
- console.log(`[Workbench] Engine response: status=${engineRes.status}, content-type=${contentType}`);
227
+ stdout.print(`[Workbench] Engine response: status=${engineRes.status}, content-type=${contentType}`);
227
228
  if (!contentType.includes('text/html')) {
228
- console.log('[Workbench] Not HTML, proxying normally');
229
+ stdout.print('[Workbench] Not HTML, proxying normally');
229
230
  return next();
230
231
  }
231
232
  const html = await engineRes.text();
232
- console.log(`[Workbench] Got HTML (${html.length} chars), injecting Workbench...`);
233
+ stdout.print(`[Workbench] Got HTML (${html.length} chars), injecting Workbench...`);
233
234
  let modifiedHtml = html;
234
235
  // If proxying to a remote engine, inject API interceptor to rewrite absolute URLs
235
236
  const isRemoteEngine = !opts.engineOrigin.includes('localhost') && !opts.engineOrigin.includes('127.0.0.1');
236
237
  if (isRemoteEngine) {
237
238
  modifiedHtml = injectApiInterceptor(modifiedHtml, opts.engineOrigin);
238
- console.log(`[Workbench] Injected API interceptor for ${opts.engineOrigin}`);
239
+ stdout.print(`[Workbench] Injected API interceptor for ${opts.engineOrigin}`);
239
240
  }
240
241
  modifiedHtml = injectReloadScript(modifiedHtml);
241
242
  const includeWorkbench = req.query?.workbench !== 'false';
@@ -248,13 +249,13 @@ export async function startProxyServer(opts) {
248
249
  else {
249
250
  console.log('[Workbench] Skipping workbench (workbench=false in URL)');
250
251
  }
251
- console.log(`[Workbench] Injection complete (${modifiedHtml.length} chars), sending response`);
252
+ stdout.print(`[Workbench] Injection complete (${modifiedHtml.length} chars), sending response`);
252
253
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
253
254
  res.setHeader('Cache-Control', engineRes.headers.get('cache-control') ?? 'no-store');
254
255
  res.status(engineRes.status).send(modifiedHtml);
255
256
  }
256
257
  catch (err) {
257
- console.error('[Workbench] Error fetching/injecting HTML:', err);
258
+ stdout.error(`[Workbench] Error fetching/injecting HTML: ${err instanceof Error ? err.message : String(err)}`);
258
259
  next();
259
260
  }
260
261
  });
@@ -265,7 +266,7 @@ export async function startProxyServer(opts) {
265
266
  ws: true,
266
267
  on: {
267
268
  proxyReq: (proxyReq, req) => {
268
- console.log(`[Proxy] ${req.method} ${req.url} → ${opts.engineOrigin}${req.url}`);
269
+ stdout.print(`[Proxy] ${req.method} ${req.url} → ${opts.engineOrigin}${req.url}`);
269
270
  },
270
271
  error: (err, req, res) => {
271
272
  // ECONNRESET/ECONNABORTED often happen when the client navigates away or the
@@ -273,10 +274,10 @@ export async function startProxyServer(opts) {
273
274
  const code = err?.code ?? err?.errno;
274
275
  const isConnectionClosed = code === 'ECONNRESET' || code === 'ECONNABORTED' || code === -54;
275
276
  if (isConnectionClosed) {
276
- console.log('[Proxy] Connection closed (client or upstream):', err.message);
277
+ stdout.print(`[Proxy] Connection closed (client or upstream): ${err.message}`);
277
278
  }
278
279
  else {
279
- console.error('[Proxy] Error proxying request:', err);
280
+ stdout.error(`[Proxy] Error proxying request: ${err instanceof Error ? err.message : String(err)}`);
280
281
  }
281
282
  if (!res.headersSent) {
282
283
  res.status(500).send('Proxy error');
@@ -285,16 +286,16 @@ export async function startProxyServer(opts) {
285
286
  },
286
287
  }));
287
288
  app.listen(opts.port, () => {
288
- console.log(`Dev proxy: http://localhost:${opts.port}`);
289
- console.log(` → Engine: ${opts.engineOrigin}`);
290
- console.log(`Override route: GET ${opts.overrideRoute}`);
291
- console.log(`Serving: ${opts.generatedJsonPath}`);
292
- console.log(`Reload SSE: /__embeddables_reload`);
289
+ stdout.print(`Dev proxy: http://localhost:${opts.port}`);
290
+ stdout.print(` → Engine: ${opts.engineOrigin}`);
291
+ stdout.print(`Override route: GET ${opts.overrideRoute}`);
292
+ stdout.print(`Serving: ${opts.generatedJsonPath}`);
293
+ stdout.print(`Reload SSE: /__embeddables_reload`);
293
294
  if (localDev) {
294
- console.log(`Workbench: built from local source`);
295
+ stdout.print(`Workbench: built from local source`);
295
296
  }
296
297
  else {
297
- console.log(`Workbench: served from ${WORKBENCH_CDN_ORIGIN}`);
298
+ stdout.print(`Workbench: served from ${WORKBENCH_CDN_ORIGIN}`);
298
299
  }
299
300
  });
300
301
  return { broadcastReload };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddables/cli",
3
- "version": "0.6.11",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "embeddables": "./bin/embeddables.mjs"
@@ -51,6 +51,7 @@
51
51
  "@babel/generator": "^7.28.6",
52
52
  "@babel/parser": "^7.26.0",
53
53
  "@babel/traverse": "^7.26.0",
54
+ "@sentry/node": "^10.39.0",
54
55
  "@supabase/supabase-js": "^2.39.0",
55
56
  "@tailwindcss/postcss": "^4.1.18",
56
57
  "autoprefixer": "^10.4.23",