@embeddables/cli 0.1.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.
Files changed (173) hide show
  1. package/README.md +116 -0
  2. package/bin/embeddables.mjs +2 -0
  3. package/dist/auth/index.d.ts +43 -0
  4. package/dist/auth/index.d.ts.map +1 -0
  5. package/dist/auth/index.js +100 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +75 -0
  9. package/dist/commands/build-workbench.d.ts +5 -0
  10. package/dist/commands/build-workbench.d.ts.map +1 -0
  11. package/dist/commands/build-workbench.js +122 -0
  12. package/dist/commands/build.d.ts +7 -0
  13. package/dist/commands/build.d.ts.map +1 -0
  14. package/dist/commands/build.js +22 -0
  15. package/dist/commands/dev.d.ts +11 -0
  16. package/dist/commands/dev.d.ts.map +1 -0
  17. package/dist/commands/dev.js +153 -0
  18. package/dist/commands/login.d.ts +2 -0
  19. package/dist/commands/login.d.ts.map +1 -0
  20. package/dist/commands/login.js +112 -0
  21. package/dist/commands/logout.d.ts +2 -0
  22. package/dist/commands/logout.d.ts.map +1 -0
  23. package/dist/commands/logout.js +18 -0
  24. package/dist/commands/pull.d.ts +7 -0
  25. package/dist/commands/pull.d.ts.map +1 -0
  26. package/dist/commands/pull.js +97 -0
  27. package/dist/compiler/errors.d.ts +20 -0
  28. package/dist/compiler/errors.d.ts.map +1 -0
  29. package/dist/compiler/errors.js +35 -0
  30. package/dist/compiler/evalStatic.d.ts +3 -0
  31. package/dist/compiler/evalStatic.d.ts.map +1 -0
  32. package/dist/compiler/evalStatic.js +57 -0
  33. package/dist/compiler/flatten.js +1 -0
  34. package/dist/compiler/helpers/duplicateIds.d.ts +9 -0
  35. package/dist/compiler/helpers/duplicateIds.d.ts.map +1 -0
  36. package/dist/compiler/helpers/duplicateIds.js +71 -0
  37. package/dist/compiler/index.d.ts +16 -0
  38. package/dist/compiler/index.d.ts.map +1 -0
  39. package/dist/compiler/index.js +934 -0
  40. package/dist/compiler/parsePage.d.ts +15 -0
  41. package/dist/compiler/parsePage.d.ts.map +1 -0
  42. package/dist/compiler/parsePage.js +562 -0
  43. package/dist/compiler/registry.d.ts +4 -0
  44. package/dist/compiler/registry.d.ts.map +1 -0
  45. package/dist/compiler/registry.js +44 -0
  46. package/dist/compiler/reverse.d.ts +17 -0
  47. package/dist/compiler/reverse.d.ts.map +1 -0
  48. package/dist/compiler/reverse.js +1632 -0
  49. package/dist/compiler/types.d.ts +21 -0
  50. package/dist/compiler/types.d.ts.map +1 -0
  51. package/dist/compiler/types.js +1 -0
  52. package/dist/components/index.d.ts +21 -0
  53. package/dist/components/index.d.ts.map +1 -0
  54. package/dist/components/index.js +21 -0
  55. package/dist/components/primitives/BaseComponent.d.ts +32 -0
  56. package/dist/components/primitives/BaseComponent.d.ts.map +1 -0
  57. package/dist/components/primitives/BaseComponent.js +26 -0
  58. package/dist/components/primitives/BookMeeting.d.ts +18 -0
  59. package/dist/components/primitives/BookMeeting.d.ts.map +1 -0
  60. package/dist/components/primitives/BookMeeting.js +5 -0
  61. package/dist/components/primitives/Chart.d.ts +41 -0
  62. package/dist/components/primitives/Chart.d.ts.map +1 -0
  63. package/dist/components/primitives/Chart.js +5 -0
  64. package/dist/components/primitives/Container.d.ts +8 -0
  65. package/dist/components/primitives/Container.d.ts.map +1 -0
  66. package/dist/components/primitives/Container.js +5 -0
  67. package/dist/components/primitives/CustomButton.d.ts +37 -0
  68. package/dist/components/primitives/CustomButton.d.ts.map +1 -0
  69. package/dist/components/primitives/CustomButton.js +10 -0
  70. package/dist/components/primitives/CustomHTML.d.ts +8 -0
  71. package/dist/components/primitives/CustomHTML.d.ts.map +1 -0
  72. package/dist/components/primitives/CustomHTML.js +5 -0
  73. package/dist/components/primitives/FileUpload.d.ts +18 -0
  74. package/dist/components/primitives/FileUpload.d.ts.map +1 -0
  75. package/dist/components/primitives/FileUpload.js +16 -0
  76. package/dist/components/primitives/InputBox.d.ts +34 -0
  77. package/dist/components/primitives/InputBox.d.ts.map +1 -0
  78. package/dist/components/primitives/InputBox.js +25 -0
  79. package/dist/components/primitives/Lottie.d.ts +11 -0
  80. package/dist/components/primitives/Lottie.d.ts.map +1 -0
  81. package/dist/components/primitives/Lottie.js +5 -0
  82. package/dist/components/primitives/MediaEmbed.d.ts +13 -0
  83. package/dist/components/primitives/MediaEmbed.d.ts.map +1 -0
  84. package/dist/components/primitives/MediaEmbed.js +6 -0
  85. package/dist/components/primitives/MediaImage.d.ts +8 -0
  86. package/dist/components/primitives/MediaImage.d.ts.map +1 -0
  87. package/dist/components/primitives/MediaImage.js +5 -0
  88. package/dist/components/primitives/OptionSelector.d.ts +35 -0
  89. package/dist/components/primitives/OptionSelector.d.ts.map +1 -0
  90. package/dist/components/primitives/OptionSelector.js +8 -0
  91. package/dist/components/primitives/PaypalCheckout.d.ts +25 -0
  92. package/dist/components/primitives/PaypalCheckout.d.ts.map +1 -0
  93. package/dist/components/primitives/PaypalCheckout.js +5 -0
  94. package/dist/components/primitives/PlainText.d.ts +6 -0
  95. package/dist/components/primitives/PlainText.d.ts.map +1 -0
  96. package/dist/components/primitives/PlainText.js +5 -0
  97. package/dist/components/primitives/ProgressBar.d.ts +15 -0
  98. package/dist/components/primitives/ProgressBar.d.ts.map +1 -0
  99. package/dist/components/primitives/ProgressBar.js +5 -0
  100. package/dist/components/primitives/RichText.d.ts +6 -0
  101. package/dist/components/primitives/RichText.d.ts.map +1 -0
  102. package/dist/components/primitives/RichText.js +5 -0
  103. package/dist/components/primitives/RichTextMarkdown.d.ts +6 -0
  104. package/dist/components/primitives/RichTextMarkdown.d.ts.map +1 -0
  105. package/dist/components/primitives/RichTextMarkdown.js +5 -0
  106. package/dist/components/primitives/Rive.d.ts +16 -0
  107. package/dist/components/primitives/Rive.d.ts.map +1 -0
  108. package/dist/components/primitives/Rive.js +8 -0
  109. package/dist/components/primitives/StripeCheckout.d.ts +52 -0
  110. package/dist/components/primitives/StripeCheckout.d.ts.map +1 -0
  111. package/dist/components/primitives/StripeCheckout.js +5 -0
  112. package/dist/components/primitives/StripeCheckout2.d.ts +30 -0
  113. package/dist/components/primitives/StripeCheckout2.d.ts.map +1 -0
  114. package/dist/components/primitives/StripeCheckout2.js +7 -0
  115. package/dist/proxy/injectApiInterceptor.d.ts +6 -0
  116. package/dist/proxy/injectApiInterceptor.d.ts.map +1 -0
  117. package/dist/proxy/injectApiInterceptor.js +66 -0
  118. package/dist/proxy/injectReload.d.ts +2 -0
  119. package/dist/proxy/injectReload.d.ts.map +1 -0
  120. package/dist/proxy/injectReload.js +14 -0
  121. package/dist/proxy/injectWorkbench.d.ts +4 -0
  122. package/dist/proxy/injectWorkbench.d.ts.map +1 -0
  123. package/dist/proxy/injectWorkbench.js +16 -0
  124. package/dist/proxy/server.d.ts +11 -0
  125. package/dist/proxy/server.d.ts.map +1 -0
  126. package/dist/proxy/server.js +246 -0
  127. package/dist/proxy/sse.d.ts +5 -0
  128. package/dist/proxy/sse.d.ts.map +1 -0
  129. package/dist/proxy/sse.js +17 -0
  130. package/dist/types-builder.d.ts +800 -0
  131. package/dist/types-builder.d.ts.map +1 -0
  132. package/dist/types-builder.js +20 -0
  133. package/dist/workbench/ActionsPanel.d.ts +6 -0
  134. package/dist/workbench/ActionsPanel.d.ts.map +1 -0
  135. package/dist/workbench/ActionsPanel.js +47 -0
  136. package/dist/workbench/AutofillPanel.d.ts +6 -0
  137. package/dist/workbench/AutofillPanel.d.ts.map +1 -0
  138. package/dist/workbench/AutofillPanel.js +543 -0
  139. package/dist/workbench/ComputedFieldsPanel.d.ts +6 -0
  140. package/dist/workbench/ComputedFieldsPanel.d.ts.map +1 -0
  141. package/dist/workbench/ComputedFieldsPanel.js +31 -0
  142. package/dist/workbench/ExperimentsPanel.d.ts +6 -0
  143. package/dist/workbench/ExperimentsPanel.d.ts.map +1 -0
  144. package/dist/workbench/ExperimentsPanel.js +182 -0
  145. package/dist/workbench/FieldEditorPanel.d.ts +9 -0
  146. package/dist/workbench/FieldEditorPanel.d.ts.map +1 -0
  147. package/dist/workbench/FieldEditorPanel.js +650 -0
  148. package/dist/workbench/InspectorPanel.d.ts +6 -0
  149. package/dist/workbench/InspectorPanel.d.ts.map +1 -0
  150. package/dist/workbench/InspectorPanel.js +341 -0
  151. package/dist/workbench/PageNavigator.d.ts +6 -0
  152. package/dist/workbench/PageNavigator.d.ts.map +1 -0
  153. package/dist/workbench/PageNavigator.js +123 -0
  154. package/dist/workbench/SchemaPanel.d.ts +6 -0
  155. package/dist/workbench/SchemaPanel.d.ts.map +1 -0
  156. package/dist/workbench/SchemaPanel.js +222 -0
  157. package/dist/workbench/UserDataPanel.d.ts +6 -0
  158. package/dist/workbench/UserDataPanel.d.ts.map +1 -0
  159. package/dist/workbench/UserDataPanel.js +350 -0
  160. package/dist/workbench/WorkbenchApp.d.ts +6 -0
  161. package/dist/workbench/WorkbenchApp.d.ts.map +1 -0
  162. package/dist/workbench/WorkbenchApp.js +193 -0
  163. package/dist/workbench/cloudflare-worker/README.md +31 -0
  164. package/dist/workbench/cloudflare-worker/public/workbench.css +1614 -0
  165. package/dist/workbench/cloudflare-worker/public/workbench.js +77 -0
  166. package/dist/workbench/cloudflare-worker/worker.js +40 -0
  167. package/dist/workbench/cloudflare-worker/wrangler.toml +10 -0
  168. package/dist/workbench/index.d.ts +9 -0
  169. package/dist/workbench/index.d.ts.map +1 -0
  170. package/dist/workbench/index.js +44 -0
  171. package/dist/workbench/workbench.css +1614 -0
  172. package/dist/workbench/workbench.js +77 -0
  173. package/package.json +79 -0
@@ -0,0 +1,153 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import chokidar from 'chokidar';
4
+ import pc from 'picocolors';
5
+ import prompts from 'prompts';
6
+ import { compileAllPages } from '../compiler/index.js';
7
+ import { startProxyServer } from '../proxy/server.js';
8
+ import { formatError } from '../compiler/errors.js';
9
+ async function discoverEmbeddables() {
10
+ const embeddablesDir = 'embeddables';
11
+ if (!fs.existsSync(embeddablesDir)) {
12
+ return [];
13
+ }
14
+ const entries = fs.readdirSync(embeddablesDir, { withFileTypes: true });
15
+ const embeddables = [];
16
+ for (const entry of entries) {
17
+ if (!entry.isDirectory())
18
+ continue;
19
+ const id = entry.name;
20
+ const configPath = path.join(embeddablesDir, id, 'config.json');
21
+ let title = null;
22
+ if (fs.existsSync(configPath)) {
23
+ try {
24
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
25
+ title = config.title || null;
26
+ }
27
+ catch {
28
+ // Ignore JSON parse errors
29
+ }
30
+ }
31
+ embeddables.push({ id, title });
32
+ }
33
+ // Sort by title (with title) first, then by id
34
+ return embeddables.sort((a, b) => {
35
+ if (a.title && !b.title)
36
+ return -1;
37
+ if (!a.title && b.title)
38
+ return 1;
39
+ const aLabel = a.title || a.id;
40
+ const bLabel = b.title || b.id;
41
+ return aLabel.localeCompare(bLabel);
42
+ });
43
+ }
44
+ async function promptForEmbeddable() {
45
+ const embeddables = await discoverEmbeddables();
46
+ if (embeddables.length === 0) {
47
+ console.error('No embeddables found in the embeddables/ directory.');
48
+ console.error('Run `embeddables pull --id <id>` to pull an embeddable first.');
49
+ return null;
50
+ }
51
+ const choices = embeddables.map((e) => ({
52
+ title: e.title ? `${e.title} (${e.id})` : e.id,
53
+ value: e.id,
54
+ }));
55
+ const response = await prompts({
56
+ type: 'select',
57
+ name: 'id',
58
+ message: 'Select an embeddable to run:',
59
+ choices,
60
+ }, {
61
+ onCancel: () => {
62
+ process.exit(0);
63
+ },
64
+ });
65
+ return response.id || null;
66
+ }
67
+ export async function runDev(opts) {
68
+ let embeddableId = opts.id;
69
+ if (!embeddableId) {
70
+ const selected = await promptForEmbeddable();
71
+ if (!selected) {
72
+ process.exit(1);
73
+ }
74
+ embeddableId = selected;
75
+ }
76
+ const pagesGlob = opts.pages || `embeddables/${embeddableId}/pages/**/*.page.tsx`;
77
+ const outPath = opts.out || path.join('embeddables', embeddableId, '.generated', 'embeddable.json');
78
+ const stylesDir = path.join('embeddables', embeddableId, 'styles');
79
+ const stylesGlob = `embeddables/${embeddableId}/styles/**/*.css`;
80
+ const configPath = path.join('embeddables', embeddableId, 'config.json');
81
+ const globalComponentsGlob = `embeddables/${embeddableId}/global-components/**/*.location.tsx`;
82
+ const computedFieldsGlob = `embeddables/${embeddableId}/computed-fields/**/*.js`;
83
+ const actionsGlob = `embeddables/${embeddableId}/actions/**/*.js`;
84
+ // Initial build
85
+ try {
86
+ await compileAllPages({
87
+ pagesGlob,
88
+ outPath,
89
+ pageKeyFrom: opts.pageKeyFrom,
90
+ stylesDir,
91
+ embeddableId,
92
+ configPath,
93
+ });
94
+ }
95
+ catch (e) {
96
+ console.error(formatError(e));
97
+ process.exit(1);
98
+ }
99
+ // Start proxy
100
+ const port = Number(opts.port);
101
+ const proxy = await startProxyServer({
102
+ port,
103
+ engineOrigin: opts.engine,
104
+ overrideRoute: opts.overrideRoute,
105
+ generatedJsonPath: outPath,
106
+ embeddableId,
107
+ watchWorkbench: true,
108
+ });
109
+ // Watch all source files: pages, styles, config, global components, computed fields, and actions
110
+ const watcher = chokidar.watch([pagesGlob, stylesGlob, configPath, globalComponentsGlob, computedFieldsGlob, actionsGlob], {
111
+ ignoreInitial: true,
112
+ });
113
+ const rebuild = async () => {
114
+ try {
115
+ await compileAllPages({
116
+ pagesGlob,
117
+ outPath,
118
+ pageKeyFrom: opts.pageKeyFrom,
119
+ stylesDir,
120
+ embeddableId,
121
+ configPath,
122
+ });
123
+ proxy.broadcastReload();
124
+ }
125
+ catch (e) {
126
+ // Keep dev server running; compiler errors show in console.
127
+ // (Proxy will still serve the last good JSON.)
128
+ console.error(formatError(e));
129
+ }
130
+ };
131
+ let t;
132
+ watcher.on('all', () => {
133
+ clearTimeout(t);
134
+ t = setTimeout(rebuild, 80);
135
+ });
136
+ console.log(`Watching embeddables/${embeddableId}/ for changes...`);
137
+ console.log('');
138
+ const terminalWidth = process.stdout.columns || 80;
139
+ const separator = '━'.repeat(terminalWidth);
140
+ console.log(`${pc.bold(pc.cyan(separator))}`);
141
+ console.log('');
142
+ if (opts.remote) {
143
+ console.log(`${pc.bold(pc.yellow('Mode:'))} ${pc.yellow('Remote')} (using ${opts.engine})`);
144
+ }
145
+ else {
146
+ console.log(`${pc.bold(pc.blue('Mode:'))} ${pc.blue('Local')} (using ${opts.engine})`);
147
+ }
148
+ console.log('');
149
+ console.log(`${pc.bold(pc.green('Preview URL:'))} ${pc.underline(pc.cyan(`http://localhost:${port}?id=${embeddableId}&version=latest`))}`);
150
+ console.log('');
151
+ console.log(`${pc.bold(pc.cyan(separator))}`);
152
+ console.log('');
153
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runLogin(): Promise<void>;
2
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAUA,wBAAsB,QAAQ,kBAyH7B"}
@@ -0,0 +1,112 @@
1
+ import prompts from 'prompts';
2
+ import pc from 'picocolors';
3
+ import { getSupabaseClient, writeAuthConfig, readAuthConfig, SUPABASE_URL, SUPABASE_ANON_KEY, } from '../auth/index.js';
4
+ export async function runLogin() {
5
+ try {
6
+ const supabase = getSupabaseClient();
7
+ // Check if already logged in
8
+ const existingConfig = readAuthConfig();
9
+ if (existingConfig?.access_token) {
10
+ const { overwrite } = await prompts({
11
+ type: 'confirm',
12
+ name: 'overwrite',
13
+ message: 'You are already logged in. Do you want to log in again?',
14
+ initial: false,
15
+ });
16
+ if (!overwrite) {
17
+ console.log(pc.green('Login cancelled.'));
18
+ return;
19
+ }
20
+ }
21
+ // Prompt for email
22
+ const { email } = await prompts({
23
+ type: 'text',
24
+ name: 'email',
25
+ message: 'Enter your email address:',
26
+ validate: (value) => {
27
+ if (!value)
28
+ return 'Email is required';
29
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
30
+ return 'Please enter a valid email address';
31
+ }
32
+ return true;
33
+ },
34
+ });
35
+ if (!email) {
36
+ console.log(pc.red('Login cancelled.'));
37
+ return;
38
+ }
39
+ console.log('');
40
+ console.log(pc.cyan('Sending verification code to your email...'));
41
+ // Send OTP code
42
+ const { error: sendError } = await supabase.auth.signInWithOtp({
43
+ email,
44
+ });
45
+ if (sendError) {
46
+ console.error(pc.red(`Error sending verification code: ${sendError.message}`));
47
+ process.exit(1);
48
+ }
49
+ console.log('');
50
+ console.log(pc.green('✓ Verification code sent!'));
51
+ console.log(pc.dim('Please check your email for the code.'));
52
+ console.log('');
53
+ // Prompt for OTP code
54
+ const { code } = await prompts({
55
+ type: 'text',
56
+ name: 'code',
57
+ message: 'Enter the verification code from your email:',
58
+ validate: (value) => {
59
+ if (!value)
60
+ return 'Verification code is required';
61
+ if (!/^\d{6}$/.test(value.trim())) {
62
+ return 'Please enter a valid 6-digit code';
63
+ }
64
+ return true;
65
+ },
66
+ });
67
+ if (!code) {
68
+ console.log(pc.red('Login cancelled.'));
69
+ return;
70
+ }
71
+ console.log('');
72
+ console.log(pc.cyan('Verifying code...'));
73
+ // Verify OTP code
74
+ const { data, error: verifyError } = await supabase.auth.verifyOtp({
75
+ email,
76
+ token: code.trim(),
77
+ type: 'email',
78
+ });
79
+ if (verifyError) {
80
+ console.error(pc.red(`Error verifying code: ${verifyError.message}`));
81
+ process.exit(1);
82
+ }
83
+ if (!data.session) {
84
+ console.error(pc.red('No session returned from verification'));
85
+ process.exit(1);
86
+ }
87
+ // Store auth config
88
+ const config = {
89
+ access_token: data.session.access_token,
90
+ refresh_token: data.session.refresh_token,
91
+ expires_at: data.session.expires_at || Math.floor(Date.now() / 1000) + 3600, // Default 1 hour if not provided
92
+ supabase_url: SUPABASE_URL,
93
+ supabase_anon_key: SUPABASE_ANON_KEY,
94
+ };
95
+ writeAuthConfig(config);
96
+ console.log('');
97
+ console.log(pc.green('✓ Successfully logged in!'));
98
+ console.log('');
99
+ }
100
+ catch (error) {
101
+ if (error.name === 'ExitPrompt') {
102
+ // User cancelled prompt (Ctrl+C)
103
+ console.log('');
104
+ console.log(pc.red('Login cancelled.'));
105
+ process.exit(0);
106
+ }
107
+ else {
108
+ console.error(pc.red(`Error during login: ${error.message}`));
109
+ process.exit(1);
110
+ }
111
+ }
112
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runLogout(): Promise<void>;
2
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,kBAe9B"}
@@ -0,0 +1,18 @@
1
+ import pc from 'picocolors';
2
+ import { deleteAuthConfig, isLoggedIn } from '../auth/index.js';
3
+ export async function runLogout() {
4
+ try {
5
+ if (!isLoggedIn()) {
6
+ console.log(pc.yellow('You are not currently logged in.'));
7
+ return;
8
+ }
9
+ deleteAuthConfig();
10
+ console.log('');
11
+ console.log(pc.green('✓ Successfully logged out!'));
12
+ console.log('');
13
+ }
14
+ catch (error) {
15
+ console.error(pc.red(`Error during logout: ${error.message}`));
16
+ process.exit(1);
17
+ }
18
+ }
@@ -0,0 +1,7 @@
1
+ export declare function runPull(opts: {
2
+ id: string;
3
+ out?: string;
4
+ branch?: string;
5
+ fix?: boolean;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAOA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,iBA0G/F"}
@@ -0,0 +1,97 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import pc from 'picocolors';
4
+ import { reverseCompile } from '../compiler/reverse.js';
5
+ import { getAccessToken } from '../auth/index.js';
6
+ export async function runPull(opts) {
7
+ const embeddableId = opts.id;
8
+ let url = `https://engine.embeddables.com/${embeddableId}?version=latest`;
9
+ if (opts.branch) {
10
+ url += `&embeddable_branch=${opts.branch}`;
11
+ }
12
+ const outPath = opts.out || path.join('embeddables', embeddableId, '.generated', 'embeddable.json');
13
+ console.log(`Fetching embeddable from ${url}...`);
14
+ try {
15
+ // Add authentication header if available
16
+ const accessToken = getAccessToken();
17
+ const headers = {};
18
+ if (accessToken) {
19
+ headers['Authorization'] = `Bearer ${accessToken}`;
20
+ }
21
+ const response = await fetch(url, {
22
+ headers,
23
+ });
24
+ if (!response.ok) {
25
+ throw new Error(`Failed to fetch embeddable: ${response.status} ${response.statusText}`);
26
+ }
27
+ const data = await response.json();
28
+ const flow = data.flow;
29
+ if (!flow) {
30
+ throw new Error("Response does not contain a 'flow' property");
31
+ }
32
+ // Save to embeddables/<id>/.generated/embeddable.json
33
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
34
+ const flowJson = JSON.stringify(flow, null, 2);
35
+ fs.writeFileSync(outPath, flowJson, 'utf8');
36
+ console.log(pc.cyan(`✓ Saved embeddable JSON to ${outPath}`));
37
+ // Also save version-specific file (e.g. embeddable-v135.json) when version is present in response
38
+ const version = data.version ?? data.embeddable_version ?? flow.version;
39
+ if (version != null) {
40
+ const versionStr = typeof version === 'string' ? version : String(version);
41
+ const versionLabel = versionStr.startsWith('v') ? versionStr : `v${versionStr}`;
42
+ const versionedBasename = `embeddable-${versionLabel}.json`;
43
+ const versionedPath = path.join(path.dirname(outPath), versionedBasename);
44
+ fs.writeFileSync(versionedPath, flowJson, 'utf8');
45
+ console.log(pc.cyan(`✓ Saved embeddable JSON to ${versionedPath}`));
46
+ }
47
+ // Clear existing pages, styles, computed-fields, actions, and global-components before generating new ones
48
+ const pagesDir = path.join('embeddables', embeddableId, 'pages');
49
+ const stylesDir = path.join('embeddables', embeddableId, 'styles');
50
+ const computedFieldsDir = path.join('embeddables', embeddableId, 'computed-fields');
51
+ const actionsDir = path.join('embeddables', embeddableId, 'actions');
52
+ const globalComponentsDir = path.join('embeddables', embeddableId, 'global-components');
53
+ if (fs.existsSync(pagesDir)) {
54
+ const existingPages = fs.readdirSync(pagesDir).filter((f) => f.endsWith('.page.tsx'));
55
+ for (const page of existingPages) {
56
+ fs.unlinkSync(path.join(pagesDir, page));
57
+ }
58
+ console.log(`${pc.gray(`Cleared ${existingPages.length} existing page(s)`)}`);
59
+ }
60
+ if (fs.existsSync(stylesDir)) {
61
+ const existingStyles = fs.readdirSync(stylesDir).filter((f) => f.endsWith('.css'));
62
+ for (const style of existingStyles) {
63
+ fs.unlinkSync(path.join(stylesDir, style));
64
+ }
65
+ console.log(`${pc.gray(`Cleared ${existingStyles.length} existing style file(s)`)}`);
66
+ }
67
+ if (fs.existsSync(computedFieldsDir)) {
68
+ const existingFields = fs.readdirSync(computedFieldsDir).filter((f) => f.endsWith('.js'));
69
+ for (const field of existingFields) {
70
+ fs.unlinkSync(path.join(computedFieldsDir, field));
71
+ }
72
+ console.log(`${pc.gray(`Cleared ${existingFields.length} existing computed field(s)`)}`);
73
+ }
74
+ if (fs.existsSync(actionsDir)) {
75
+ const existingActions = fs.readdirSync(actionsDir).filter((f) => f.endsWith('.js'));
76
+ for (const action of existingActions) {
77
+ fs.unlinkSync(path.join(actionsDir, action));
78
+ }
79
+ console.log(`${pc.gray(`Cleared ${existingActions.length} existing action(s)`)}`);
80
+ }
81
+ if (fs.existsSync(globalComponentsDir)) {
82
+ const existingGlobalComponents = fs
83
+ .readdirSync(globalComponentsDir)
84
+ .filter((f) => f.endsWith('.location.tsx'));
85
+ for (const component of existingGlobalComponents) {
86
+ fs.unlinkSync(path.join(globalComponentsDir, component));
87
+ }
88
+ console.log(`${pc.gray(`Cleared ${existingGlobalComponents.length} existing global component(s)`)}`);
89
+ }
90
+ // Run reverse compiler
91
+ await reverseCompile(flow, embeddableId, { fix: opts.fix });
92
+ }
93
+ catch (error) {
94
+ console.error('Error pulling embeddable:', error);
95
+ process.exit(1);
96
+ }
97
+ }
@@ -0,0 +1,20 @@
1
+ export declare class CompileError extends Error {
2
+ info?: {
3
+ file?: string;
4
+ line?: number;
5
+ column?: number;
6
+ pageKey?: string;
7
+ componentId?: string;
8
+ componentKey?: string;
9
+ } | undefined;
10
+ constructor(message: string, info?: {
11
+ file?: string;
12
+ line?: number;
13
+ column?: number;
14
+ pageKey?: string;
15
+ componentId?: string;
16
+ componentKey?: string;
17
+ } | undefined);
18
+ }
19
+ export declare function formatError(e: unknown): string;
20
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/compiler/errors.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAa,SAAQ,KAAK;IAG5B,IAAI,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB;gBARD,OAAO,EAAE,MAAM,EACR,IAAI,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,YAAA;CAIJ;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,UAkCrC"}
@@ -0,0 +1,35 @@
1
+ import pc from 'picocolors';
2
+ export class CompileError extends Error {
3
+ info;
4
+ constructor(message, info) {
5
+ super(message);
6
+ this.info = info;
7
+ }
8
+ }
9
+ export function formatError(e) {
10
+ if (e instanceof CompileError) {
11
+ const parts = [];
12
+ // File location
13
+ if (e.info?.file && e.info?.line != null) {
14
+ parts.push(`${pc.cyan(e.info.file)}:${pc.yellow(String(e.info.line))}:${pc.yellow(String(e.info.column ?? 0))}`);
15
+ }
16
+ // Page context
17
+ if (e.info?.pageKey) {
18
+ parts.push(`page: ${pc.magenta(e.info.pageKey)}`);
19
+ }
20
+ // Component context
21
+ if (e.info?.componentId || e.info?.componentKey) {
22
+ const componentParts = [];
23
+ if (e.info.componentId) {
24
+ componentParts.push(`id=${pc.cyan(e.info.componentId)}`);
25
+ }
26
+ if (e.info.componentKey) {
27
+ componentParts.push(`key=${pc.cyan(e.info.componentKey)}`);
28
+ }
29
+ parts.push(`component (${componentParts.join(', ')})`);
30
+ }
31
+ const where = parts.length > 0 ? parts.join(' | ') : '';
32
+ return `${pc.red('Error')} ${where}\n${e.message}`;
33
+ }
34
+ return String(e);
35
+ }
@@ -0,0 +1,3 @@
1
+ import type * as t from '@babel/types';
2
+ export declare function evalStatic(node: t.Node, constEnv: Map<string, any>, file: string): any;
3
+ //# sourceMappingURL=evalStatic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evalStatic.d.ts","sourceRoot":"","sources":["../../src/compiler/evalStatic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,CAAC,MAAM,cAAc,CAAA;AAEtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA+DtF"}
@@ -0,0 +1,57 @@
1
+ import { CompileError } from './errors.js';
2
+ export function evalStatic(node, constEnv, file) {
3
+ switch (node.type) {
4
+ case 'StringLiteral':
5
+ return node.value;
6
+ case 'TemplateLiteral': {
7
+ // Support template literals with {{variable}} syntax (templating system)
8
+ // These are written as {`{{variable}}`} in JSX and should be converted to plain strings
9
+ // Note: {{variable}} is just a string pattern, not a JavaScript expression
10
+ // Template literals with actual expressions (${...}) are not supported
11
+ if (node.expressions.length > 0) {
12
+ throw new CompileError('Template literals with expressions are not supported. Use plain strings only.', loc(file, node));
13
+ }
14
+ // For simple template literals (no expressions), concatenate all quasis
15
+ // Use cooked value if available, otherwise fall back to raw
16
+ // This handles {`{{first_name}}'s plan`} → "{{first_name}}'s plan"
17
+ return node.quasis.map((q) => q.value.cooked ?? q.value.raw).join('');
18
+ }
19
+ case 'NumericLiteral':
20
+ return node.value;
21
+ case 'BooleanLiteral':
22
+ return node.value;
23
+ case 'NullLiteral':
24
+ return null;
25
+ case 'ArrayExpression':
26
+ return node.elements.map((el) => {
27
+ if (!el)
28
+ return null;
29
+ return evalStatic(el, constEnv, file);
30
+ });
31
+ case 'ObjectExpression': {
32
+ const out = {};
33
+ for (const prop of node.properties) {
34
+ if (prop.type !== 'ObjectProperty') {
35
+ throw new CompileError('Only plain object literals are supported.', loc(file, node));
36
+ }
37
+ if (prop.key.type !== 'Identifier' && prop.key.type !== 'StringLiteral') {
38
+ throw new CompileError('Only identifier/string keys supported in objects.', loc(file, node));
39
+ }
40
+ const k = prop.key.type === 'Identifier' ? prop.key.name : prop.key.value;
41
+ out[k] = evalStatic(prop.value, constEnv, file);
42
+ }
43
+ return out;
44
+ }
45
+ case 'Identifier': {
46
+ if (!constEnv.has(node.name)) {
47
+ throw new CompileError(`Unknown identifier "${node.name}" (must be a static const).`, loc(file, node));
48
+ }
49
+ return constEnv.get(node.name);
50
+ }
51
+ default:
52
+ throw new CompileError(`Unsupported expression "${node.type}". Use literals/arrays/objects/static const identifiers only.`, loc(file, node));
53
+ }
54
+ }
55
+ function loc(file, node) {
56
+ return { file, line: node.loc?.start?.line, column: node.loc?.start?.column };
57
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared helpers for deduplicating component/button IDs in forward and reverse compilers.
3
+ */
4
+ /**
5
+ * Generates a new unique ID based on component/button type, e.g. plaintext_abcdefghij,
6
+ * button_abcdef, option_abcde. Used when deduplicating IDs in forward and reverse compilers.
7
+ */
8
+ export declare function generateRandomIdByType(componentType: string, isOptionButton: boolean, existingIds: Set<string>, alsoExclude: Iterable<string>): string;
9
+ //# sourceMappingURL=duplicateIds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicateIds.d.ts","sourceRoot":"","sources":["../../../src/compiler/helpers/duplicateIds.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwDH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,OAAO,EACvB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC5B,MAAM,CAaR"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shared helpers for deduplicating component/button IDs in forward and reverse compilers.
3
+ */
4
+ const ID_RANDOM_CHARS = 'abcdefghijklmnopqrstuvwxyz';
5
+ /**
6
+ * Returns { prefix, suffixLen } for type-based ID generation.
7
+ * OptionSelector buttons use prefix "option" and length 5; components use a switch over type.
8
+ */
9
+ function getIdPrefixAndLength(componentType, isOptionButton) {
10
+ if (isOptionButton) {
11
+ return { prefix: 'option', suffixLen: 12 };
12
+ }
13
+ switch (componentType) {
14
+ case 'PlainText':
15
+ return { prefix: 'text', suffixLen: 12 };
16
+ case 'CustomButton':
17
+ return { prefix: 'button', suffixLen: 12 };
18
+ case 'Container':
19
+ return { prefix: 'container', suffixLen: 12 };
20
+ case 'RichTextMarkdown':
21
+ return { prefix: 'richtext', suffixLen: 12 };
22
+ case 'CustomHTML':
23
+ return { prefix: 'html', suffixLen: 12 };
24
+ case 'InputBox':
25
+ return { prefix: 'input', suffixLen: 12 };
26
+ case 'OptionSelector':
27
+ return { prefix: 'optionselector', suffixLen: 12 };
28
+ case 'StripeCheckout2':
29
+ return { prefix: 'stripe', suffixLen: 12 };
30
+ case 'PaypalCheckout':
31
+ return { prefix: 'paypal', suffixLen: 12 };
32
+ case 'MediaImage':
33
+ return { prefix: 'image', suffixLen: 12 };
34
+ case 'MediaEmbed':
35
+ return { prefix: 'embed', suffixLen: 12 };
36
+ case 'Lottie':
37
+ return { prefix: 'lottie', suffixLen: 12 };
38
+ case 'Rive':
39
+ return { prefix: 'rive', suffixLen: 12 };
40
+ case 'ProgressBar':
41
+ return { prefix: 'progressbar', suffixLen: 12 };
42
+ case 'FileUpload':
43
+ return { prefix: 'fileupload', suffixLen: 12 };
44
+ case 'BookMeeting':
45
+ return { prefix: 'bookmeeting', suffixLen: 12 };
46
+ case 'Chart':
47
+ return { prefix: 'chart', suffixLen: 12 };
48
+ default:
49
+ return { prefix: componentType.toLowerCase(), suffixLen: 12 };
50
+ }
51
+ }
52
+ /**
53
+ * Generates a new unique ID based on component/button type, e.g. plaintext_abcdefghij,
54
+ * button_abcdef, option_abcde. Used when deduplicating IDs in forward and reverse compilers.
55
+ */
56
+ export function generateRandomIdByType(componentType, isOptionButton, existingIds, alsoExclude) {
57
+ const { prefix, suffixLen } = getIdPrefixAndLength(componentType, isOptionButton);
58
+ const excluded = new Set(existingIds);
59
+ for (const id of alsoExclude)
60
+ excluded.add(id);
61
+ for (;;) {
62
+ let suffix = '';
63
+ for (let i = 0; i < suffixLen; i++) {
64
+ suffix += ID_RANDOM_CHARS[Math.floor(Math.random() * ID_RANDOM_CHARS.length)];
65
+ }
66
+ const candidate = `${prefix}_${suffix}`;
67
+ if (!excluded.has(candidate))
68
+ return candidate;
69
+ excluded.add(candidate); // avoid retrying same value
70
+ }
71
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Returns a copy of newVal with object key order (recursively) matching oldVal
3
+ * where possible. Keeps existing keys in old order; appends new keys at the end.
4
+ * Arrays are not reordered; we recurse into elements by index for nested objects.
5
+ * Used so embeddable.json diffs show only actual changes, not reordering noise.
6
+ */
7
+ export declare function reorderObjectKeysToMatch(oldVal: unknown, newVal: unknown): unknown;
8
+ export declare function compileAllPages(opts: {
9
+ pagesGlob: string;
10
+ outPath: string;
11
+ pageKeyFrom: 'filename' | 'export';
12
+ stylesDir?: string;
13
+ embeddableId?: string;
14
+ configPath?: string;
15
+ }): Promise<void>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,iBA8WA"}