@livx.cc/appwrap 0.38.2 → 0.39.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livx.cc/appwrap",
3
- "version": "0.38.2",
3
+ "version": "0.39.0",
4
4
  "description": "Wrap any PWA into a native app with native capabilities (appwrap runtime + @livx.cc/native-kit).",
5
5
  "license": "MIT",
6
6
  "author": "Elya Livshitz",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrap-shell",
3
3
  "main": "app/app.ts",
4
- "version": "0.32.0",
4
+ "version": "0.32.1",
5
5
  "private": true,
6
6
  "scripts": {
7
7
  "dev:ios": "ns run ios",
@@ -17,5 +17,11 @@
17
17
  "@nativescript/webpack": "~5.0.25",
18
18
  "copy-webpack-plugin": "^13.0.1",
19
19
  "typescript": "~5.4.0"
20
- }
20
+ },
21
+ "//trustedDependencies": "bun blocks lifecycle scripts by default; allow the NativeScript toolchain's (parcel/watcher native build for live-reload, core-js postinstall) so `appwrap run` behaves like npm on every platform.",
22
+ "trustedDependencies": [
23
+ "@nativescript/core",
24
+ "@parcel/watcher",
25
+ "core-js-pure"
26
+ ]
21
27
  }
@@ -3,6 +3,14 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
3
3
  const path = require('path');
4
4
 
5
5
  module.exports = (env) => {
6
+ // Force CommonJS bundle output. @nativescript/ios >=9 flips @nativescript/webpack to ESM (.mjs),
7
+ // which makes @nativescript/core install its polyfills EAGERLY at bundle eval (matchMedia /
8
+ // media-query-list) — and that eager install crashes on launch ("Cannot read properties of
9
+ // undefined" in installPolyfills→matchMedia), white-screening/killing the app at startup. CommonJS
10
+ // uses the lazy polyfill path (the long-stable NS mode). appwrap runtime uses no import.meta, so
11
+ // CommonJS is safe. Remove only once the NS-core ESM eager-install bug is fixed upstream.
12
+ env = env || {};
13
+ env.commonjs = true;
6
14
  webpack.init(env);
7
15
 
8
16
  webpack.chainWebpack((config) => {
package/src/cli.ts CHANGED
@@ -387,6 +387,24 @@ async function loadConfig(cwd: string, flags: Record<string, string>): Promise<A
387
387
  process.exit(1);
388
388
  }
389
389
  }
390
+
391
+ // loader:'server' bakes serverUrl into the shell and loads it via NSURL/WKWebView. A scheme-less
392
+ // value (e.g. "agf.circlesup.com") produces an unusable URL — the app silently fails to load (or
393
+ // shows a stale page) with no error. Normalize to https:// when no scheme is present, and fail loud
394
+ // on a genuinely malformed URL rather than shipping a broken build.
395
+ if (cfg.serverUrl) {
396
+ const raw = String(cfg.serverUrl).trim();
397
+ const withScheme = /^https?:\/\//i.test(raw) ? raw : `https://${raw}`;
398
+ try {
399
+ new URL(withScheme);
400
+ } catch {
401
+ console.error(`✖ invalid serverUrl: ${JSON.stringify(cfg.serverUrl)} — must be an absolute http(s) URL (e.g. https://app.example.com)`);
402
+ process.exit(1);
403
+ }
404
+ if (withScheme !== raw) console.log(` serverUrl ← ${withScheme} (added https:// — scheme was missing)`);
405
+ cfg.serverUrl = withScheme;
406
+ }
407
+
390
408
  return cfg;
391
409
  }
392
410
 
@@ -907,6 +925,9 @@ function copyPwa(cwd: string, outDir: string, cfg: AppwrapConfig): void {
907
925
  // www so it isn't shipped.
908
926
  if (cfg.loader === 'server') {
909
927
  rmSync(www, { recursive: true, force: true });
928
+ // Loudly surface the live URL the app will load — the single most deploy-critical value for a
929
+ // server loader (easy to get wrong via env/scheme/cache). Visible in every sync/deploy output.
930
+ console.log(` 🌐 serverUrl → ${cfg.serverUrl} (the app loads this live; verify it before shipping)`);
910
931
  console.log(' www ← skipped (loader:server loads serverUrl)');
911
932
  return;
912
933
  }
@@ -1104,7 +1125,7 @@ async function init(cwd: string, flags: Record<string, string>): Promise<void> {
1104
1125
  writeFileSync(join(outDir, '.gitignore'), 'node_modules/\nplatforms/\nhooks/\n');
1105
1126
  applyOverrides(cwd, outDir, cfg); // escape hatch — last, so custom native code wins
1106
1127
  stampVersionManifest(outDir, cfg); // provenance — also marks the dir appwrap-managed
1107
- console.log(`✓ Wrapper ready (generated — gitignore \`${flags.out ?? 'native'}/\`, regenerate with \`appwrap init\`).\n cd ${flags.out ?? 'native'} && npm install && ns run ios`);
1128
+ console.log(`✓ Wrapper ready (generated — gitignore \`${flags.out ?? 'native'}/\`, regenerate with \`appwrap init\`).\n Run it: appwrap run ios (or: appwrap run android)`);
1108
1129
  }
1109
1130
 
1110
1131
  // `sync` = the same regenerate as `init`, minus the first-time guard/scaffold. It is a TRUE refresh from
@@ -1162,7 +1183,41 @@ async function dev(cwd: string, flags: Record<string, string>): Promise<void> {
1162
1183
  console.log(` ⚠ Android: serve the dev server over HTTP, not HTTPS — the WebView can't bypass wss TLS`);
1163
1184
  console.log(` errors, so HMR won't live-reload on-device (the page still loads). iOS is fine with HTTPS.`);
1164
1185
  }
1165
- console.log(` Then: cd ${flags.out ?? 'native'} && ns run ios (revert with \`appwrap sync\`)`);
1186
+ console.log(` Then: appwrap run ios (revert with \`appwrap sync\`)`);
1187
+ }
1188
+
1189
+ /** Ensure the wrapper's deps are installed (bun — honoring the repo's package manager, so callers
1190
+ * never `cd native` or remember the tool) then exec an `ns` subcommand in it with inherited stdio.
1191
+ * The single place appwrap shells out to ns for the interactive run loop. Best-effort bun: we only
1192
+ * install when node_modules is absent — if ns later reinstalls on package.json drift it uses npm
1193
+ * (NativeScript has no bun package-manager mode), so trustedDependencies in the shell package.json
1194
+ * is what keeps the bun-installed tree behaving like npm's (parcel/watcher, ns CLI hooks). */
1195
+ function runNs(outDir: string, args: string[]): void {
1196
+ if (!existsSync(join(outDir, 'node_modules'))) {
1197
+ console.log(`▶ bun install (cwd: ${outDir})`);
1198
+ execFileSync('bun', ['install'], { cwd: outDir, stdio: 'inherit' });
1199
+ }
1200
+ console.log(`▶ ns ${args.join(' ')} (cwd: ${outDir})`);
1201
+ execFileSync('ns', args, { cwd: outDir, stdio: 'inherit' });
1202
+ }
1203
+
1204
+ /** `appwrap run <ios|android> [--device <id|name>]` — compile + boot the wrapper in a
1205
+ * simulator/emulator (or named device) with live reload: the appwrap-managed replacement for raw
1206
+ * `ns run`, driven from the PWA project root with deps auto-installed. Like `ns run`, it reflects
1207
+ * whatever loader is currently stamped (`init`/`sync`/`dev`/`build` own stamping) and does NOT
1208
+ * re-stamp — so it won't clobber a `dev` loader. */
1209
+ async function run(cwd: string, flags: Record<string, string>, positionals: string[]): Promise<void> {
1210
+ const platform = positionals[0];
1211
+ if (platform !== 'ios' && platform !== 'android') {
1212
+ console.error('Usage: appwrap run <ios|android> [--device <id|name>] [--out native]');
1213
+ process.exit(1);
1214
+ }
1215
+ const outDir = resolve(cwd, flags.out ?? 'native');
1216
+ if (!existsSync(outDir)) {
1217
+ console.error(`✖ Wrapper not found at ${outDir} — run \`appwrap init\` first`);
1218
+ process.exit(1);
1219
+ }
1220
+ runNs(outDir, ['run', platform, ...(flags.device ? ['--device', flags.device] : [])]);
1166
1221
  }
1167
1222
 
1168
1223
  /** `appwrap build <ios|android> [--release] [--aab]` — store-readiness build path. Re-stamps config,
@@ -1590,7 +1645,7 @@ function pickDevice(devices: DeviceInfo[], explicitId?: string): DeviceInfo {
1590
1645
  async function deploy(cwd: string, flags: Record<string, string>, positionals: string[]): Promise<void> {
1591
1646
  const platform = positionals[0];
1592
1647
  if (platform !== 'ios') {
1593
- console.error('Usage: appwrap deploy ios [--device <id|name>] [--no-launch] (android: use `ns run android`)');
1648
+ console.error('Usage: appwrap deploy ios [--device <id|name>] [--no-launch] (android: use `appwrap run android`)');
1594
1649
  process.exit(1);
1595
1650
  }
1596
1651
  const cfg = await loadConfig(cwd, flags);
@@ -1845,6 +1900,9 @@ async function main(): Promise<void> {
1845
1900
  case 'dev':
1846
1901
  await dev(cwd, flags);
1847
1902
  break;
1903
+ case 'run':
1904
+ await run(cwd, flags, positionals);
1905
+ break;
1848
1906
  case 'build':
1849
1907
  await build(cwd, flags, positionals);
1850
1908
  break;
@@ -1861,8 +1919,9 @@ async function main(): Promise<void> {
1861
1919
  await logs(cwd, flags, positionals);
1862
1920
  break;
1863
1921
  default:
1864
- console.log('Usage: appwrap <init|sync|dev|build|deploy|release|submit|logs> [--config <path>] [--out native]\n' +
1922
+ console.log('Usage: appwrap <init|sync|dev|run|build|deploy|release|submit|logs> [--config <path>] [--out native]\n' +
1865
1923
  ' config: appwrap.config.ts (preferred) → .js → appwrap.json\n' +
1924
+ ' run <ios|android> [--device <id|name>] (compile + boot in a simulator/emulator, live reload)\n' +
1866
1925
  ' build <ios|android> [--release] [--aab] deploy ios [--device <id|name>] [--no-launch]\n' +
1867
1926
  ' release ios [--server-url <url>] [--env <name>] [--build-number <n>] (build+sign+upload to TestFlight)\n' +
1868
1927
  ' submit ios [--build-number <n>] [--submit-for-review] (promote the binary to the App Store; metadata stays in ASC)\n' +