serve-sim 0.1.8 → 0.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serve-sim",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Evan Bacon",
@@ -20,6 +20,9 @@
20
20
  "bin": {
21
21
  "serve-sim": "dist/serve-sim.js"
22
22
  },
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
23
26
  "files": [
24
27
  "dist/serve-sim.js",
25
28
  "dist/middleware.js",
package/src/middleware.ts CHANGED
@@ -7,7 +7,7 @@ import { join } from "path";
7
7
  declare const __PREVIEW_HTML_B64__: string;
8
8
  const STATE_DIR = join(tmpdir(), "serve-sim");
9
9
 
10
- interface ServeSimState {
10
+ export interface ServeSimState {
11
11
  pid: number;
12
12
  port: number;
13
13
  device: string;
@@ -125,6 +125,27 @@ function readServeSimStates(): ServeSimState[] {
125
125
  return states;
126
126
  }
127
127
 
128
+ export function selectServeSimState(
129
+ states: ServeSimState[],
130
+ device?: string | null,
131
+ ): ServeSimState | null {
132
+ if (device) {
133
+ return states.find((state) => state.device === device) ?? null;
134
+ }
135
+ return states[0] ?? null;
136
+ }
137
+
138
+ function queryDevice(rawUrl: string): string | null {
139
+ const qIndex = rawUrl.indexOf("?");
140
+ if (qIndex === -1) return null;
141
+ return new URLSearchParams(rawUrl.slice(qIndex + 1)).get("device");
142
+ }
143
+
144
+ function endpoint(base: string, path: string, device: string): string {
145
+ const value = `${base}${path}`;
146
+ return `${value}?device=${encodeURIComponent(device)}`;
147
+ }
148
+
128
149
  let _html: string | null = null;
129
150
  function loadHtml(): string {
130
151
  if (!_html) {
@@ -136,6 +157,8 @@ function loadHtml(): string {
136
157
  export interface SimMiddlewareOptions {
137
158
  /** Base path to serve the preview at. Default: "/.sim" */
138
159
  basePath?: string;
160
+ /** Pin this preview server to a specific simulator UDID. */
161
+ device?: string;
139
162
  }
140
163
 
141
164
  /**
@@ -153,11 +176,12 @@ export function simMiddleware(options?: SimMiddlewareOptions) {
153
176
  const rawUrl: string = req.url ?? "";
154
177
  const qIndex = rawUrl.indexOf("?");
155
178
  const url = qIndex === -1 ? rawUrl : rawUrl.slice(0, qIndex);
179
+ const selectedDevice = queryDevice(rawUrl) ?? options?.device ?? null;
156
180
 
157
181
  // Serve the preview page
158
182
  if (url === base || url === base + "/") {
159
183
  const states = readServeSimStates();
160
- const state = states[0] ?? null;
184
+ const state = selectServeSimState(states, selectedDevice);
161
185
  let html = loadHtml();
162
186
 
163
187
  if (state) {
@@ -166,7 +190,8 @@ export function simMiddleware(options?: SimMiddlewareOptions) {
166
190
  // and connects to the WS directly (WS has no CORS).
167
191
  const config = JSON.stringify({
168
192
  ...state,
169
- logsEndpoint: base + "/logs",
193
+ logsEndpoint: endpoint(base, "/logs", state.device),
194
+ appStateEndpoint: endpoint(base, "/appstate", state.device),
170
195
  });
171
196
  const configScript = `<script>window.__SIM_PREVIEW__=${config}</script>`;
172
197
  html = html.replace("<!--__SIM_PREVIEW_CONFIG__-->", configScript);
@@ -183,11 +208,12 @@ export function simMiddleware(options?: SimMiddlewareOptions) {
183
208
  // JSON API: serve-sim state
184
209
  if (url === base + "/api") {
185
210
  const states = readServeSimStates();
211
+ const state = selectServeSimState(states, selectedDevice);
186
212
  res.writeHead(200, {
187
213
  "Content-Type": "application/json",
188
214
  "Cache-Control": "no-store",
189
215
  });
190
- res.end(JSON.stringify(states[0] || null));
216
+ res.end(JSON.stringify(state || null));
191
217
  return;
192
218
  }
193
219
 
@@ -224,12 +250,13 @@ export function simMiddleware(options?: SimMiddlewareOptions) {
224
250
  // SSE: simctl log stream
225
251
  if (url === base + "/logs") {
226
252
  const states = readServeSimStates();
227
- if (states.length === 0) {
253
+ const state = selectServeSimState(states, selectedDevice);
254
+ if (!state) {
228
255
  res.writeHead(404);
229
256
  res.end("No serve-sim device");
230
257
  return;
231
258
  }
232
- const udid = states[0].device;
259
+ const udid = state.device;
233
260
  res.writeHead(200, {
234
261
  "Content-Type": "text/event-stream",
235
262
  "Cache-Control": "no-cache",
@@ -266,12 +293,13 @@ export function simMiddleware(options?: SimMiddlewareOptions) {
266
293
  // stays narrow and the client can listen without rate-limit concerns.
267
294
  if (url === base + "/appstate") {
268
295
  const states = readServeSimStates();
269
- if (states.length === 0) {
296
+ const state = selectServeSimState(states, selectedDevice);
297
+ if (!state) {
270
298
  res.writeHead(404);
271
299
  res.end("No serve-sim device");
272
300
  return;
273
301
  }
274
- const udid = states[0].device;
302
+ const udid = state.device;
275
303
  res.writeHead(200, {
276
304
  "Content-Type": "text/event-stream",
277
305
  "Cache-Control": "no-cache",