@superlayer/cli 1.0.67

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 (329) hide show
  1. package/LICENSE.md +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +67 -0
  4. package/bin/index.js +3 -0
  5. package/dist/auth/index.d.ts +4 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +103 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/commands/app/delete.d.ts +7 -0
  10. package/dist/commands/app/delete.d.ts.map +1 -0
  11. package/dist/commands/app/delete.js +57 -0
  12. package/dist/commands/app/delete.js.map +1 -0
  13. package/dist/commands/app/list.d.ts +6 -0
  14. package/dist/commands/app/list.d.ts.map +1 -0
  15. package/dist/commands/app/list.js +29 -0
  16. package/dist/commands/app/list.js.map +1 -0
  17. package/dist/commands/auth/client/add.d.ts +9 -0
  18. package/dist/commands/auth/client/add.d.ts.map +1 -0
  19. package/dist/commands/auth/client/add.js +409 -0
  20. package/dist/commands/auth/client/add.js.map +1 -0
  21. package/dist/commands/auth/client/delete.d.ts +11 -0
  22. package/dist/commands/auth/client/delete.d.ts.map +1 -0
  23. package/dist/commands/auth/client/delete.js +48 -0
  24. package/dist/commands/auth/client/delete.js.map +1 -0
  25. package/dist/commands/auth/client/list.d.ts +6 -0
  26. package/dist/commands/auth/client/list.d.ts.map +1 -0
  27. package/dist/commands/auth/client/list.js +38 -0
  28. package/dist/commands/auth/client/list.js.map +1 -0
  29. package/dist/commands/auth/client/shared.d.ts +70 -0
  30. package/dist/commands/auth/client/shared.d.ts.map +1 -0
  31. package/dist/commands/auth/client/shared.js +140 -0
  32. package/dist/commands/auth/client/shared.js.map +1 -0
  33. package/dist/commands/auth/client/update.d.ts +8 -0
  34. package/dist/commands/auth/client/update.d.ts.map +1 -0
  35. package/dist/commands/auth/client/update.js +445 -0
  36. package/dist/commands/auth/client/update.js.map +1 -0
  37. package/dist/commands/auth/email/pull.d.ts +24 -0
  38. package/dist/commands/auth/email/pull.d.ts.map +1 -0
  39. package/dist/commands/auth/email/pull.js +100 -0
  40. package/dist/commands/auth/email/pull.js.map +1 -0
  41. package/dist/commands/auth/email/push.d.ts +8 -0
  42. package/dist/commands/auth/email/push.d.ts.map +1 -0
  43. package/dist/commands/auth/email/push.js +58 -0
  44. package/dist/commands/auth/email/push.js.map +1 -0
  45. package/dist/commands/auth/email/resend.d.ts +3 -0
  46. package/dist/commands/auth/email/resend.d.ts.map +1 -0
  47. package/dist/commands/auth/email/resend.js +7 -0
  48. package/dist/commands/auth/email/resend.js.map +1 -0
  49. package/dist/commands/auth/email/reset.d.ts +5 -0
  50. package/dist/commands/auth/email/reset.d.ts.map +1 -0
  51. package/dist/commands/auth/email/reset.js +25 -0
  52. package/dist/commands/auth/email/reset.js.map +1 -0
  53. package/dist/commands/auth/email/status.d.ts +57 -0
  54. package/dist/commands/auth/email/status.d.ts.map +1 -0
  55. package/dist/commands/auth/email/status.js +96 -0
  56. package/dist/commands/auth/email/status.js.map +1 -0
  57. package/dist/commands/auth/email/verify.d.ts +5 -0
  58. package/dist/commands/auth/email/verify.d.ts.map +1 -0
  59. package/dist/commands/auth/email/verify.js +12 -0
  60. package/dist/commands/auth/email/verify.js.map +1 -0
  61. package/dist/commands/auth/origin/add.d.ts +12 -0
  62. package/dist/commands/auth/origin/add.d.ts.map +1 -0
  63. package/dist/commands/auth/origin/add.js +153 -0
  64. package/dist/commands/auth/origin/add.js.map +1 -0
  65. package/dist/commands/auth/origin/delete.d.ts +8 -0
  66. package/dist/commands/auth/origin/delete.d.ts.map +1 -0
  67. package/dist/commands/auth/origin/delete.js +38 -0
  68. package/dist/commands/auth/origin/delete.js.map +1 -0
  69. package/dist/commands/auth/origin/list.d.ts +9 -0
  70. package/dist/commands/auth/origin/list.d.ts.map +1 -0
  71. package/dist/commands/auth/origin/list.js +52 -0
  72. package/dist/commands/auth/origin/list.js.map +1 -0
  73. package/dist/commands/backup/download.d.ts +10 -0
  74. package/dist/commands/backup/download.d.ts.map +1 -0
  75. package/dist/commands/backup/download.js +174 -0
  76. package/dist/commands/backup/download.js.map +1 -0
  77. package/dist/commands/backup/list.d.ts +11 -0
  78. package/dist/commands/backup/list.d.ts.map +1 -0
  79. package/dist/commands/backup/list.js +74 -0
  80. package/dist/commands/backup/list.js.map +1 -0
  81. package/dist/commands/claim.d.ts +6 -0
  82. package/dist/commands/claim.d.ts.map +1 -0
  83. package/dist/commands/claim.js +22 -0
  84. package/dist/commands/claim.js.map +1 -0
  85. package/dist/commands/explorer.d.ts +6 -0
  86. package/dist/commands/explorer.d.ts.map +1 -0
  87. package/dist/commands/explorer.js +13 -0
  88. package/dist/commands/explorer.js.map +1 -0
  89. package/dist/commands/info.d.ts +9 -0
  90. package/dist/commands/info.d.ts.map +1 -0
  91. package/dist/commands/info.js +41 -0
  92. package/dist/commands/info.js.map +1 -0
  93. package/dist/commands/init.d.ts +5 -0
  94. package/dist/commands/init.d.ts.map +1 -0
  95. package/dist/commands/init.js +41 -0
  96. package/dist/commands/init.js.map +1 -0
  97. package/dist/commands/initWithoutFiles.d.ts +6 -0
  98. package/dist/commands/initWithoutFiles.d.ts.map +1 -0
  99. package/dist/commands/initWithoutFiles.js +64 -0
  100. package/dist/commands/initWithoutFiles.js.map +1 -0
  101. package/dist/commands/login.d.ts +9 -0
  102. package/dist/commands/login.d.ts.map +1 -0
  103. package/dist/commands/login.js +44 -0
  104. package/dist/commands/login.js.map +1 -0
  105. package/dist/commands/logout.d.ts +3 -0
  106. package/dist/commands/logout.d.ts.map +1 -0
  107. package/dist/commands/logout.js +14 -0
  108. package/dist/commands/logout.js.map +1 -0
  109. package/dist/commands/pull.d.ts +5 -0
  110. package/dist/commands/pull.d.ts.map +1 -0
  111. package/dist/commands/pull.js +15 -0
  112. package/dist/commands/pull.js.map +1 -0
  113. package/dist/commands/push.d.ts +6 -0
  114. package/dist/commands/push.d.ts.map +1 -0
  115. package/dist/commands/push.js +20 -0
  116. package/dist/commands/push.js.map +1 -0
  117. package/dist/commands/query.d.ts +7 -0
  118. package/dist/commands/query.d.ts.map +1 -0
  119. package/dist/commands/query.js +52 -0
  120. package/dist/commands/query.js.map +1 -0
  121. package/dist/commands/webhooks/add.d.ts +9 -0
  122. package/dist/commands/webhooks/add.d.ts.map +1 -0
  123. package/dist/commands/webhooks/add.js +75 -0
  124. package/dist/commands/webhooks/add.js.map +1 -0
  125. package/dist/commands/webhooks/delete.d.ts +6 -0
  126. package/dist/commands/webhooks/delete.d.ts.map +1 -0
  127. package/dist/commands/webhooks/delete.js +17 -0
  128. package/dist/commands/webhooks/delete.js.map +1 -0
  129. package/dist/commands/webhooks/disable.d.ts +7 -0
  130. package/dist/commands/webhooks/disable.d.ts.map +1 -0
  131. package/dist/commands/webhooks/disable.js +18 -0
  132. package/dist/commands/webhooks/disable.js.map +1 -0
  133. package/dist/commands/webhooks/enable.d.ts +6 -0
  134. package/dist/commands/webhooks/enable.d.ts.map +1 -0
  135. package/dist/commands/webhooks/enable.js +18 -0
  136. package/dist/commands/webhooks/enable.js.map +1 -0
  137. package/dist/commands/webhooks/events/list.d.ts +7 -0
  138. package/dist/commands/webhooks/events/list.d.ts.map +1 -0
  139. package/dist/commands/webhooks/events/list.js +31 -0
  140. package/dist/commands/webhooks/events/list.js.map +1 -0
  141. package/dist/commands/webhooks/events/payload.d.ts +8 -0
  142. package/dist/commands/webhooks/events/payload.d.ts.map +1 -0
  143. package/dist/commands/webhooks/events/payload.js +39 -0
  144. package/dist/commands/webhooks/events/payload.js.map +1 -0
  145. package/dist/commands/webhooks/events/resend.d.ts +8 -0
  146. package/dist/commands/webhooks/events/resend.d.ts.map +1 -0
  147. package/dist/commands/webhooks/events/resend.js +43 -0
  148. package/dist/commands/webhooks/events/resend.js.map +1 -0
  149. package/dist/commands/webhooks/list.d.ts +8 -0
  150. package/dist/commands/webhooks/list.d.ts.map +1 -0
  151. package/dist/commands/webhooks/list.js +29 -0
  152. package/dist/commands/webhooks/list.js.map +1 -0
  153. package/dist/commands/webhooks/shared.d.ts +40 -0
  154. package/dist/commands/webhooks/shared.d.ts.map +1 -0
  155. package/dist/commands/webhooks/shared.js +248 -0
  156. package/dist/commands/webhooks/shared.js.map +1 -0
  157. package/dist/commands/webhooks/update.d.ts +10 -0
  158. package/dist/commands/webhooks/update.d.ts.map +1 -0
  159. package/dist/commands/webhooks/update.js +189 -0
  160. package/dist/commands/webhooks/update.js.map +1 -0
  161. package/dist/context/authToken.d.ts +29 -0
  162. package/dist/context/authToken.d.ts.map +1 -0
  163. package/dist/context/authToken.js +73 -0
  164. package/dist/context/authToken.js.map +1 -0
  165. package/dist/context/currentApp.d.ts +38 -0
  166. package/dist/context/currentApp.d.ts.map +1 -0
  167. package/dist/context/currentApp.js +222 -0
  168. package/dist/context/currentApp.js.map +1 -0
  169. package/dist/context/globalOpts.d.ts +11 -0
  170. package/dist/context/globalOpts.d.ts.map +1 -0
  171. package/dist/context/globalOpts.js +13 -0
  172. package/dist/context/globalOpts.js.map +1 -0
  173. package/dist/context/platformApi.d.ts +19 -0
  174. package/dist/context/platformApi.d.ts.map +1 -0
  175. package/dist/context/platformApi.js +24 -0
  176. package/dist/context/platformApi.js.map +1 -0
  177. package/dist/context/projectInfo.d.ts +30 -0
  178. package/dist/context/projectInfo.d.ts.map +1 -0
  179. package/dist/context/projectInfo.js +152 -0
  180. package/dist/context/projectInfo.js.map +1 -0
  181. package/dist/errors.d.ts +10 -0
  182. package/dist/errors.d.ts.map +1 -0
  183. package/dist/errors.js +6 -0
  184. package/dist/errors.js.map +1 -0
  185. package/dist/index.d.ts +159 -0
  186. package/dist/index.d.ts.map +1 -0
  187. package/dist/index.js +714 -0
  188. package/dist/index.js.map +1 -0
  189. package/dist/layer.d.ts +25 -0
  190. package/dist/layer.d.ts.map +1 -0
  191. package/dist/layer.js +119 -0
  192. package/dist/layer.js.map +1 -0
  193. package/dist/lib/args.d.ts +212 -0
  194. package/dist/lib/args.d.ts.map +1 -0
  195. package/dist/lib/args.js +313 -0
  196. package/dist/lib/args.js.map +1 -0
  197. package/dist/lib/backupDownload.d.ts +21 -0
  198. package/dist/lib/backupDownload.d.ts.map +1 -0
  199. package/dist/lib/backupDownload.js +151 -0
  200. package/dist/lib/backupDownload.js.map +1 -0
  201. package/dist/lib/backups.d.ts +12 -0
  202. package/dist/lib/backups.d.ts.map +1 -0
  203. package/dist/lib/backups.js +26 -0
  204. package/dist/lib/backups.js.map +1 -0
  205. package/dist/lib/config.d.ts +6 -0
  206. package/dist/lib/config.d.ts.map +1 -0
  207. package/dist/lib/config.js +39 -0
  208. package/dist/lib/config.js.map +1 -0
  209. package/dist/lib/createApp.d.ts +12 -0
  210. package/dist/lib/createApp.d.ts.map +1 -0
  211. package/dist/lib/createApp.js +15 -0
  212. package/dist/lib/createApp.js.map +1 -0
  213. package/dist/lib/email.d.ts +47 -0
  214. package/dist/lib/email.d.ts.map +1 -0
  215. package/dist/lib/email.js +71 -0
  216. package/dist/lib/email.js.map +1 -0
  217. package/dist/lib/handleEnv.d.ts +7 -0
  218. package/dist/lib/handleEnv.d.ts.map +1 -0
  219. package/dist/lib/handleEnv.js +99 -0
  220. package/dist/lib/handleEnv.js.map +1 -0
  221. package/dist/lib/http.d.ts +30 -0
  222. package/dist/lib/http.d.ts.map +1 -0
  223. package/dist/lib/http.js +55 -0
  224. package/dist/lib/http.js.map +1 -0
  225. package/dist/lib/login.d.ts +12 -0
  226. package/dist/lib/login.d.ts.map +1 -0
  227. package/dist/lib/login.js +38 -0
  228. package/dist/lib/login.js.map +1 -0
  229. package/dist/lib/oauth.d.ts +306 -0
  230. package/dist/lib/oauth.d.ts.map +1 -0
  231. package/dist/lib/oauth.js +195 -0
  232. package/dist/lib/oauth.js.map +1 -0
  233. package/dist/lib/platformApi.d.ts +5 -0
  234. package/dist/lib/platformApi.d.ts.map +1 -0
  235. package/dist/lib/platformApi.js +11 -0
  236. package/dist/lib/platformApi.js.map +1 -0
  237. package/dist/lib/pullPerms.d.ts +7 -0
  238. package/dist/lib/pullPerms.d.ts.map +1 -0
  239. package/dist/lib/pullPerms.js +41 -0
  240. package/dist/lib/pullPerms.js.map +1 -0
  241. package/dist/lib/pullSchema.d.ts +12 -0
  242. package/dist/lib/pullSchema.d.ts.map +1 -0
  243. package/dist/lib/pullSchema.js +62 -0
  244. package/dist/lib/pullSchema.js.map +1 -0
  245. package/dist/lib/pushPerms.d.ts +13 -0
  246. package/dist/lib/pushPerms.d.ts.map +1 -0
  247. package/dist/lib/pushPerms.js +54 -0
  248. package/dist/lib/pushPerms.js.map +1 -0
  249. package/dist/lib/pushSchema.d.ts +53 -0
  250. package/dist/lib/pushSchema.d.ts.map +1 -0
  251. package/dist/lib/pushSchema.js +165 -0
  252. package/dist/lib/pushSchema.js.map +1 -0
  253. package/dist/lib/ui.d.ts +18 -0
  254. package/dist/lib/ui.d.ts.map +1 -0
  255. package/dist/lib/ui.js +32 -0
  256. package/dist/lib/ui.js.map +1 -0
  257. package/dist/lib/webhooks.d.ts +27 -0
  258. package/dist/lib/webhooks.d.ts.map +1 -0
  259. package/dist/lib/webhooks.js +95 -0
  260. package/dist/lib/webhooks.js.map +1 -0
  261. package/dist/logging.d.ts +5 -0
  262. package/dist/logging.d.ts.map +1 -0
  263. package/dist/logging.js +25 -0
  264. package/dist/logging.js.map +1 -0
  265. package/dist/old.d.ts +17 -0
  266. package/dist/old.d.ts.map +1 -0
  267. package/dist/old.js +410 -0
  268. package/dist/old.js.map +1 -0
  269. package/dist/program.d.ts +3 -0
  270. package/dist/program.d.ts.map +1 -0
  271. package/dist/program.js +3 -0
  272. package/dist/program.js.map +1 -0
  273. package/dist/renderSchemaPlan.d.ts +19 -0
  274. package/dist/renderSchemaPlan.d.ts.map +1 -0
  275. package/dist/renderSchemaPlan.js +220 -0
  276. package/dist/renderSchemaPlan.js.map +1 -0
  277. package/dist/ui/index.d.ts +292 -0
  278. package/dist/ui/index.d.ts.map +1 -0
  279. package/dist/ui/index.js +1296 -0
  280. package/dist/ui/index.js.map +1 -0
  281. package/dist/ui/lib.d.ts +124 -0
  282. package/dist/ui/lib.d.ts.map +1 -0
  283. package/dist/ui/lib.js +333 -0
  284. package/dist/ui/lib.js.map +1 -0
  285. package/dist/util/findConfigCandidates.d.ts +13 -0
  286. package/dist/util/findConfigCandidates.d.ts.map +1 -0
  287. package/dist/util/findConfigCandidates.js +211 -0
  288. package/dist/util/findConfigCandidates.js.map +1 -0
  289. package/dist/util/fs.d.ts +4 -0
  290. package/dist/util/fs.d.ts.map +1 -0
  291. package/dist/util/fs.js +22 -0
  292. package/dist/util/fs.js.map +1 -0
  293. package/dist/util/getAppName.d.ts +5 -0
  294. package/dist/util/getAppName.d.ts.map +1 -0
  295. package/dist/util/getAppName.js +14 -0
  296. package/dist/util/getAppName.js.map +1 -0
  297. package/dist/util/instantConfig.d.ts +9 -0
  298. package/dist/util/instantConfig.d.ts.map +1 -0
  299. package/dist/util/instantConfig.js +13 -0
  300. package/dist/util/instantConfig.js.map +1 -0
  301. package/dist/util/isHeadlessEnvironment.d.ts +4 -0
  302. package/dist/util/isHeadlessEnvironment.d.ts.map +1 -0
  303. package/dist/util/isHeadlessEnvironment.js +11 -0
  304. package/dist/util/isHeadlessEnvironment.js.map +1 -0
  305. package/dist/util/loadConfig.d.ts +3 -0
  306. package/dist/util/loadConfig.d.ts.map +1 -0
  307. package/dist/util/loadConfig.js +72 -0
  308. package/dist/util/loadConfig.js.map +1 -0
  309. package/dist/util/loadEnv.d.ts +2 -0
  310. package/dist/util/loadEnv.d.ts.map +1 -0
  311. package/dist/util/loadEnv.js +10 -0
  312. package/dist/util/loadEnv.js.map +1 -0
  313. package/dist/util/mergeSchema.d.ts +10 -0
  314. package/dist/util/mergeSchema.d.ts.map +1 -0
  315. package/dist/util/mergeSchema.js +338 -0
  316. package/dist/util/mergeSchema.js.map +1 -0
  317. package/dist/util/projectDir.d.ts +7 -0
  318. package/dist/util/projectDir.d.ts.map +1 -0
  319. package/dist/util/projectDir.js +43 -0
  320. package/dist/util/projectDir.js.map +1 -0
  321. package/dist/util/renamePrompt.d.ts +15 -0
  322. package/dist/util/renamePrompt.d.ts.map +1 -0
  323. package/dist/util/renamePrompt.js +57 -0
  324. package/dist/util/renamePrompt.js.map +1 -0
  325. package/dist/version.d.ts +3 -0
  326. package/dist/version.d.ts.map +1 -0
  327. package/dist/version.js +3 -0
  328. package/dist/version.js.map +1 -0
  329. package/package.json +96 -0
@@ -0,0 +1,153 @@
1
+ import { Effect, Match, Option, Schema } from 'effect';
2
+ import { BadArgsError } from "../../../errors.js";
3
+ import { GlobalOpts } from "../../../context/globalOpts.js";
4
+ import { Args } from "../../../lib/args.js";
5
+ import { runUIEffect } from "../../../lib/ui.js";
6
+ import { addAuthorizedOrigin } from "../../../lib/oauth.js";
7
+ import { UI } from "../../../ui/index.js";
8
+ import chalk from 'chalk';
9
+ import boxen from 'boxen';
10
+ import { originDisplay, originSource } from "./list.js";
11
+ export const OriginTypeSchema = Schema.Literal('website', 'vercel', 'netlify', 'custom-scheme');
12
+ const validateGenericUrl = (input) => {
13
+ const trimmed = input.trim();
14
+ try {
15
+ const url = new URL(trimmed);
16
+ const host = url.host;
17
+ if (!host) {
18
+ throw new Error('missing host');
19
+ }
20
+ if (host.split('.').length === 1 && !url.port) {
21
+ throw new Error('invalid url');
22
+ }
23
+ return { type: 'success', params: [host] };
24
+ }
25
+ catch {
26
+ if (!trimmed.startsWith('http')) {
27
+ return validateGenericUrl(`http://${trimmed}`);
28
+ }
29
+ return { type: 'error', message: 'Invalid URL.' };
30
+ }
31
+ };
32
+ const validateNetlifyUrl = (input) => {
33
+ const trimmed = input.trim();
34
+ if (!trimmed) {
35
+ return { type: 'error', message: 'Netlify site name is required.' };
36
+ }
37
+ return { type: 'success', params: [trimmed] };
38
+ };
39
+ const validateVercelUrl = (input) => {
40
+ const trimmed = input.trim();
41
+ if (!trimmed) {
42
+ return { type: 'error', message: 'Vercel project name is required.' };
43
+ }
44
+ return { type: 'success', params: ['vercel.app', trimmed] };
45
+ };
46
+ const validateCustomScheme = (input) => {
47
+ const trimmed = input.trim();
48
+ try {
49
+ const url = new URL(trimmed);
50
+ const scheme = url.protocol.slice(0, -1);
51
+ return { type: 'success', params: [scheme] };
52
+ }
53
+ catch {
54
+ return { type: 'error', message: 'Invalid scheme.' };
55
+ }
56
+ };
57
+ const addOriginHandler = Effect.fn(function* (type, validated) {
58
+ const response = yield* addAuthorizedOrigin({
59
+ service: type === 'website' ? 'generic' : type,
60
+ params: validated.params,
61
+ });
62
+ yield* Effect.log('\n' +
63
+ boxen([
64
+ `Origin added: ${originDisplay(response.origin)}`,
65
+ `Type: ${originSource(response.origin)}`,
66
+ `ID: ${response.origin.id}`,
67
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
68
+ });
69
+ const handleGenericOrigin = Effect.fn(function* (opts) {
70
+ const url = yield* Args.text(opts, 'url').pipe(Args.prompt({
71
+ prompt: 'Website URL:',
72
+ placeholder: 'example.com',
73
+ modifyOutput: UI.modifiers.piped([
74
+ UI.modifiers.topPadding,
75
+ UI.modifiers.dimOnComplete,
76
+ ]),
77
+ }), Args.required());
78
+ const validated = validateGenericUrl(url);
79
+ if (validated.type === 'error') {
80
+ return yield* BadArgsError.make({ message: validated.message });
81
+ }
82
+ yield* addOriginHandler('website', validated);
83
+ });
84
+ const handleVercelOrigin = Effect.fn(function* (opts) {
85
+ const project = yield* Args.text(opts, 'project').pipe(Args.prompt({
86
+ prompt: 'Vercel project name:',
87
+ placeholder: 'vercel-project-name',
88
+ modifyOutput: UI.modifiers.piped([
89
+ UI.modifiers.topPadding,
90
+ UI.modifiers.dimOnComplete,
91
+ ]),
92
+ }), Args.required());
93
+ const validated = validateVercelUrl(project);
94
+ if (validated.type === 'error') {
95
+ return yield* BadArgsError.make({ message: validated.message });
96
+ }
97
+ yield* addOriginHandler('vercel', validated);
98
+ });
99
+ const handleNetlifyOrigin = Effect.fn(function* (opts) {
100
+ const site = yield* Args.text(opts, 'site').pipe(Args.prompt({
101
+ prompt: 'Netlify site name:',
102
+ placeholder: 'netlify-site-name',
103
+ modifyOutput: UI.modifiers.piped([
104
+ UI.modifiers.topPadding,
105
+ UI.modifiers.dimOnComplete,
106
+ ]),
107
+ }), Args.required());
108
+ const validated = validateNetlifyUrl(site);
109
+ if (validated.type === 'error') {
110
+ return yield* BadArgsError.make({ message: validated.message });
111
+ }
112
+ yield* addOriginHandler('netlify', validated);
113
+ });
114
+ const handleCustomSchemeOrigin = Effect.fn(function* (opts) {
115
+ const scheme = yield* Args.text(opts, 'scheme').pipe(Args.prompt({
116
+ prompt: 'App scheme:',
117
+ placeholder: 'app-scheme://',
118
+ modifyOutput: UI.modifiers.piped([
119
+ UI.modifiers.topPadding,
120
+ UI.modifiers.dimOnComplete,
121
+ ]),
122
+ }), Args.required());
123
+ const validated = validateCustomScheme(scheme);
124
+ if (validated.type === 'error') {
125
+ return yield* BadArgsError.make({ message: validated.message });
126
+ }
127
+ yield* addOriginHandler('custom-scheme', validated);
128
+ });
129
+ export const authOriginAddCmd = Effect.fn(function* (opts) {
130
+ const { yes } = yield* GlobalOpts;
131
+ if (!opts.type && yes) {
132
+ return yield* BadArgsError.make({
133
+ message: `Missing required value for --type. Expected one of: ${OriginTypeSchema.literals.join(', ')}`,
134
+ });
135
+ }
136
+ const originType = yield* Option.fromNullable(opts.type).pipe(Effect.catchTag('NoSuchElementException', () => runUIEffect(new UI.Select({
137
+ options: [
138
+ { label: 'Website', value: 'website' },
139
+ { label: 'Vercel previews', value: 'vercel' },
140
+ { label: 'Netlify previews', value: 'netlify' },
141
+ { label: 'App scheme', value: 'custom-scheme' },
142
+ ],
143
+ promptText: 'Select an origin type:',
144
+ modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),
145
+ }))), Effect.andThen((s) => Schema.decodeUnknown(OriginTypeSchema)(s)), Effect.catchTag('ParseError', () => BadArgsError.make({
146
+ message: `Invalid origin type, must be one of: ${OriginTypeSchema.literals.join(', ')}`,
147
+ })));
148
+ yield* Match.value(originType).pipe(Match.withReturnType(), Match.when('website', () => handleGenericOrigin(opts)), Match.when('vercel', () => handleVercelOrigin(opts)), Match.when('netlify', () => handleNetlifyOrigin(opts)), Match.when('custom-scheme', () => handleCustomSchemeOrigin(opts)), Match.exhaustive);
149
+ }, Effect.catchTag('BadArgsError', (e) => Effect.gen(function* () {
150
+ yield* Effect.logError(e.message);
151
+ yield* Effect.log(chalk.dim('hint: run `superlayer auth origin add --help` for available arguments'));
152
+ })));
153
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../../../src/commands/auth/origin/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAC5C,SAAS,EACT,QAAQ,EACR,SAAS,EACT,eAAe,CAChB,CAAC;AAQF,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAa,EAAE;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,OAAO,kBAAkB,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IACpD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAa,EAAE;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAa,EAAE;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC;AAC9D,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAAa,EAAE;IACxD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;IACvD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC1C,IAAiD,EACjD,SAAmC;IAEnC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC;QAC1C,OAAO,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;QAC9C,MAAM,EAAE,SAAS,CAAC,MAAM;KACzB,CAAC,CAAC;IAEH,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CACf,IAAI;QACF,KAAK,CACH;YACE,iBAAiB,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;YACjD,SAAS,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;YACxC,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE;SAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CACpD,CACJ,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC7C,IAA6B;IAE7B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAC5C,IAAI,CAAC,MAAM,CAAC;QACV,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,aAAa;QAC1B,YAAY,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;YAC/B,EAAE,CAAC,SAAS,CAAC,UAAU;YACvB,EAAE,CAAC,SAAS,CAAC,aAAa;SAC3B,CAAC;KACH,CAAC,EACF,IAAI,CAAC,QAAQ,EAAE,CAChB,CAAC;IAEF,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,IAA6B;IAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,CACpD,IAAI,CAAC,MAAM,CAAC;QACV,MAAM,EAAE,sBAAsB;QAC9B,WAAW,EAAE,qBAAqB;QAClC,YAAY,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;YAC/B,EAAE,CAAC,SAAS,CAAC,UAAU;YACvB,EAAE,CAAC,SAAS,CAAC,aAAa;SAC3B,CAAC;KACH,CAAC,EACF,IAAI,CAAC,QAAQ,EAAE,CAChB,CAAC;IAEF,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,CAAC,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC7C,IAA6B;IAE7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAC9C,IAAI,CAAC,MAAM,CAAC;QACV,MAAM,EAAE,oBAAoB;QAC5B,WAAW,EAAE,mBAAmB;QAChC,YAAY,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;YAC/B,EAAE,CAAC,SAAS,CAAC,UAAU;YACvB,EAAE,CAAC,SAAS,CAAC,aAAa;SAC3B,CAAC;KACH,CAAC,EACF,IAAI,CAAC,QAAQ,EAAE,CAChB,CAAC;IAEF,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAClD,IAA6B;IAE7B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAClD,IAAI,CAAC,MAAM,CAAC;QACV,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE,eAAe;QAC5B,YAAY,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;YAC/B,EAAE,CAAC,SAAS,CAAC,UAAU;YACvB,EAAE,CAAC,SAAS,CAAC,aAAa;SAC3B,CAAC;KACH,CAAC,EACF,IAAI,CAAC,QAAQ,EAAE,CAChB,CAAC;IAEF,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,CAAC,gBAAgB,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CACvC,QAAQ,CAAC,EACP,IAAwE;IAExE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IAClC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;YAC9B,OAAO,EAAE,uDAAuD,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SACvG,CAAC,CAAC;IACL,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAC3D,MAAM,CAAC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE,CAC7C,WAAW,CACT,IAAI,EAAE,CAAC,MAAM,CAAC;QACZ,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YACtC,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,QAAQ,EAAE;YAC7C,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAS,EAAE;YAC/C,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE;SAChD;QACD,UAAU,EAAE,wBAAwB;QACpC,YAAY,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;KAC/D,CAAC,CACH,CACF,EACD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAChE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE,CACjC,YAAY,CAAC,IAAI,CAAC;QAChB,OAAO,EAAE,wCAAwC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;KACxF,CAAC,CACH,CACF,CAAC;IAEF,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CACjC,KAAK,CAAC,cAAc,EAAiC,EACrD,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,EACtD,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,EACpD,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,EACtD,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,EACjE,KAAK,CAAC,UAAU,CACjB,CAAC;AACJ,CAAC,EACD,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CACpC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CACP,uEAAuE,CACxE,CACF,CAAC;AACJ,CAAC,CAAC,CACH,CACF,CAAC","sourcesContent":["import { Effect, Match, Option, Schema } from 'effect';\nimport type { authOriginAddDef, OptsFromCommand } from '../../../index.ts';\nimport { BadArgsError } from '../../../errors.ts';\nimport { GlobalOpts } from '../../../context/globalOpts.ts';\nimport { Args } from '../../../lib/args.ts';\nimport { runUIEffect } from '../../../lib/ui.ts';\nimport { addAuthorizedOrigin } from '../../../lib/oauth.ts';\nimport { UI } from '../../../ui/index.ts';\nimport chalk from 'chalk';\nimport boxen from 'boxen';\nimport { originDisplay, originSource } from './list.ts';\n\nexport const OriginTypeSchema = Schema.Literal(\n 'website',\n 'vercel',\n 'netlify',\n 'custom-scheme',\n);\n\ntype OriginParams = string[];\n\ntype Validated =\n | { type: 'success'; params: OriginParams }\n | { type: 'error'; message: string };\n\nconst validateGenericUrl = (input: string): Validated => {\n const trimmed = input.trim();\n try {\n const url = new URL(trimmed);\n const host = url.host;\n if (!host) {\n throw new Error('missing host');\n }\n if (host.split('.').length === 1 && !url.port) {\n throw new Error('invalid url');\n }\n return { type: 'success', params: [host] };\n } catch {\n if (!trimmed.startsWith('http')) {\n return validateGenericUrl(`http://${trimmed}`);\n }\n return { type: 'error', message: 'Invalid URL.' };\n }\n};\n\nconst validateNetlifyUrl = (input: string): Validated => {\n const trimmed = input.trim();\n if (!trimmed) {\n return { type: 'error', message: 'Netlify site name is required.' };\n }\n return { type: 'success', params: [trimmed] };\n};\n\nconst validateVercelUrl = (input: string): Validated => {\n const trimmed = input.trim();\n if (!trimmed) {\n return { type: 'error', message: 'Vercel project name is required.' };\n }\n return { type: 'success', params: ['vercel.app', trimmed] };\n};\n\nconst validateCustomScheme = (input: string): Validated => {\n const trimmed = input.trim();\n try {\n const url = new URL(trimmed);\n const scheme = url.protocol.slice(0, -1);\n return { type: 'success', params: [scheme] };\n } catch {\n return { type: 'error', message: 'Invalid scheme.' };\n }\n};\n\nconst addOriginHandler = Effect.fn(function* (\n type: Schema.Schema.Type<typeof OriginTypeSchema>,\n validated: { params: OriginParams },\n) {\n const response = yield* addAuthorizedOrigin({\n service: type === 'website' ? 'generic' : type,\n params: validated.params,\n });\n\n yield* Effect.log(\n '\\n' +\n boxen(\n [\n `Origin added: ${originDisplay(response.origin)}`,\n `Type: ${originSource(response.origin)}`,\n `ID: ${response.origin.id}`,\n ].join('\\n'),\n { dimBorder: true, padding: { right: 1, left: 1 } },\n ),\n );\n});\n\nconst handleGenericOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const url = yield* Args.text(opts, 'url').pipe(\n Args.prompt({\n prompt: 'Website URL:',\n placeholder: 'example.com',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n }),\n Args.required(),\n );\n\n const validated = validateGenericUrl(url);\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('website', validated);\n});\n\nconst handleVercelOrigin = Effect.fn(function* (opts: Record<string, unknown>) {\n const project = yield* Args.text(opts, 'project').pipe(\n Args.prompt({\n prompt: 'Vercel project name:',\n placeholder: 'vercel-project-name',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n }),\n Args.required(),\n );\n\n const validated = validateVercelUrl(project);\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('vercel', validated);\n});\n\nconst handleNetlifyOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const site = yield* Args.text(opts, 'site').pipe(\n Args.prompt({\n prompt: 'Netlify site name:',\n placeholder: 'netlify-site-name',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n }),\n Args.required(),\n );\n\n const validated = validateNetlifyUrl(site);\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('netlify', validated);\n});\n\nconst handleCustomSchemeOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const scheme = yield* Args.text(opts, 'scheme').pipe(\n Args.prompt({\n prompt: 'App scheme:',\n placeholder: 'app-scheme://',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n }),\n Args.required(),\n );\n\n const validated = validateCustomScheme(scheme);\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('custom-scheme', validated);\n});\n\nexport const authOriginAddCmd = Effect.fn(\n function* (\n opts: OptsFromCommand<typeof authOriginAddDef> & Record<string, unknown>,\n ) {\n const { yes } = yield* GlobalOpts;\n if (!opts.type && yes) {\n return yield* BadArgsError.make({\n message: `Missing required value for --type. Expected one of: ${OriginTypeSchema.literals.join(', ')}`,\n });\n }\n const originType = yield* Option.fromNullable(opts.type).pipe(\n Effect.catchTag('NoSuchElementException', () =>\n runUIEffect(\n new UI.Select({\n options: [\n { label: 'Website', value: 'website' },\n { label: 'Vercel previews', value: 'vercel' },\n { label: 'Netlify previews', value: 'netlify' },\n { label: 'App scheme', value: 'custom-scheme' },\n ],\n promptText: 'Select an origin type:',\n modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),\n }),\n ),\n ),\n Effect.andThen((s) => Schema.decodeUnknown(OriginTypeSchema)(s)),\n Effect.catchTag('ParseError', () =>\n BadArgsError.make({\n message: `Invalid origin type, must be one of: ${OriginTypeSchema.literals.join(', ')}`,\n }),\n ),\n );\n\n yield* Match.value(originType).pipe(\n Match.withReturnType<Effect.Effect<void, any, any>>(),\n Match.when('website', () => handleGenericOrigin(opts)),\n Match.when('vercel', () => handleVercelOrigin(opts)),\n Match.when('netlify', () => handleNetlifyOrigin(opts)),\n Match.when('custom-scheme', () => handleCustomSchemeOrigin(opts)),\n Match.exhaustive,\n );\n },\n Effect.catchTag('BadArgsError', (e) =>\n Effect.gen(function* () {\n yield* Effect.logError(e.message);\n yield* Effect.log(\n chalk.dim(\n 'hint: run `superlayer auth origin add --help` for available arguments',\n ),\n );\n }),\n ),\n);\n"]}
@@ -0,0 +1,8 @@
1
+ import { Effect } from 'effect';
2
+ import { BadArgsError } from '../../../errors.ts';
3
+ import { GlobalOpts } from '../../../context/globalOpts.ts';
4
+ export declare const authOriginDeleteCmd: (opts: {
5
+ id?: string | undefined;
6
+ app?: string | undefined;
7
+ }) => Effect.Effect<undefined, BadArgsError | import("../../../lib/ui.ts").UIError | import("effect/ParseResult").ParseError | import("../../../lib/http.ts").InstantHttpError | import("effect/Cause").TimeoutException | import("@effect/platform/HttpClientError").RequestError | import("@effect/platform/HttpClientError").ResponseError, GlobalOpts | import("../../../lib/http.ts").InstantHttpAuthed | import("../../../context/currentApp.ts").CurrentApp>;
8
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/origin/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAK5D,eAAO,MAAM,mBAAmB;;;mcAuC9B,CAAC"}
@@ -0,0 +1,38 @@
1
+ import chalk from 'chalk';
2
+ import { Effect } from 'effect';
3
+ import { BadArgsError } from "../../../errors.js";
4
+ import { getAppsAuth, removeAuthorizedOrigin } from "../../../lib/oauth.js";
5
+ import { GlobalOpts } from "../../../context/globalOpts.js";
6
+ import { runUIEffect } from "../../../lib/ui.js";
7
+ import { UI } from "../../../ui/index.js";
8
+ import { originDisplay, originSource } from "./list.js";
9
+ export const authOriginDeleteCmd = Effect.fn(function* (opts) {
10
+ const info = yield* getAppsAuth();
11
+ const origins = info.authorized_redirect_origins ?? [];
12
+ if (origins.length === 0) {
13
+ yield* Effect.log('No authorized redirect origins configured.');
14
+ return;
15
+ }
16
+ if (!opts.id) {
17
+ const { yes } = yield* GlobalOpts;
18
+ if (yes) {
19
+ return yield* BadArgsError.make({
20
+ message: 'Must specify --id',
21
+ });
22
+ }
23
+ const picked = yield* runUIEffect(new UI.Select({
24
+ options: origins.map((origin) => ({
25
+ label: `${originSource(origin)} — ${originDisplay(origin)} ` +
26
+ chalk.dim(`(${origin.id})`),
27
+ value: origin,
28
+ })),
29
+ promptText: 'Select an origin to delete:',
30
+ }));
31
+ yield* removeAuthorizedOrigin(picked.id);
32
+ }
33
+ if (opts.id) {
34
+ yield* removeAuthorizedOrigin(opts.id);
35
+ }
36
+ yield* Effect.log('Origin deleted!');
37
+ });
38
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../../src/commands/auth/origin/delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EACpD,IAAiD;IAEjD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,2BAA2B,IAAI,EAAE,CAAC;IAEvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;QAClC,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;gBAC9B,OAAO,EAAE,mBAAmB;aAC7B,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,WAAW,CAC/B,IAAI,EAAE,CAAC,MAAM,CAAC;YACZ,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAChC,KAAK,EACH,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,aAAa,CAAC,MAAM,CAAC,GAAG;oBACrD,KAAK,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC;gBAC7B,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YACH,UAAU,EAAE,6BAA6B;SAC1C,CAAC,CACH,CAAC;QAEF,KAAK,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;QACZ,KAAK,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC","sourcesContent":["import chalk from 'chalk';\nimport { Effect } from 'effect';\nimport type { authOriginDeleteDef, OptsFromCommand } from '../../../index.ts';\nimport { BadArgsError } from '../../../errors.ts';\nimport { getAppsAuth, removeAuthorizedOrigin } from '../../../lib/oauth.ts';\nimport { GlobalOpts } from '../../../context/globalOpts.ts';\nimport { runUIEffect } from '../../../lib/ui.ts';\nimport { UI } from '../../../ui/index.ts';\nimport { originDisplay, originSource } from './list.ts';\n\nexport const authOriginDeleteCmd = Effect.fn(function* (\n opts: OptsFromCommand<typeof authOriginDeleteDef>,\n) {\n const info = yield* getAppsAuth();\n const origins = info.authorized_redirect_origins ?? [];\n\n if (origins.length === 0) {\n yield* Effect.log('No authorized redirect origins configured.');\n return;\n }\n\n if (!opts.id) {\n const { yes } = yield* GlobalOpts;\n if (yes) {\n return yield* BadArgsError.make({\n message: 'Must specify --id',\n });\n }\n\n const picked = yield* runUIEffect(\n new UI.Select({\n options: origins.map((origin) => ({\n label:\n `${originSource(origin)} — ${originDisplay(origin)} ` +\n chalk.dim(`(${origin.id})`),\n value: origin,\n })),\n promptText: 'Select an origin to delete:',\n }),\n );\n\n yield* removeAuthorizedOrigin(picked.id);\n }\n\n if (opts.id) {\n yield* removeAuthorizedOrigin(opts.id);\n }\n\n yield* Effect.log('Origin deleted!');\n});\n"]}
@@ -0,0 +1,9 @@
1
+ import { Effect, Schema } from 'effect';
2
+ import { AuthorizedOrigin } from '../../../lib/oauth.ts';
3
+ export declare const originSource: (origin: Schema.Schema.Type<typeof AuthorizedOrigin>) => string;
4
+ export declare const originDisplay: (origin: Schema.Schema.Type<typeof AuthorizedOrigin>) => string;
5
+ export declare const authOriginListCmd: (_opts: {
6
+ app?: string | undefined;
7
+ json?: true | undefined;
8
+ }) => Effect.Effect<void, import("effect/ParseResult").ParseError | import("../../../lib/http.ts").InstantHttpError | import("effect/Cause").TimeoutException | import("@effect/platform/HttpClientError").RequestError | import("@effect/platform/HttpClientError").ResponseError, import("../../../lib/http.ts").InstantHttpAuthed | import("../../../context/currentApp.ts").CurrentApp>;
9
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/origin/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAe,MAAM,uBAAuB,CAAC;AAEtE,eAAO,MAAM,YAAY,GACvB,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,WAiBpD,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,WAcpD,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;2XAuB5B,CAAC"}
@@ -0,0 +1,52 @@
1
+ import chalk from 'chalk';
2
+ import { Effect, Schema } from 'effect';
3
+ import { AuthorizedOrigin, getAppsAuth } from "../../../lib/oauth.js";
4
+ export const originSource = (origin) => {
5
+ switch (origin.service) {
6
+ case 'generic':
7
+ return 'Website';
8
+ case 'netlify':
9
+ return 'Netlify site';
10
+ case 'vercel':
11
+ if (origin.params[0] !== 'vercel.app') {
12
+ return `Vercel project (${origin.params[0]})`;
13
+ }
14
+ return 'Vercel project';
15
+ case 'custom-scheme':
16
+ return 'Native app';
17
+ default:
18
+ return origin.service;
19
+ }
20
+ };
21
+ export const originDisplay = (origin) => {
22
+ switch (origin.service) {
23
+ case 'generic':
24
+ return origin.params[0];
25
+ case 'netlify':
26
+ return origin.params[0];
27
+ case 'vercel':
28
+ return origin.params[1];
29
+ case 'custom-scheme':
30
+ return `${origin.params[0]}://`;
31
+ default:
32
+ return origin.params[0];
33
+ }
34
+ };
35
+ export const authOriginListCmd = Effect.fn(function* (_opts) {
36
+ const info = yield* getAppsAuth();
37
+ if (_opts.json) {
38
+ yield* Effect.log(JSON.stringify(info.authorized_redirect_origins, null, 2));
39
+ return;
40
+ }
41
+ const origins = info.authorized_redirect_origins ?? [];
42
+ if (origins.length === 0) {
43
+ yield* Effect.log('No authorized redirect origins configured.');
44
+ return;
45
+ }
46
+ for (const origin of origins) {
47
+ yield* Effect.log(chalk.cyan(originDisplay(origin)));
48
+ yield* Effect.log(` Type: ${originSource(origin)}`);
49
+ yield* Effect.log(` ID: ${origin.id}`);
50
+ }
51
+ });
52
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/commands/auth/origin/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAmD,EACnD,EAAE;IACF,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,cAAc,CAAC;QACxB,KAAK,QAAQ;YACX,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,EAAE,CAAC;gBACtC,OAAO,mBAAmB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,CAAC;YACD,OAAO,gBAAgB,CAAC;QAC1B,KAAK,eAAe;YAClB,OAAO,YAAY,CAAC;QACtB;YACE,OAAO,MAAM,CAAC,OAAO,CAAC;IAC1B,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,MAAmD,EACnD,EAAE;IACF,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,KAAK,eAAe;YAClB,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QAClC;YACE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAClD,KAAgD;IAEhD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,2BAA2B,EAAE,IAAI,EAAE,CAAC,CAAC,CAC1D,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,2BAA2B,IAAI,EAAE,CAAC;IAEvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrD,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC,CAAC,CAAC","sourcesContent":["import chalk from 'chalk';\nimport { Effect, Schema } from 'effect';\nimport type { authOriginListDef, OptsFromCommand } from '../../../index.ts';\nimport { AuthorizedOrigin, getAppsAuth } from '../../../lib/oauth.ts';\n\nexport const originSource = (\n origin: Schema.Schema.Type<typeof AuthorizedOrigin>,\n) => {\n switch (origin.service) {\n case 'generic':\n return 'Website';\n case 'netlify':\n return 'Netlify site';\n case 'vercel':\n if (origin.params[0] !== 'vercel.app') {\n return `Vercel project (${origin.params[0]})`;\n }\n return 'Vercel project';\n case 'custom-scheme':\n return 'Native app';\n default:\n return origin.service;\n }\n};\n\nexport const originDisplay = (\n origin: Schema.Schema.Type<typeof AuthorizedOrigin>,\n) => {\n switch (origin.service) {\n case 'generic':\n return origin.params[0];\n case 'netlify':\n return origin.params[0];\n case 'vercel':\n return origin.params[1];\n case 'custom-scheme':\n return `${origin.params[0]}://`;\n default:\n return origin.params[0];\n }\n};\n\nexport const authOriginListCmd = Effect.fn(function* (\n _opts: OptsFromCommand<typeof authOriginListDef>,\n) {\n const info = yield* getAppsAuth();\n if (_opts.json) {\n yield* Effect.log(\n JSON.stringify(info.authorized_redirect_origins, null, 2),\n );\n return;\n }\n\n const origins = info.authorized_redirect_origins ?? [];\n\n if (origins.length === 0) {\n yield* Effect.log('No authorized redirect origins configured.');\n return;\n }\n\n for (const origin of origins) {\n yield* Effect.log(chalk.cyan(originDisplay(origin)));\n yield* Effect.log(` Type: ${originSource(origin)}`);\n yield* Effect.log(` ID: ${origin.id}`);\n }\n});\n"]}
@@ -0,0 +1,10 @@
1
+ import { Effect } from 'effect';
2
+ import { BadArgsError } from '../../errors.ts';
3
+ import { GlobalOpts } from '../../context/globalOpts.ts';
4
+ import { PlatformApiError } from '../../context/platformApi.ts';
5
+ export declare const backupDownloadCmd: (backupId: string | undefined, opts: {
6
+ app?: string | undefined;
7
+ latest?: true | undefined;
8
+ out?: string | undefined;
9
+ }) => Effect.Effect<undefined, BadArgsError | import("../../lib/ui.ts").UIError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, GlobalOpts | import("../../context/authToken.ts").AuthToken | import("../../context/currentApp.ts").CurrentApp>;
10
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/commands/backup/download.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAShC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAyJhE,eAAO,MAAM,iBAAiB;;;;wSA+D5B,CAAC"}
@@ -0,0 +1,174 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { Effect } from 'effect';
5
+ import { backupZipName, estimateZipSize, formatFileSize, } from '@superlayer/platform';
6
+ import { BadArgsError } from "../../errors.js";
7
+ import { GlobalOpts } from "../../context/globalOpts.js";
8
+ import { PlatformApiError } from "../../context/platformApi.js";
9
+ import { buildBackupsManager, useBackupsManager } from "../../lib/backups.js";
10
+ import { downloadBackupToFile, } from "../../lib/backupDownload.js";
11
+ import { promptOk, runUIEffect } from "../../lib/ui.js";
12
+ import { onTerminate, renderUnwrap } from "../../ui/lib.js";
13
+ import { UI } from "../../ui/index.js";
14
+ import { relativeTime, renderBackupsTable, stripControlChars } from "./list.js";
15
+ const pickBackup = (backups, backupId, opts) => Effect.gen(function* () {
16
+ if (backupId && opts.latest) {
17
+ return yield* BadArgsError.make({
18
+ message: 'Pass either a backup id or --latest, not both.',
19
+ });
20
+ }
21
+ if (backupId) {
22
+ const found = backups.find((b) => b.id === backupId);
23
+ if (!found) {
24
+ return yield* BadArgsError.make({
25
+ message: `No backup found with id ${backupId}.`,
26
+ });
27
+ }
28
+ return found;
29
+ }
30
+ // The server returns newest first; sort anyway so --latest can't silently
31
+ // pick the wrong one.
32
+ const sorted = [...backups].sort((a, b) => b.backupAt.getTime() - a.backupAt.getTime());
33
+ if (opts.latest) {
34
+ return sorted[0];
35
+ }
36
+ const { yes } = yield* GlobalOpts;
37
+ if (yes) {
38
+ return yield* BadArgsError.make({
39
+ message: 'Must specify a backup id or --latest',
40
+ });
41
+ }
42
+ // The picker stays lean: id, age, and description are what you choose
43
+ // by, in the table's column order. Sizes and expiry show up in the
44
+ // confirm table right after, where headers explain them.
45
+ const cells = sorted.map((backup) => [
46
+ backup.id,
47
+ `created ${relativeTime(backup.backupAt)}`,
48
+ backup.description ? stripControlChars(backup.description) : '',
49
+ ]);
50
+ const widths = cells[0].map((_, i) => Math.max(...cells.map((row) => row[i].length)));
51
+ return yield* runUIEffect(new UI.Select({
52
+ options: sorted.map((backup, idx) => ({
53
+ label: cells[idx].map((cell, i) => cell.padEnd(widths[i])).join(' '),
54
+ value: backup,
55
+ })),
56
+ promptText: 'Select a backup to download:',
57
+ }));
58
+ });
59
+ // One compact line for the spinner as the pipeline ticks.
60
+ function progressLine(p) {
61
+ const parts = [];
62
+ parts.push(p.entitiesTotal == null
63
+ ? 'listing namespaces…'
64
+ : `namespaces ${p.entitiesCompleted}/${p.entitiesTotal}`);
65
+ if (p.filesTotal !== 0) {
66
+ parts.push(p.filesTotal == null
67
+ ? 'listing storage files…'
68
+ : `storage files ${p.filesCompleted}/${p.filesTotal}`);
69
+ }
70
+ let bytes = formatFileSize(p.zipBytes);
71
+ if (p.bytesTotal != null && p.bytesTotal > 0) {
72
+ const pct = Math.min(100, Math.round((p.bytesRead / p.bytesTotal) * 100));
73
+ bytes += ` (${pct}%)`;
74
+ }
75
+ parts.push(bytes);
76
+ const currentEntry = p.currentEntity || p.currentFile;
77
+ if (currentEntry) {
78
+ parts.push(currentEntry);
79
+ }
80
+ let line = parts.join(' · ');
81
+ // The spinner prefixes a frame glyph; truncate so the line can't wrap.
82
+ const width = (process.stdout.columns || 80) - 4;
83
+ if (line.length > width) {
84
+ line = line.slice(0, Math.max(0, width - 1)) + '…';
85
+ }
86
+ return line;
87
+ }
88
+ // Returns null when the download was cancelled. While the spinner is
89
+ // attached the terminal is raw, so ctrl-c arrives through the UI's
90
+ // terminate hook rather than SIGINT; both routes abort the same controller
91
+ // and the pipeline removes its partial file before we return. Outside the
92
+ // spinner (non-TTY runs), SIGINT covers it.
93
+ async function runDownload(manager, backup, outPath) {
94
+ const controller = new AbortController();
95
+ const onSigint = () => controller.abort();
96
+ process.once('SIGINT', onSigint);
97
+ onTerminate(() => controller.abort());
98
+ try {
99
+ let spinner = null;
100
+ // Settled into a sentinel so the spinner always disappears cleanly and
101
+ // cancellation/error output stays with the command below.
102
+ const settled = downloadBackupToFile({
103
+ manager,
104
+ backup,
105
+ outPath,
106
+ signal: controller.signal,
107
+ onProgress: (p) => spinner?.updateText(progressLine(p)),
108
+ }).then((result) => ({ result, error: null }), (error) => ({ result: null, error }));
109
+ if (process.stdout.isTTY) {
110
+ spinner = new UI.Spinner({
111
+ promise: settled,
112
+ workingText: 'Preparing download…',
113
+ disappearWhenDone: true,
114
+ });
115
+ await renderUnwrap(spinner);
116
+ }
117
+ const { result, error } = await settled;
118
+ if (error) {
119
+ if (error?.name === 'AbortError')
120
+ return null;
121
+ throw error;
122
+ }
123
+ return result;
124
+ }
125
+ finally {
126
+ process.removeListener('SIGINT', onSigint);
127
+ onTerminate(undefined);
128
+ }
129
+ }
130
+ export const backupDownloadCmd = Effect.fn(function* (backupId, opts) {
131
+ const backups = yield* useBackupsManager((m) => m.list(), 'Error listing backups');
132
+ if (backups.length === 0) {
133
+ yield* Effect.log('No backups yet.');
134
+ return;
135
+ }
136
+ const backup = yield* pickBackup(backups, backupId, opts);
137
+ const outPath = path.resolve(opts.out ?? backupZipName(backup));
138
+ // Catch this before the download runs, not at the final rename.
139
+ if (existsSync(outPath) && statSync(outPath).isDirectory()) {
140
+ return yield* BadArgsError.make({
141
+ message: `${outPath} is a directory.`,
142
+ });
143
+ }
144
+ yield* renderBackupsTable([backup]);
145
+ const sizes = estimateZipSize(backup);
146
+ if (sizes) {
147
+ yield* Effect.log(`The zip file will be between ${formatFileSize(sizes.min)} and ${formatFileSize(sizes.max)}, depending on the compression ratio.`);
148
+ }
149
+ yield* Effect.log(chalk.dim(`Saving to ${outPath} (pass -o to change).`));
150
+ const ok = yield* promptOk({ promptText: 'Download this backup?' });
151
+ if (!ok)
152
+ return;
153
+ if (existsSync(outPath)) {
154
+ const overwrite = yield* promptOk({
155
+ promptText: `${path.basename(outPath)} already exists. Overwrite?`,
156
+ });
157
+ if (!overwrite)
158
+ return;
159
+ }
160
+ const manager = yield* buildBackupsManager;
161
+ const result = yield* Effect.tryPromise({
162
+ try: () => runDownload(manager, backup, outPath),
163
+ catch: (e) => new PlatformApiError({ message: 'Error downloading backup', cause: e }),
164
+ });
165
+ if (result === null) {
166
+ yield* Effect.log('Download cancelled.');
167
+ return;
168
+ }
169
+ const filesPart = result.files > 0
170
+ ? ` and ${result.files.toLocaleString()} storage files`
171
+ : '';
172
+ yield* Effect.log(`Saved ${result.entities.toLocaleString()} namespaces${filesPart} (${formatFileSize(result.zipBytes)})`);
173
+ });
174
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/commands/backup/download.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport chalk from 'chalk';\nimport { Effect } from 'effect';\nimport {\n backupZipName,\n estimateZipSize,\n formatFileSize,\n type AppBackup,\n type BackupsManager,\n} from '@superlayer/platform';\nimport type { backupDownloadDef, OptsFromCommand } from '../../index.ts';\nimport { BadArgsError } from '../../errors.ts';\nimport { GlobalOpts } from '../../context/globalOpts.ts';\nimport { PlatformApiError } from '../../context/platformApi.ts';\nimport { buildBackupsManager, useBackupsManager } from '../../lib/backups.ts';\nimport {\n downloadBackupToFile,\n type BackupDownloadProgress,\n type BackupDownloadResult,\n} from '../../lib/backupDownload.ts';\nimport { promptOk, runUIEffect } from '../../lib/ui.ts';\nimport { onTerminate, renderUnwrap } from '../../ui/lib.ts';\nimport { UI } from '../../ui/index.ts';\nimport { relativeTime, renderBackupsTable, stripControlChars } from './list.ts';\n\nconst pickBackup = (\n backups: AppBackup[],\n backupId: string | undefined,\n opts: { latest?: boolean },\n) =>\n Effect.gen(function* () {\n if (backupId && opts.latest) {\n return yield* BadArgsError.make({\n message: 'Pass either a backup id or --latest, not both.',\n });\n }\n if (backupId) {\n const found = backups.find((b) => b.id === backupId);\n if (!found) {\n return yield* BadArgsError.make({\n message: `No backup found with id ${backupId}.`,\n });\n }\n return found;\n }\n\n // The server returns newest first; sort anyway so --latest can't silently\n // pick the wrong one.\n const sorted = [...backups].sort(\n (a, b) => b.backupAt.getTime() - a.backupAt.getTime(),\n );\n if (opts.latest) {\n return sorted[0];\n }\n\n const { yes } = yield* GlobalOpts;\n if (yes) {\n return yield* BadArgsError.make({\n message: 'Must specify a backup id or --latest',\n });\n }\n\n // The picker stays lean: id, age, and description are what you choose\n // by, in the table's column order. Sizes and expiry show up in the\n // confirm table right after, where headers explain them.\n const cells = sorted.map((backup) => [\n backup.id,\n `created ${relativeTime(backup.backupAt)}`,\n backup.description ? stripControlChars(backup.description) : '',\n ]);\n const widths = cells[0].map((_, i) =>\n Math.max(...cells.map((row) => row[i].length)),\n );\n return yield* runUIEffect(\n new UI.Select({\n options: sorted.map((backup, idx) => ({\n label: cells[idx].map((cell, i) => cell.padEnd(widths[i])).join(' '),\n value: backup,\n })),\n promptText: 'Select a backup to download:',\n }),\n );\n });\n\n// One compact line for the spinner as the pipeline ticks.\nfunction progressLine(p: BackupDownloadProgress): string {\n const parts: string[] = [];\n parts.push(\n p.entitiesTotal == null\n ? 'listing namespaces…'\n : `namespaces ${p.entitiesCompleted}/${p.entitiesTotal}`,\n );\n if (p.filesTotal !== 0) {\n parts.push(\n p.filesTotal == null\n ? 'listing storage files…'\n : `storage files ${p.filesCompleted}/${p.filesTotal}`,\n );\n }\n let bytes = formatFileSize(p.zipBytes);\n if (p.bytesTotal != null && p.bytesTotal > 0) {\n const pct = Math.min(100, Math.round((p.bytesRead / p.bytesTotal) * 100));\n bytes += ` (${pct}%)`;\n }\n parts.push(bytes);\n const currentEntry = p.currentEntity || p.currentFile;\n if (currentEntry) {\n parts.push(currentEntry);\n }\n let line = parts.join(' · ');\n // The spinner prefixes a frame glyph; truncate so the line can't wrap.\n const width = (process.stdout.columns || 80) - 4;\n if (line.length > width) {\n line = line.slice(0, Math.max(0, width - 1)) + '…';\n }\n return line;\n}\n\n// Returns null when the download was cancelled. While the spinner is\n// attached the terminal is raw, so ctrl-c arrives through the UI's\n// terminate hook rather than SIGINT; both routes abort the same controller\n// and the pipeline removes its partial file before we return. Outside the\n// spinner (non-TTY runs), SIGINT covers it.\nasync function runDownload(\n manager: BackupsManager,\n backup: AppBackup,\n outPath: string,\n): Promise<BackupDownloadResult | null> {\n const controller = new AbortController();\n const onSigint = () => controller.abort();\n process.once('SIGINT', onSigint);\n onTerminate(() => controller.abort());\n try {\n let spinner: UI.Spinner<unknown> | null = null;\n // Settled into a sentinel so the spinner always disappears cleanly and\n // cancellation/error output stays with the command below.\n const settled = downloadBackupToFile({\n manager,\n backup,\n outPath,\n signal: controller.signal,\n onProgress: (p) => spinner?.updateText(progressLine(p)),\n }).then(\n (result) => ({ result, error: null as unknown }),\n (error: unknown) => ({ result: null, error }),\n );\n if (process.stdout.isTTY) {\n spinner = new UI.Spinner({\n promise: settled,\n workingText: 'Preparing download…',\n disappearWhenDone: true,\n });\n await renderUnwrap(spinner);\n }\n const { result, error } = await settled;\n if (error) {\n if ((error as { name?: string })?.name === 'AbortError') return null;\n throw error;\n }\n return result;\n } finally {\n process.removeListener('SIGINT', onSigint);\n onTerminate(undefined);\n }\n}\n\nexport const backupDownloadCmd = Effect.fn(function* (\n backupId: string | undefined,\n opts: OptsFromCommand<typeof backupDownloadDef>,\n) {\n const backups = yield* useBackupsManager(\n (m) => m.list(),\n 'Error listing backups',\n );\n\n if (backups.length === 0) {\n yield* Effect.log('No backups yet.');\n return;\n }\n\n const backup = yield* pickBackup(backups, backupId, opts);\n\n const outPath = path.resolve(opts.out ?? backupZipName(backup));\n // Catch this before the download runs, not at the final rename.\n if (existsSync(outPath) && statSync(outPath).isDirectory()) {\n return yield* BadArgsError.make({\n message: `${outPath} is a directory.`,\n });\n }\n\n yield* renderBackupsTable([backup]);\n const sizes = estimateZipSize(backup);\n if (sizes) {\n yield* Effect.log(\n `The zip file will be between ${formatFileSize(sizes.min)} and ${formatFileSize(sizes.max)}, depending on the compression ratio.`,\n );\n }\n yield* Effect.log(chalk.dim(`Saving to ${outPath} (pass -o to change).`));\n\n const ok = yield* promptOk({ promptText: 'Download this backup?' });\n if (!ok) return;\n\n if (existsSync(outPath)) {\n const overwrite = yield* promptOk({\n promptText: `${path.basename(outPath)} already exists. Overwrite?`,\n });\n if (!overwrite) return;\n }\n\n const manager = yield* buildBackupsManager;\n\n const result = yield* Effect.tryPromise({\n try: () => runDownload(manager, backup, outPath),\n catch: (e) =>\n new PlatformApiError({ message: 'Error downloading backup', cause: e }),\n });\n\n if (result === null) {\n yield* Effect.log('Download cancelled.');\n return;\n }\n\n const filesPart =\n result.files > 0\n ? ` and ${result.files.toLocaleString()} storage files`\n : '';\n yield* Effect.log(\n `Saved ${result.entities.toLocaleString()} namespaces${filesPart} (${formatFileSize(result.zipBytes)})`,\n );\n});\n"]}
@@ -0,0 +1,11 @@
1
+ import { Effect } from 'effect';
2
+ import { type AppBackup } from '@superlayer/platform';
3
+ export declare const formatBackupDate: (date: Date) => string;
4
+ export declare const stripControlChars: (s: string) => string;
5
+ export declare const relativeTime: (date: Date) => string;
6
+ export declare const renderBackupsTable: (backups: AppBackup[]) => Effect.Effect<void, never, never>;
7
+ export declare const backupListCmd: (opts: {
8
+ app?: string | undefined;
9
+ json?: true | undefined;
10
+ }) => Effect.Effect<void, import("../../errors.ts").BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | import("../../context/platformApi.ts").PlatformApiError, import("../../context/authToken.ts").AuthToken | import("../../context/currentApp.ts").CurrentApp>;
11
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/backup/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItE,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,WACiB,CAAC;AAI7D,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,WAA8B,CAAC;AAG1E,eAAO,MAAM,YAAY,GAAI,MAAM,IAAI,KAAG,MAezC,CAAC;AAIF,eAAO,MAAM,kBAAkB,GAAI,SAAS,SAAS,EAAE,sCAmCnD,CAAC;AAEL,eAAO,MAAM,aAAa;;;mTAuBxB,CAAC"}