@swiftbrowser/web 0.1.0 → 0.3.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 (99) hide show
  1. package/README.md +141 -63
  2. package/app/index.html +21 -10
  3. package/node/dist/node/apps.d.ts +16 -0
  4. package/node/dist/node/apps.d.ts.map +1 -1
  5. package/node/dist/node/apps.js +9 -0
  6. package/node/dist/node/apps.js.map +1 -1
  7. package/node/dist/node/config.d.ts +14 -1
  8. package/node/dist/node/config.d.ts.map +1 -1
  9. package/node/dist/node/config.js +20 -3
  10. package/node/dist/node/config.js.map +1 -1
  11. package/node/dist/node/examples.d.ts +2 -1
  12. package/node/dist/node/examples.d.ts.map +1 -1
  13. package/node/dist/node/examples.js +12 -2
  14. package/node/dist/node/examples.js.map +1 -1
  15. package/node/dist/plugins/app-manifests.d.ts +4 -1
  16. package/node/dist/plugins/app-manifests.d.ts.map +1 -1
  17. package/node/dist/plugins/app-manifests.js +3 -2
  18. package/node/dist/plugins/app-manifests.js.map +1 -1
  19. package/node/dist/plugins/asset-catalogs.d.ts +15 -3
  20. package/node/dist/plugins/asset-catalogs.d.ts.map +1 -1
  21. package/node/dist/plugins/asset-catalogs.js +111 -13
  22. package/node/dist/plugins/asset-catalogs.js.map +1 -1
  23. package/node/dist/plugins/included-sites.d.ts +26 -0
  24. package/node/dist/plugins/included-sites.d.ts.map +1 -0
  25. package/node/dist/plugins/included-sites.js +70 -0
  26. package/node/dist/plugins/included-sites.js.map +1 -0
  27. package/node/dist/plugins/pdfImages.d.ts +27 -0
  28. package/node/dist/plugins/pdfImages.d.ts.map +1 -0
  29. package/node/dist/plugins/pdfImages.js +145 -0
  30. package/node/dist/plugins/pdfImages.js.map +1 -0
  31. package/node/dist/plugins/swift-wasm.d.ts +19 -1
  32. package/node/dist/plugins/swift-wasm.d.ts.map +1 -1
  33. package/node/dist/plugins/swift-wasm.js +45 -7
  34. package/node/dist/plugins/swift-wasm.js.map +1 -1
  35. package/node/dist/plugins/symbolTemplates.d.ts +22 -0
  36. package/node/dist/plugins/symbolTemplates.d.ts.map +1 -0
  37. package/node/dist/plugins/symbolTemplates.js +83 -0
  38. package/node/dist/plugins/symbolTemplates.js.map +1 -0
  39. package/package.json +4 -2
  40. package/plugins/app-manifests.ts +3 -2
  41. package/plugins/asset-catalogs.ts +119 -14
  42. package/plugins/included-sites.ts +74 -0
  43. package/plugins/pdfImages.ts +163 -0
  44. package/plugins/swift-wasm.ts +52 -6
  45. package/plugins/symbolTemplates.ts +88 -0
  46. package/public/_headers +7 -0
  47. package/public/app/oauth-callback.html +62 -0
  48. package/src/animation.ts +235 -8
  49. package/src/appFiles.ts +201 -0
  50. package/src/base64.ts +43 -0
  51. package/src/bitmapPlan.ts +143 -0
  52. package/src/bitmapStore.ts +206 -0
  53. package/src/bitmapWorker.ts +41 -0
  54. package/src/bitmapWorkerProtocol.ts +15 -0
  55. package/src/bitmaps.ts +283 -0
  56. package/src/blockedHosts.ts +29 -0
  57. package/src/canvasDrawing.ts +361 -0
  58. package/src/chartDom.ts +2 -2
  59. package/src/chromeColor.ts +179 -0
  60. package/src/clipboard.ts +78 -0
  61. package/src/colorMultiply.ts +93 -0
  62. package/src/colorPicker.ts +44 -0
  63. package/src/corsProxy.ts +45 -0
  64. package/src/gaugeRing.ts +74 -0
  65. package/src/gif.ts +297 -0
  66. package/src/hostRequests.ts +426 -0
  67. package/src/imageOps.ts +592 -0
  68. package/src/interaction.ts +68 -3
  69. package/src/landing.ts +2 -2
  70. package/src/largeTitle.ts +79 -0
  71. package/src/layout/chart.ts +9 -3
  72. package/src/layout/engine.ts +681 -174
  73. package/src/layout/index.ts +3 -1
  74. package/src/layout/text.ts +217 -1
  75. package/src/layout/types.ts +31 -0
  76. package/src/layout/typography.ts +24 -7
  77. package/src/layout/video.ts +24 -0
  78. package/src/layoutDom.ts +66 -6
  79. package/src/main.ts +127 -4
  80. package/src/media.ts +132 -0
  81. package/src/mock.ts +4 -3
  82. package/src/notifications.ts +109 -0
  83. package/src/pathShape.ts +156 -0
  84. package/src/protocol.ts +782 -13
  85. package/src/renderer.ts +603 -44
  86. package/src/richText.ts +65 -0
  87. package/src/scanner.ts +234 -0
  88. package/src/scrollTo.ts +123 -0
  89. package/src/styles.css +521 -100
  90. package/src/styles.ts +61 -0
  91. package/src/swiftData.ts +128 -0
  92. package/src/symbols.ts +658 -28
  93. package/src/translation.ts +126 -0
  94. package/src/video.ts +299 -0
  95. package/src/vite-env.d.ts +6 -0
  96. package/src/wasm.ts +227 -32
  97. package/src/webAuth.ts +267 -0
  98. package/src/webSocket.ts +148 -0
  99. package/src/zoneinfo.ts +269 -0
package/README.md CHANGED
@@ -14,6 +14,7 @@ app/index.html The app page (served at /app/): toolbar, iPhone frame, #scre
14
14
  src/landing.ts Landing page script: app cards (qrcode SVGs), build info from the `define`s
15
15
  src/landing.css Landing page styles
16
16
  src/deviceMode.ts Frame vs device mode decision, env(safe-area-inset-*) reader, viewport watcher
17
+ src/chromeColor.ts Device mode: the browser's status bar strip and safe areas take the app's top-edge color
17
18
  src/vite-env.d.ts Types of the build-time defines (__SB_APPS__, __SB_COMMIT__, …)
18
19
  src/protocol.ts TypeScript mirror of the ops protocol (Op, element kinds, Style, Color, Animation, events)
19
20
  src/renderer.ts Renderer: Map<id, HTMLElement> + LayoutNode tree, ops, navigation, sheets, layout on commit
@@ -26,6 +27,11 @@ src/wasm.ts loadApp(): WASI shim, _start, sb_ops_*, sb_event, sb_alloc +
26
27
  src/mock.ts Counter, Todos, Gallery and Settings fixtures + in-page mock "Swift core" for ?mock=1
27
28
  src/main.ts App page wiring: mode, theme toggle, Text size control, app label, boot, hot-reload state stash
28
29
  src/devEvents.ts Payload types for the sb:build-* websocket events
30
+ src/hostRequests.ts Phase 13: performs the app's `request` ops (URLSession → fetch, AsyncImage → an Image() probe) and answers with `response` events
31
+ src/bitmaps.ts UIImage bitmaps: draws recipes on each image's <canvas>, through the store in a worker or on the page
32
+ src/bitmapStore.ts The bitmap store: keeps `imagedata` sources, decodes them, draws recipes (bitmapPlan.ts, imageOps.ts); no DOM
33
+ src/bitmapWorker.ts The store in a worker, answering drawings with ImageBitmaps
34
+ src/imageOps.ts Core Image's steps (sepia, crystallize, edges, blur, pixellate, unsharp mask, vignette, crop) on rasters; no DOM
29
35
  src/styles.css iOS tokens, device frame, device mode, element styles
30
36
  node/ Node side: apps.ts (the AppSpec registry type), config.ts (Vite config from specs),
31
37
  examples.ts (Examples/* as specs, build-wasm.sh runner, descriptions),
@@ -86,6 +92,14 @@ from `displayName`, `description` and `icon`.
86
92
  `SB_WASM_OPT=0`, `watch` = `Sources/` + the example's directory), which is
87
93
  what `npm run dev` / `vite build` use.
88
94
 
95
+ A built site lists its apps in `apps.json`, and other built sites can join a
96
+ build (`SiteOptions.sites`; `SB_SITES` for `vite build`, directories separated
97
+ like `PATH`): `plugins/included-sites.ts` adds their apps to the landing page
98
+ and copies their files (modules, catalogs, bundles, manifests) next to this
99
+ site's, keeping this site's pages and any file it already has. CI's deploy
100
+ adds Apple's Backyard Birds this way, built from its repository with
101
+ `swiftbrowser build`.
102
+
89
103
  Other packages (the CLI) import the same machinery through the package entry,
90
104
  compiled by `npm run build:node` (`tsconfig.node-build.json` → `node/dist/`):
91
105
 
@@ -165,6 +179,9 @@ The app page's query parameters:
165
179
 
166
180
  - `?mode=device` / `?mode=frame` forces device mode or the iPhone frame (see
167
181
  "Device mode" below).
182
+ - `?arg=<value>` (repeatable) adds launch arguments after the app's name,
183
+ as `simctl launch` passes them: `?app=Fidelity&arg=-screen&arg=form` opens
184
+ that screen of Examples/Fidelity (`ProcessInfo.processInfo.arguments`).
168
185
 
169
186
  The light/dark toggle in the toolbar flips `data-theme` on the device frame and
170
187
  is remembered in `localStorage` (`sb-theme`). It only affects the phone; the
@@ -210,11 +227,28 @@ job scheduler are unaffected. `window.__sb.mode` reports the mode.
210
227
  `apple-mobile-web-app-status-bar-style: black-translucent` (the OS status bar
211
228
  stays transparent, the app's own background shows under it and the layout
212
229
  engine gets the bar as a safe-area inset; `default` draws an opaque light bar
213
- whatever the app's color scheme), light/dark `theme-color`s, a web app
214
- manifest and the icons `public/icon.svg` + `public/apple-touch-icon.png`
230
+ whatever the app's color scheme), light/dark `theme-color`s (the defaults
231
+ until the app draws), a web app manifest and the icons `public/icon.svg` + `public/apple-touch-icon.png`
215
232
  (180×180, drawn with ImageMagick to match the SVG). In Safari, Share → Add to
216
233
  Home Screen then runs an app full screen.
217
234
 
235
+ In the browser itself (not standalone), Safari tints its status bar strip and
236
+ the safe areas from `theme-color`, the page background and (in recent Safari)
237
+ the fixed element at the top edge. `src/chromeColor.ts` keeps those in step
238
+ with the app: after each layout pass, a theme change and the end of each push,
239
+ pop or sheet animation (at most four times a second), it composites the
240
+ backgrounds the app paints at the middle of its top edge, walking only the
241
+ elements whose box holds that point (about 270 on Ice Cubes' timeline, under a
242
+ millisecond). The
243
+ result becomes the one `theme-color`, the `html`, `body` and `#device`
244
+ backgrounds, and `html`'s `color-scheme` is the app's scheme, so an app's own
245
+ bar color, its `.preferredColorScheme` or a sheet's dimming reach the strip
246
+ instead of the OS appearance's defaults. Safari seems to take the strip's
247
+ color from the first paint and not follow later changes, so in device mode the
248
+ first paint already has the OS appearance: an inline script after `#device`
249
+ sets its `data-theme` from `prefers-color-scheme`, and the page background is
250
+ the system background for it (white / black) before `main.ts` runs.
251
+
218
252
  Safari takes a home-screen icon's launch URL and label from the manifest, not
219
253
  from the page URL, so there is one manifest per example: `plugins/app-manifests.ts`
220
254
  serves `/manifests/<Name>.webmanifest` (`start_url: /app/?app=<Name>`,
@@ -244,9 +278,9 @@ Those files are build products and are git-ignored (`public/*.wasm`); only
244
278
  From the repo root:
245
279
 
246
280
  ```sh
247
- scripts/build-wasm.sh # swift build --swift-sdk <wasm sdk> -c release, wasm-opt -Os (when installed), then
248
- # copies Counter.wasm into Web/public/
249
- scripts/build-wasm.sh Todos # same for the Todos example
281
+ scripts/build-wasm.sh # every example through the CLI (swiftbrowser build: release, wasm-opt -Oz
282
+ # when installed), each <App>.wasm copied into Web/public/
283
+ scripts/build-wasm.sh Todos # the Todos example only
250
284
  ```
251
285
 
252
286
  ## Hot reload
@@ -373,20 +407,34 @@ color scheme or the fonts change (`renderer.setEnvironment`,
373
407
  content inset, so the last row can scroll clear of the home indicator (the
374
408
  engine's frames are unchanged).
375
409
  - Compound kinds use the engine's `chrome` rects: `navscreen` {bar (status bar
376
- + 44, padded so the 44px row is at the bottom), largeTitle (52px row, text
377
- from `chromeText`), back, content}, `sheet` {grabber}, `toggle` {switch},
378
- `section` {rows (the inset card), header, footer}, `navlink` rows {chevron},
379
- `tabview` {bar, item0 … itemN-1}, `picker` {segment0 … / label, value}.
410
+ + 44, padded so the 44px row is at the bottom), largeTitle (62px row, text
411
+ from `chromeText`), back, content}, `sheet` {grabber, floating}, `toggle`
412
+ {switch}, `section` {rows (the inset card), header, footer}, `navlink`
413
+ rows {chevron}, `tabview` {bar, item0 … itemN-1}, `picker` {segment0 … /
414
+ label, value}.
380
415
  A `list` or `scrollview` under a tab bar gets a `bottomInset` rect (the
381
416
  part of its frame the bar covers): its height replaces the 34px safe-area
382
417
  content inset.
383
- Section headers come upper-cased from the engine in the footnote font;
384
- footers are drawn from the section's own `footer` prop (sentence case).
418
+ A `list` or `scrollview` with a `largeTitle` rect carries its screen's
419
+ large title (src/largeTitle.ts): the title follows its scroll offset and
420
+ fades out over 16px at the bar's edge, as the scrolled content does
421
+ (`data-sb-scrolled`, a mask standing in for iOS 26's scroll edge effect);
422
+ past 44 the screen gets `data-sb-collapsed`, which fades the inline title
423
+ in (its text is always set; CSS hides it on a large screen until then). On
424
+ an overscroll the title moves down with the content (iOS 26 no longer
425
+ grows it).
426
+ Section headers keep their case (iOS 26) and come from the engine in the
427
+ headline font (17 semibold), secondary color; footers are drawn from the
428
+ section's own `footer` prop in the engine's footnote font and rect.
385
429
  - A list row's DOM box is the engine's full-width `row` rect (so the cell
386
- background, the 16px-inset separator and the hit area match iOS); leaf rows
430
+ background, the separator and the hit area match iOS); leaf rows
387
431
  (`text`, `image`, `textfield`) pad their content frame back into place.
388
- Rows whose own chrome replaced the `row` key (`toggle`, bordered `button`)
389
- rebuild it from the card and the engine's rule `max(44, content + 2 × 11)`.
432
+ The separator (`--sb-color-row-separator`, light `rgba(0,0,0,0.09)`)
433
+ starts at the row's first text (the engine's row chrome `separator`, set
434
+ as `--sb-separator-leading`, else 16px) and ends 16px before the trailing
435
+ edge. Rows whose own chrome replaced the `row` key (`toggle`, bordered
436
+ `button`) rebuild it from the card and the engine's rule
437
+ `max(52, content + 2 × 13)`.
390
438
  - Layout-only style fields (`padding`, `frame`, `layoutPriority`, `fixedSize`,
391
439
  `lineLimit`, `multilineTextAlignment`) leave data attributes
392
440
  (`data-sb-padding`, `data-sb-frame`, `data-sb-line-limit`, …) and are read by
@@ -394,8 +442,10 @@ color scheme or the fonts change (`renderer.setEnvironment`,
394
442
  (+ `overflow: hidden`), `opacity` and `disabled` are inline CSS as before.
395
443
  - Expected geometry with the real modules: Counter's three buttons are 88×44
396
444
  at x = 48 / 152 / 256, y = 521 (16px gaps, centered); Todos' bar spans
397
- y 0–103, the large title 103–155, the list starts at 155 and its rows are
398
- 44 high and inset 16; a pushed inline screen's bar row is y 59–103.
445
+ y 0–103, the large title 103–165 (scrolling with the list, which starts
446
+ under the bar at 103 with its content 62 down, so its first card is at
447
+ 183), and its rows are 52 high and inset 16; a pushed inline screen's bar
448
+ row is y 59–103.
399
449
 
400
450
  ### Fonts and Dynamic Type
401
451
 
@@ -416,14 +466,21 @@ color scheme or the fonts change (`renderer.setEnvironment`,
416
466
  - Semantic colors resolve to CSS variables (`--sb-color-primary`, `-secondary`,
417
467
  `-accent`, `-system-background`, `-secondary-system-background`); `clear` is
418
468
  `transparent`. Values for both schemes live in `styles.css` under
419
- `.device[data-theme]`. An `a` on a semantic color is an opacity multiplier,
420
- rendered as `color-mix(in srgb, var(--token) <a*100>%, transparent)`.
469
+ `.device[data-theme]`: iOS 26's palette (accent and blue `#0088ff`, dark
470
+ `#0091ff`; red `#ff383c`, orange `#ff8d28`, …). An `a` on a semantic
471
+ color is an opacity multiplier, rendered as
472
+ `color-mix(in srgb, var(--token) <a*100>%, transparent)`.
421
473
  - `Style.disabled` multiplies the box's opacity by 0.4 and sets
422
474
  `pointer-events: none` (plus `data-sb-disabled` / `aria-disabled`).
423
475
  - `button.style` and `button.role` become `data-sb-style` / `data-sb-role`;
424
- `bordered` is a gray capsule, `borderedProminent` a filled accent capsule
425
- (label + 14/7 padding, 34px minimum, from the engine), `destructive` red
426
- text. Phase 1 modules send `{}`, which reads as `automatic`.
476
+ `bordered` is a capsule in the secondary fill, or in the view's `tint` at
477
+ 18% (25% in dark mode, `--sb-tint-fill`, which the renderer sets beside
478
+ `--sb-tint`), `borderedProminent` a filled accent capsule
479
+ (label + 12/6 padding, 34px minimum, from the engine; with a `controlSize`
480
+ prop: `small` 28, `mini` 24, `large` 50, `extraLarge` 58), `destructive`
481
+ red text; a disabled bordered button keeps the gray fill and dims its label
482
+ rather than fading. Phase 1
483
+ modules send `{}`, which reads as `automatic`.
427
484
  - `image`: `systemName` is looked up in `src/symbols.ts` (SF Symbol name →
428
485
  lucide glyph, including `.fill` / `.circle` variants) and rendered as an
429
486
  inline `<svg>` in `currentColor`. Unknown names draw a dashed square with
@@ -433,14 +490,15 @@ color scheme or the fonts change (`renderer.setEnvironment`,
433
490
  (`50%`) and `capsule` (`9999px`). `fill` is the background; `fill: null`
434
491
  without a stroke paints `currentColor` (a bare `Circle()`), with a stroke it
435
492
  paints nothing (`Shape.stroke(_:)`); `stroke` is a solid border of
436
- `lineWidth` (inside the frame, `box-sizing: border-box`). Both take exactly
437
- the size the engine proposes (10pt on an unconstrained axis).
438
- - `list` / `section` render iOS inset-grouped: grouped background on the
439
- list, white (dark: `#1C1C1E`) 10px-rounded cards inset 16px, 44px rows
440
- with 16px content insets and separators inset 16px. Every direct child of a
441
- section (and every non-`section` child of a list) is a row; a `navlink`
442
- row shows a trailing chevron, a `toggle` row puts the switch at the
443
- trailing inset.
493
+ `lineWidth` (inside the frame, `box-sizing: border-box`), dashed when it
494
+ carries a `dash` pattern (the dash lengths are the browser's). Both take
495
+ exactly the size the engine proposes (10pt on an unconstrained axis).
496
+ - `list` / `section` render iOS 26 inset-grouped: grouped background on the
497
+ list, white (dark: `#1C1C1E`) 26px-rounded cards inset 16px, rows at least
498
+ 52px with 16px content insets and separators from the first text to 16px
499
+ before the trailing edge. Every direct child of a section (and every
500
+ non-`section` child of a list) is a row; a `navlink` row shows a trailing
501
+ chevron, a `toggle` row puts the switch at the trailing inset.
444
502
  - Compound kinds (`navstack`, `navscreen`, `section`, `toggle`, `navlink`,
445
503
  `list`, `scrollview`, `sheet`) own some chrome. Their protocol children go
446
504
  into a slot element (`.sb-slot`), so `insert` indices are exact;
@@ -449,26 +507,30 @@ color scheme or the fonts change (`renderer.setEnvironment`,
449
507
  (`data-sb-nav-position`, `inert`); a new screen slides in from the right
450
508
  over 0.35s and the one below parks at `translateX(-30%)`. A removed top
451
509
  screen animates out through a visual clone stripped of element ids. Screens
452
- at `depth > 0` show a back button (`chevron.left` + the previous screen's
453
- current title) that sends a `tap` with the `navscreen`'s own id. A title
454
- `update` on any screen also refreshes the back labels above it.
510
+ at `depth > 0` show a back button that sends a `tap` with the
511
+ `navscreen`'s own id: iOS 26's 44×44 glass circle at x 16 with
512
+ `chevron.left` alone, in the label color (the engine's back label is
513
+ empty; the previous screen's title shows only until the engine has run).
455
514
  - `textfield` is an `<input>` (34px `roundedBorder`, 22px `plain`); `input`
456
515
  events send `{"type":"text"}`. An `update` whose `text` equals the current
457
- value leaves `.value` (and the caret) alone. `toggle` renders a 51×31 switch
458
- (`role="switch"`); clicking it flips the switch optimistically and sends
459
- `{"type":"toggle"}`; Swift's `update` confirms the state.
516
+ value leaves `.value` (and the caret) alone. `toggle` renders a 63×28
517
+ switch with a 37×24 pill knob (`role="switch"`); clicking it flips the
518
+ switch optimistically and sends `{"type":"toggle"}`; Swift's `update`
519
+ confirms the state.
460
520
 
461
521
  ### Tab views, pickers, list styles and GeometryReader (Phase 4)
462
522
 
463
523
  - `tabview` fills the screen like a `navstack` (safe areas ignored). Its
464
524
  `tab` children go into `.sb-tabview-content` and all share the tab view's
465
- frame; the bar (`.sb-tabbar`, the engine's `bar` rect: 49 + the bottom
466
- safe area when the tab view reaches the screen bottom) is drawn on top with
467
- a translucent system background (`rgba(249,249,249,0.94)`, dark
468
- `rgba(29,29,29,0.94)`), a hairline on top and one `.sb-tabbar-item` per
469
- tab at the engine's `item<i>` rect (equal widths, 49 high): the tab's
470
- `systemImage` through the symbol table at 24px over a 10px title, accent
471
- when selected (`aria-selected`), secondary otherwise. Tapping an item sends
525
+ frame; the bar (`.sb-tabbar`, the engine's `bar` rect) is iOS 26's
526
+ floating glass capsule drawn on top: 62 high, x 21…372 on a 393 screen,
527
+ 22 above the screen bottom (8 above the bottom of a tab view that ends
528
+ higher), `--sb-glass-background` with `--sb-glass-shadow` and a backdrop
529
+ blur, 31px radius. One `.sb-tabbar-item` per tab sits at the engine's
530
+ `item<i>` rect (equal widths inside a 4 inset, 54 high): the tab's
531
+ `systemImage` through the symbol table at 24px over a 10px semibold title,
532
+ in the label color, the selected one (`aria-selected`) in the accent color
533
+ on a gray glass pill (`--sb-glass-selected`). Tapping an item sends
472
534
  `{"type":"select","id":<tabview id>,"value":<index>}` and nothing else:
473
535
  the `selected` prop is authoritative, the `update` switches tabs. Only the
474
536
  selected tab's content is laid out; the other tabs keep their DOM (and
@@ -476,19 +538,21 @@ color scheme or the fonts change (`renderer.setEnvironment`,
476
538
  `inert`, `aria-hidden`), driven by `LayoutResult.hidden`.
477
539
  - Tab content is placed like a navscreen's: a `navstack` fills the whole tab
478
540
  (its screens reserve the status bar and their lists run under the
479
- translucent bar); a `list`/`scrollview` starts below the status bar and
541
+ floating bar); a `list`/`scrollview` starts below the status bar and
480
542
  also runs to the bottom; anything else is centered between the status bar
481
- and the bar. Scrolling views under the bar get the bar height (83) as
482
- scrollable content inset instead of the 34px safe area (engine chrome
483
- `bottomInset`), so the last row scrolls clear of the bar like iOS.
543
+ and the bar. Scrolling views under the bar get what the bar covers (the
544
+ capsule and the gap under it, 84) as scrollable content inset instead of
545
+ the 34px safe area (engine chrome `bottomInset`), so the last row scrolls
546
+ clear of the bar like iOS.
484
547
  - `picker` `segmented`: an iOS segmented control, 32 high, width = proposal
485
- (or every label + 20): `.sb-segment-track` (`rgba(118,118,128,0.12)`, 8px
486
- radius; dark `rgba(118,118,128,0.24)`) at the control's frame and one
548
+ (or every label + 20): `.sb-segment-track` (`rgba(118,118,128,0.12)`, a
549
+ capsule; dark `rgba(118,118,128,0.24)`) at the control's frame and one
487
550
  `.sb-segment` radio button per option at the engine's `segment<i>` rect
488
- (13px semibold); the checked one carries a white pill (dark `#636366`)
551
+ (13px semibold); the checked one carries a white capsule (dark `#5a5a5f`)
489
552
  inset 2px with a soft shadow. Tapping a segment moves the pill
490
553
  optimistically and sends `select` with the index; Swift's `update`
491
- confirms. In a list row the row is 44 high with the control centered.
554
+ confirms. In a list row it gets the 13px row padding (a 58 row) with the
555
+ control centered.
492
556
  - `picker` `menu`: 44 high in a list row, 34 elsewhere; `role="button"` with
493
557
  `.sb-picker-label` at the engine's `label` rect (leading) and
494
558
  `.sb-picker-value` (the selected option plus `chevron.up.chevron.down`,
@@ -501,12 +565,12 @@ color scheme or the fonts change (`renderer.setEnvironment`,
501
565
  closes it (a tap inside the screen is swallowed so the control under it
502
566
  does not fire); an `update` or removal of the picker closes it too.
503
567
  `renderer.openMenuElement` exposes the open menu.
504
- - `list.style`: `insetGrouped` (default; Phase 2 modules send `{}`) is the
505
- existing card layout; `grouped` (`Form`) makes sections full width with no
506
- corner radius, a hairline above and below each card and the usual 16px
507
- content inset and 35px between sections; `plain` drops the cards, the top
508
- gap and the gaps between sections and uses the system background. The
509
- list carries `data-sb-list-style`.
568
+ - `list.style`: `insetGrouped` (default, and what `Form` sends; Phase 2
569
+ modules send `{}`) is the existing card layout; `grouped` makes sections
570
+ full width with no corner radius, a hairline above and below each card and
571
+ the usual 16px content inset and 35px between sections; `plain` drops the
572
+ cards, the top gap and the gaps between sections and uses the system
573
+ background. The list carries `data-sb-list-style`.
510
574
  - `geometry` (`GeometryReader`) is a plain box the engine sizes to its
511
575
  proposal (10 on an unconstrained axis, so one in a list row needs a frame
512
576
  height) and whose child is proposed that size and placed top leading.
@@ -522,18 +586,26 @@ color scheme or the fonts change (`renderer.setEnvironment`,
522
586
 
523
587
  A root-level `sheet` (child of id 0) is a full-screen layer (`role="dialog"`):
524
588
  a scrim (`rgba(0,0,0,0.4)`) over the presenting tree and a card at the
525
- engine's frame (large: screen height − status bar − 10; medium: half the
526
- screen) with 10px top corners, a 36×5 grabber 8px from the top, and the
527
- sheet background (`#FFFFFF`, dark: `#1C1C1E`, the elevated background). The
528
- card slides up over 0.4s on insert (`sb-sheet-in`); on remove a clone
529
- (`.sb-sheet--out`, no element ids) slides down and fades its scrim, then goes.
589
+ engine's frame (large: screen height − status bar − 10, 10px top corners;
590
+ medium: 433 high) and the sheet background (`#FFFFFF`, dark: `#1C1C1E`, the
591
+ elevated background). A 36×5 grabber sits 8px from the top only when the
592
+ sheet has more than one detent (iOS 26). A medium, height or fraction sheet
593
+ floats (engine chrome `floating`, `data-sb-floating`): a card inset 8px from
594
+ the screen sides and 15px above its bottom, 38px corners all round, the
595
+ sheet background at 55% over a backdrop blur, a lighter scrim
596
+ (`rgba(0,0,0,0.22)`); navigation screens in it are transparent, so the
597
+ glass shows through them. A navigation stack in a sheet fills the card from
598
+ its top, its bar taking 16px (20 with a grabber) above the 44px row. The card slides up over 0.4s on insert
599
+ (`sb-sheet-in`); on remove a clone (`.sb-sheet--out`, no element ids) slides
600
+ down and fades its scrim, then goes.
530
601
  While the top sheet is `large`, `#screen` carries `data-sb-sheet="large"` and
531
602
  the other root children scale to 0.92 behind the scrim; a `medium` sheet only
532
603
  dims. Sheets stack: only the last is interactive (`data-sb-sheet-position`,
533
604
  `inert`), sheets below park slightly scaled. A tap on the scrim, or a
534
605
  downward drag of the card past 100px (pointer events; shorter drags spring
535
606
  back), sends `{"type":"tap","id":<sheet id>}`: the dismiss request Swift
536
- answers by removing the element. `detents` only matters by its first entry.
607
+ answers by removing the element. `detents` matters by its first entry (and
608
+ its count, for the grabber).
537
609
 
538
610
  ### Animation (Phase 3)
539
611
 
@@ -579,7 +651,13 @@ transaction override); everything else in an animated commit uses the commit's.
579
651
  ## Testing
580
652
 
581
653
  `npm run test:unit` runs the layout engine's vitest suite (Node, no browser).
582
- `npm run test:e2e` runs Playwright with Chromium. The config boots
654
+ `npm run test:e2e` runs Playwright with Chromium, in three projects: `mock`
655
+ (the specs listed in `MOCK_SPECS` in `playwright.config.ts`, which load no
656
+ compiled module), `wasm-heavy` (the slowest specs against real modules,
657
+ `HEAVY_SPECS`) and `wasm` (every other spec; these need `public/<App>.wasm`).
658
+ `--project=mock` runs without any module built; CI runs it while the examples
659
+ build, and runs `wasm-heavy` and `wasm` in two jobs of about the same length.
660
+ The config boots
583
661
  `npm run dev -- --port 5173 --strictPort` itself. `e2e/renderer.spec.ts`
584
662
  covers the Counter mock and op semantics, `e2e/phase2.spec.ts` the Phase 2
585
663
  kinds against the Todos mock, `e2e/phase3.spec.ts` Dynamic Type, color/shape,
package/app/index.html CHANGED
@@ -90,23 +90,23 @@
90
90
  <span class="status-time">9:41</span>
91
91
  <span class="status-glyphs">
92
92
  <!-- Cellular -->
93
- <svg class="glyph glyph-cellular" viewBox="0 0 18 12" width="18" height="12">
94
- <rect x="0" y="8" width="3" height="4" rx="0.8" />
95
- <rect x="5" y="5.5" width="3" height="6.5" rx="0.8" />
96
- <rect x="10" y="3" width="3" height="9" rx="0.8" />
97
- <rect x="15" y="0" width="3" height="12" rx="0.8" />
93
+ <svg class="glyph glyph-cellular" viewBox="0 0 19.33 12.33" width="19.33" height="12.33">
94
+ <rect x="0" y="7.67" width="3.33" height="4.67" rx="1" />
95
+ <rect x="5.33" y="5.33" width="3.33" height="7" rx="1" />
96
+ <rect x="10.67" y="2.67" width="3.33" height="9.67" rx="1" />
97
+ <rect x="16" y="0" width="3.33" height="12.33" rx="1" />
98
98
  </svg>
99
99
  <!-- Wi-Fi -->
100
- <svg class="glyph glyph-wifi" viewBox="0 0 16 12" width="16" height="12">
101
- <path d="M8 2.6c2.4 0 4.6.9 6.3 2.5l1.1-1.2A10.6 10.6 0 0 0 8 .9 10.6 10.6 0 0 0 .6 3.9l1.1 1.2A9 9 0 0 1 8 2.6Z" />
102
- <path d="M8 6.2c1.5 0 2.9.6 3.9 1.5l1.1-1.2A7.2 7.2 0 0 0 8 4.5a7.2 7.2 0 0 0-5 2l1.1 1.2A5.6 5.6 0 0 1 8 6.2Z" />
103
- <path d="M8 9.8c.7 0 1.3.3 1.7.7L8 12.3l-1.7-1.8c.4-.4 1-.7 1.7-.7Z" />
100
+ <svg class="glyph glyph-wifi" viewBox="0 0 16.3 12.33" width="16.3" height="12.33">
101
+ <path class="wifi-band" d="M1.08 3.87A11.0 11.0 0 0 1 15.22 3.87" stroke-width="2.6" />
102
+ <path class="wifi-band" d="M3.91 7.24A6.6 6.6 0 0 1 12.39 7.24" stroke-width="2.9" />
103
+ <path d="M8.15 12.3L5.64 9.31A3.9 3.9 0 0 1 10.66 9.31Z" />
104
104
  </svg>
105
105
  <!-- Battery -->
106
106
  <svg class="glyph glyph-battery" viewBox="0 0 28 13" width="28" height="13">
107
107
  <rect class="battery-shell" x="0.5" y="0.5" width="24" height="12" rx="3.5" />
108
108
  <rect class="battery-fill" x="2" y="2" width="21" height="9" rx="2" />
109
- <path class="battery-cap" d="M26 4.3v4.4c.9-.3 1.5-1.1 1.5-2.2S26.9 4.6 26 4.3Z" />
109
+ <path class="battery-cap" d="M26 4.3v4.4c.8-.3 1.33-1.1 1.33-2.2S26.8 4.6 26 4.3Z" />
110
110
  </svg>
111
111
  </span>
112
112
  </div>
@@ -117,6 +117,17 @@
117
117
  <div class="home-indicator" aria-hidden="true"></div>
118
118
  </div>
119
119
  </div>
120
+ <script>
121
+ // Device mode follows the OS appearance (main.ts); set it before the
122
+ // first paint. Safari tints its status bar strip and safe areas from
123
+ // the first paint and does not follow later changes, so a light device
124
+ // here kept the strip white under a dark app.
125
+ (function () {
126
+ if (document.documentElement.getAttribute('data-sb-mode') !== 'device') return;
127
+ var dark = typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)').matches;
128
+ document.getElementById('device').setAttribute('data-theme', dark ? 'dark' : 'light');
129
+ })();
130
+ </script>
120
131
  <p id="status" class="status" role="alert" hidden></p>
121
132
  </main>
122
133
 
@@ -45,6 +45,22 @@ export interface AppSpec {
45
45
  * else in the first; default `["en"]`.
46
46
  */
47
47
  locales?: string[];
48
+ /**
49
+ * The app's URL schemes (`CFBundleURLSchemes` of its Info.plist's
50
+ * `CFBundleURLTypes`). OAuth redirects in these schemes come back through the
51
+ * page's callback page (docs/ops-protocol.md, "Signing in").
52
+ */
53
+ urlSchemes?: string[];
54
+ /**
55
+ * A CORS proxy (packages/cors-proxy): the page retries a cross-origin GET or
56
+ * HEAD the browser refused through `<corsProxy>?url=<target>` (src/corsProxy.ts).
57
+ */
58
+ corsProxy?: string;
59
+ /**
60
+ * Hosts (and their subdomains) the app's requests may not reach: they fail
61
+ * as a network error does (src/blockedHosts.ts).
62
+ */
63
+ blockedHosts?: string[];
48
64
  }
49
65
  /** The name rule `?app=` in src/main.ts and every plugin URL applies. */
50
66
  export declare const APP_NAME: RegExp;
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,gHAAgH;IAChH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,yEAAyE;AACzE,eAAO,MAAM,QAAQ,QAAqB,CAAC;AAE3C,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,MAAM,CAEjF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAsChE"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,gHAAgH;IAChH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,yEAAyE;AACzE,eAAO,MAAM,QAAQ,QAAqB,CAAC;AAE3C,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,MAAM,CAEjF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CA+ChE"}
@@ -52,6 +52,15 @@ export function validateAppSpecs(specs) {
52
52
  if (spec.locales !== undefined && (!Array.isArray(spec.locales) || !spec.locales.every((l) => typeof l === 'string' && l.length > 0))) {
53
53
  throw new Error(`${label}: "locales" must be an array of language tags`);
54
54
  }
55
+ if (spec.urlSchemes !== undefined && (!Array.isArray(spec.urlSchemes) || !spec.urlSchemes.every((u) => typeof u === 'string' && /^[A-Za-z][A-Za-z0-9+.-]*$/.test(u)))) {
56
+ throw new Error(`${label}: "urlSchemes" must be an array of URL schemes`);
57
+ }
58
+ if (spec.corsProxy !== undefined && (typeof spec.corsProxy !== 'string' || !/^https?:\/\/[^\s]+$/.test(spec.corsProxy))) {
59
+ throw new Error(`${label}: "corsProxy" must be an http(s) URL`);
60
+ }
61
+ if (spec.blockedHosts !== undefined && (!Array.isArray(spec.blockedHosts) || !spec.blockedHosts.every((h) => typeof h === 'string' && /^[A-Za-z0-9.-]+$/.test(h)))) {
62
+ throw new Error(`${label}: "blockedHosts" must be an array of host names`);
63
+ }
55
64
  if (spec.build !== undefined && typeof spec.build !== 'function') {
56
65
  throw new Error(`${label}: "build" must be a function`);
57
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"apps.js","sourceRoot":"","sources":["../../apps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apps.js","sourceRoot":"","sources":["../../apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AA4D7B,yEAAyE;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AAE3C,sCAAsC;AACtC,MAAM,UAAU,aAAa,CAAC,IAA2C;IACvE,OAAO,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAC1G,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,0CAA0C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,iDAAiD,CAAC,CAAC;QAC9G,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACnC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAC9F,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,0CAA0C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClG,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;YAC5C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC/D,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtI,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,+CAA+C,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtK,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gDAAgD,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YACxH,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,sCAAsC,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACnK,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,iDAAiD,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Builds the Vite config for a set of apps: the registry plugins
3
3
  * (plugins/swift-wasm.ts, asset-catalogs.ts, app-manifests.ts), the two
4
- * pages (landing + app) and the `define`s the landing page reads.
4
+ * pages (landing + app), the `define`s the landing page reads, and the apps
5
+ * of other built sites joining this one (plugins/included-sites.ts).
5
6
  *
6
7
  * `vite.config.ts` calls this with the example apps; the programmatic API
7
8
  * (./index.ts) with whatever the caller registered.
@@ -14,6 +15,12 @@ export interface SiteOptions {
14
15
  commit?: string;
15
16
  /** Build info shown on the landing page: the branch name ("" when unknown). */
16
17
  branch?: string;
18
+ /**
19
+ * Directories of sites built before (`buildSite`, `swiftbrowser build`)
20
+ * whose apps join this one's: their cards on the landing page, their files
21
+ * copied into the build (plugins/included-sites.ts). Build only.
22
+ */
23
+ sites?: string[];
17
24
  }
18
25
  /** One entry of `__SB_APPS__`, what the landing page renders a card from (see src/vite-env.d.ts). */
19
26
  export interface LandingApp {
@@ -24,6 +31,12 @@ export interface LandingApp {
24
31
  icon?: string;
25
32
  /** The languages the module carries locale data for (`AppSpec.locales`); the page picks the viewer's among them. */
26
33
  locales?: string[];
34
+ /** The app's URL schemes (`AppSpec.urlSchemes`); the page passes them to the app as `SB_URL_SCHEMES`. */
35
+ urlSchemes?: string[];
36
+ /** The app's CORS proxy (`AppSpec.corsProxy`); the page retries refused cross-origin reads through it. */
37
+ corsProxy?: string;
38
+ /** Hosts the app's requests may not reach (`AppSpec.blockedHosts`). */
39
+ blockedHosts?: string[];
27
40
  }
28
41
  /**
29
42
  * The Vite root: the `Web/` directory of this package (holds `index.html`,
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAKvC,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qGAAqG;AACrG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oHAAoH;IACpH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAOD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAoBhC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,EAAE,CAQnE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CA+BjE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAMvC,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,qGAAqG;AACrG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oHAAoH;IACpH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,0GAA0G;IAC1G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAOD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAoBhC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,EAAE,CAWnE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAuCjE"}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Builds the Vite config for a set of apps: the registry plugins
3
3
  * (plugins/swift-wasm.ts, asset-catalogs.ts, app-manifests.ts), the two
4
- * pages (landing + app) and the `define`s the landing page reads.
4
+ * pages (landing + app), the `define`s the landing page reads, and the apps
5
+ * of other built sites joining this one (plugins/included-sites.ts).
5
6
  *
6
7
  * `vite.config.ts` calls this with the example apps; the programmatic API
7
8
  * (./index.ts) with whatever the caller registered.
@@ -12,6 +13,7 @@ import { fileURLToPath } from 'node:url';
12
13
  import { appManifests } from '../plugins/app-manifests.js';
13
14
  import { assetCatalogs } from '../plugins/asset-catalogs.js';
14
15
  import { bundleResources } from '../plugins/bundle-resources.js';
16
+ import { includedSites, readSiteApps } from '../plugins/included-sites.js';
15
17
  import { swiftWasm } from '../plugins/swift-wasm.js';
16
18
  import { displayNameOf, validateAppSpecs } from './apps.js';
17
19
  /** The package name that marks the Vite root. */
@@ -57,6 +59,12 @@ export function landingApps(specs) {
57
59
  entry.icon = `/manifests/${spec.name}-icon.png`;
58
60
  if (spec.locales !== undefined)
59
61
  entry.locales = [...spec.locales];
62
+ if (spec.urlSchemes?.length)
63
+ entry.urlSchemes = [...spec.urlSchemes];
64
+ if (spec.corsProxy)
65
+ entry.corsProxy = spec.corsProxy;
66
+ if (spec.blockedHosts?.length)
67
+ entry.blockedHosts = [...spec.blockedHosts];
60
68
  return entry;
61
69
  });
62
70
  }
@@ -68,14 +76,23 @@ export function createViteConfig(options) {
68
76
  validateAppSpecs(options.apps);
69
77
  const root = webRoot();
70
78
  const apps = options.apps;
79
+ const sites = (options.sites ?? []).map((dir) => path.resolve(dir));
80
+ const included = sites.flatMap(readSiteApps);
81
+ const landing = [...landingApps(apps), ...included];
82
+ const names = new Set();
83
+ for (const app of landing) {
84
+ if (names.has(app.name))
85
+ throw new Error(`Duplicate app name ${JSON.stringify(app.name)} in the included sites`);
86
+ names.add(app.name);
87
+ }
71
88
  return {
72
89
  root,
73
- plugins: [swiftWasm(apps), appManifests(apps), assetCatalogs(apps), bundleResources(apps)],
90
+ plugins: [swiftWasm(apps), appManifests(apps, included), assetCatalogs(apps), bundleResources(apps), includedSites(landing, sites)],
74
91
  // Two pages: the landing page at `/` and the app at `/app/`. `mpa` keeps the
75
92
  // dev server from answering unknown URLs with the landing page.
76
93
  appType: 'mpa',
77
94
  define: {
78
- __SB_APPS__: JSON.stringify(landingApps(apps)),
95
+ __SB_APPS__: JSON.stringify(landing),
79
96
  __SB_COMMIT__: JSON.stringify(options.commit ?? 'dev'),
80
97
  __SB_BRANCH__: JSON.stringify(options.branch ?? ''),
81
98
  __SB_BUILT_AT__: JSON.stringify(new Date().toISOString()),
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,8 @@ export interface BuildScriptOptions {
20
20
  /**
21
21
  * `bash scripts/build-wasm.sh <app>` in `repoRoot` with `SB_WASM_OPT=0`: hot
22
22
  * rebuilds skip wasm-opt, which costs 15-30 s per module and strips the names
23
- * that make stack traces readable while developing. Rejects with an Error
23
+ * that make stack traces readable while developing. The script builds through
24
+ * the CLI, so the workspace packages must be built (`npm run build:packages`). Rejects with an Error
24
25
  * whose message is the script's combined output when it fails.
25
26
  */
26
27
  export declare function runBuildScript(repoRoot: string, app: string, options?: BuildScriptOptions): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../../examples.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOjE,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAIjD;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7G;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAOvD;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,QAAQ,SAAgC,GAAG,OAAO,EAAE,CAkBnF;AAYD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAK9E"}
1
+ {"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../../examples.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcjE,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAIjD;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7G;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAOvD;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,QAAQ,SAAgC,GAAG,OAAO,EAAE,CAoBnF;AAYD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAK9E"}