@solidrt/cli 0.0.52 → 0.0.54

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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "solidrt-components-demos",
3
+ "type": "module",
4
+ "private": true,
5
+ "solidrt": {
6
+ "appId": "dev.solidrt.demos.components",
7
+ "displayName": "Gallery"
8
+ }
9
+ }
package/dist/server.js CHANGED
@@ -1083,6 +1083,7 @@ function clientList(withAddress = false) {
1083
1083
  os: info.os,
1084
1084
  kernel: info.kernel,
1085
1085
  videoDriver: info.videoDriver,
1086
+ refreshRate: info.refreshRate,
1086
1087
  gpu: info.gpu,
1087
1088
  ...withAddress ? { address: ws.remoteAddr ?? null } : {}
1088
1089
  }));
@@ -1335,8 +1336,14 @@ async function handleControl(req, path, query) {
1335
1336
  return handleQuery(query, "snapshot", extra);
1336
1337
  }
1337
1338
  case "/__control__/gpu": {
1339
+ let extra = {};
1338
1340
  let label = query.get("label");
1339
- return handleQuery(query, "gpu", label === undefined ? undefined : { label });
1341
+ if (label !== undefined)
1342
+ extra.label = label;
1343
+ let draw = parseInt(query.get("draw") ?? "", 10);
1344
+ if (Number.isFinite(draw))
1345
+ extra.draw = draw;
1346
+ return handleQuery(query, "gpu", extra);
1340
1347
  }
1341
1348
  case "/__control__/debug": {
1342
1349
  if (req.method !== "POST")
@@ -3765,6 +3772,7 @@ function onOpen(ws) {
3765
3772
  os: null,
3766
3773
  kernel: null,
3767
3774
  videoDriver: null,
3775
+ refreshRate: null,
3768
3776
  gpu: null
3769
3777
  });
3770
3778
  console.log(`[cli] Client connected ${ws.remoteAddr ?? "unknown"}`);
@@ -3777,8 +3785,6 @@ function onClose(ws) {
3777
3785
  let info = state.clients.get(ws);
3778
3786
  state.clients.delete(ws);
3779
3787
  console.log(`[cli] Client disconnected: ${info?.platform ?? "unknown"}`);
3780
- if (config.client && localClientExited && state.clients.size === 0)
3781
- shutdown();
3782
3788
  }
3783
3789
  function onMessage(ws, msg) {
3784
3790
  try {
@@ -3801,6 +3807,7 @@ function onMessage(ws, msg) {
3801
3807
  os: text(data.os),
3802
3808
  kernel: text(data.kernel),
3803
3809
  videoDriver: text(data.videoDriver),
3810
+ refreshRate: typeof data.refreshRate === "number" ? data.refreshRate : null,
3804
3811
  gpu: data.gpu && typeof data.gpu === "object" ? { vendor: text(data.gpu.vendor) ?? "", renderer: text(data.gpu.renderer) ?? "", version: text(data.gpu.version) ?? "" } : null
3805
3812
  });
3806
3813
  console.log(`[cli] Client info ${ws.remoteAddr ?? "unknown"} ${data.platform} (${data.version})`);
@@ -3842,7 +3849,7 @@ async function bindFirstFree() {
3842
3849
  candidates.push(p);
3843
3850
  let last = null;
3844
3851
  for (let port of candidates) {
3845
- if (await probe("127.0.0.1", port, { timeoutMs: 200 }) !== "closed")
3852
+ if (await probe("127.0.0.1", port, { timeoutMs: 200 }) === "open")
3846
3853
  continue;
3847
3854
  try {
3848
3855
  return bind(port);
@@ -3870,7 +3877,6 @@ var keepalive = setInterval(() => {
3870
3877
  var shuttingDown = false;
3871
3878
  var stopRepl = () => {};
3872
3879
  var localClient = null;
3873
- var localClientExited = false;
3874
3880
  var signalOffs = ["SIGINT", "SIGTERM"].map((signal) => onSignal(signal, () => {
3875
3881
  shutdown();
3876
3882
  }));
@@ -3924,13 +3930,7 @@ if (config.client) {
3924
3930
  pump(child.stderr, (line) => console.error(line));
3925
3931
  child.status().then(() => {
3926
3932
  localClient = null;
3927
- localClientExited = true;
3928
- if (shuttingDown)
3929
- return;
3930
- if (state.clients.size === 0) {
3931
- shutdown();
3932
- } else {
3933
- console.log(`[cli] Local client exited, ${state.clients.size} remote client(s) still connected`);
3934
- }
3933
+ if (!shuttingDown)
3934
+ console.log("[cli] Local client exited; the server keeps running (srt client reattaches)");
3935
3935
  });
3936
3936
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/cli",
3
- "version": "0.0.52",
3
+ "version": "0.0.54",
4
4
  "license": "MIT",
5
5
  "funding": "https://github.com/sponsors/wellawaretech",
6
6
  "author": "Antoine van Wel",
@@ -24,22 +24,22 @@
24
24
  "@jridgewell/remapping": "^2.3.0",
25
25
  "@jridgewell/trace-mapping": "^0.3.25",
26
26
  "@modelcontextprotocol/sdk": "^1.29.0",
27
- "babel-preset-solid": "2.0.0-rc.1",
27
+ "@solidjs/babel-plugin": "2.0.0-rc.3",
28
28
  "bonjour-service": "^1.4.0",
29
29
  "qrcode-generator": "^2.0.4",
30
30
  "zod": "^4.4.3"
31
31
  },
32
32
  "optionalDependencies": {
33
- "@solidrt/darwin-arm64": "0.0.52",
34
- "@solidrt/linux-arm64-gnu": "0.0.52",
35
- "@solidrt/linux-x64-gnu": "0.0.52",
36
- "@solidrt/win32-x64-msvc": "0.0.52"
33
+ "@solidrt/darwin-arm64": "0.0.54",
34
+ "@solidrt/linux-arm64-gnu": "0.0.54",
35
+ "@solidrt/linux-x64-gnu": "0.0.54",
36
+ "@solidrt/win32-x64-msvc": "0.0.54"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "typescript": "^7"
40
40
  },
41
41
  "devDependencies": {
42
- "@solidrt/flux-types": "0.0.52",
42
+ "@solidrt/flux-types": "0.0.54",
43
43
  "@types/babel__core": "^7.20.5",
44
44
  "@types/bun": "latest"
45
45
  }
@@ -8,8 +8,11 @@ file) in the current directory, or `--port`. A running instance is restarted
8
8
  so it picks the server up. The command then waits a few seconds for the
9
9
  client to appear on the server and reports its client id. The server must
10
10
  run with `--lan` so the device can reach it; an emulator reaches a loopback
11
- server through its host alias. `--device` picks one of several connected
12
- devices by serial or unique prefix.
11
+ server through its host alias. Without a running server the client starts
12
+ on its own, into the launcher (`--port` must name a live server). With several
13
+ devices connected a terminal asks which ones (all preselected, so enter
14
+ launches on every device); `--device` picks one by serial or unique prefix
15
+ (a script must).
13
16
 
14
17
  `--install` installs (or updates) the client first, from the
15
18
  `@solidrt/android-<abi>` dev dependency matching the device's ABI; the
@@ -3,6 +3,8 @@ import { networkInterfaces } from "node:os"
3
3
  import { resolve } from "node:path"
4
4
  import { androidPackageVersion, resolveApk, ANDROID_PKG_MAP } from "../lib/artifacts"
5
5
  import { values, port } from "../lib/args"
6
+ import { CLI_VERSION } from "../lib/project"
7
+ import { multiselect } from "../lib/prompt"
6
8
  import { resolveByPort, resolveFromCwd } from "../lib/registry"
7
9
  import type { LiveRecord } from "../types/registry"
8
10
 
@@ -97,14 +99,19 @@ function devServerAddress(adb: string, target: string, server: LiveRecord): stri
97
99
  }
98
100
 
99
101
  // The dev server the device should dial: --port picks a local server by
100
- // port, otherwise the project (or file) in the current directory.
101
- async function resolveServer(): Promise<LiveRecord> {
102
- let resolved = port !== undefined ? await resolveByPort(port) : await resolveFromCwd(process.cwd())
103
- if (!resolved.ok) {
104
- console.error(resolved.message)
105
- process.exit(1)
102
+ // port (and must exist), otherwise the project (or file) in the current
103
+ // directory, or none: the client then starts on its own, into the launcher.
104
+ async function resolveServer(): Promise<LiveRecord | null> {
105
+ if (port !== undefined) {
106
+ let resolved = await resolveByPort(port)
107
+ if (!resolved.ok) {
108
+ console.error(resolved.message)
109
+ process.exit(1)
110
+ }
111
+ return resolved.record
106
112
  }
107
- return resolved.record
113
+ let resolved = await resolveFromCwd(process.cwd())
114
+ return resolved.ok ? resolved.record : null
108
115
  }
109
116
 
110
117
  // Serials of connected, authorized devices (excludes offline/unauthorized).
@@ -132,25 +139,39 @@ function deviceAbi(adb: string, target: string): string {
132
139
  return res.stdout.toString().trim()
133
140
  }
134
141
 
135
- // Always shown up front, regardless of how many devices are connected or
136
- // whether --device narrows it down: one line per device with the ABI its APK
137
- // build would target, then (with --install) a dev-dependency hint for each
138
- // ABI that isn't resolvable locally yet. Returns the device->abi map so
139
- // callers don't have to re-query it.
140
- function printDeviceStatus(adb: string, devices: string[]): Map<string, string> {
141
- let abiByDevice = new Map<string, string>()
142
- let missingAbis = new Set<string>()
143
- for (let d of devices) {
144
- let abi = deviceAbi(adb, d)
145
- abiByDevice.set(d, abi)
146
- console.log(`${d} - ${abi}`)
147
- if (!resolveApk(abi)) missingAbis.add(abi)
142
+ // One line per connected device with the ABI its APK build would target;
143
+ // the picker shows the same lines, so this is for the cases without one.
144
+ function printDeviceStatus(devices: string[], abiByDevice: Map<string, string>) {
145
+ for (let d of devices) console.log(`${d} - ${abiByDevice.get(d)}`)
146
+ }
147
+
148
+ // A published CLI version (x.y.z): the release action publishes the CLI and
149
+ // the android packages at one version, so that is the one to pin. A checkout
150
+ // reports a git describe (or the 0.0.0 placeholder), which npm does not have.
151
+ let RELEASE_VERSION = /^\d+\.\d+\.\d+$/
152
+
153
+ // The APK for `abi`, adding the project's @solidrt/android-<abi> dev
154
+ // dependency in the cwd first when it is not installed. ABIs without a
155
+ // published package (e.g. x86) only resolve through SRT_HOME.
156
+ function ensureApk(abi: string): string {
157
+ let apk = resolveApk(abi)
158
+ if (apk) return apk
159
+ let pkg = ANDROID_PKG_MAP[abi]
160
+ if (!pkg) {
161
+ console.error(`Could not find a SolidRT-Go APK for ABI "${abi}".`)
162
+ process.exit(1)
148
163
  }
149
- let missingPkgs = [...missingAbis].map((abi) => ANDROID_PKG_MAP[abi]).filter((pkg): pkg is string => Boolean(pkg))
150
- if (values.install && missingPkgs.length > 0) {
151
- console.log(`Add dev dependencies with: bun add -d ${missingPkgs.join(" ")}`)
164
+ let spec = RELEASE_VERSION.test(CLI_VERSION) && CLI_VERSION !== "0.0.0" ? `${pkg}@${CLI_VERSION}` : pkg
165
+ console.log(`[cli] Adding dev dependency ${spec}`)
166
+ let add = Bun.spawnSync(["bun", "add", "-d", spec], { cwd: process.cwd(), stdout: "inherit", stderr: "inherit" })
167
+ if (add.exitCode !== 0) {
168
+ console.error(`Could not add ${spec}; retry with bun add -d ${spec}`)
169
+ process.exit(1)
152
170
  }
153
- return abiByDevice
171
+ apk = resolveApk(abi)
172
+ if (apk) return apk
173
+ console.error(`${pkg} is installed but carries no solidrt-go.apk for ABI "${abi}".`)
174
+ process.exit(1)
154
175
  }
155
176
 
156
177
  // The versionName of the client installed on `target`, null when none is.
@@ -171,25 +192,31 @@ async function connectedClients(server: LiveRecord): Promise<Client[]> {
171
192
  }
172
193
  }
173
194
 
174
- // The first Android client that appears beyond `before`, or null after ~10 s.
175
- async function waitForClient(server: LiveRecord, before: Set<number>): Promise<Client | null> {
176
- for (let attempt = 0; attempt < 20; attempt++) {
195
+ // The Android clients that appear beyond `before`: all of them once `count`
196
+ // have, else whatever showed up within ~10 s.
197
+ async function waitForClients(server: LiveRecord, before: Set<number>, count: number): Promise<Client[]> {
198
+ let fresh: Client[] = []
199
+ for (let attempt = 0; attempt < 20 && fresh.length < count; attempt++) {
177
200
  await sleep(500)
178
- let fresh = (await connectedClients(server)).find((c) => c.platform === "android" && !before.has(c.id))
179
- if (fresh) return fresh
201
+ fresh = (await connectedClients(server)).filter((c) => c.platform === "android" && !before.has(c.id))
180
202
  }
181
- return null
203
+ return fresh
182
204
  }
183
205
 
184
- // Resolve the target device serial (and its ABI). With --device, treat the
206
+ type Device = { target: string; abi: string }
207
+
208
+ // Resolve the target devices (serial and ABI). With --device, treat the
185
209
  // value as a serial prefix and require it to match exactly one connected
186
- // device; without it, use the sole connected device. Exits with a clear
187
- // message on any ambiguity.
188
- function resolveTarget(adb: string): { target: string; abi: string } {
210
+ // device; without it, use the sole connected device, or pick any number of
211
+ // several on a terminal (all preselected: enter means every device). Exits
212
+ // with a clear message on any ambiguity.
213
+ async function resolveTargets(adb: string): Promise<Device[]> {
189
214
  let devices = listDevices(adb)
190
- let abiByDevice = printDeviceStatus(adb, devices)
215
+ let abiByDevice = new Map(devices.map((d) => [d, deviceAbi(adb, d)]))
216
+ let device = (target: string): Device => ({ target, abi: abiByDevice.get(target)! })
191
217
 
192
218
  if (values.device) {
219
+ printDeviceStatus(devices, abiByDevice)
193
220
  let prefix = values.device
194
221
  let matches = devices.filter((d) => d.startsWith(prefix))
195
222
  if (matches.length > 1) {
@@ -201,86 +228,108 @@ function resolveTarget(adb: string): { target: string; abi: string } {
201
228
  console.error(`No connected device matches --device "${prefix}".`)
202
229
  process.exit(1)
203
230
  }
204
- return { target: match, abi: abiByDevice.get(match)! }
231
+ return [device(match)]
205
232
  }
206
233
 
207
234
  if (devices.length > 1) {
208
- console.error("Pick one with --device <serial or prefix>.")
209
- process.exit(1)
235
+ // The prompt's non-TTY default is no way to pick devices, so a script has
236
+ // to say which.
237
+ if (!process.stdin.isTTY) {
238
+ printDeviceStatus(devices, abiByDevice)
239
+ console.error("Pick one with --device <serial or prefix>.")
240
+ process.exit(1)
241
+ }
242
+ let picked = await multiselect(
243
+ "Pick devices",
244
+ devices.map((d) => ({ label: `${d} - ${abiByDevice.get(d)}`, value: d, checked: true })),
245
+ )
246
+ if (picked.length === 0) {
247
+ console.error("No device picked.")
248
+ process.exit(1)
249
+ }
250
+ return picked.map(device)
210
251
  }
252
+ printDeviceStatus(devices, abiByDevice)
211
253
  let [only] = devices
212
254
  if (!only) {
213
255
  console.error("No authorized Android device found. Enable USB debugging and check `adb devices`.")
214
256
  process.exit(1)
215
257
  }
216
- return { target: only, abi: abiByDevice.get(only)! }
258
+ return [device(only)]
217
259
  }
218
260
 
219
- // Launch the Android client on a connected device over adb (installing it
220
- // first on --install), passing it the dev-server address to dial as a
221
- // launch-intent extra (see devServerAddress), then wait briefly for it to show
222
- // up on the dev server. The client is not a child process here: its lifecycle
223
- // is the WS connect/disconnect the server sees.
224
- export async function main() {
225
- let server = await resolveServer()
226
- let adb = requireAdb()
227
-
228
- let { target, abi } = resolveTarget(adb)
229
-
261
+ // Install the client on `target` (on --install), else check that one is there
262
+ // and note when its version is not the one the project's package carries.
263
+ async function prepare(adb: string, { target, abi }: Device) {
230
264
  if (values.install) {
231
- let apk = resolveApk(abi)
232
- if (!apk) {
233
- console.error(`Could not find a SolidRT-Go APK for ABI "${abi}".`)
234
- let pkg = ANDROID_PKG_MAP[abi]
235
- if (pkg) console.error(`Add it with: bun add -d ${pkg}`)
236
- process.exit(1)
237
- }
265
+ let apk = ensureApk(abi)
238
266
  console.log(`[cli] Installing SolidRT-Go on ${target}`)
239
267
  let install = Bun.spawn([adb, "-s", target, "install", "-r", apk], { stdout: "pipe", stderr: "pipe" })
240
268
  if ((await install.exited) !== 0) {
241
269
  console.error("adb install failed:\n" + (await new Response(install.stderr).text()))
242
270
  process.exit(1)
243
271
  }
244
- } else {
245
- let installed = installedVersion(adb, target)
246
- if (installed === null) {
247
- console.error(`No SolidRT-Go client on ${target}; install one with srt android --install`)
248
- process.exit(1)
249
- }
250
- let expected = androidPackageVersion(abi)
251
- if (expected !== null && expected !== installed) {
252
- console.log(
253
- `[cli] Installed client is ${installed}; the project's ${ANDROID_PKG_MAP[abi]} is ${expected} (srt android --install updates it)`,
254
- )
255
- }
272
+ return
273
+ }
274
+ let installed = installedVersion(adb, target)
275
+ if (installed === null) {
276
+ console.error(`No SolidRT-Go client on ${target}; install one with srt android --install`)
277
+ process.exit(1)
256
278
  }
279
+ let expected = androidPackageVersion(abi)
280
+ if (expected !== null && expected !== installed) {
281
+ console.log(
282
+ `[cli] Installed client is ${installed}; the project's ${ANDROID_PKG_MAP[abi]} is ${expected} (srt android --install updates it)`,
283
+ )
284
+ }
285
+ }
257
286
 
258
- // Hand the client the dev-server address to dial, as a launch-intent extra that
259
- // MainActivity forwards to native argv (--dev-server); the client auto-connects
260
- // to it. Replaces adb reverse, which never worked over wireless adb. -S stops
261
- // a running instance first: a delivered intent does not reach one, so without
262
- // it the client would keep whatever server it had.
263
- let before = new Set((await connectedClients(server)).map((c) => c.id))
264
- let devServer = devServerAddress(adb, target, server)
287
+ // Launch the client on `target`, handing it the dev-server address to dial as
288
+ // a launch-intent extra that MainActivity forwards to native argv
289
+ // (--dev-server); the client auto-connects to it. Replaces adb reverse, which
290
+ // never worked over wireless adb. -S stops a running instance first: a
291
+ // delivered intent does not reach one, so without it the client would keep
292
+ // whatever server it had. With no server there is no extra to pass.
293
+ async function launch(adb: string, { target }: Device, server: LiveRecord | null) {
294
+ let devServer = server ? devServerAddress(adb, target, server) : null
265
295
  let launchArgs = [adb, "-s", target, "shell", "am", "start", "-S", "-n", PACKAGE_ACTIVITY]
266
296
  if (devServer) {
267
- console.log(`[cli] Client will dial dev server at ${devServer}`)
297
+ console.log(`[cli] Client on ${target} will dial dev server at ${devServer}`)
268
298
  launchArgs.push("--es", "srt_dev_server", devServer)
269
- } else {
270
- console.log("[cli] Could not resolve a host address for the device; client will need a manual/QR connect")
299
+ } else if (server) {
300
+ console.log(`[cli] Could not resolve a host address for ${target}; client will need a manual/QR connect`)
271
301
  }
272
-
273
302
  let start = Bun.spawn(launchArgs, { stdout: "pipe", stderr: "pipe" })
274
303
  if ((await start.exited) !== 0) {
275
304
  console.error("adb start failed:\n" + (await new Response(start.stderr).text()))
276
305
  process.exit(1)
277
306
  }
307
+ console.log(`[cli] Launched SolidRT-Go on ${target}`)
308
+ }
309
+
310
+ // Launch the Android client on the connected devices over adb (installing it
311
+ // first on --install), then wait briefly for them to show up on the dev
312
+ // server. The clients are not child processes here: their lifecycle is the
313
+ // WS connect/disconnect the server sees.
314
+ export async function main() {
315
+ let server = await resolveServer()
316
+ let adb = requireAdb()
317
+
318
+ let devices = await resolveTargets(adb)
319
+ for (let device of devices) await prepare(adb, device)
320
+
321
+ let before = new Set(server ? (await connectedClients(server)).map((c) => c.id) : [])
322
+ for (let device of devices) await launch(adb, device, server)
323
+ if (!server) return
278
324
 
279
- console.log(`[cli] Launched SolidRT-Go on ${target}; waiting for it to connect to the dev server...`)
280
- let client = await waitForClient(server, before)
281
- if (client) {
325
+ console.log("[cli] Waiting for the client(s) to connect to the dev server...")
326
+ let clients = await waitForClients(server, before, devices.length)
327
+ for (let client of clients) {
282
328
  console.log(`[cli] Client ${client.id} connected (${client.platform}, ${client.version})`)
283
- } else {
284
- console.log(`[cli] No connection after 10 s. The server must run with --lan and the device must reach this machine.`)
285
329
  }
286
- }
330
+ if (clients.length < devices.length) {
331
+ console.log(
332
+ `[cli] ${devices.length - clients.length} of ${devices.length} not connected after 10 s. The server must run with --lan and the device must reach this machine.`,
333
+ )
334
+ }
335
+ }
@@ -2,7 +2,7 @@ import { transformAsync } from "@babel/core"
2
2
  import jsx from "@babel/plugin-syntax-jsx"
3
3
  import ts from "@babel/preset-typescript"
4
4
  import remapping from "@jridgewell/remapping"
5
- import solid from "babel-preset-solid"
5
+ import solid from "@solidjs/babel-plugin"
6
6
  import { type BunPlugin, type BuildArtifact } from "bun"
7
7
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"
8
8
  import { dirname, join, relative, resolve as resolvePath, sep } from "node:path"
@@ -76,7 +76,7 @@ async function codeFromOutputs(outputs: BuildArtifact[]): Promise<string> {
76
76
  return code
77
77
  }
78
78
 
79
- // Bun build plugin that runs JSX/TSX through babel-preset-solid (universal
79
+ // Bun build plugin that runs JSX/TSX through @solidjs/babel-plugin (universal
80
80
  // generate, targeting @solidrt/core) plus the TS preset. `moduleName` only ends
81
81
  // up as an import specifier in the emitted code, resolved from the app's tree at
82
82
  // bundle time; the CLI itself never loads core, so core is deliberately neither
@@ -108,8 +108,8 @@ function solidPlugin(inputs: Set<string>, babelMaps?: Map<string, object>, isola
108
108
  let transforms = await transformAsync(code, {
109
109
  filename: args.path,
110
110
  sourceMaps: !!babelMaps,
111
- presets: [[solid, { moduleName: "@solidrt/core", generate: "universal" }], [ts]],
112
- plugins: [jsx, inlineImport(inputs)],
111
+ presets: [[ts]],
112
+ plugins: [jsx, [solid, { moduleName: "@solidrt/core", generate: "universal" }], inlineImport(inputs)],
113
113
  })
114
114
  if (babelMaps && transforms?.map) babelMaps.set(args.path, transforms.map)
115
115
  return { contents: transforms?.code ?? "", loader: "js" }
@@ -11,8 +11,8 @@ declare module "@babel/preset-typescript" {
11
11
  let preset: PluginItem
12
12
  export default preset
13
13
  }
14
- declare module "babel-preset-solid" {
14
+ declare module "@solidjs/babel-plugin" {
15
15
  import { type PluginItem } from "@babel/core"
16
- let preset: PluginItem
17
- export default preset
16
+ let plugin: PluginItem
17
+ export default plugin
18
18
  }
@@ -6,4 +6,6 @@ The client half of [srt run](../server/docs.md), on its own. Without flags
6
6
  it attaches to the dev server of the project (or file) in the current
7
7
  directory; `--port` picks a local server by port and `--server` names any
8
8
  address, which is how a second machine joins a server started with `--lan`.
9
- A phone or tablet is [srt android](../android/docs.md).
9
+ Without a running server the client starts on its own, into the launcher
10
+ (`--port` and `--server` must name a live server). A phone or tablet is
11
+ [srt android](../android/docs.md).
@@ -4,13 +4,14 @@ import { resolveFromCwd } from "../lib/registry"
4
4
 
5
5
  // Standalone solidrt-go client (no dev server of its own). Without flags it
6
6
  // attaches to the dev server of the project (or file) in the current
7
- // directory, resolved from the registry; --port picks a local server by port
8
- // and --server names any address. A device is `srt android`.
7
+ // directory, resolved from the registry, and starts on its own (into the
8
+ // launcher) when there is none; --port picks a local server by port and
9
+ // --server names any address, and those must exist. A device is `srt android`.
9
10
  export async function main() {
10
11
  let runner = requireBinary("solidrt-go")
11
12
  let args: string[] = [...clientStorageArgs()]
12
13
  if (values.size) args.push("--size", values.size)
13
- let address: string
14
+ let address: string | null
14
15
  if (values.server) {
15
16
  if (!values.server.includes(":")) {
16
17
  console.error(`--server needs host:port (got "${values.server}"); dev servers have no fixed port`)
@@ -21,13 +22,9 @@ export async function main() {
21
22
  address = `127.0.0.1:${port}`
22
23
  } else {
23
24
  let resolved = await resolveFromCwd(process.cwd())
24
- if (!resolved.ok) {
25
- console.error(resolved.message)
26
- process.exit(1)
27
- }
28
- address = `127.0.0.1:${resolved.record.port}`
25
+ address = resolved.ok ? `127.0.0.1:${resolved.record.port}` : null
29
26
  }
30
- args.push("--dev-server", address)
27
+ if (address) args.push("--dev-server", address)
31
28
  let exit = await run(runner, args)
32
29
  process.exit(exit)
33
30
  }
package/src/demo/docs.md CHANGED
@@ -2,26 +2,32 @@
2
2
 
3
3
  {{ usage demo }}
4
4
 
5
- The demos that come with the packages this project installs. Without an
6
- argument it lists them, numbered:
5
+ The demos the SolidRT packages come with, shipped pre-bundled with the CLI so
6
+ every install has all of them, whether or not the packages themselves are
7
+ installed. Without an argument it lists them, numbered:
7
8
 
8
9
  ```
9
10
  1 3d/the-third-dimension
11
+ 2 components/gallery
10
12
  ```
11
13
 
12
14
  `srt demo 1` runs that one, exactly as [srt run](../server/docs.md) runs any
13
- project: a dev server, a local client window, reload on save, and the same
14
- server options (`--lan` to reach it from a device, `--port`, `--tunnel`). The qualified
15
- name works too (`srt demo 3d/the-third-dimension`), which is the stable way to
16
- name one in a script - the numbers follow the list, and the list follows what
17
- is installed.
15
+ project: a dev server and a local client window, with the same server
16
+ options (`--lan` to reach it from a device, `--port`, `--tunnel`). So a
17
+ running demo is an app the [console](../console/docs.md) picks up like any
18
+ other, with its tree, stats and control API. The qualified name works too
19
+ (`srt demo 3d/the-third-dimension`), which is the stable way to name one in
20
+ a script - the numbers follow the list.
18
21
 
19
- A package keeps its demos in `demos/`, and that folder is one project: its own
20
- package.json, one `assets/` folder, and `src/<name>.tsx` per demo. So the
21
- demos of one package share a dev server and a port - start a second one while
22
- the first is up and it says so. Demos from different packages run side by
23
- side.
22
+ A package keeps its demos in `demos/` in the repository, and that folder is
23
+ one project: its own package.json, one `assets/` folder, and `src/<name>.tsx`
24
+ per demo. The CLI ships that project bundled (`dist/demos/<package>/`, built
25
+ by `make -C packages/cli demos`), and `srt demo` serves it with the chosen
26
+ bundle as its entry. So the demos of one package share a dev server and a
27
+ port - start a second one while the first is up and it says so. Demos from
28
+ different packages run side by side.
24
29
 
25
- The demos ship inside the packages, so `node_modules` is where they are found:
26
- `srt demo` looks in the current directory and nowhere above it. Run it from
27
- the project root.
30
+ The bundles are what runs, so editing a demo's source does not reload it. In
31
+ a checkout, work on a demo with `srt run src/<name>.tsx --project` from the
32
+ package's `demos/` folder, and rebuild the shipped bundles with
33
+ `make -C packages/cli demos` when done.