@scalebun-release/cli 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/bin/scalebun.js +2 -0
  2. package/lib/api/client.d.ts +52 -0
  3. package/lib/api/client.d.ts.map +1 -0
  4. package/lib/api/client.js +335 -0
  5. package/lib/api/client.js.map +1 -0
  6. package/lib/commands/ci-init.d.ts +3 -0
  7. package/lib/commands/ci-init.d.ts.map +1 -0
  8. package/lib/commands/ci-init.js +348 -0
  9. package/lib/commands/ci-init.js.map +1 -0
  10. package/lib/commands/doctor.d.ts +31 -0
  11. package/lib/commands/doctor.d.ts.map +1 -0
  12. package/lib/commands/doctor.js +559 -0
  13. package/lib/commands/doctor.js.map +1 -0
  14. package/lib/commands/launch.d.ts +3 -0
  15. package/lib/commands/launch.d.ts.map +1 -0
  16. package/lib/commands/launch.js +23 -0
  17. package/lib/commands/launch.js.map +1 -0
  18. package/lib/commands/link.d.ts +16 -0
  19. package/lib/commands/link.d.ts.map +1 -0
  20. package/lib/commands/link.js +164 -0
  21. package/lib/commands/link.js.map +1 -0
  22. package/lib/commands/login.d.ts +12 -0
  23. package/lib/commands/login.d.ts.map +1 -0
  24. package/lib/commands/login.js +124 -0
  25. package/lib/commands/login.js.map +1 -0
  26. package/lib/commands/migrate-codepush.d.ts +13 -0
  27. package/lib/commands/migrate-codepush.d.ts.map +1 -0
  28. package/lib/commands/migrate-codepush.js +98 -0
  29. package/lib/commands/migrate-codepush.js.map +1 -0
  30. package/lib/commands/ota-bundle.d.ts +22 -0
  31. package/lib/commands/ota-bundle.d.ts.map +1 -0
  32. package/lib/commands/ota-bundle.js +253 -0
  33. package/lib/commands/ota-bundle.js.map +1 -0
  34. package/lib/commands/ota-channels.d.ts +3 -0
  35. package/lib/commands/ota-channels.d.ts.map +1 -0
  36. package/lib/commands/ota-channels.js +231 -0
  37. package/lib/commands/ota-channels.js.map +1 -0
  38. package/lib/commands/ota-delete-bundle.d.ts +16 -0
  39. package/lib/commands/ota-delete-bundle.d.ts.map +1 -0
  40. package/lib/commands/ota-delete-bundle.js +96 -0
  41. package/lib/commands/ota-delete-bundle.js.map +1 -0
  42. package/lib/commands/ota-inspect.d.ts +3 -0
  43. package/lib/commands/ota-inspect.d.ts.map +1 -0
  44. package/lib/commands/ota-inspect.js +258 -0
  45. package/lib/commands/ota-inspect.js.map +1 -0
  46. package/lib/commands/ota-keys.d.ts +91 -0
  47. package/lib/commands/ota-keys.d.ts.map +1 -0
  48. package/lib/commands/ota-keys.js +765 -0
  49. package/lib/commands/ota-keys.js.map +1 -0
  50. package/lib/commands/ota-promote.d.ts +3 -0
  51. package/lib/commands/ota-promote.d.ts.map +1 -0
  52. package/lib/commands/ota-promote.js +194 -0
  53. package/lib/commands/ota-promote.js.map +1 -0
  54. package/lib/commands/ota-publish.d.ts +26 -0
  55. package/lib/commands/ota-publish.d.ts.map +1 -0
  56. package/lib/commands/ota-publish.js +892 -0
  57. package/lib/commands/ota-publish.js.map +1 -0
  58. package/lib/commands/ota-rollout.d.ts +3 -0
  59. package/lib/commands/ota-rollout.d.ts.map +1 -0
  60. package/lib/commands/ota-rollout.js +265 -0
  61. package/lib/commands/ota-rollout.js.map +1 -0
  62. package/lib/commands/ota-sign.d.ts +19 -0
  63. package/lib/commands/ota-sign.d.ts.map +1 -0
  64. package/lib/commands/ota-sign.js +245 -0
  65. package/lib/commands/ota-sign.js.map +1 -0
  66. package/lib/commands/push-apns.d.ts +3 -0
  67. package/lib/commands/push-apns.d.ts.map +1 -0
  68. package/lib/commands/push-apns.js +166 -0
  69. package/lib/commands/push-apns.js.map +1 -0
  70. package/lib/commands/quickstart.d.ts +4 -0
  71. package/lib/commands/quickstart.d.ts.map +1 -0
  72. package/lib/commands/quickstart.js +672 -0
  73. package/lib/commands/quickstart.js.map +1 -0
  74. package/lib/commands/shell.d.ts +28 -0
  75. package/lib/commands/shell.d.ts.map +1 -0
  76. package/lib/commands/shell.js +512 -0
  77. package/lib/commands/shell.js.map +1 -0
  78. package/lib/commands/tls-pins.d.ts +27 -0
  79. package/lib/commands/tls-pins.d.ts.map +1 -0
  80. package/lib/commands/tls-pins.js +209 -0
  81. package/lib/commands/tls-pins.js.map +1 -0
  82. package/lib/index.d.ts +2 -0
  83. package/lib/index.d.ts.map +1 -0
  84. package/lib/index.js +233 -0
  85. package/lib/index.js.map +1 -0
  86. package/lib/ui/banner.d.ts +23 -0
  87. package/lib/ui/banner.d.ts.map +1 -0
  88. package/lib/ui/banner.js +162 -0
  89. package/lib/ui/banner.js.map +1 -0
  90. package/lib/ui/graphics.d.ts +18 -0
  91. package/lib/ui/graphics.d.ts.map +1 -0
  92. package/lib/ui/graphics.js +134 -0
  93. package/lib/ui/graphics.js.map +1 -0
  94. package/lib/ui/mark.d.ts +4 -0
  95. package/lib/ui/mark.d.ts.map +1 -0
  96. package/lib/ui/mark.js +21 -0
  97. package/lib/ui/mark.js.map +1 -0
  98. package/lib/ui/menu.d.ts +109 -0
  99. package/lib/ui/menu.d.ts.map +1 -0
  100. package/lib/ui/menu.js +314 -0
  101. package/lib/ui/menu.js.map +1 -0
  102. package/lib/ui/sixel.d.ts +6 -0
  103. package/lib/ui/sixel.d.ts.map +1 -0
  104. package/lib/ui/sixel.js +9 -0
  105. package/lib/ui/sixel.js.map +1 -0
  106. package/lib/utils/apps.d.ts +29 -0
  107. package/lib/utils/apps.d.ts.map +1 -0
  108. package/lib/utils/apps.js +19 -0
  109. package/lib/utils/apps.js.map +1 -0
  110. package/lib/utils/browser.d.ts +9 -0
  111. package/lib/utils/browser.d.ts.map +1 -0
  112. package/lib/utils/browser.js +39 -0
  113. package/lib/utils/browser.js.map +1 -0
  114. package/lib/utils/bundle.d.ts +153 -0
  115. package/lib/utils/bundle.d.ts.map +1 -0
  116. package/lib/utils/bundle.js +459 -0
  117. package/lib/utils/bundle.js.map +1 -0
  118. package/lib/utils/bundleStore.d.ts +128 -0
  119. package/lib/utils/bundleStore.d.ts.map +1 -0
  120. package/lib/utils/bundleStore.js +250 -0
  121. package/lib/utils/bundleStore.js.map +1 -0
  122. package/lib/utils/context.d.ts +88 -0
  123. package/lib/utils/context.d.ts.map +1 -0
  124. package/lib/utils/context.js +247 -0
  125. package/lib/utils/context.js.map +1 -0
  126. package/lib/utils/credentials.d.ts +59 -0
  127. package/lib/utils/credentials.d.ts.map +1 -0
  128. package/lib/utils/credentials.js +147 -0
  129. package/lib/utils/credentials.js.map +1 -0
  130. package/lib/utils/guide.d.ts +63 -0
  131. package/lib/utils/guide.d.ts.map +1 -0
  132. package/lib/utils/guide.js +191 -0
  133. package/lib/utils/guide.js.map +1 -0
  134. package/lib/utils/hash.d.ts +3 -0
  135. package/lib/utils/hash.d.ts.map +1 -0
  136. package/lib/utils/hash.js +44 -0
  137. package/lib/utils/hash.js.map +1 -0
  138. package/lib/utils/native-id.d.ts +17 -0
  139. package/lib/utils/native-id.d.ts.map +1 -0
  140. package/lib/utils/native-id.js +105 -0
  141. package/lib/utils/native-id.js.map +1 -0
  142. package/lib/utils/output.d.ts +96 -0
  143. package/lib/utils/output.d.ts.map +1 -0
  144. package/lib/utils/output.js +135 -0
  145. package/lib/utils/output.js.map +1 -0
  146. package/lib/utils/prompt.d.ts +106 -0
  147. package/lib/utils/prompt.d.ts.map +1 -0
  148. package/lib/utils/prompt.js +457 -0
  149. package/lib/utils/prompt.js.map +1 -0
  150. package/lib/utils/provenance.d.ts +30 -0
  151. package/lib/utils/provenance.d.ts.map +1 -0
  152. package/lib/utils/provenance.js +157 -0
  153. package/lib/utils/provenance.js.map +1 -0
  154. package/lib/utils/resolve.d.ts +81 -0
  155. package/lib/utils/resolve.d.ts.map +1 -0
  156. package/lib/utils/resolve.js +139 -0
  157. package/lib/utils/resolve.js.map +1 -0
  158. package/lib/utils/sdkBin.d.ts +18 -0
  159. package/lib/utils/sdkBin.d.ts.map +1 -0
  160. package/lib/utils/sdkBin.js +76 -0
  161. package/lib/utils/sdkBin.js.map +1 -0
  162. package/lib/utils/signer.d.ts +94 -0
  163. package/lib/utils/signer.d.ts.map +1 -0
  164. package/lib/utils/signer.js +230 -0
  165. package/lib/utils/signer.js.map +1 -0
  166. package/lib/utils/signing.d.ts +102 -0
  167. package/lib/utils/signing.d.ts.map +1 -0
  168. package/lib/utils/signing.js +229 -0
  169. package/lib/utils/signing.js.map +1 -0
  170. package/lib/utils/transportSecurity.d.ts +36 -0
  171. package/lib/utils/transportSecurity.d.ts.map +1 -0
  172. package/lib/utils/transportSecurity.js +74 -0
  173. package/lib/utils/transportSecurity.js.map +1 -0
  174. package/lib/utils/trustAnchor.d.ts +109 -0
  175. package/lib/utils/trustAnchor.d.ts.map +1 -0
  176. package/lib/utils/trustAnchor.js +169 -0
  177. package/lib/utils/trustAnchor.js.map +1 -0
  178. package/lib/utils/ui.d.ts +12 -0
  179. package/lib/utils/ui.d.ts.map +1 -0
  180. package/lib/utils/ui.js +60 -0
  181. package/lib/utils/ui.js.map +1 -0
  182. package/lib/utils/validate.d.ts +62 -0
  183. package/lib/utils/validate.d.ts.map +1 -0
  184. package/lib/utils/validate.js +189 -0
  185. package/lib/utils/validate.js.map +1 -0
  186. package/lib/vendor/ota-protocol/base64.d.ts +11 -0
  187. package/lib/vendor/ota-protocol/base64.d.ts.map +1 -0
  188. package/lib/vendor/ota-protocol/base64.js +39 -0
  189. package/lib/vendor/ota-protocol/base64.js.map +1 -0
  190. package/lib/vendor/ota-protocol/codec.d.ts +26 -0
  191. package/lib/vendor/ota-protocol/codec.d.ts.map +1 -0
  192. package/lib/vendor/ota-protocol/codec.js +349 -0
  193. package/lib/vendor/ota-protocol/codec.js.map +1 -0
  194. package/lib/vendor/ota-protocol/hex.d.ts +8 -0
  195. package/lib/vendor/ota-protocol/hex.d.ts.map +1 -0
  196. package/lib/vendor/ota-protocol/hex.js +31 -0
  197. package/lib/vendor/ota-protocol/hex.js.map +1 -0
  198. package/lib/vendor/ota-protocol/index.d.ts +17 -0
  199. package/lib/vendor/ota-protocol/index.d.ts.map +1 -0
  200. package/lib/vendor/ota-protocol/index.js +41 -0
  201. package/lib/vendor/ota-protocol/index.js.map +1 -0
  202. package/lib/vendor/ota-protocol/limits.d.ts +39 -0
  203. package/lib/vendor/ota-protocol/limits.d.ts.map +1 -0
  204. package/lib/vendor/ota-protocol/limits.js +42 -0
  205. package/lib/vendor/ota-protocol/limits.js.map +1 -0
  206. package/lib/vendor/ota-protocol/types.d.ts +73 -0
  207. package/lib/vendor/ota-protocol/types.d.ts.map +1 -0
  208. package/lib/vendor/ota-protocol/types.js +24 -0
  209. package/lib/vendor/ota-protocol/types.js.map +1 -0
  210. package/package.json +37 -0
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerOtaBundleCommand = registerOtaBundleCommand;
37
+ const crypto = __importStar(require("crypto"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const bundle_1 = require("../utils/bundle");
41
+ const validate_1 = require("../utils/validate");
42
+ const provenance_1 = require("../utils/provenance");
43
+ const bundleStore_1 = require("../utils/bundleStore");
44
+ /**
45
+ * Ensure that the bundles folder and its artifacts are ignored by git.
46
+ */
47
+ function ensureBundlesGitIgnored(bundleFilePath) {
48
+ const bundleDir = path.dirname(bundleFilePath);
49
+ if (!fs.existsSync(bundleDir)) {
50
+ fs.mkdirSync(bundleDir, { recursive: true });
51
+ }
52
+ let updatedGitignore = false;
53
+ // 1. Inside the bundles directory itself, create a .gitignore so all files are ignored by default
54
+ const baseDirName = path.basename(bundleDir).toLowerCase();
55
+ if (baseDirName === 'bundles' || baseDirName === 'bundels') {
56
+ const localGitignore = path.join(bundleDir, '.gitignore');
57
+ if (!fs.existsSync(localGitignore)) {
58
+ try {
59
+ fs.writeFileSync(localGitignore, '# Ignore all bundle files in this directory\n*\n!.gitignore\n', 'utf8');
60
+ }
61
+ catch {
62
+ /* ignore */
63
+ }
64
+ }
65
+ }
66
+ // 2. Also ensure root project .gitignore ignores bundles/
67
+ let curr = process.cwd();
68
+ for (let i = 0; i < 5; i++) {
69
+ const gitignorePath = path.join(curr, '.gitignore');
70
+ const isGitRepo = fs.existsSync(path.join(curr, '.git'));
71
+ if (fs.existsSync(gitignorePath) || isGitRepo) {
72
+ const gitignoreTarget = fs.existsSync(gitignorePath) ? gitignorePath : path.join(curr, '.gitignore');
73
+ let content = '';
74
+ try {
75
+ if (fs.existsSync(gitignoreTarget)) {
76
+ content = fs.readFileSync(gitignoreTarget, 'utf8');
77
+ }
78
+ }
79
+ catch {
80
+ content = '';
81
+ }
82
+ // Check if bundles or bundles/ is already ignored
83
+ const lines = content.split(/\r?\n/).map((l) => l.trim());
84
+ const alreadyIgnored = lines.some((l) => l === 'bundles' ||
85
+ l === 'bundles/' ||
86
+ l === '/bundles' ||
87
+ l === '/bundles/' ||
88
+ l === '**/bundles/**' ||
89
+ l === '**/bundles');
90
+ if (!alreadyIgnored) {
91
+ const prefix = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
92
+ const entry = `${prefix}\n# Scalebun OTA bundles\nbundles/\n`;
93
+ try {
94
+ fs.writeFileSync(gitignoreTarget, content + entry, 'utf8');
95
+ updatedGitignore = true;
96
+ }
97
+ catch {
98
+ /* ignore */
99
+ }
100
+ }
101
+ break;
102
+ }
103
+ const parent = path.dirname(curr);
104
+ if (parent === curr)
105
+ break;
106
+ curr = parent;
107
+ }
108
+ return updatedGitignore;
109
+ }
110
+ /**
111
+ * `scalebun ota bundle build` — package a standalone bundle file for upload.
112
+ *
113
+ * ── Why this is `bundle build` and not `bundle` ────────────────────────────
114
+ *
115
+ * `ota bundles` (plural) lists what is on the server; `ota bundle` (singular)
116
+ * ran Metro and hermesc and wrote a file to disk. Two commands one character
117
+ * apart doing entirely different things is a footgun: reaching for the list
118
+ * and getting a full Hermes compile is a minute of confusion at best, and at
119
+ * worst it happens in a pipeline.
120
+ *
121
+ * Moving the builder under an explicit verb makes bare `ota bundle` print the
122
+ * group's help — which disambiguates instead of guessing. `bundle` is kept as
123
+ * an alias of the group, so nothing that already worked stops working.
124
+ *
125
+ * Usage:
126
+ * npx scalebun ota bundle build --platform android
127
+ * npx scalebun ota bundle build --platform ios --output ./bundles/my-app.bundle
128
+ */
129
+ function registerOtaBundleCommand(ota) {
130
+ const bundle = ota
131
+ .command('bundle')
132
+ .description('Build a bundle file locally (see `ota bundles` to list uploaded ones)');
133
+ bundle
134
+ .command('build', { isDefault: false })
135
+ .description('Build a standalone OTA bundle file for manual upload in the Scalebun Dashboard')
136
+ .option('--platform <platform>', 'Target platform: android | ios', 'android')
137
+ .option('--entry-file <path>', 'JS entry file', 'index.js')
138
+ .option('--output <path>', 'Output bundle destination path (default: ./bundles/index.<platform>.bundle)')
139
+ .option('--key-dir <path>', 'Directory containing ota-signing-key.pem (default: .scalebun)')
140
+ .option('--hermes', 'Compile to Hermes bytecode (the default — flag kept for compatibility)')
141
+ .option('--hermes-disabled', 'Ship plain JS instead of Hermes bytecode (~20-30% slower cold start)')
142
+ .option('--allow-plain-js', 'Emit uncompiled JS if hermesc fails, instead of aborting')
143
+ .option('--sourcemap', 'Generate sourcemap alongside the bundle')
144
+ .action(async (opts) => {
145
+ const platform = (0, validate_1.checkedEnum)('--platform', opts.platform, ['android', 'ios'], {
146
+ caseInsensitive: true,
147
+ });
148
+ const useHermes = opts.hermesDisabled ? false : true;
149
+ console.log(`📦 Bundling ${platform} application${useHermes ? ' (Hermes bytecode)' : ''}…`);
150
+ try {
151
+ const result = (0, bundle_1.buildBundle)({
152
+ platform,
153
+ entryFile: opts.entryFile,
154
+ dev: false,
155
+ hermes: useHermes,
156
+ allowPlainJs: opts.allowPlainJs ?? false,
157
+ sourcemap: opts.sourcemap,
158
+ });
159
+ // Resolve destination inside bundles/ by default
160
+ let destPath;
161
+ // A DIRECTORY gets the same distinct name the default path uses:
162
+ // pointing builds at ./artifacts should not quietly reintroduce the
163
+ // overwrite-every-time behaviour that made older builds unrecoverable.
164
+ // A full FILE path is an explicit choice and is honoured verbatim, so
165
+ // CI referencing a fixed filename keeps working.
166
+ const named = (0, bundleStore_1.bundleFileName)(platform, (0, provenance_1.collectProvenance)().gitSha);
167
+ if (opts.output) {
168
+ const resolved = path.resolve(opts.output);
169
+ if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
170
+ destPath = path.join(resolved, named);
171
+ }
172
+ else if (opts.output.endsWith('/') || opts.output.endsWith('\\')) {
173
+ destPath = path.join(resolved, named);
174
+ }
175
+ else {
176
+ destPath = resolved;
177
+ }
178
+ }
179
+ else {
180
+ // One file per build, not one file overwritten by every build.
181
+ // `bundles/index.<platform>.bundle` meant build #3 destroyed #2 and
182
+ // #1 — so the moment the newest turns out to be broken there is
183
+ // nothing left to fall back to. The timestamp orders them; the short
184
+ // git sha is what a human recognises when choosing between them.
185
+ destPath = path.resolve(bundleStore_1.BUNDLES_DIR, (0, bundleStore_1.bundleFileName)(platform, (0, provenance_1.collectProvenance)().gitSha));
186
+ }
187
+ const destDir = path.dirname(destPath);
188
+ if (!fs.existsSync(destDir)) {
189
+ fs.mkdirSync(destDir, { recursive: true });
190
+ }
191
+ // Ensure bundles directory is git-ignored
192
+ const gitignoreUpdated = ensureBundlesGitIgnored(destPath);
193
+ fs.copyFileSync(result.bundlePath, destPath);
194
+ // Compute SHA-256. Under SB-OTA-RSA-SHA256-V1 the signature is not a
195
+ // detached `.sig` over the hash — it is an RSA signature over a binary
196
+ // signed-release payload whose identity fields (releaseId, bundleId,
197
+ // releaseSequence) are reserved by the server at publish time. A bundle
198
+ // built offline for manual dashboard upload therefore cannot be signed
199
+ // here; sign at `scalebun ota publish`, or use the dashboard's signed
200
+ // upload flow. This command emits the bundle + its hash only.
201
+ const bundleBytes = fs.readFileSync(destPath);
202
+ const sha256 = crypto.createHash('sha256').update(bundleBytes).digest('hex');
203
+ // If sourcemap was generated, also copy it alongside the bundle in bundles/
204
+ if (opts.sourcemap && result.sourcemapPath && fs.existsSync(result.sourcemapPath)) {
205
+ const mapDest = `${destPath}.map`;
206
+ fs.copyFileSync(result.sourcemapPath, mapDest);
207
+ }
208
+ const stats = fs.statSync(destPath);
209
+ const sizeMb = (stats.size / (1024 * 1024)).toFixed(2);
210
+ // Record what this bundle IS, beside it. `ota sign` shows these so the
211
+ // right build can be chosen later — and the git sha, not the clock, is
212
+ // what identifies a build to the person who made it.
213
+ const prov = (0, provenance_1.collectProvenance)();
214
+ let gitDirty;
215
+ try {
216
+ const st = require('child_process')
217
+ .execSync('git status --porcelain', { cwd: process.cwd(), stdio: ['ignore', 'pipe', 'ignore'] })
218
+ .toString()
219
+ .trim();
220
+ gitDirty = st.length > 0;
221
+ }
222
+ catch {
223
+ gitDirty = undefined;
224
+ }
225
+ const meta = {
226
+ platform,
227
+ createdAt: new Date().toISOString(),
228
+ sha256,
229
+ size: stats.size,
230
+ gitSha: prov.gitSha,
231
+ gitBranch: prov.gitBranch,
232
+ gitDirty,
233
+ };
234
+ fs.writeFileSync((0, bundleStore_1.metaPathFor)(destPath), JSON.stringify(meta, null, 2) + '\n');
235
+ // Old builds are cheap to keep and expensive to lose; prune generously.
236
+ const pruned = (0, bundleStore_1.pruneBundles)();
237
+ console.log(`\n✔ Bundle successfully created!`);
238
+ console.log(` Output Path: ${destPath}`);
239
+ console.log(` Size: ${sizeMb} MB (${stats.size} bytes)`);
240
+ console.log(` SHA-256: ${sha256}`);
241
+ console.log(` Signature: signed at publish time (RSA-3072 / SB-OTA-RSA-SHA256-V1)`);
242
+ if (gitignoreUpdated) {
243
+ console.log(` Git Status: Added 'bundles/' to .gitignore`);
244
+ }
245
+ console.log(`\n💡 You can now drag & drop this file into the Scalebun Dashboard at https://dash.scalebun.com/ota/publish`);
246
+ }
247
+ catch (err) {
248
+ console.error(`✖ Bundling failed: ${err?.message || err}`);
249
+ process.exit(1);
250
+ }
251
+ });
252
+ }
253
+ //# sourceMappingURL=ota-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-bundle.js","sourceRoot":"","sources":["../../src/commands/ota-bundle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerOtaChannelsCommand(ota: Command): void;
3
+ //# sourceMappingURL=ota-channels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-channels.d.ts","sourceRoot":"","sources":["../../src/commands/ota-channels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsHpC,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA2M7D"}
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerOtaChannelsCommand = registerOtaChannelsCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const credentials_1 = require("../utils/credentials");
9
+ const client_1 = require("../api/client");
10
+ const resolve_1 = require("../utils/resolve");
11
+ const prompt_1 = require("../utils/prompt");
12
+ const output_1 = require("../utils/output");
13
+ async function loadChannels(api, appId) {
14
+ try {
15
+ const res = await api.get(`/saas/apps/${appId}/ota/channels`);
16
+ return Array.isArray(res) ? res : [];
17
+ }
18
+ catch (err) {
19
+ (0, output_1.failFromError)('Could not list channels', err);
20
+ }
21
+ }
22
+ /**
23
+ * Accept a channel by name OR id.
24
+ *
25
+ * Operators think in names — "production" — and ids appear nowhere in their
26
+ * workflow. The backend already resolves either for bundle lookups, so the CLI
27
+ * matching only ids would be gratuitously stricter than the API.
28
+ */
29
+ function findChannel(channels, nameOrId) {
30
+ return (channels.find((c) => c.id === nameOrId) ||
31
+ channels.find((c) => c.name.toLowerCase() === nameOrId.toLowerCase()));
32
+ }
33
+ function client() {
34
+ const creds = (0, credentials_1.readCredentials)();
35
+ if (!creds)
36
+ (0, output_1.fail)('Not signed in.', ['Run `scalebun login` first.'], output_1.ExitCode.Usage);
37
+ return new client_1.ApiClient(creds);
38
+ }
39
+ /**
40
+ * Which environment a new channel belongs to.
41
+ *
42
+ * Order: an explicit --env (by name or id) > the environment an existing
43
+ * channel already uses > the app's only environment. Fails with the real list
44
+ * rather than a bare 400 when none of those resolve, because "environmentId
45
+ * must be a string" tells the operator nothing they can act on.
46
+ */
47
+ async function resolveEnvironmentId(api, appId, existing, wanted) {
48
+ let environments = [];
49
+ try {
50
+ const paged = await api.get(`/saas/apps/${appId}/ota/channels/paged?page=1&pageSize=1`);
51
+ environments = paged?.environments ?? [];
52
+ }
53
+ catch {
54
+ // Listing is a convenience here; the fallbacks below still work.
55
+ }
56
+ if (wanted) {
57
+ const hit = environments.find((e) => e.id === wanted) ||
58
+ environments.find((e) => e.name.toLowerCase() === wanted.toLowerCase());
59
+ if (hit)
60
+ return hit.id;
61
+ (0, output_1.fail)(`No environment "${wanted}" on this app.`, environments.length
62
+ ? [`Existing: ${environments.map((e) => e.name).join(', ')}`]
63
+ : ['This app has no environments yet — create one in the dashboard.'], output_1.ExitCode.Usage);
64
+ }
65
+ const fromChannel = existing.find((c) => c.environmentId)?.environmentId;
66
+ if (fromChannel)
67
+ return fromChannel;
68
+ if (environments.length === 1)
69
+ return environments[0].id;
70
+ if (environments.length > 1) {
71
+ (0, output_1.fail)('This app has several environments — say which one with --env.', environments.map((e) => ` ${e.name} ${e.id}`), output_1.ExitCode.Usage);
72
+ }
73
+ (0, output_1.fail)('Could not determine which environment this channel belongs to.', ['Pass --env <name>, or create the first channel from the dashboard.'], output_1.ExitCode.Usage);
74
+ }
75
+ function registerOtaChannelsCommand(ota) {
76
+ const channels = ota
77
+ .command('channels')
78
+ .alias('channel')
79
+ .description('List, create, rename or remove OTA channels');
80
+ // Bare `ota channels` keeps listing, which is what it has always done.
81
+ channels
82
+ .option('--app-id <id>', 'Scalebun app ID (resolved from scalebun.json when omitted)')
83
+ .option('--json', 'Machine-readable output')
84
+ .action(async (opts) => {
85
+ // A subcommand was given — commander runs that action, not this one.
86
+ if (channels.args.length && channels.commands.some((c) => c.name() === channels.args[0]))
87
+ return;
88
+ const api = client();
89
+ const appId = await (0, resolve_1.resolveAppId)({ appId: opts.appId, nonInteractive: opts.json });
90
+ const rows = await loadChannels(api, appId);
91
+ (0, output_1.emit)(() => {
92
+ console.log('');
93
+ if (!rows.length) {
94
+ console.log(' No channels yet — `scalebun ota publish` creates `default` automatically.\n');
95
+ return;
96
+ }
97
+ for (const c of rows) {
98
+ const env = c.environment?.name ? chalk_1.default.dim(` env ${c.environment.name}`) : '';
99
+ console.log(` ${chalk_1.default.bold(c.name.padEnd(16))}${env}`);
100
+ console.log(chalk_1.default.dim(` ${c.id}`));
101
+ }
102
+ // One channel means every bundle ever built goes straight to
103
+ // production with nowhere to test first. Worth saying out loud.
104
+ if (rows.length === 1) {
105
+ console.log(chalk_1.default.yellow(`\n Only one channel. Everything ships straight to ${rows[0].name} —\n` +
106
+ ' `scalebun ota channels create --name staging` gives you somewhere to test.'));
107
+ }
108
+ console.log('');
109
+ }, { ok: true, count: rows.length, channels: rows });
110
+ });
111
+ // ── create ────────────────────────────────────────────────────────────────
112
+ channels
113
+ .command('create')
114
+ .description('Create a channel')
115
+ .requiredOption('--name <name>', 'Channel name, e.g. staging')
116
+ .option('--app-id <id>', 'Scalebun app ID (resolved from scalebun.json when omitted)')
117
+ .option('--env <nameOrId>', 'Environment to attach it to')
118
+ .option('--json', 'Machine-readable output')
119
+ .action(async (_raw, cmd) => {
120
+ // optsWithGlobals, not the action's own opts. The PARENT `ota channels`
121
+ // also declares --app-id, and commander gives a flag to the first command
122
+ // that declares it — so `ota channels create --app-id X` parsed X onto the
123
+ // parent and handed this action an undefined, which then reported
124
+ // "--app-id is required" with the id sitting right there in the command.
125
+ // Only the env var worked, which is a miserable thing to discover.
126
+ const opts = cmd.optsWithGlobals();
127
+ const api = client();
128
+ const appId = await (0, resolve_1.resolveAppId)({ appId: opts.appId, nonInteractive: opts.json });
129
+ const existing = await loadChannels(api, appId);
130
+ if (findChannel(existing, opts.name)) {
131
+ (0, output_1.fail)(`A channel named "${opts.name}" already exists on this app.`, [], output_1.ExitCode.Usage);
132
+ }
133
+ // environmentId is REQUIRED by the API and this never sent it, so every
134
+ // `channels create` failed with `400 environmentId must be a string` —
135
+ // the command could not have worked once since it was added.
136
+ //
137
+ // Channels live inside an environment, and an app that already has one
138
+ // channel already has the answer. Reuse it rather than making the user
139
+ // find an id that never appears in their workflow.
140
+ const environmentId = await resolveEnvironmentId(api, appId, existing, opts.env);
141
+ const body = { name: opts.name, environmentId };
142
+ let created;
143
+ try {
144
+ created = await api.post(`/saas/apps/${appId}/ota/channels`, body);
145
+ }
146
+ catch (err) {
147
+ (0, output_1.failFromError)('Could not create the channel', err);
148
+ }
149
+ (0, output_1.emit)(() => {
150
+ console.log(`\n✅ Created channel ${chalk_1.default.bold(created.name)}`);
151
+ console.log(chalk_1.default.dim(` ${created.id}`));
152
+ (0, output_1.printNextSteps)([
153
+ { label: 'Ship to it', argv: ['ota', 'publish', '--channel', created.name] },
154
+ { label: 'See every channel', argv: ['ota', 'channels'] },
155
+ ], chalk_1.default.cyan);
156
+ }, { ok: true, channel: created });
157
+ });
158
+ // ── rename ────────────────────────────────────────────────────────────────
159
+ channels
160
+ .command('rename')
161
+ .description('Rename a channel (this route had no client anywhere)')
162
+ .requiredOption('--channel <nameOrId>', 'Channel to rename')
163
+ .requiredOption('--name <newName>', 'New name')
164
+ .option('--app-id <id>', 'Scalebun app ID (resolved from scalebun.json when omitted)')
165
+ .option('--json', 'Machine-readable output')
166
+ .action(async (_raw, cmd) => {
167
+ // Same parent-swallow as `create`: --app-id lands on the parent
168
+ // `ota channels`, so read the merged view.
169
+ const opts = cmd.optsWithGlobals();
170
+ const api = client();
171
+ const appId = await (0, resolve_1.resolveAppId)({ appId: opts.appId, nonInteractive: opts.json });
172
+ const rows = await loadChannels(api, appId);
173
+ const target = findChannel(rows, opts.channel);
174
+ if (!target) {
175
+ (0, output_1.fail)(`No channel "${opts.channel}" on this app.`, rows.map((c) => ` ${c.name} ${c.id}`), output_1.ExitCode.Usage);
176
+ }
177
+ try {
178
+ await api.patch(`/saas/apps/${appId}/ota/channels/${target.id}`, { name: opts.name });
179
+ }
180
+ catch (err) {
181
+ (0, output_1.failFromError)('Could not rename the channel', err);
182
+ }
183
+ (0, output_1.emit)(() => console.log(`\n✅ ${chalk_1.default.bold(target.name)} → ${chalk_1.default.bold(opts.name)}\n`), { ok: true, channelId: target.id, from: target.name, to: opts.name });
184
+ });
185
+ // ── remove ────────────────────────────────────────────────────────────────
186
+ channels
187
+ .command('rm')
188
+ .alias('delete')
189
+ .description('Delete a channel — cascades to its bundles and releases')
190
+ .requiredOption('--channel <nameOrId>', 'Channel to delete')
191
+ .option('--app-id <id>', 'Scalebun app ID (resolved from scalebun.json when omitted)')
192
+ .option('--yes', 'Skip the confirmation (required off a TTY)')
193
+ .option('--json', 'Machine-readable output')
194
+ .action(async (_raw, cmd) => {
195
+ // Same parent-swallow as `create`: --app-id lands on the parent
196
+ // `ota channels`, so read the merged view.
197
+ const opts = cmd.optsWithGlobals();
198
+ const api = client();
199
+ const appId = await (0, resolve_1.resolveAppId)({ appId: opts.appId, nonInteractive: opts.json });
200
+ const rows = await loadChannels(api, appId);
201
+ const target = findChannel(rows, opts.channel);
202
+ if (!target) {
203
+ (0, output_1.fail)(`No channel "${opts.channel}" on this app.`, rows.map((c) => ` ${c.name} ${c.id}`), output_1.ExitCode.Usage);
204
+ }
205
+ // This destroys the channel's bundles and releases. Confirming by name
206
+ // rather than y/n is the same bar delete-bundle sets for one bundle.
207
+ if (!opts.yes) {
208
+ if ((0, resolve_1.isNonInteractive)({ nonInteractive: opts.json })) {
209
+ (0, output_1.fail)('Refusing to delete a channel without confirmation.', ['Pass --yes if this is intentional.'], output_1.ExitCode.Usage);
210
+ }
211
+ console.log('');
212
+ console.log(chalk_1.default.yellow(`⚠️ Deleting ${chalk_1.default.bold(target.name)} also deletes every bundle and release on it.`));
213
+ const ok = await (0, prompt_1.confirmPhrase)(' Type the channel name to confirm: ', target.name);
214
+ (0, prompt_1.closePrompts)();
215
+ if (!ok) {
216
+ console.log('Cancelled — nothing was deleted.');
217
+ process.exit(output_1.ExitCode.Ok);
218
+ }
219
+ }
220
+ try {
221
+ await api.delete(`/saas/apps/${appId}/ota/channels/${target.id}`);
222
+ }
223
+ catch (err) {
224
+ (0, output_1.failFromError)('Could not delete the channel', err, [
225
+ 'Deleting a channel requires an owner or admin role.',
226
+ ]);
227
+ }
228
+ (0, output_1.emit)(() => console.log(`\n🗑 Deleted channel ${chalk_1.default.bold(target.name)}\n`), { ok: true, channelId: target.id, name: target.name });
229
+ });
230
+ }
231
+ //# sourceMappingURL=ota-channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-channels.js","sourceRoot":"","sources":["../../src/commands/ota-channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * `scalebun ota delete-bundle` — permanent, irreversible artifact deletion.
4
+ *
5
+ * `--app-id` resolves from scalebun.json like every other command, and
6
+ * `--bundle-id` opens a picker on a TTY when omitted, so choosing "delete-bundle"
7
+ * from the interactive menu lands on a bundle list instead of erroring on a
8
+ * missing required flag.
9
+ *
10
+ * It still asks first. This used to delete on sight: one mis-pasted --bundle-id
11
+ * and the artifact was gone, with devices possibly still running it. `ota rollback`
12
+ * already had this shape (prompt on a TTY, explicit --yes off-TTY); a command
13
+ * whose own description says "permanently" needs it at least as much.
14
+ */
15
+ export declare function registerOtaDeleteBundleCommand(ota: Command): void;
16
+ //# sourceMappingURL=ota-delete-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-delete-bundle.d.ts","sourceRoot":"","sources":["../../src/commands/ota-delete-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;;;;;;;;;;;GAYG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAyFjE"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerOtaDeleteBundleCommand = registerOtaDeleteBundleCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const credentials_1 = require("../utils/credentials");
9
+ const client_1 = require("../api/client");
10
+ const resolve_1 = require("../utils/resolve");
11
+ const prompt_1 = require("../utils/prompt");
12
+ const output_1 = require("../utils/output");
13
+ /**
14
+ * `scalebun ota delete-bundle` — permanent, irreversible artifact deletion.
15
+ *
16
+ * `--app-id` resolves from scalebun.json like every other command, and
17
+ * `--bundle-id` opens a picker on a TTY when omitted, so choosing "delete-bundle"
18
+ * from the interactive menu lands on a bundle list instead of erroring on a
19
+ * missing required flag.
20
+ *
21
+ * It still asks first. This used to delete on sight: one mis-pasted --bundle-id
22
+ * and the artifact was gone, with devices possibly still running it. `ota rollback`
23
+ * already had this shape (prompt on a TTY, explicit --yes off-TTY); a command
24
+ * whose own description says "permanently" needs it at least as much.
25
+ */
26
+ function registerOtaDeleteBundleCommand(ota) {
27
+ ota
28
+ .command('delete-bundle')
29
+ .alias('delete')
30
+ .description('Delete an OTA bundle permanently')
31
+ .option('--app-id <id>', 'Scalebun app ID (resolved from scalebun.json when omitted)')
32
+ .option('--bundle-id <id>', 'OTA bundle ID to delete (picker on a TTY when omitted)')
33
+ .option('--yes', 'Skip the confirmation prompt (required in CI / non-interactive shells)')
34
+ .action(async (opts) => {
35
+ const creds = (0, credentials_1.readCredentials)();
36
+ if (!creds)
37
+ (0, output_1.fail)('Not logged in. Run `scalebun login` first.', [], output_1.ExitCode.Usage);
38
+ const appId = await (0, resolve_1.resolveAppId)({ appId: opts.appId });
39
+ const client = new client_1.ApiClient(creds);
40
+ // Resolve the bundle: an explicit --bundle-id, or a picker on a TTY.
41
+ let bundleId = opts.bundleId;
42
+ let picked;
43
+ if (!bundleId) {
44
+ if (!process.stdin.isTTY) {
45
+ (0, output_1.fail)('--bundle-id is required.', [
46
+ 'Find one with `scalebun ota bundles`.',
47
+ 'This shell is not interactive, so the bundle cannot be chosen here.',
48
+ ], output_1.ExitCode.Usage);
49
+ }
50
+ let rows;
51
+ try {
52
+ const res = await client.get(`/saas/apps/${appId}/ota/bundles?sort=newest`);
53
+ rows = Array.isArray(res) ? res : (res?.rows ?? []);
54
+ }
55
+ catch (err) {
56
+ (0, output_1.failFromError)('Could not list bundles', err);
57
+ }
58
+ if (!rows.length) {
59
+ (0, output_1.fail)('No bundles on this app.', ['Nothing to delete.'], output_1.ExitCode.Usage);
60
+ }
61
+ picked = await (0, prompt_1.select)('Which bundle should be deleted permanently?', rows.slice(0, 15).map((b) => ({
62
+ label: `${b.version != null ? `v${b.version}` : b.id.slice(0, 8)} ` +
63
+ chalk_1.default.dim(`${b.platform ?? '?'} · ${b.channel?.name ?? 'default'} · ${b.signature ? 'signed' : 'unsigned'}`),
64
+ value: b,
65
+ })));
66
+ (0, prompt_1.closePrompts)();
67
+ bundleId = picked.id;
68
+ }
69
+ const label = picked?.version != null ? `v${picked.version}` : bundleId.slice(0, 8);
70
+ // Confirmation. --yes skips it; a non-interactive shell without --yes is a
71
+ // hard stop rather than a silent destructive delete.
72
+ if (!opts.yes) {
73
+ if (!process.stdin.isTTY) {
74
+ (0, output_1.fail)('Refusing to delete without confirmation in a non-interactive shell.', ['Re-run with --yes if this is intentional.'], output_1.ExitCode.Usage);
75
+ }
76
+ console.log(`\n⚠️ This permanently deletes bundle ${label} (${bundleId}) from app ${appId}.\n` +
77
+ ' Devices still running it keep their local copy, but it can never be\n' +
78
+ ' re-served, and any release pointing at it becomes undeliverable.\n');
79
+ const ok = await (0, prompt_1.confirmPhrase)('Type the bundle id to confirm:', bundleId);
80
+ (0, prompt_1.closePrompts)();
81
+ if (!ok) {
82
+ console.log('Aborted — nothing was deleted.');
83
+ return;
84
+ }
85
+ }
86
+ try {
87
+ console.log(`🗑️ Deleting bundle ${label} from app ${appId}…`);
88
+ await client.delete(`/saas/apps/${appId}/ota/bundles/${bundleId}`);
89
+ console.log(`✅ Bundle ${label} deleted successfully.`);
90
+ }
91
+ catch (err) {
92
+ (0, output_1.failFromError)('Failed to delete bundle', err);
93
+ }
94
+ });
95
+ }
96
+ //# sourceMappingURL=ota-delete-bundle.js.map