@nativescript/cloudflare-cli 0.1.0-beta.8 → 0.1.0-beta.9

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 (3) hide show
  1. package/README.md +25 -25
  2. package/dist/bin.js +51 -31
  3. package/package.json +43 -43
package/README.md CHANGED
@@ -1,25 +1,25 @@
1
- # @nativescript/cloudflare-cli
2
-
3
- ```sh
4
- npx @nativescript/cloudflare-cli live # a phone app: opens the IDE and prints a QR code for NativeScript Preview
5
- npx @nativescript/cloudflare-cli live --react # the same with a framework: --ng (Angular), --react, --vue, --svelte or --solid
6
- npx @nativescript/cloudflare-cli live --mac # a Mac app: opens the IDE and runs the app on this Mac, streamed into the IDE
7
- npx @nativescript/cloudflare-cli live --electron # an Electron app with native views, run the same way
8
- ```
9
-
10
- `live` creates a project on preview.nativescript.org (`--server` or `NS_EDGE_SERVER` for another edge), saves it to `.ns-edge.json` and opens its IDE. The framework flags are `ns create`'s (`--ng`/`--angular`, `--react`, `--vue`, `--svelte`, `--solid`, `--ts`); without one a phone project is plain TypeScript with XML views. Run it again in the same folder to reopen that project (no flag needed), or add `--new` for another; a flag for a different kind of project than the folder's asks for `--new`. While `live` runs a Mac app it restarts the app if it crashes, unless it crashes three times in a minute. Without a create token the project is free: a few hosted agent turns a day, no backend, deleted after 30 days unused. `--no-open` skips the browser; with `--mac` or `--electron`, `--allow-eval` lets the agent run code on this Mac.
11
-
12
- ## Mirror a local project
13
-
14
- Mirror a NativeScript project into an ns-edge project from a terminal or a Vite dev server.
15
-
16
- ```sh
17
- npm i -D @nativescript/cloudflare-cli@beta
18
- npx ns-edge create --server https://preview.nativescript.org --token <create token> # --template vue for nativescript-vue
19
- npx ns-edge watch # push, then every save
20
- npx ns-edge qr # print the pairing QR code again
21
- ```
22
-
23
- Also: `ns-edge push` uploads `app/` and `server/` once, `ns-edge pull` downloads the project's files.
24
-
25
- `ns-edge create` writes `.ns-edge.json` (project id and keys; keep it out of git). In a Vite config, `@nativescript/cloudflare-cli/vite` mirrors `app/` and `server/` on every save.
1
+ # @nativescript/cloudflare-cli
2
+
3
+ ```sh
4
+ npx @nativescript/cloudflare-cli live # a phone app: opens the IDE and prints a QR code for NativeScript Preview
5
+ npx @nativescript/cloudflare-cli live --react # the same with a framework: --ng (Angular), --react, --vue, --svelte or --solid
6
+ npx @nativescript/cloudflare-cli live --mac # a Mac app: opens the IDE and runs the app on this Mac, streamed into the IDE
7
+ npx @nativescript/cloudflare-cli live --electron # an Electron app with native views, run the same way
8
+ ```
9
+
10
+ `live` creates a project on preview.nativescript.org (`--server` or `NS_EDGE_SERVER` for another edge), saves it to `.ns-edge.json` and opens its IDE. The framework flags are `ns create`'s (`--ng`/`--angular`, `--react`, `--vue`, `--svelte`, `--solid`, `--ts`); without one a phone project is plain TypeScript with XML views. Run it again in the same folder to reopen that project (no flag needed), or add `--new` for another; a flag for a different kind of project than the folder's asks for `--new`. While `live` runs a Mac app it restarts the app if it crashes, unless it crashes three times in a minute. Without a create token the project is free: a few hosted agent turns a day, no backend, deleted after 30 days unused. `--no-open` skips the browser; with `--mac` or `--electron`, `--allow-eval` lets the agent run code on this Mac.
11
+
12
+ ## Mirror a local project
13
+
14
+ Mirror a NativeScript project into an ns-edge project from a terminal or a Vite dev server.
15
+
16
+ ```sh
17
+ npm i -D @nativescript/cloudflare-cli@beta
18
+ npx ns-edge create --server https://preview.nativescript.org --token <create token> # --template vue for nativescript-vue
19
+ npx ns-edge watch # push, then every save
20
+ npx ns-edge qr # print the pairing QR code again
21
+ ```
22
+
23
+ Also: `ns-edge push` uploads `app/` and `server/` once, `ns-edge pull` downloads the project's files.
24
+
25
+ `ns-edge create` writes `.ns-edge.json` (project id and keys; keep it out of git). In a Vite config, `@nativescript/cloudflare-cli/vite` mirrors `app/` and `server/` on every save.
package/dist/bin.js CHANGED
@@ -2,21 +2,22 @@
2
2
  import { spawn } from 'node:child_process';
3
3
  import { existsSync, watch } from 'node:fs';
4
4
  import { readFile, writeFile } from 'node:fs/promises';
5
- import { join, sep } from 'node:path';
5
+ import { dirname, join, sep } from 'node:path';
6
6
  import { createInterface } from 'node:readline/promises';
7
7
  import QRCode from 'qrcode';
8
8
  import { applyChanges, collect, createProject, projectUrl, report, SYNCED } from './sync.js';
9
9
  const CONFIG = '.ns-edge.json';
10
10
  const DEBOUNCE_MS = 120;
11
11
  const LIVE_SERVER = process.env.NS_EDGE_SERVER ?? 'https://preview.nativescript.org';
12
- /** The hosts `live --mac`, `--electron` and `--expo` run; bump them with each host release this CLI is tested against. */
12
+ /** The hosts `live --desktop` (or `--mac`, `--windows`), `--electron` and `--expo` run; bump them with each host release this CLI is tested against. */
13
13
  const DESKTOP_HOSTS = {
14
- macos: { spec: '@nativescript/cloudflare-desktop@0.1.0-alpha.5', bin: 'ns-edge-desktop' },
15
- electron: { spec: '@nativescript/cloudflare-electron@0.1.0-alpha.2', bin: 'ns-edge-electron' },
16
- expo: { spec: '@nativescript/cloudflare-expo-desktop@0.1.0-alpha.0', bin: 'ns-edge-expo-desktop' },
14
+ macos: { spec: '@nativescript/cloudflare-desktop@0.1.0-alpha.6', bin: 'ns-edge-desktop' },
15
+ electron: { spec: '@nativescript/cloudflare-electron@0.1.0-alpha.3', bin: 'ns-edge-electron' },
16
+ expo: { spec: '@nativescript/cloudflare-expo-desktop@0.1.0-alpha.1', bin: 'ns-edge-expo-desktop' },
17
17
  };
18
18
  const DESKTOP_TEMPLATES = new Set(['macos', 'electron', 'expo']);
19
- const DESKTOP_FLAGS = { macos: 'mac', electron: 'electron', expo: 'expo' };
19
+ /** The macos template is the desktop one: it runs on a Mac with AppKit and on Windows with WinUI, so all three flags pick it. */
20
+ const DESKTOP_FLAGS = { macos: ['desktop', 'mac', 'windows'], electron: ['electron'], expo: ['expo'] };
20
21
  /** The NativeScript CLI's `ns create` framework flags, so `live` and `create` take the same ones. */
21
22
  const FRAMEWORK_FLAGS = {
22
23
  angular: ['ng', 'angular'],
@@ -33,7 +34,7 @@ const TEMPLATE_KINDS = {
33
34
  vue: 'a Vue phone',
34
35
  svelte: 'a Svelte phone',
35
36
  solid: 'a Solid phone',
36
- macos: 'a Mac',
37
+ macos: 'a desktop',
37
38
  electron: 'an Electron',
38
39
  expo: 'an Expo Desktop',
39
40
  };
@@ -61,8 +62,8 @@ function requestedTemplate() {
61
62
  for (const [template, names] of Object.entries(FRAMEWORK_FLAGS))
62
63
  if (names.some((name) => has(name)))
63
64
  asked.add(template);
64
- for (const [template, name] of Object.entries(DESKTOP_FLAGS))
65
- if (has(name))
65
+ for (const [template, names] of Object.entries(DESKTOP_FLAGS))
66
+ if (names.some((name) => has(name)))
66
67
  asked.add(template);
67
68
  if (asked.size > 1)
68
69
  throw new Error(`Pick one kind of project: this asked for ${[...asked].join(' and ')}.`);
@@ -116,14 +117,31 @@ function openInBrowser(url) {
116
117
  const [command, ...rest] = process.platform === 'darwin' ? ['open', url] : process.platform === 'win32' ? ['cmd', '/c', 'start', '""', url.replace(/&/g, '^&')] : ['xdg-open', url];
117
118
  spawn(command, rest, { stdio: 'ignore', detached: true }).on('error', () => { }).unref();
118
119
  }
120
+ const COMPUTER = process.platform === 'win32' ? 'PC' : 'Mac';
119
121
  /**
120
- * Runs the Mac host for a desktop project until it quits or Ctrl+C. A host that
121
- * crashes is started again, since nothing in the browser can reach this Mac to
122
- * do it, unless it keeps crashing. The host says what joining allows.
122
+ * How to run npx. On Windows it's npx.cmd, which Node won't spawn without a
123
+ * shell (and a shell would re-parse the arguments), so npm's own npx-cli.js
124
+ * runs with this Node instead when it's where Node's installer puts it.
125
+ */
126
+ function npx() {
127
+ if (process.platform !== 'win32')
128
+ return ['npx'];
129
+ const cli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npx-cli.js');
130
+ return existsSync(cli) ? [process.execPath, cli] : ['npx.cmd'];
131
+ }
132
+ /**
133
+ * Runs the desktop host for a desktop project until it quits or Ctrl+C. A host
134
+ * that crashes is started again, since nothing in the browser can reach this
135
+ * computer to do it, unless it keeps crashing. The host says what joining allows.
123
136
  */
124
137
  async function runDesktopHost(ref) {
125
- if (process.platform !== 'darwin' || process.arch !== 'arm64') {
126
- throw new Error('Mac projects run on an Apple Silicon Mac (macOS 14.4 or later). Run the same command there.');
138
+ const mac = process.platform === 'darwin' && process.arch === 'arm64';
139
+ const windows = process.platform === 'win32' && (process.arch === 'x64' || process.arch === 'arm64');
140
+ if (ref.template === 'expo' && !mac && !(windows && process.arch === 'x64')) {
141
+ throw new Error('Expo Desktop projects run on an Apple Silicon Mac (macOS 14.4 or later) or a Windows x64 PC. Run the same command on one.');
142
+ }
143
+ if (!mac && !windows) {
144
+ throw new Error('Desktop projects run on an Apple Silicon Mac (macOS 14.4 or later) or a Windows 10 (1903 or later) or Windows 11 PC. Run the same command there.');
127
145
  }
128
146
  const device = `${projectUrl(ref)}#${ref.deviceKey}`;
129
147
  const extra = has('allow-eval') ? ['--allow-eval'] : [];
@@ -140,7 +158,8 @@ async function runDesktopHost(ref) {
140
158
  }
141
159
  const crashes = [];
142
160
  for (;;) {
143
- child = spawn('npx', ['-y', '--package', spec, '--', host.bin, device, '--yes', ...extra], { stdio: 'inherit' });
161
+ const [command, ...prefix] = npx();
162
+ child = spawn(command, [...prefix, '-y', '--package', spec, '--', host.bin, device, '--yes', ...extra], { stdio: 'inherit' });
144
163
  const exit = await new Promise((resolve, reject) => {
145
164
  child.on('error', reject);
146
165
  child.on('exit', (code, signal) => resolve({ code, signal }));
@@ -153,9 +172,9 @@ async function runDesktopHost(ref) {
153
172
  crashes.shift();
154
173
  const why = exit.signal ?? `code ${exit.code}`;
155
174
  if (crashes.length > MAX_CRASHES) {
156
- throw new Error(`The Mac host crashed ${crashes.length} times in a minute (last: ${why}), so it wasn't restarted. Fix the error above, then run this command again.`);
175
+ throw new Error(`The desktop host crashed ${crashes.length} times in a minute (last: ${why}), so it wasn't restarted. Fix the error above, then run this command again.`);
157
176
  }
158
- console.log(`\nThe Mac host stopped (${why}). Starting it again…\n`);
177
+ console.log(`\nThe desktop host stopped (${why}). Starting it again…\n`);
159
178
  await new Promise((r) => setTimeout(r, RESTART_DELAY_MS));
160
179
  }
161
180
  }
@@ -163,7 +182,7 @@ const commands = {
163
182
  async live() {
164
183
  for (const later of ['ios', 'android', 'all']) {
165
184
  if (has(later))
166
- throw new Error(`--${later} isn't available yet. Run \`live\` for a phone app, or \`live --mac\`, \`--electron\` or \`--expo\` for a Mac app.`);
185
+ throw new Error(`--${later} isn't available yet. Run \`live\` for a phone app, or \`live --desktop\`, \`--electron\` or \`--expo\` for a desktop app.`);
167
186
  }
168
187
  let ref = has('new') ? null : await savedProject();
169
188
  const requested = requestedTemplate();
@@ -192,7 +211,7 @@ const commands = {
192
211
  openInBrowser(ide);
193
212
  if (desktop) {
194
213
  const first = template === 'electron' ? ' (the first run downloads Electron)' : template === 'expo' ? ' (the first run downloads the Expo Desktop shell)' : '';
195
- console.log(`Starting the app on this Mac${first}. Its window streams to the IDE's Device pane. Press Ctrl+C to stop.\n`);
214
+ console.log(`Starting the app on this ${COMPUTER}${first}. Its window streams to the IDE's Device pane. Press Ctrl+C to stop.\n`);
196
215
  return runDesktopHost(ref);
197
216
  }
198
217
  const device = `${projectUrl(ref)}#${ref.deviceKey}`;
@@ -270,18 +289,19 @@ const commands = {
270
289
  await printPairing(await loadRef());
271
290
  },
272
291
  async help() {
273
- console.log(`ns-edge <command>
274
-
275
- live [--ng|--react|--vue|--svelte|--solid|--mac|--electron|--expo] [--new] [--no-open] [--allow-eval]
276
- create a project (or reopen this folder's), open its IDE, and print a QR code
277
- for your phone; --ng, --react, --vue, --svelte or --solid picks the framework
278
- (plain TypeScript with XML views otherwise); --mac, --electron or --expo runs it
279
- on this Mac instead
280
- create [--server <url>] [--token <t>] [--ng|--react|--vue|--svelte|--solid|--template <name>]
281
- create an edge project and save .ns-edge.json
282
- push upload app/ and server/ in one transaction
283
- watch push, then stream every save to the edge
284
- pull download the project's files here
292
+ console.log(`ns-edge <command>
293
+
294
+ live [--ng|--react|--vue|--svelte|--solid|--desktop|--electron|--expo] [--new] [--no-open] [--allow-eval]
295
+ create a project (or reopen this folder's), open its IDE, and print a QR code
296
+ for your phone; --ng, --react, --vue, --svelte or --solid picks the framework
297
+ (plain TypeScript with XML views otherwise); --desktop (or --mac, --windows)
298
+ or --electron runs it on this Mac or Windows PC instead, with that OS's own
299
+ controls; --expo runs an Expo Desktop app on this Mac or Windows x64 PC
300
+ create [--server <url>] [--token <t>] [--ng|--react|--vue|--svelte|--solid|--template <name>]
301
+ create an edge project and save .ns-edge.json
302
+ push upload app/ and server/ in one transaction
303
+ watch push, then stream every save to the edge
304
+ pull download the project's files here
285
305
  qr print the pairing QR code`);
286
306
  },
287
307
  };
package/package.json CHANGED
@@ -1,43 +1,43 @@
1
- {
2
- "name": "@nativescript/cloudflare-cli",
3
- "version": "0.1.0-beta.8",
4
- "description": "Mirror a NativeScript project into an ns-edge project from a terminal or a Vite dev server",
5
- "license": "Apache-2.0",
6
- "type": "module",
7
- "bin": {
8
- "ns-edge": "./dist/bin.js"
9
- },
10
- "exports": {
11
- ".": "./dist/sync.js",
12
- "./vite": "./dist/vite.js"
13
- },
14
- "scripts": {
15
- "build": "tsc -p .",
16
- "typecheck": "tsc -p . --noEmit",
17
- "prepack": "npm run build"
18
- },
19
- "dependencies": {
20
- "qrcode": "^1.5.4"
21
- },
22
- "devDependencies": {
23
- "@types/node": "^24.0.0",
24
- "@types/qrcode": "^1.5.6",
25
- "typescript": "^6.0.0",
26
- "vite": "^8.3.5"
27
- },
28
- "peerDependencies": {
29
- "vite": ">=6"
30
- },
31
- "peerDependenciesMeta": {
32
- "vite": {
33
- "optional": true
34
- }
35
- },
36
- "files": [
37
- "dist"
38
- ],
39
- "publishConfig": {
40
- "access": "public",
41
- "tag": "beta"
42
- }
43
- }
1
+ {
2
+ "name": "@nativescript/cloudflare-cli",
3
+ "version": "0.1.0-beta.9",
4
+ "description": "Mirror a NativeScript project into an ns-edge project from a terminal or a Vite dev server",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "bin": {
8
+ "ns-edge": "./dist/bin.js"
9
+ },
10
+ "exports": {
11
+ ".": "./dist/sync.js",
12
+ "./vite": "./dist/vite.js"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p .",
16
+ "typecheck": "tsc -p . --noEmit",
17
+ "prepack": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "qrcode": "^1.5.4"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^24.0.0",
24
+ "@types/qrcode": "^1.5.6",
25
+ "typescript": "^6.0.0",
26
+ "vite": "^8.3.5"
27
+ },
28
+ "peerDependencies": {
29
+ "vite": ">=6"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "vite": {
33
+ "optional": true
34
+ }
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "tag": "beta"
42
+ }
43
+ }