@scalebun/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/bin/scalebun.js +2 -0
  2. package/lib/api/client.d.ts +21 -0
  3. package/lib/api/client.d.ts.map +1 -0
  4. package/lib/api/client.js +151 -0
  5. package/lib/api/client.js.map +1 -0
  6. package/lib/commands/ci-init.d.ts +9 -0
  7. package/lib/commands/ci-init.d.ts.map +1 -0
  8. package/lib/commands/ci-init.js +100 -0
  9. package/lib/commands/ci-init.js.map +1 -0
  10. package/lib/commands/launch.d.ts +3 -0
  11. package/lib/commands/launch.d.ts.map +1 -0
  12. package/lib/commands/launch.js +23 -0
  13. package/lib/commands/launch.js.map +1 -0
  14. package/lib/commands/login.d.ts +10 -0
  15. package/lib/commands/login.d.ts.map +1 -0
  16. package/lib/commands/login.js +110 -0
  17. package/lib/commands/login.js.map +1 -0
  18. package/lib/commands/migrate-codepush.d.ts +13 -0
  19. package/lib/commands/migrate-codepush.d.ts.map +1 -0
  20. package/lib/commands/migrate-codepush.js +98 -0
  21. package/lib/commands/migrate-codepush.js.map +1 -0
  22. package/lib/commands/ota-bundle.d.ts +9 -0
  23. package/lib/commands/ota-bundle.d.ts.map +1 -0
  24. package/lib/commands/ota-bundle.js +87 -0
  25. package/lib/commands/ota-bundle.js.map +1 -0
  26. package/lib/commands/ota-channels.d.ts +3 -0
  27. package/lib/commands/ota-channels.d.ts.map +1 -0
  28. package/lib/commands/ota-channels.js +39 -0
  29. package/lib/commands/ota-channels.js.map +1 -0
  30. package/lib/commands/ota-delete-bundle.d.ts +3 -0
  31. package/lib/commands/ota-delete-bundle.d.ts.map +1 -0
  32. package/lib/commands/ota-delete-bundle.js +31 -0
  33. package/lib/commands/ota-delete-bundle.js.map +1 -0
  34. package/lib/commands/ota-publish.d.ts +16 -0
  35. package/lib/commands/ota-publish.d.ts.map +1 -0
  36. package/lib/commands/ota-publish.js +223 -0
  37. package/lib/commands/ota-publish.js.map +1 -0
  38. package/lib/index.d.ts +2 -0
  39. package/lib/index.d.ts.map +1 -0
  40. package/lib/index.js +39 -0
  41. package/lib/index.js.map +1 -0
  42. package/lib/utils/bundle.d.ts +37 -0
  43. package/lib/utils/bundle.d.ts.map +1 -0
  44. package/lib/utils/bundle.js +94 -0
  45. package/lib/utils/bundle.js.map +1 -0
  46. package/lib/utils/credentials.d.ts +15 -0
  47. package/lib/utils/credentials.d.ts.map +1 -0
  48. package/lib/utils/credentials.js +83 -0
  49. package/lib/utils/credentials.js.map +1 -0
  50. package/lib/utils/hash.d.ts +3 -0
  51. package/lib/utils/hash.d.ts.map +1 -0
  52. package/lib/utils/hash.js +44 -0
  53. package/lib/utils/hash.js.map +1 -0
  54. package/lib/utils/ui.d.ts +4 -0
  55. package/lib/utils/ui.d.ts.map +1 -0
  56. package/lib/utils/ui.js +51 -0
  57. package/lib/utils/ui.js.map +1 -0
  58. package/package.json +33 -0
@@ -0,0 +1,87 @@
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 fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const bundle_1 = require("../utils/bundle");
40
+ /**
41
+ * `scalebun ota bundle` — package a standalone bundle file for Dashboard upload.
42
+ *
43
+ * Usage:
44
+ * npx scalebun ota bundle --platform android --output ./my-app.bundle
45
+ */
46
+ function registerOtaBundleCommand(ota) {
47
+ ota
48
+ .command('bundle')
49
+ .description('Build a standalone OTA bundle file for manual upload in the Scalebun Dashboard')
50
+ .option('--platform <platform>', 'Target platform: android | ios', 'android')
51
+ .option('--entry-file <path>', 'JS entry file', 'index.js')
52
+ .option('--output <path>', 'Output bundle destination path', './index.android.bundle')
53
+ .option('--hermes', 'Compile to Hermes bytecode (recommended for production)')
54
+ .option('--hermes-disabled', 'Explicitly disable Hermes bytecode compilation')
55
+ .option('--sourcemap', 'Generate sourcemap alongside the bundle')
56
+ .action(async (opts) => {
57
+ const platform = opts.platform;
58
+ const useHermes = opts.hermesDisabled ? false : opts.hermes;
59
+ console.log(`📦 Bundling ${platform} application${useHermes ? ' (Hermes bytecode)' : ''}…`);
60
+ try {
61
+ const result = (0, bundle_1.buildBundle)({
62
+ platform,
63
+ entryFile: opts.entryFile,
64
+ dev: false,
65
+ hermes: useHermes,
66
+ sourcemap: opts.sourcemap,
67
+ });
68
+ const destPath = path.resolve(opts.output);
69
+ const destDir = path.dirname(destPath);
70
+ if (!fs.existsSync(destDir)) {
71
+ fs.mkdirSync(destDir, { recursive: true });
72
+ }
73
+ fs.copyFileSync(result.bundlePath, destPath);
74
+ const stats = fs.statSync(destPath);
75
+ const sizeMb = (stats.size / (1024 * 1024)).toFixed(2);
76
+ console.log(`\n✅ Bundle successfully created!`);
77
+ console.log(` Output Path: ${destPath}`);
78
+ console.log(` Size: ${sizeMb} MB (${stats.size} bytes)`);
79
+ console.log(`\n👉 You can now drag & drop this file into the Scalebun Dashboard at http://localhost:3000/ota`);
80
+ }
81
+ catch (err) {
82
+ console.error(`❌ Bundling failed: ${err?.message || err}`);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ }
87
+ //# sourceMappingURL=ota-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-bundle.js","sourceRoot":"","sources":["../../src/commands/ota-bundle.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,4DAqDC;AAhED,uCAAyB;AACzB,2CAA6B;AAE7B,4CAA8C;AAE9C;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,GAAY;IACnD,GAAG;SACA,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,gFAAgF,CAAC;SAC7F,MAAM,CAAC,uBAAuB,EAAE,gCAAgC,EAAE,SAAS,CAAC;SAC5E,MAAM,CAAC,qBAAqB,EAAE,eAAe,EAAE,UAAU,CAAC;SAC1D,MAAM,CAAC,iBAAiB,EAAE,gCAAgC,EAAE,wBAAwB,CAAC;SACrF,MAAM,CAAC,UAAU,EAAE,yDAAyD,CAAC;SAC7E,MAAM,CAAC,mBAAmB,EAAE,gDAAgD,CAAC;SAC7E,MAAM,CAAC,aAAa,EAAE,yCAAyC,CAAC;SAChE,MAAM,CACL,KAAK,EAAE,IAON,EAAE,EAAE;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,QAA6B,CAAC;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAE5D,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,eAAe,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAE5F,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAA,oBAAW,EAAC;gBACzB,QAAQ;gBACR,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,KAAK;gBACV,MAAM,EAAE,SAAS;gBACjB,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;YAED,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAEvD,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,QAAQ,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC;YAClE,OAAO,CAAC,GAAG,CAAC,iGAAiG,CAAC,CAAC;QACjH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,sBAAsB,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
@@ -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;AAapC,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA+B7D"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerOtaChannelsCommand = registerOtaChannelsCommand;
4
+ const credentials_1 = require("../utils/credentials");
5
+ const client_1 = require("../api/client");
6
+ function registerOtaChannelsCommand(ota) {
7
+ ota
8
+ .command('channels')
9
+ .alias('ota channel list')
10
+ .description('List all OTA channels for an app')
11
+ .requiredOption('--app-id <id>', 'Scalebun app ID')
12
+ .action(async (opts) => {
13
+ const creds = (0, credentials_1.readCredentials)();
14
+ if (!creds) {
15
+ console.error('❌ Not logged in. Run `scalebun login` first.');
16
+ process.exit(1);
17
+ }
18
+ const client = new client_1.ApiClient(creds);
19
+ try {
20
+ const channels = await client.get(`/saas/apps/${opts.appId}/ota/channels`);
21
+ console.log(`\n📋 OTA Channels for App (${opts.appId}):\n`);
22
+ if (!channels || channels.length === 0) {
23
+ console.log(' (No channels found yet. Running `scalebun ota publish` will automatically create the `default` channel.)');
24
+ }
25
+ else {
26
+ channels.forEach((c) => {
27
+ const envName = c.environment?.name ? ` [Env: ${c.environment.name}]` : '';
28
+ console.log(` • Name: ${c.name.padEnd(16)} ID: ${c.id}${envName}`);
29
+ });
30
+ }
31
+ console.log('');
32
+ }
33
+ catch (err) {
34
+ console.error(`❌ Failed to list channels: ${err.message}`);
35
+ process.exit(1);
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=ota-channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-channels.js","sourceRoot":"","sources":["../../src/commands/ota-channels.ts"],"names":[],"mappings":";;AAaA,gEA+BC;AA3CD,sDAAuD;AACvD,0CAA0C;AAW1C,SAAgB,0BAA0B,CAAC,GAAY;IACrD,GAAG;SACA,OAAO,CAAC,UAAU,CAAC;SACnB,KAAK,CAAC,kBAAkB,CAAC;SACzB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,cAAc,CAAC,eAAe,EAAE,iBAAiB,CAAC;SAClD,MAAM,CAAC,KAAK,EAAE,IAAuB,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,IAAA,6BAAe,GAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAgB,cAAc,IAAI,CAAC,KAAK,eAAe,CAAC,CAAC;YAC1F,OAAO,CAAC,GAAG,CAAC,8BAA8B,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC;YAC5D,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvC,OAAO,CAAC,GAAG,CAAC,4GAA4G,CAAC,CAAC;YAC5H,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;oBACrB,MAAM,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3E,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;gBACtE,CAAC,CAAC,CAAC;YACL,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerOtaDeleteBundleCommand(ota: Command): void;
3
+ //# 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;AAIpC,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAwBjE"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerOtaDeleteBundleCommand = registerOtaDeleteBundleCommand;
4
+ const credentials_1 = require("../utils/credentials");
5
+ const client_1 = require("../api/client");
6
+ function registerOtaDeleteBundleCommand(ota) {
7
+ ota
8
+ .command('delete-bundle')
9
+ .alias('delete')
10
+ .description('Delete an OTA bundle permanently')
11
+ .requiredOption('--app-id <id>', 'Scalebun app ID')
12
+ .requiredOption('--bundle-id <id>', 'OTA bundle ID to delete')
13
+ .action(async (opts) => {
14
+ const creds = (0, credentials_1.readCredentials)();
15
+ if (!creds) {
16
+ console.error('❌ Not logged in. Run `scalebun login` first.');
17
+ process.exit(1);
18
+ }
19
+ const client = new client_1.ApiClient(creds);
20
+ try {
21
+ console.log(`🗑️ Deleting bundle ${opts.bundleId} from App ${opts.appId}…`);
22
+ await client.delete(`/saas/apps/${opts.appId}/ota/bundles/${opts.bundleId}`);
23
+ console.log(`✅ Bundle ${opts.bundleId} deleted successfully.`);
24
+ }
25
+ catch (err) {
26
+ console.error(`❌ Failed to delete bundle: ${err.message}`);
27
+ process.exit(1);
28
+ }
29
+ });
30
+ }
31
+ //# sourceMappingURL=ota-delete-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-delete-bundle.js","sourceRoot":"","sources":["../../src/commands/ota-delete-bundle.ts"],"names":[],"mappings":";;AAIA,wEAwBC;AA3BD,sDAAuD;AACvD,0CAA0C;AAE1C,SAAgB,8BAA8B,CAAC,GAAY;IACzD,GAAG;SACA,OAAO,CAAC,eAAe,CAAC;SACxB,KAAK,CAAC,QAAQ,CAAC;SACf,WAAW,CAAC,kCAAkC,CAAC;SAC/C,cAAc,CAAC,eAAe,EAAE,iBAAiB,CAAC;SAClD,cAAc,CAAC,kBAAkB,EAAE,yBAAyB,CAAC;SAC7D,MAAM,CAAC,KAAK,EAAE,IAAyC,EAAE,EAAE;QAC1D,MAAM,KAAK,GAAG,IAAA,6BAAe,GAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,QAAQ,aAAa,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;YAC5E,MAAM,MAAM,CAAC,MAAM,CAAM,cAAc,IAAI,CAAC,KAAK,gBAAgB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClF,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,QAAQ,wBAAwB,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+ export type InstallMode = 'IMMEDIATE' | 'ON_NEXT_RESTART' | 'ON_NEXT_RESUME';
3
+ /**
4
+ * `scalebun ota publish` — the flagship CLI command.
5
+ *
6
+ * Flow:
7
+ * 1. Build the RN JS bundle (npx react-native bundle, Hermes default)
8
+ * 2. Compute SHA-256 of the output
9
+ * 3. POST /saas/apps/:appId/ota/bundles/presign → presigned PUT URL
10
+ * 4. PUT the bytes directly to storage (R2/S3)
11
+ * 5. POST /saas/apps/:appId/ota/bundles/:id/finalize → version assigned
12
+ * 6. POST /saas/apps/:appId/ota/bundles/:id/promote → configure installMode & rollout
13
+ * 7. Print success
14
+ */
15
+ export declare function registerOtaPublishCommand(ota: Command): void;
16
+ //# sourceMappingURL=ota-publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-publish.d.ts","sourceRoot":"","sources":["../../src/commands/ota-publish.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAwN5D"}
@@ -0,0 +1,223 @@
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.registerOtaPublishCommand = registerOtaPublishCommand;
37
+ const fs = __importStar(require("fs"));
38
+ const credentials_1 = require("../utils/credentials");
39
+ const client_1 = require("../api/client");
40
+ const bundle_1 = require("../utils/bundle");
41
+ const hash_1 = require("../utils/hash");
42
+ /**
43
+ * `scalebun ota publish` — the flagship CLI command.
44
+ *
45
+ * Flow:
46
+ * 1. Build the RN JS bundle (npx react-native bundle, Hermes default)
47
+ * 2. Compute SHA-256 of the output
48
+ * 3. POST /saas/apps/:appId/ota/bundles/presign → presigned PUT URL
49
+ * 4. PUT the bytes directly to storage (R2/S3)
50
+ * 5. POST /saas/apps/:appId/ota/bundles/:id/finalize → version assigned
51
+ * 6. POST /saas/apps/:appId/ota/bundles/:id/promote → configure installMode & rollout
52
+ * 7. Print success
53
+ */
54
+ function registerOtaPublishCommand(ota) {
55
+ ota
56
+ .command('publish')
57
+ .description('Bundle, hash, upload, and finalize an OTA update release')
58
+ .requiredOption('--app-id <id>', 'Scalebun application ID')
59
+ .option('--channel <nameOrId>', 'OTA channel name (e.g. default, beta, production) or channel ID', 'default')
60
+ .option('--channel-id <id>', 'OTA channel ID (legacy alias)')
61
+ .option('--platform <platform>', 'Target platform: android | ios', 'android')
62
+ .option('--install-mode <mode>', 'Install & execution behavior: IMMEDIATE (forces instant app restart on download), ON_NEXT_RESTART (applies silently on next cold boot - default), ON_NEXT_RESUME (applies when app resumes)', 'ON_NEXT_RESTART')
63
+ .option('--target-version <semver>', 'Target app native semver range (e.g. ">=1.0.0", "1.0.0")', '>=1.0.0')
64
+ .option('--rollout <percent>', 'Target rollout percentage (1-100)', '100')
65
+ .option('--entry-file <path>', 'JS entry file', 'index.js')
66
+ .option('--release-note <text>', 'Release note for dashboard display and device changelog')
67
+ .option('--hermes', 'Compile to Hermes bytecode (recommended for production)')
68
+ .option('--hermes-disabled', 'Explicitly disable Hermes bytecode compilation')
69
+ .option('--skip-bundle', 'Skip react-native bundle (provide --bundle-path instead)')
70
+ .option('--bundle-path <path>', 'Path to a pre-built bundle file')
71
+ .option('--custom-bundle-path <path>', 'Alias for --bundle-path (explicit naming)')
72
+ .option('--sourcemap', 'Generate and upload sourcemap for crash symbolication')
73
+ .option('--keep-artifacts', 'Keep build artifacts (bundle + sourcemap) after upload')
74
+ .action(async (opts) => {
75
+ const creds = (0, credentials_1.readCredentials)();
76
+ if (!creds) {
77
+ console.error('❌ Not logged in. Run `scalebun login` first.');
78
+ process.exit(1);
79
+ }
80
+ const rawInstallMode = (opts.installMode || 'ON_NEXT_RESTART').toUpperCase();
81
+ const validModes = ['IMMEDIATE', 'ON_NEXT_RESTART', 'ON_NEXT_RESUME'];
82
+ if (!validModes.includes(rawInstallMode)) {
83
+ console.error(`❌ Invalid --install-mode "${opts.installMode}". Valid options: IMMEDIATE, ON_NEXT_RESTART, ON_NEXT_RESUME`);
84
+ process.exit(1);
85
+ }
86
+ const installMode = rawInstallMode;
87
+ const targetChannel = opts.channelId || opts.channel || 'default';
88
+ const client = new client_1.ApiClient(creds);
89
+ const platform = opts.platform;
90
+ // Step 1: Build the bundle (or use pre-built)
91
+ let bundlePath;
92
+ if (opts.skipBundle && (opts.bundlePath || opts.customBundlePath)) {
93
+ bundlePath = opts.bundlePath || opts.customBundlePath;
94
+ if (!fs.existsSync(bundlePath)) {
95
+ console.error(`❌ Bundle file not found: ${bundlePath}`);
96
+ process.exit(1);
97
+ }
98
+ console.log(`📦 Using pre-built bundle: ${bundlePath}`);
99
+ }
100
+ else {
101
+ // Resolve Hermes: --hermes-disabled takes precedence
102
+ const useHermes = opts.hermesDisabled ? false : opts.hermes;
103
+ console.log(`📦 Building ${platform} bundle${useHermes ? ' (Hermes bytecode)' : ''}…`);
104
+ const result = (0, bundle_1.buildBundle)({
105
+ platform,
106
+ entryFile: opts.entryFile,
107
+ dev: false,
108
+ hermes: useHermes,
109
+ sourcemap: opts.sourcemap,
110
+ });
111
+ bundlePath = result.bundlePath;
112
+ console.log(` ✅ Bundle built: ${bundlePath}`);
113
+ }
114
+ // Step 2: Hash the bundle
115
+ console.log('🔒 Computing SHA-256…');
116
+ const sha256 = (0, hash_1.sha256File)(bundlePath);
117
+ const sizeBytes = fs.statSync(bundlePath).size;
118
+ console.log(` Hash: ${sha256}`);
119
+ console.log(` Size: ${(sizeBytes / 1024 / 1024).toFixed(2)} MB`);
120
+ if (sizeBytes > 50000000) {
121
+ console.error(`❌ Bundle is ${(sizeBytes / 1024 / 1024).toFixed(1)} MB — exceeds 50 MB limit`);
122
+ process.exit(1);
123
+ }
124
+ // Step 3: Get presigned upload URL
125
+ console.log('🔗 Requesting presigned upload URL…');
126
+ let presigned;
127
+ try {
128
+ presigned = await client.post(`/saas/apps/${opts.appId}/ota/bundles/presign`, {
129
+ channelId: targetChannel,
130
+ platform,
131
+ sha256,
132
+ sizeBytes,
133
+ releaseNote: opts.releaseNote,
134
+ });
135
+ }
136
+ catch (err) {
137
+ console.error(`❌ Presign failed: ${err.message}`);
138
+ process.exit(1);
139
+ }
140
+ console.log(` Bundle ID: ${presigned.bundleId}`);
141
+ console.log(` Upload URL expires in ${presigned.expiresIn}s`);
142
+ // Step 4: Upload to R2/S3
143
+ console.log('⬆️ Uploading bundle to storage…');
144
+ const bundleData = fs.readFileSync(bundlePath);
145
+ try {
146
+ await client.putBytes(presigned.uploadUrl, bundleData, 'application/octet-stream');
147
+ }
148
+ catch (err) {
149
+ console.error(`❌ Upload failed: ${err.message}`);
150
+ process.exit(1);
151
+ }
152
+ console.log(' ✅ Upload complete');
153
+ // Step 5: Finalize — server-side SHA-256 verification + version assignment
154
+ console.log('🔍 Finalizing (server-side hash verification)…');
155
+ let finalized;
156
+ try {
157
+ finalized = await client.post(`/saas/apps/${opts.appId}/ota/bundles/${presigned.bundleId}/finalize`);
158
+ }
159
+ catch (err) {
160
+ console.error(`❌ Finalize failed: ${err.message}`);
161
+ process.exit(1);
162
+ }
163
+ // Step 6: Promote release to ACTIVE status with installMode
164
+ console.log('🚀 Promoting release to active target channel…');
165
+ try {
166
+ const rolloutPercent = parseInt(opts.rollout, 10) || 100;
167
+ await client.post(`/saas/apps/${opts.appId}/ota/bundles/${presigned.bundleId}/promote`, {
168
+ targetAppVersion: opts.targetVersion || '>=1.0.0',
169
+ rolloutPercent,
170
+ isMandatory: installMode === 'IMMEDIATE',
171
+ installMode,
172
+ releaseNote: opts.releaseNote,
173
+ });
174
+ }
175
+ catch (err) {
176
+ console.warn(` ⚠️ Promotion notice: ${err.message}`);
177
+ }
178
+ // Step 7: Upload sourcemap if generated
179
+ if (opts.sourcemap) {
180
+ const sourcemapPath = bundlePath + '.map';
181
+ if (fs.existsSync(sourcemapPath)) {
182
+ console.log('🗺️ Uploading sourcemap for crash symbolication…');
183
+ try {
184
+ const mapData = fs.readFileSync(sourcemapPath);
185
+ await client.post(`/saas/apps/${opts.appId}/ota/bundles/${presigned.bundleId}/sourcemap`, { sourcemap: mapData.toString('base64'), encoding: 'base64' });
186
+ console.log(' ✅ Sourcemap uploaded');
187
+ if (!opts.keepArtifacts) {
188
+ fs.unlinkSync(sourcemapPath);
189
+ }
190
+ }
191
+ catch (err) {
192
+ console.warn(` ⚠️ Sourcemap upload failed (non-fatal): ${err.message}`);
193
+ }
194
+ }
195
+ }
196
+ // Step 8: Print detailed success summary
197
+ const installModeLabel = installMode === 'IMMEDIATE'
198
+ ? '⚡ IMMEDIATE (App restarts right after download)'
199
+ : installMode === 'ON_NEXT_RESUME'
200
+ ? '🔄 ON_NEXT_RESUME (Applies when app resumes)'
201
+ : '🌙 ON_NEXT_RESTART (Applies silently on next launch)';
202
+ console.log('');
203
+ console.log(`✅ Bundle v${finalized.version} published successfully!`);
204
+ console.log(` Channel: ${finalized.channelName} (${finalized.environmentName})`);
205
+ console.log(` Platform: ${finalized.platform}`);
206
+ console.log(` Install Mode: ${installModeLabel}`);
207
+ console.log(` SHA-256: ${finalized.sha256}`);
208
+ console.log(` Size: ${(finalized.sizeBytes / 1024).toFixed(1)} KB`);
209
+ if (opts.sourcemap) {
210
+ console.log(` Sourcemap: Uploaded ✓ (Stack traces will auto-symbolicate)`);
211
+ }
212
+ // Clean up bundle unless --keep-artifacts or using pre-built
213
+ if (!opts.keepArtifacts && !opts.skipBundle) {
214
+ try {
215
+ fs.unlinkSync(bundlePath);
216
+ }
217
+ catch {
218
+ // non-fatal
219
+ }
220
+ }
221
+ });
222
+ }
223
+ //# sourceMappingURL=ota-publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ota-publish.js","sourceRoot":"","sources":["../../src/commands/ota-publish.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/lib/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commander_1 = require("commander");
4
+ const ota_publish_1 = require("./commands/ota-publish");
5
+ const ota_bundle_1 = require("./commands/ota-bundle");
6
+ const ota_channels_1 = require("./commands/ota-channels");
7
+ const ota_delete_bundle_1 = require("./commands/ota-delete-bundle");
8
+ const launch_1 = require("./commands/launch");
9
+ const migrate_codepush_1 = require("./commands/migrate-codepush");
10
+ const ci_init_1 = require("./commands/ci-init");
11
+ const ui_1 = require("./utils/ui");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('scalebun')
15
+ .description('Scalebun CLI — OTA bundle publishing and management')
16
+ .version('0.1.0')
17
+ .action(() => {
18
+ (0, ui_1.renderBanner)();
19
+ (0, ui_1.renderStatus)();
20
+ (0, ui_1.renderCommands)();
21
+ });
22
+ const ota = program.command('ota').description('OTA update management');
23
+ (0, ota_publish_1.registerOtaPublishCommand)(ota);
24
+ (0, ota_bundle_1.registerOtaBundleCommand)(ota);
25
+ (0, ota_channels_1.registerOtaChannelsCommand)(ota);
26
+ (0, ota_delete_bundle_1.registerOtaDeleteBundleCommand)(ota);
27
+ (0, launch_1.registerLaunchCommand)(program);
28
+ const migrate = program.command('migrate').description('Migration utilities from other platforms');
29
+ (0, migrate_codepush_1.registerMigrateCodepushCommand)(migrate);
30
+ (0, ci_init_1.registerCiInitCommand)(program);
31
+ if (process.argv.length <= 2) {
32
+ (0, ui_1.renderBanner)();
33
+ (0, ui_1.renderStatus)();
34
+ (0, ui_1.renderCommands)();
35
+ }
36
+ else {
37
+ program.parse(process.argv);
38
+ }
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AAEpC,wDAAmE;AACnE,sDAAiE;AACjE,0DAAqE;AACrE,oEAA8E;AAC9E,8CAA0D;AAC1D,kEAA6E;AAC7E,gDAA2D;AAC3D,mCAAwE;AAExE,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,qDAAqD,CAAC;KAClE,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,GAAG,EAAE;IACX,IAAA,iBAAY,GAAE,CAAC;IACf,IAAA,iBAAY,GAAE,CAAC;IACf,IAAA,mBAAc,GAAE,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AACxE,IAAA,uCAAyB,EAAC,GAAG,CAAC,CAAC;AAC/B,IAAA,qCAAwB,EAAC,GAAG,CAAC,CAAC;AAC9B,IAAA,yCAA0B,EAAC,GAAG,CAAC,CAAC;AAChC,IAAA,kDAA8B,EAAC,GAAG,CAAC,CAAC;AACpC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;AAE/B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,0CAA0C,CAAC,CAAC;AACnG,IAAA,iDAA8B,EAAC,OAAO,CAAC,CAAC;AACxC,IAAA,+BAAqB,EAAC,OAAO,CAAC,CAAC;AAE/B,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAC7B,IAAA,iBAAY,GAAE,CAAC;IACf,IAAA,iBAAY,GAAE,CAAC;IACf,IAAA,mBAAc,GAAE,CAAC;AACnB,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,37 @@
1
+ export interface BundleOptions {
2
+ platform: 'android' | 'ios';
3
+ entryFile: string;
4
+ dev: boolean;
5
+ /**
6
+ * If true, run hermesc to compile the JS bundle to Hermes bytecode (.hbc).
7
+ * Default: false (Sprint 2). Sprint 7 patch engine requires .hbc for
8
+ * correct diffing — enable this flag when binary patching ships.
9
+ *
10
+ * NOTE: `react-native bundle` in RN 0.74+ with Hermes enabled in the
11
+ * project config (build.gradle / Podfile) outputs plain JS that gets
12
+ * compiled to Hermes bytecode during the native build step, NOT during
13
+ * `react-native bundle`. For OTA bundles that skip the native build,
14
+ * we must explicitly run hermesc to produce the .hbc artifact.
15
+ *
16
+ * CAVEAT (Sprint 2): Without hermesc, OTA bundles are plain JS interpreted
17
+ * by Hermes (works correctly, but ~20-30% slower cold startup compared to
18
+ * pre-compiled bytecode). This is acceptable for Sprint 2; the hermesc
19
+ * step will be mandatory when the patch engine ships.
20
+ */
21
+ hermes?: boolean;
22
+ /** If true, generate a sourcemap alongside the bundle. */
23
+ sourcemap?: boolean;
24
+ }
25
+ export interface BundleResult {
26
+ bundlePath: string;
27
+ assetsPath: string;
28
+ }
29
+ /**
30
+ * Shell out to `npx react-native bundle` to produce a JS bundle.
31
+ *
32
+ * When opts.hermes is true, also runs hermesc to compile to bytecode.
33
+ * The native runtime detects the format from magic bytes (\x1f\x\xbc —
34
+ * Hermes bytecode header), so the same .jsbundle extension works for both.
35
+ */
36
+ export declare function buildBundle(opts: BundleOptions): BundleResult;
37
+ //# sourceMappingURL=bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/utils/bundle.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,OAAO,CAAC;IACb;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CA+D7D"}
@@ -0,0 +1,94 @@
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.buildBundle = buildBundle;
37
+ const childProcess = __importStar(require("child_process"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ /**
42
+ * Shell out to `npx react-native bundle` to produce a JS bundle.
43
+ *
44
+ * When opts.hermes is true, also runs hermesc to compile to bytecode.
45
+ * The native runtime detects the format from magic bytes (\x1f\x\xbc —
46
+ * Hermes bytecode header), so the same .jsbundle extension works for both.
47
+ */
48
+ function buildBundle(opts) {
49
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'scalebun-bundle-'));
50
+ const bundlePath = path.join(tmpDir, 'bundle.jsbundle');
51
+ const assetsPath = path.join(tmpDir, 'assets');
52
+ fs.mkdirSync(assetsPath, { recursive: true });
53
+ const args = [
54
+ 'react-native', 'bundle',
55
+ '--platform', opts.platform,
56
+ '--dev', String(opts.dev),
57
+ '--entry-file', opts.entryFile,
58
+ '--bundle-output', bundlePath,
59
+ '--assets-dest', assetsPath,
60
+ ];
61
+ // Sprint 8: Generate sourcemap if requested
62
+ if (opts.sourcemap) {
63
+ args.push('--sourcemap-output', bundlePath + '.map');
64
+ }
65
+ console.log(` Running: npx ${args.join(' ')}`);
66
+ const result = childProcess.spawnSync('npx', args, {
67
+ stdio: 'inherit',
68
+ shell: true,
69
+ timeout: 300000, // 5 minutes
70
+ });
71
+ if (result.status !== 0) {
72
+ throw new Error(`react-native bundle failed with exit code ${result.status}`);
73
+ }
74
+ if (!fs.existsSync(bundlePath)) {
75
+ throw new Error(`Bundle file not found at ${bundlePath}`);
76
+ }
77
+ // Hermes bytecode compilation (opt-in)
78
+ if (opts.hermes) {
79
+ console.log(' Compiling to Hermes bytecode…');
80
+ const hbcPath = bundlePath; // overwrite in-place — same extension
81
+ const hermescResult = childProcess.spawnSync('npx', ['hermesc', '-emit-binary', '-out', hbcPath, bundlePath], { stdio: 'inherit', shell: true, timeout: 120000 });
82
+ if (hermescResult.status !== 0) {
83
+ console.warn(` ⚠️ hermesc failed (exit ${hermescResult.status}) — shipping plain JS bundle`);
84
+ }
85
+ else {
86
+ console.log(' ✅ Hermes bytecode compiled');
87
+ }
88
+ }
89
+ else {
90
+ console.log(' ℹ️ Shipping plain JS (no hermesc). Use --hermes for bytecode compilation.');
91
+ }
92
+ return { bundlePath, assetsPath };
93
+ }
94
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/utils/bundle.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,kCA+DC;AAzGD,4DAA8C;AAC9C,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AAgCzB;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,IAAmB;IAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAE/C,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,QAAQ;QACxB,YAAY,EAAE,IAAI,CAAC,QAAQ;QAC3B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACzB,cAAc,EAAE,IAAI,CAAC,SAAS;QAC9B,iBAAiB,EAAE,UAAU;QAC7B,eAAe,EAAE,UAAU;KAC5B,CAAC;IAEF,4CAA4C;IAC5C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QACjD,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,MAAO,EAAE,YAAY;KAC/B,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6CAA6C,MAAM,CAAC,MAAM,EAAE,CAC7D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,uCAAuC;IACvC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,sCAAsC;QAClE,MAAM,aAAa,GAAG,YAAY,CAAC,SAAS,CAC1C,KAAK,EACL,CAAC,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EACxD,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAO,EAAE,CACpD,CAAC;QAEF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CACV,8BAA8B,aAAa,CAAC,MAAM,8BAA8B,CACjF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CACT,8EAA8E,CAC/E,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC"}