@embeddables/cli 0.7.13 → 0.7.14

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 (236) hide show
  1. package/.prompts/custom/build-funnel.md +1 -1
  2. package/.prompts/embeddables-cli.md +9 -2
  3. package/package.json +1 -1
  4. package/dist/auth/index.d.ts +0 -43
  5. package/dist/auth/index.d.ts.map +0 -1
  6. package/dist/auth/index.js +0 -102
  7. package/dist/cli.d.ts +0 -2
  8. package/dist/cli.d.ts.map +0 -1
  9. package/dist/cli.js +0 -174
  10. package/dist/commands/branch.d.ts +0 -4
  11. package/dist/commands/branch.d.ts.map +0 -1
  12. package/dist/commands/branch.js +0 -68
  13. package/dist/commands/build-workbench.d.ts +0 -5
  14. package/dist/commands/build-workbench.d.ts.map +0 -1
  15. package/dist/commands/build-workbench.js +0 -128
  16. package/dist/commands/build.d.ts +0 -8
  17. package/dist/commands/build.d.ts.map +0 -1
  18. package/dist/commands/build.js +0 -55
  19. package/dist/commands/dev.d.ts +0 -12
  20. package/dist/commands/dev.d.ts.map +0 -1
  21. package/dist/commands/dev.js +0 -221
  22. package/dist/commands/experiments-connect.d.ts +0 -6
  23. package/dist/commands/experiments-connect.d.ts.map +0 -1
  24. package/dist/commands/experiments-connect.js +0 -140
  25. package/dist/commands/init.d.ts +0 -5
  26. package/dist/commands/init.d.ts.map +0 -1
  27. package/dist/commands/init.js +0 -327
  28. package/dist/commands/login.d.ts +0 -2
  29. package/dist/commands/login.d.ts.map +0 -1
  30. package/dist/commands/login.js +0 -122
  31. package/dist/commands/logout.d.ts +0 -2
  32. package/dist/commands/logout.d.ts.map +0 -1
  33. package/dist/commands/logout.js +0 -22
  34. package/dist/commands/pull.d.ts +0 -14
  35. package/dist/commands/pull.d.ts.map +0 -1
  36. package/dist/commands/pull.js +0 -383
  37. package/dist/commands/save.d.ts +0 -30
  38. package/dist/commands/save.d.ts.map +0 -1
  39. package/dist/commands/save.js +0 -591
  40. package/dist/commands/upgrade.d.ts +0 -2
  41. package/dist/commands/upgrade.d.ts.map +0 -1
  42. package/dist/commands/upgrade.js +0 -51
  43. package/dist/compiler/errors.d.ts +0 -20
  44. package/dist/compiler/errors.d.ts.map +0 -1
  45. package/dist/compiler/errors.js +0 -35
  46. package/dist/compiler/evalStatic.d.ts +0 -3
  47. package/dist/compiler/evalStatic.d.ts.map +0 -1
  48. package/dist/compiler/evalStatic.js +0 -57
  49. package/dist/compiler/flatten.js +0 -1
  50. package/dist/compiler/helpers/duplicateIds.d.ts +0 -9
  51. package/dist/compiler/helpers/duplicateIds.d.ts.map +0 -1
  52. package/dist/compiler/helpers/duplicateIds.js +0 -71
  53. package/dist/compiler/helpers/numericLeadingKeys.d.ts +0 -8
  54. package/dist/compiler/helpers/numericLeadingKeys.d.ts.map +0 -1
  55. package/dist/compiler/helpers/numericLeadingKeys.js +0 -17
  56. package/dist/compiler/index.d.ts +0 -18
  57. package/dist/compiler/index.d.ts.map +0 -1
  58. package/dist/compiler/index.js +0 -1245
  59. package/dist/compiler/parsePage.d.ts +0 -15
  60. package/dist/compiler/parsePage.d.ts.map +0 -1
  61. package/dist/compiler/parsePage.js +0 -631
  62. package/dist/compiler/registry.d.ts +0 -4
  63. package/dist/compiler/registry.d.ts.map +0 -1
  64. package/dist/compiler/registry.js +0 -44
  65. package/dist/compiler/reverse.d.ts +0 -23
  66. package/dist/compiler/reverse.d.ts.map +0 -1
  67. package/dist/compiler/reverse.js +0 -1875
  68. package/dist/compiler/types.d.ts +0 -21
  69. package/dist/compiler/types.d.ts.map +0 -1
  70. package/dist/compiler/types.js +0 -1
  71. package/dist/components/index.d.ts +0 -21
  72. package/dist/components/index.d.ts.map +0 -1
  73. package/dist/components/index.js +0 -21
  74. package/dist/components/primitives/BaseComponent.d.ts +0 -32
  75. package/dist/components/primitives/BaseComponent.d.ts.map +0 -1
  76. package/dist/components/primitives/BaseComponent.js +0 -26
  77. package/dist/components/primitives/BookMeeting.d.ts +0 -18
  78. package/dist/components/primitives/BookMeeting.d.ts.map +0 -1
  79. package/dist/components/primitives/BookMeeting.js +0 -5
  80. package/dist/components/primitives/Chart.d.ts +0 -41
  81. package/dist/components/primitives/Chart.d.ts.map +0 -1
  82. package/dist/components/primitives/Chart.js +0 -5
  83. package/dist/components/primitives/Container.d.ts +0 -8
  84. package/dist/components/primitives/Container.d.ts.map +0 -1
  85. package/dist/components/primitives/Container.js +0 -5
  86. package/dist/components/primitives/CustomButton.d.ts +0 -37
  87. package/dist/components/primitives/CustomButton.d.ts.map +0 -1
  88. package/dist/components/primitives/CustomButton.js +0 -10
  89. package/dist/components/primitives/CustomHTML.d.ts +0 -8
  90. package/dist/components/primitives/CustomHTML.d.ts.map +0 -1
  91. package/dist/components/primitives/CustomHTML.js +0 -5
  92. package/dist/components/primitives/FileUpload.d.ts +0 -18
  93. package/dist/components/primitives/FileUpload.d.ts.map +0 -1
  94. package/dist/components/primitives/FileUpload.js +0 -16
  95. package/dist/components/primitives/InputBox.d.ts +0 -34
  96. package/dist/components/primitives/InputBox.d.ts.map +0 -1
  97. package/dist/components/primitives/InputBox.js +0 -25
  98. package/dist/components/primitives/Lottie.d.ts +0 -11
  99. package/dist/components/primitives/Lottie.d.ts.map +0 -1
  100. package/dist/components/primitives/Lottie.js +0 -5
  101. package/dist/components/primitives/MediaEmbed.d.ts +0 -13
  102. package/dist/components/primitives/MediaEmbed.d.ts.map +0 -1
  103. package/dist/components/primitives/MediaEmbed.js +0 -6
  104. package/dist/components/primitives/MediaImage.d.ts +0 -8
  105. package/dist/components/primitives/MediaImage.d.ts.map +0 -1
  106. package/dist/components/primitives/MediaImage.js +0 -5
  107. package/dist/components/primitives/OptionSelector.d.ts +0 -35
  108. package/dist/components/primitives/OptionSelector.d.ts.map +0 -1
  109. package/dist/components/primitives/OptionSelector.js +0 -8
  110. package/dist/components/primitives/PaypalCheckout.d.ts +0 -25
  111. package/dist/components/primitives/PaypalCheckout.d.ts.map +0 -1
  112. package/dist/components/primitives/PaypalCheckout.js +0 -5
  113. package/dist/components/primitives/PlainText.d.ts +0 -6
  114. package/dist/components/primitives/PlainText.d.ts.map +0 -1
  115. package/dist/components/primitives/PlainText.js +0 -5
  116. package/dist/components/primitives/ProgressBar.d.ts +0 -15
  117. package/dist/components/primitives/ProgressBar.d.ts.map +0 -1
  118. package/dist/components/primitives/ProgressBar.js +0 -5
  119. package/dist/components/primitives/RichText.d.ts +0 -6
  120. package/dist/components/primitives/RichText.d.ts.map +0 -1
  121. package/dist/components/primitives/RichText.js +0 -5
  122. package/dist/components/primitives/RichTextMarkdown.d.ts +0 -6
  123. package/dist/components/primitives/RichTextMarkdown.d.ts.map +0 -1
  124. package/dist/components/primitives/RichTextMarkdown.js +0 -5
  125. package/dist/components/primitives/Rive.d.ts +0 -16
  126. package/dist/components/primitives/Rive.d.ts.map +0 -1
  127. package/dist/components/primitives/Rive.js +0 -8
  128. package/dist/components/primitives/StripeCheckout.d.ts +0 -52
  129. package/dist/components/primitives/StripeCheckout.d.ts.map +0 -1
  130. package/dist/components/primitives/StripeCheckout.js +0 -5
  131. package/dist/components/primitives/StripeCheckout2.d.ts +0 -30
  132. package/dist/components/primitives/StripeCheckout2.d.ts.map +0 -1
  133. package/dist/components/primitives/StripeCheckout2.js +0 -7
  134. package/dist/config/index.d.ts +0 -23
  135. package/dist/config/index.d.ts.map +0 -1
  136. package/dist/config/index.js +0 -42
  137. package/dist/constants.d.ts +0 -9
  138. package/dist/constants.d.ts.map +0 -1
  139. package/dist/constants.js +0 -9
  140. package/dist/helpers/TEMP helpers file.d.ts +0 -1
  141. package/dist/helpers/TEMP helpers file.d.ts.map +0 -1
  142. package/dist/helpers/TEMP helpers file.js +0 -1
  143. package/dist/helpers/dates.d.ts +0 -5
  144. package/dist/helpers/dates.d.ts.map +0 -1
  145. package/dist/helpers/dates.js +0 -7
  146. package/dist/helpers/json.d.ts +0 -47
  147. package/dist/helpers/json.d.ts.map +0 -1
  148. package/dist/helpers/json.js +0 -622
  149. package/dist/helpers/utils.d.ts +0 -13
  150. package/dist/helpers/utils.d.ts.map +0 -1
  151. package/dist/helpers/utils.js +0 -28
  152. package/dist/logger.d.ts +0 -11
  153. package/dist/logger.d.ts.map +0 -1
  154. package/dist/logger.js +0 -21
  155. package/dist/prompts/branches.d.ts +0 -20
  156. package/dist/prompts/branches.d.ts.map +0 -1
  157. package/dist/prompts/branches.js +0 -90
  158. package/dist/prompts/embeddables.d.ts +0 -43
  159. package/dist/prompts/embeddables.d.ts.map +0 -1
  160. package/dist/prompts/embeddables.js +0 -198
  161. package/dist/prompts/experiments.d.ts +0 -28
  162. package/dist/prompts/experiments.d.ts.map +0 -1
  163. package/dist/prompts/experiments.js +0 -87
  164. package/dist/prompts/index.d.ts +0 -11
  165. package/dist/prompts/index.d.ts.map +0 -1
  166. package/dist/prompts/index.js +0 -6
  167. package/dist/prompts/projects.d.ts +0 -22
  168. package/dist/prompts/projects.d.ts.map +0 -1
  169. package/dist/prompts/projects.js +0 -86
  170. package/dist/prompts/versions.d.ts +0 -18
  171. package/dist/prompts/versions.d.ts.map +0 -1
  172. package/dist/prompts/versions.js +0 -99
  173. package/dist/proxy/injectApiInterceptor.d.ts +0 -6
  174. package/dist/proxy/injectApiInterceptor.d.ts.map +0 -1
  175. package/dist/proxy/injectApiInterceptor.js +0 -66
  176. package/dist/proxy/injectReload.d.ts +0 -2
  177. package/dist/proxy/injectReload.d.ts.map +0 -1
  178. package/dist/proxy/injectReload.js +0 -14
  179. package/dist/proxy/injectWorkbench.d.ts +0 -5
  180. package/dist/proxy/injectWorkbench.d.ts.map +0 -1
  181. package/dist/proxy/injectWorkbench.js +0 -22
  182. package/dist/proxy/server.d.ts +0 -11
  183. package/dist/proxy/server.d.ts.map +0 -1
  184. package/dist/proxy/server.js +0 -316
  185. package/dist/proxy/sse.d.ts +0 -5
  186. package/dist/proxy/sse.d.ts.map +0 -1
  187. package/dist/proxy/sse.js +0 -17
  188. package/dist/sentry-context.d.ts +0 -48
  189. package/dist/sentry-context.d.ts.map +0 -1
  190. package/dist/sentry-context.js +0 -156
  191. package/dist/stdout.d.ts +0 -17
  192. package/dist/stdout.d.ts.map +0 -1
  193. package/dist/stdout.js +0 -23
  194. package/dist/types-builder.d.ts +0 -800
  195. package/dist/types-builder.d.ts.map +0 -1
  196. package/dist/types-builder.js +0 -20
  197. package/dist/workbench/ActionsPanel.d.ts +0 -6
  198. package/dist/workbench/ActionsPanel.d.ts.map +0 -1
  199. package/dist/workbench/ActionsPanel.js +0 -47
  200. package/dist/workbench/AutofillPanel.d.ts +0 -6
  201. package/dist/workbench/AutofillPanel.d.ts.map +0 -1
  202. package/dist/workbench/AutofillPanel.js +0 -543
  203. package/dist/workbench/ComputedFieldsPanel.d.ts +0 -6
  204. package/dist/workbench/ComputedFieldsPanel.d.ts.map +0 -1
  205. package/dist/workbench/ComputedFieldsPanel.js +0 -31
  206. package/dist/workbench/ExperimentsPanel.d.ts +0 -6
  207. package/dist/workbench/ExperimentsPanel.d.ts.map +0 -1
  208. package/dist/workbench/ExperimentsPanel.js +0 -182
  209. package/dist/workbench/FieldEditorPanel.d.ts +0 -9
  210. package/dist/workbench/FieldEditorPanel.d.ts.map +0 -1
  211. package/dist/workbench/FieldEditorPanel.js +0 -650
  212. package/dist/workbench/InspectorPanel.d.ts +0 -6
  213. package/dist/workbench/InspectorPanel.d.ts.map +0 -1
  214. package/dist/workbench/InspectorPanel.js +0 -341
  215. package/dist/workbench/PageNavigator.d.ts +0 -6
  216. package/dist/workbench/PageNavigator.d.ts.map +0 -1
  217. package/dist/workbench/PageNavigator.js +0 -123
  218. package/dist/workbench/SchemaPanel.d.ts +0 -6
  219. package/dist/workbench/SchemaPanel.d.ts.map +0 -1
  220. package/dist/workbench/SchemaPanel.js +0 -222
  221. package/dist/workbench/UserDataPanel.d.ts +0 -6
  222. package/dist/workbench/UserDataPanel.d.ts.map +0 -1
  223. package/dist/workbench/UserDataPanel.js +0 -350
  224. package/dist/workbench/WorkbenchApp.d.ts +0 -7
  225. package/dist/workbench/WorkbenchApp.d.ts.map +0 -1
  226. package/dist/workbench/WorkbenchApp.js +0 -193
  227. package/dist/workbench/cloudflare-worker/README.md +0 -31
  228. package/dist/workbench/cloudflare-worker/public/workbench.css +0 -1614
  229. package/dist/workbench/cloudflare-worker/public/workbench.js +0 -77
  230. package/dist/workbench/cloudflare-worker/worker.js +0 -40
  231. package/dist/workbench/cloudflare-worker/wrangler.toml +0 -10
  232. package/dist/workbench/index.d.ts +0 -10
  233. package/dist/workbench/index.d.ts.map +0 -1
  234. package/dist/workbench/index.js +0 -44
  235. package/dist/workbench/workbench.css +0 -1614
  236. package/dist/workbench/workbench.js +0 -77
@@ -1,591 +0,0 @@
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, getAuthenticatedSupabaseClient, 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
- import { captureException, createLogger, exit } from '../logger.js';
12
- import { getSentryContextFromEmbeddableConfig, getSentryContextFromProjectConfig, setSentryContext, } from '../sentry-context.js';
13
- import * as stdout from '../stdout.js';
14
- import { translateJsonDiffToEditCommands } from '../helpers/json.js';
15
- import { generateId, inferEmbeddableFromCwd } from '../helpers/utils.js';
16
- /** Error with optional gray detail line (hint/next step) for the user. */
17
- class SaveError extends Error {
18
- detail;
19
- constructor(message, detail) {
20
- super(message);
21
- this.detail = detail;
22
- this.name = 'SaveError';
23
- }
24
- }
25
- /**
26
- * Parse response body as JSON. Returns null if body is not valid JSON (e.g. HTML error page).
27
- */
28
- async function safeParseJson(response) {
29
- try {
30
- const data = await response.json();
31
- return data;
32
- }
33
- catch {
34
- return null;
35
- }
36
- }
37
- function isSaveErrorResponse(value) {
38
- return (typeof value === 'object' &&
39
- value !== null &&
40
- 'error' in value &&
41
- typeof value.error === 'string');
42
- }
43
- function isSaveConflictResponse(value) {
44
- return (typeof value === 'object' &&
45
- value !== null &&
46
- 'latestVersionNumber' in value &&
47
- 'yourVersionNumber' in value &&
48
- typeof value.latestVersionNumber === 'number' &&
49
- typeof value.yourVersionNumber === 'number');
50
- }
51
- function isSaveResponse(value) {
52
- return (typeof value === 'object' &&
53
- value !== null &&
54
- value.success === true &&
55
- typeof value.data === 'object' &&
56
- typeof value.data?.newVersionNumber === 'number');
57
- }
58
- /**
59
- * Read `_version` from config.json for the given embeddable.
60
- */
61
- function getVersionFromConfig(embeddableId) {
62
- const configPath = path.join('embeddables', embeddableId, 'config.json');
63
- if (!fs.existsSync(configPath)) {
64
- return null;
65
- }
66
- try {
67
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
68
- if (typeof config._version === 'number') {
69
- return config._version;
70
- }
71
- }
72
- catch {
73
- // Ignore parse errors
74
- }
75
- return null;
76
- }
77
- /**
78
- * Read `_branch_id` from config.json for the given embeddable (set when on a branch via `embeddables branch`).
79
- */
80
- function getBranchFromConfig(embeddableId) {
81
- const configPath = path.join('embeddables', embeddableId, 'config.json');
82
- if (!fs.existsSync(configPath)) {
83
- return null;
84
- }
85
- try {
86
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
87
- if (typeof config._branch_id === 'string' && config._branch_id) {
88
- return config._branch_id;
89
- }
90
- }
91
- catch {
92
- // Ignore parse errors
93
- }
94
- return null;
95
- }
96
- /** Slug for branch name/id for versioned filenames (e.g. "my branch" -> "my_branch"). */
97
- function slugForBranch(nameOrId) {
98
- return (String(nameOrId)
99
- .replace(/[^a-zA-Z0-9_.-]/g, '_')
100
- .replace(/_+/g, '_') || 'main');
101
- }
102
- /** Get branch slug from config (_branch_name preferred, else _branch_id, else main). */
103
- function getBranchSlugFromConfig(embeddableId) {
104
- const configPath = path.join('embeddables', embeddableId, 'config.json');
105
- if (!fs.existsSync(configPath))
106
- return 'main';
107
- try {
108
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
109
- const name = config._branch_name ?? config._branch_id;
110
- if (typeof name === 'string' && name)
111
- return slugForBranch(name);
112
- }
113
- catch {
114
- /* ignore */
115
- }
116
- return 'main';
117
- }
118
- /**
119
- * Update `_version` in config.json for the given embeddable.
120
- */
121
- function setVersionInConfig(embeddableId, version) {
122
- const configPath = path.join('embeddables', embeddableId, 'config.json');
123
- if (!fs.existsSync(configPath)) {
124
- return;
125
- }
126
- try {
127
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
128
- config._version = version;
129
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
130
- }
131
- catch {
132
- // Ignore errors - versioned files are a fallback
133
- }
134
- }
135
- /**
136
- * Scan the .generated/ directory for versioned files (embeddable-v*.json or embeddable-*@*.json)
137
- * and return the highest version number found.
138
- */
139
- function getLatestVersionFromFiles(generatedDir) {
140
- if (!fs.existsSync(generatedDir)) {
141
- return null;
142
- }
143
- const files = fs.readdirSync(generatedDir);
144
- const legacyPattern = /^embeddable-v(\d+)\.json$/;
145
- const branchPattern = /^embeddable-[^@]+@(\d+)\.json$/;
146
- let maxVersion = null;
147
- for (const file of files) {
148
- const match = file.match(legacyPattern) ?? file.match(branchPattern);
149
- if (match) {
150
- const version = parseInt(match[1], 10);
151
- if (maxVersion === null || version > maxVersion) {
152
- maxVersion = version;
153
- }
154
- }
155
- }
156
- return maxVersion;
157
- }
158
- /**
159
- * Fetch active drafts from other users on the same version (status=DRAFT, not saved/discarded).
160
- * Used to warn before saving that others may have unsaved edits.
161
- */
162
- async function fetchOtherUsersDrafts(supabase, flowId, versionNumber, branchId, currentUserId) {
163
- try {
164
- let query = supabase
165
- .from('flow_versions')
166
- .select('id, author_id, author_name')
167
- .eq('flow_id', flowId)
168
- .eq('status', 'DRAFT')
169
- .eq('version_number', versionNumber)
170
- .not('draft_saved', 'is', true)
171
- .not('draft_discarded', 'is', true)
172
- .neq('author_id', currentUserId);
173
- if (branchId === null) {
174
- query = query.is('branch_id', null);
175
- }
176
- else {
177
- query = query.eq('branch_id', branchId);
178
- }
179
- const { data, error } = await query;
180
- if (error) {
181
- return [];
182
- }
183
- return (data || []).map((row) => ({
184
- id: row.id,
185
- author_id: row.author_id,
186
- author_name: row.author_name ?? null,
187
- }));
188
- }
189
- catch {
190
- return [];
191
- }
192
- }
193
- export async function runSave(opts) {
194
- const logger = createLogger('runSave');
195
- try {
196
- await runSaveInner(opts);
197
- }
198
- catch (error) {
199
- captureException(error);
200
- if (error instanceof SaveError) {
201
- stdout.error(pc.red(`Save failed: ${error.message}`));
202
- if (error.detail) {
203
- stdout.print(pc.gray(error.detail));
204
- }
205
- }
206
- else if (error instanceof Error) {
207
- stdout.error(pc.red(`Save failed: ${error.message}`));
208
- }
209
- else {
210
- stdout.error(pc.red('Save failed with an unexpected error.'));
211
- }
212
- logger.error('save failed', {
213
- message: error instanceof Error ? error.message : 'unexpected error',
214
- });
215
- await exit(1);
216
- }
217
- }
218
- async function runSaveInner(opts) {
219
- const logger = createLogger('runSave');
220
- // 1. Check login
221
- if (!isLoggedIn()) {
222
- stdout.error(pc.red('Not logged in.'));
223
- stdout.print(pc.gray('Run "embeddables login" first.'));
224
- logger.error('not logged in');
225
- await exit(1);
226
- return;
227
- }
228
- // 2. Get access token
229
- const accessToken = getAccessToken();
230
- if (!accessToken) {
231
- stdout.error(pc.red('Could not retrieve access token.'));
232
- stdout.print(pc.gray('Run "embeddables login" to re-authenticate.'));
233
- logger.error('no access token');
234
- await exit(1);
235
- return;
236
- }
237
- // 3. Get embeddable ID (from option, cwd inference, or interactive prompt)
238
- const inferred = inferEmbeddableFromCwd();
239
- let embeddableId = opts.id ?? inferred?.embeddableId;
240
- if (inferred && !opts.id && embeddableId) {
241
- process.chdir(inferred.projectRoot);
242
- }
243
- setSentryContext(getSentryContextFromProjectConfig());
244
- if (!embeddableId) {
245
- const selected = await promptForLocalEmbeddable({
246
- message: 'Select an embeddable to save:',
247
- });
248
- if (!selected) {
249
- await exit(1);
250
- return;
251
- }
252
- embeddableId = selected;
253
- stdout.print('');
254
- }
255
- if (embeddableId) {
256
- const embeddableCtx = getSentryContextFromEmbeddableConfig(embeddableId);
257
- setSentryContext({
258
- embeddable: { id: embeddableId },
259
- ...embeddableCtx,
260
- });
261
- }
262
- // Resolve branch: explicit -b flag wins, otherwise use current branch from config (set by `embeddables branch`)
263
- const effectiveBranch = opts.branch ?? getBranchFromConfig(embeddableId) ?? undefined;
264
- logger.info('save started', { fromVersion: opts.fromVersion });
265
- // 4. Get project ID (from config or interactive prompt)
266
- let projectId = getProjectId();
267
- if (!projectId) {
268
- stdout.print(pc.cyan('No project configured. Fetching projects...'));
269
- const selectedProject = await promptForProject();
270
- if (!selectedProject) {
271
- await exit(1);
272
- return;
273
- }
274
- projectId = selectedProject.id;
275
- writeProjectConfig({
276
- org_id: selectedProject.org_id || undefined,
277
- org_title: selectedProject.org_title || undefined,
278
- project_id: projectId,
279
- project_name: selectedProject.title || undefined,
280
- });
281
- stdout.print(pc.green('✓ Saved project to embeddables.json'));
282
- stdout.print('');
283
- }
284
- // 5. Build (compile TSX → JSON) unless --skip-build is set
285
- const generatedDir = path.join('embeddables', embeddableId, '.generated');
286
- const outPath = path.join(generatedDir, 'embeddable.json');
287
- if (!opts.skipBuild) {
288
- const pagesGlob = `embeddables/${embeddableId}/pages/**/*.page.tsx`;
289
- const stylesDir = path.join('embeddables', embeddableId, 'styles');
290
- const configPath = path.join('embeddables', embeddableId, 'config.json');
291
- stdout.print(pc.cyan('Building embeddable...'));
292
- try {
293
- await compileAllPages({
294
- pagesGlob,
295
- outPath,
296
- pageKeyFrom: 'filename',
297
- stylesDir,
298
- embeddableId,
299
- configPath,
300
- });
301
- }
302
- catch (e) {
303
- captureException(e);
304
- stdout.error(formatError(e));
305
- logger.error('build failed');
306
- await exit(1);
307
- return;
308
- }
309
- stdout.print(pc.green('✓ Build successful'));
310
- stdout.print('');
311
- }
312
- // 6. Read the compiled JSON
313
- if (!fs.existsSync(outPath)) {
314
- stdout.error(pc.red(`No compiled embeddable found at ${outPath}`));
315
- stdout.print(pc.gray('Run "embeddables build" or "embeddables pull" first.'));
316
- logger.error('compiled json not found', { outPath });
317
- await exit(1);
318
- return;
319
- }
320
- const jsonContent = fs.readFileSync(outPath, 'utf8');
321
- let embeddableJson;
322
- try {
323
- embeddableJson = JSON.parse(jsonContent);
324
- }
325
- catch {
326
- stdout.error(pc.red('Failed to parse embeddable JSON.'));
327
- logger.error('failed to parse compiled json');
328
- await exit(1);
329
- return;
330
- }
331
- // Validate that pages array exists and is non-empty
332
- if (!embeddableJson.pages ||
333
- !Array.isArray(embeddableJson.pages) ||
334
- embeddableJson.pages.length === 0) {
335
- stdout.error(pc.red('Embeddable JSON must contain a non-empty pages array.'));
336
- logger.error('empty pages array');
337
- await exit(1);
338
- return;
339
- }
340
- // 7. Determine fromVersionNumber
341
- let fromVersionNumber;
342
- if (opts.fromVersion) {
343
- fromVersionNumber = parseInt(opts.fromVersion, 10);
344
- if (isNaN(fromVersionNumber)) {
345
- stdout.error(pc.red(`Invalid --from-version value: ${opts.fromVersion}`));
346
- logger.error('invalid from-version', { fromVersion: opts.fromVersion });
347
- await exit(1);
348
- return;
349
- }
350
- }
351
- else {
352
- // Primary: read _version from config.json; fallback: scan .generated/ for versioned files
353
- const detectedVersion = getVersionFromConfig(embeddableId) ?? getLatestVersionFromFiles(generatedDir);
354
- if (detectedVersion === null) {
355
- stdout.error(pc.red('Could not determine the current version number.'));
356
- stdout.print(pc.gray('Make sure you have pulled the embeddable first (embeddables pull), or specify --from-version <number>.'));
357
- logger.error('could not determine version');
358
- await exit(1);
359
- return;
360
- }
361
- fromVersionNumber = detectedVersion;
362
- }
363
- const embeddableCtxForBranch = getSentryContextFromEmbeddableConfig(embeddableId);
364
- setSentryContext({
365
- versionNumber: fromVersionNumber,
366
- branch: effectiveBranch ?
367
- {
368
- id: effectiveBranch,
369
- name: embeddableCtxForBranch.branch?.id === effectiveBranch
370
- ? embeddableCtxForBranch.branch?.name ?? null
371
- : null,
372
- }
373
- : undefined,
374
- });
375
- // 7b. Check for other users' drafts on this version; warn and optionally abort
376
- let currentUserId = null;
377
- const supabase = await getAuthenticatedSupabaseClient();
378
- if (supabase) {
379
- const { data: { user }, } = await supabase.auth.getUser();
380
- currentUserId = user?.id ?? null;
381
- if (currentUserId) {
382
- const branchIdForDrafts = effectiveBranch ?? null;
383
- const otherDrafts = await fetchOtherUsersDrafts(supabase, embeddableId, fromVersionNumber, branchIdForDrafts, currentUserId);
384
- if (otherDrafts.length > 0) {
385
- const names = otherDrafts
386
- .map((d) => d.author_name?.trim() || d.author_id || 'Someone')
387
- .filter((n, i, a) => a.indexOf(n) === i);
388
- const namesText = names.length === 1
389
- ? names[0]
390
- : `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
391
- stdout.print('');
392
- stdout.warn(pc.yellow(`⚠ ${namesText} ${names.length === 1 ? 'has' : 'have'} unsaved edits on version ${fromVersionNumber}. Saving may cause conflicts.`));
393
- const { proceed } = await prompts({
394
- type: 'confirm',
395
- name: 'proceed',
396
- message: 'Save anyway?',
397
- initial: false,
398
- }, {
399
- onCancel: () => {
400
- process.exit(1);
401
- },
402
- });
403
- if (!proceed) {
404
- stdout.print(pc.gray('Save cancelled.'));
405
- await exit(0);
406
- }
407
- stdout.print('');
408
- }
409
- }
410
- }
411
- // 8. POST to save-version API
412
- stdout.print(pc.cyan(`Saving embeddable (based on v${fromVersionNumber})...`));
413
- // Resolve current user id (required by API)
414
- if (!currentUserId && supabase) {
415
- const { data: { user }, } = await supabase.auth.getUser();
416
- currentUserId = user?.id ?? null;
417
- }
418
- if (!currentUserId) {
419
- throw new SaveError('You must be logged in to save.', 'Run "embeddables login" to authenticate.');
420
- }
421
- // Previous version JSON: from versioned snapshot file, or {} if not found (e.g. --from-version without pull)
422
- const previousVersionPath = path.join(generatedDir, `embeddable-${getBranchSlugFromConfig(embeddableId)}@${fromVersionNumber}.json`);
423
- const legacyVersionPath = path.join(generatedDir, `embeddable-v${fromVersionNumber}.json`);
424
- const previousJsonContent = fs.existsSync(previousVersionPath)
425
- ? fs.readFileSync(previousVersionPath, 'utf8')
426
- : fs.existsSync(legacyVersionPath)
427
- ? fs.readFileSync(legacyVersionPath, 'utf8')
428
- : '{}';
429
- const commands = translateJsonDiffToEditCommands({
430
- previousObject: JSON.parse(previousJsonContent),
431
- currentObject: JSON.parse(jsonContent),
432
- basePath: [],
433
- });
434
- const body = {
435
- userId: currentUserId,
436
- embeddableId,
437
- jsonString: JSON.stringify(embeddableJson),
438
- projectId,
439
- fromVersionNumber,
440
- editHistoryLength: 1,
441
- editHistoryDescriptions: [{ origin: 'CLI', description: 'Saved version from CLI' }],
442
- editHistory: [
443
- setMultipleFlowUpdates({
444
- commands,
445
- metadata: {
446
- description: 'Saved version from CLI',
447
- trigger: { origin: 'CLI', editor: 'CLI' },
448
- },
449
- }),
450
- ],
451
- };
452
- if (opts.label) {
453
- body.label = opts.label;
454
- }
455
- if (effectiveBranch) {
456
- body.branchId = effectiveBranch;
457
- }
458
- const url = `${WEB_APP_BASE_URL}/api/embeddables/save-version`;
459
- const headers = {
460
- Authorization: `Bearer ${accessToken}`,
461
- 'Content-Type': 'application/json',
462
- };
463
- let response;
464
- try {
465
- response = await fetch(url, {
466
- method: 'POST',
467
- headers,
468
- body: JSON.stringify(body),
469
- });
470
- }
471
- catch (networkError) {
472
- const message = networkError instanceof Error ? networkError.message : 'Network request failed';
473
- if (message.includes('fetch') ||
474
- message.includes('ECONNREFUSED') ||
475
- message.includes('ETIMEDOUT') ||
476
- message.includes('ENOTFOUND') ||
477
- message.includes('network')) {
478
- throw new SaveError(`Could not reach the server (${message}).`, `Check your connection and that the base URL is correct (currently ${WEB_APP_BASE_URL}).`);
479
- }
480
- throw new SaveError(`Network error: ${message}`, 'Check your network and firewall settings.');
481
- }
482
- if (response.status === 404) {
483
- throw new SaveError('Save endpoint not found. The server may not support this feature or the URL may be incorrect.', `The request was sent to ${WEB_APP_BASE_URL}. If you use a custom deployment, ensure the save-version API is available there.`);
484
- }
485
- if (response.status === 401 || response.status === 403) {
486
- throw new SaveError('Not authorized.', 'Run "embeddables login" to re-authenticate.');
487
- }
488
- if (response.status >= 500) {
489
- throw new SaveError(`Server error (HTTP ${response.status}). Please try again later.`, 'If this keeps happening, try again later or contact support.');
490
- }
491
- if (response.status === 409) {
492
- const conflictResult = await safeParseJson(response);
493
- if (!conflictResult || !isSaveConflictResponse(conflictResult)) {
494
- throw new SaveError(`Version conflict but invalid response (HTTP ${response.status}).`, 'Try saving again; if it persists, the server may be misconfigured.');
495
- }
496
- stdout.print('');
497
- stdout.warn(pc.yellow(`⚠ Version conflict: the server has version ${conflictResult.latestVersionNumber}, but you are saving from version ${conflictResult.yourVersionNumber}.`));
498
- const { forceSave } = await prompts({
499
- type: 'confirm',
500
- name: 'forceSave',
501
- message: 'A newer version exists on the server. Save anyway?',
502
- initial: false,
503
- }, {
504
- onCancel: () => {
505
- process.exit(1);
506
- },
507
- });
508
- if (!forceSave) {
509
- stdout.print(pc.gray('Save cancelled.'));
510
- await exit(0);
511
- }
512
- // Retry with force flag
513
- stdout.print(pc.cyan('Retrying save with force...'));
514
- let forceResponse;
515
- try {
516
- forceResponse = await fetch(url, {
517
- method: 'POST',
518
- headers,
519
- body: JSON.stringify({ ...body, force: true }),
520
- });
521
- }
522
- catch (forceNetworkError) {
523
- const message = forceNetworkError instanceof Error ? forceNetworkError.message : 'Network request failed';
524
- throw new SaveError(`Retry failed: ${message}`, 'The initial save hit a version conflict; the force-save retry could not reach the server.');
525
- }
526
- if (forceResponse.status === 404) {
527
- throw new SaveError('Save endpoint not found. The server may not support this feature or the URL may be incorrect.', `The request was sent to ${WEB_APP_BASE_URL}. If you use a custom deployment, ensure the save-version API is available there.`);
528
- }
529
- const forceResult = await safeParseJson(forceResponse);
530
- if (!forceResponse.ok) {
531
- const errorMessage = forceResult && isSaveErrorResponse(forceResult)
532
- ? forceResult.error
533
- : `HTTP ${forceResponse.status}`;
534
- throw new SaveError(errorMessage, 'If the problem persists, run "embeddables login" or try again later.');
535
- }
536
- if (!forceResult || !isSaveResponse(forceResult)) {
537
- throw new SaveError(`Invalid response from server (HTTP ${forceResponse.status}).`, 'The server returned an unexpected format. Try again or contact support if it persists.');
538
- }
539
- const { newVersionNumber } = forceResult.data;
540
- stdout.print(pc.green(`✓ Saved as version ${newVersionNumber}`));
541
- logger.info('save complete', { newVersionNumber, forced: true });
542
- setVersionInConfig(embeddableId, newVersionNumber);
543
- const branchSlug = getBranchSlugFromConfig(embeddableId);
544
- const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
545
- fs.mkdirSync(generatedDir, { recursive: true });
546
- fs.writeFileSync(versionedPath, jsonContent, 'utf8');
547
- stdout.print(pc.cyan(`✓ Saved version file to ${versionedPath}`));
548
- return;
549
- }
550
- const result = await safeParseJson(response);
551
- if (!response.ok) {
552
- const errorMessage = result && isSaveErrorResponse(result) ? result.error : `HTTP ${response.status}`;
553
- throw new SaveError(errorMessage, 'If the problem persists, run "embeddables login" or try again later.');
554
- }
555
- if (!result || !isSaveResponse(result)) {
556
- throw new SaveError(`Invalid response from server (HTTP ${response.status}).`, 'The server returned an unexpected format. Try again or contact support if it persists.');
557
- }
558
- const { newVersionNumber } = result.data;
559
- stdout.print(pc.green(`✓ Saved as version ${newVersionNumber}`));
560
- logger.info('save complete', { newVersionNumber });
561
- // Update _version in config.json so future saves know the base version
562
- setVersionInConfig(embeddableId, newVersionNumber);
563
- // Also save the versioned file to .generated/ as a snapshot (embeddable-{branch}@{version}.json)
564
- const branchSlug = getBranchSlugFromConfig(embeddableId);
565
- const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
566
- fs.mkdirSync(generatedDir, { recursive: true });
567
- fs.writeFileSync(versionedPath, jsonContent, 'utf8');
568
- stdout.print(pc.cyan(`✓ Saved version file to ${versionedPath}`));
569
- }
570
- function setMultipleFlowUpdates({ commands, metadata, }) {
571
- const type = 'set_multiple_embeddable_updates';
572
- const simpleCommandTypes = {
573
- add: 'add_embeddable_property',
574
- remove: 'remove_embeddable_property',
575
- set: 'update_embeddable_property',
576
- move: 'move_embeddable_property',
577
- };
578
- //* Map the commands to the correct type and data
579
- const mappedCommands = commands.map((command) => ({
580
- type: Object.keys(simpleCommandTypes).includes(command.type)
581
- ? simpleCommandTypes[command.type]
582
- : command.type,
583
- data: command.data,
584
- }));
585
- return {
586
- id: generateId('edit'),
587
- type,
588
- data: { commands: mappedCommands },
589
- metadata,
590
- };
591
- }
@@ -1,2 +0,0 @@
1
- export declare function runUpgrade(): Promise<void>;
2
- //# sourceMappingURL=upgrade.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAwBA,wBAAsB,UAAU,kBAqC/B"}
@@ -1,51 +0,0 @@
1
- import { createRequire } from 'node:module';
2
- import { execSync } from 'node:child_process';
3
- import { fileURLToPath } from 'node:url';
4
- import { dirname, join } from 'node:path';
5
- import pc from 'picocolors';
6
- const require = createRequire(import.meta.url);
7
- function getCurrentVersion() {
8
- const __dirname = dirname(fileURLToPath(import.meta.url));
9
- const pkgPath = join(__dirname, '..', '..', 'package.json');
10
- const pkg = require(pkgPath);
11
- return pkg.version;
12
- }
13
- async function getLatestVersion() {
14
- const res = await fetch('https://registry.npmjs.org/@embeddables/cli/latest');
15
- if (!res.ok) {
16
- throw new Error(`Failed to fetch latest version: ${res.status}`);
17
- }
18
- const data = (await res.json());
19
- return data.version;
20
- }
21
- export async function runUpgrade() {
22
- try {
23
- const currentVersion = getCurrentVersion();
24
- console.log('');
25
- console.log(pc.cyan('Checking for updates...'));
26
- const latestVersion = await getLatestVersion();
27
- if (currentVersion === latestVersion) {
28
- console.log(pc.green(`✓ Already on the latest version (${latestVersion})`));
29
- console.log('');
30
- return;
31
- }
32
- console.log(pc.cyan(`Upgrading from ${currentVersion} to ${latestVersion}...`));
33
- console.log('');
34
- execSync(`npm install -g @embeddables/cli@latest`, {
35
- stdio: 'inherit',
36
- });
37
- console.log('');
38
- console.log(pc.green(`✓ Successfully upgraded to @embeddables/cli@${latestVersion}`));
39
- console.log('');
40
- }
41
- catch (error) {
42
- const message = error instanceof Error ? error.message : String(error);
43
- if (message.includes('EACCES') || message.includes('permission')) {
44
- console.error(pc.red('Permission denied. Try running with sudo: sudo npm install -g @embeddables/cli@latest'));
45
- }
46
- else {
47
- console.error(pc.red(`Error during upgrade: ${message}`));
48
- }
49
- process.exit(1);
50
- }
51
- }
@@ -1,20 +0,0 @@
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
@@ -1 +0,0 @@
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"}