@swiftbrowser/native 0.17.7 → 0.18.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 (100) hide show
  1. package/README.md +99 -11
  2. package/dist/blob.d.ts +60 -0
  3. package/dist/blob.d.ts.map +1 -0
  4. package/dist/blob.js +153 -0
  5. package/dist/blob.js.map +1 -0
  6. package/dist/bridge.d.ts +65 -1
  7. package/dist/bridge.d.ts.map +1 -1
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/fetch.d.ts +11 -3
  10. package/dist/fetch.d.ts.map +1 -1
  11. package/dist/fetch.js +26 -2
  12. package/dist/fetch.js.map +1 -1
  13. package/dist/hostRequests.d.ts +55 -0
  14. package/dist/hostRequests.d.ts.map +1 -0
  15. package/dist/hostRequests.js +196 -0
  16. package/dist/hostRequests.js.map +1 -0
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +8 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/matchMedia.d.ts +43 -0
  22. package/dist/matchMedia.d.ts.map +1 -0
  23. package/dist/matchMedia.js +63 -0
  24. package/dist/matchMedia.js.map +1 -0
  25. package/dist/notifications.d.ts +108 -0
  26. package/dist/notifications.d.ts.map +1 -0
  27. package/dist/notifications.js +251 -0
  28. package/dist/notifications.js.map +1 -0
  29. package/dist/run.d.ts.map +1 -1
  30. package/dist/run.js +23 -2
  31. package/dist/run.js.map +1 -1
  32. package/dist/runtime.d.ts +2 -0
  33. package/dist/runtime.d.ts.map +1 -1
  34. package/dist/runtime.js +69 -0
  35. package/dist/runtime.js.map +1 -1
  36. package/dist/secureStorage.d.ts +20 -0
  37. package/dist/secureStorage.d.ts.map +1 -0
  38. package/dist/secureStorage.js +28 -0
  39. package/dist/secureStorage.js.map +1 -0
  40. package/dist/site.d.ts +3 -3
  41. package/dist/site.d.ts.map +1 -1
  42. package/dist/site.js +1 -1
  43. package/dist/site.js.map +1 -1
  44. package/dist/subtle.d.ts +38 -0
  45. package/dist/subtle.d.ts.map +1 -0
  46. package/dist/subtle.js +72 -0
  47. package/dist/subtle.js.map +1 -0
  48. package/dist/undo.d.ts +23 -0
  49. package/dist/undo.d.ts.map +1 -0
  50. package/dist/undo.js +44 -0
  51. package/dist/undo.js.map +1 -0
  52. package/dist/webSocket.d.ts +73 -0
  53. package/dist/webSocket.d.ts.map +1 -0
  54. package/dist/webSocket.js +145 -0
  55. package/dist/webSocket.js.map +1 -0
  56. package/package.json +3 -3
  57. package/src/blob.ts +186 -0
  58. package/src/bridge.ts +74 -1
  59. package/src/fetch.ts +29 -3
  60. package/src/hostRequests.ts +216 -0
  61. package/src/index.ts +8 -0
  62. package/src/matchMedia.ts +79 -0
  63. package/src/notifications.ts +317 -0
  64. package/src/run.ts +21 -2
  65. package/src/runtime.ts +71 -0
  66. package/src/secureStorage.ts +39 -0
  67. package/src/site.ts +3 -3
  68. package/src/subtle.ts +87 -0
  69. package/src/undo.ts +47 -0
  70. package/src/webSocket.ts +175 -0
  71. package/swift/Sources/SwiftBrowserNative/Host/AudioRecorderBridge.swift +199 -0
  72. package/swift/Sources/SwiftBrowserNative/Host/FilesBridge.swift +154 -0
  73. package/swift/Sources/SwiftBrowserNative/Host/HostBridge.swift +211 -0
  74. package/swift/Sources/SwiftBrowserNative/Host/HostRequestBridge.swift +451 -0
  75. package/swift/Sources/SwiftBrowserNative/Host/NotificationBridge.swift +304 -0
  76. package/swift/Sources/SwiftBrowserNative/Host/SecureStorage.swift +60 -0
  77. package/swift/Sources/SwiftBrowserNative/Host/ShimAliases.swift +1 -0
  78. package/swift/Sources/SwiftBrowserNative/Host/TextMeasureBridge.swift +139 -0
  79. package/swift/Sources/SwiftBrowserNative/Host/UndoBridge.swift +170 -0
  80. package/swift/Sources/SwiftBrowserNative/Host/WebSocketBridge.swift +118 -0
  81. package/swift/Sources/SwiftBrowserNative/Runtime/NativeApp.swift +56 -0
  82. package/swift/Sources/SwiftBrowserNative/Runtime/NativeAppDelegate.swift +36 -0
  83. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Controls.swift +362 -16
  84. package/swift/Sources/SwiftBrowserNative/Views/Kinds/DeleteBackward.swift +147 -0
  85. package/swift/Sources/SwiftBrowserNative/Views/Kinds/KeyboardBar.swift +84 -0
  86. package/swift/Sources/SwiftBrowserNative/Views/Kinds/More.swift +116 -11
  87. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Navigation.swift +12 -1
  88. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Shapes.swift +30 -9
  89. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Stacks.swift +163 -10
  90. package/swift/Sources/SwiftBrowserNative/Views/Kinds/TextAndImages.swift +17 -4
  91. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Video.swift +8 -3
  92. package/swift/Sources/SwiftBrowserNative/Views/NativeRootView.swift +8 -0
  93. package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +41 -0
  94. package/swift/Sources/SwiftBrowserProtocol/Op.swift +27 -4
  95. package/swift/Sources/SwiftBrowserProtocol/Props.swift +110 -3
  96. package/swift/Sources/SwiftBrowserProtocol/RendererEvent.swift +47 -0
  97. package/swift/Sources/SwiftBrowserProtocol/SVGPath.swift +260 -0
  98. package/swift/Sources/SwiftBrowserProtocol/Style.swift +58 -0
  99. package/swift/Sources/SwiftBrowserTree/OpTree.swift +22 -2
  100. package/wasm/SwiftBrowserNative.wasm +2 -2
package/README.md CHANGED
@@ -33,10 +33,11 @@ build against the exact version of the renderer this JavaScript was written
33
33
  for. `swiftbrowser native init` lays a project out that way:
34
34
 
35
35
  ```sh
36
- npx @swiftbrowser/cli native init MyApp # MyApp.xcodeproj, MyApp/MyAppApp.swift, js/
37
- cd MyApp/js && npm install # React, @swiftbrowser/react and this package
38
- npm run build # ../MyApp/app.js, the bundle the app ships
39
- open ../MyApp.xcodeproj # run it on a simulator
36
+ npx @swiftbrowser/cli native init MyApp # MyApp.xcodeproj, ios/, src/, web/
37
+ cd MyApp && npm install # React, @swiftbrowser/react, @swiftbrowser/web and this package
38
+ npm run build # ios/app.js, the bundle the app ships
39
+ open MyApp.xcodeproj # run it on a simulator
40
+ npm run dev:web # the same app as a web page
40
41
  ```
41
42
 
42
43
  For a hand-made project:
@@ -71,8 +72,8 @@ run(<App />);
71
72
  ```
72
73
 
73
74
  ```sh
74
- npx swiftbrowser-native build src/index.tsx --out ../MyApp/app.js # the bundle Xcode ships
75
- npx swiftbrowser-native dev src/index.tsx --out ../MyApp/app.js # http://localhost:5173/, Fast Refresh on save
75
+ npx swiftbrowser-native build src/index.tsx --out ../ios/app.js # the bundle Xcode ships
76
+ npx swiftbrowser-native dev src/index.tsx --out ../ios/app.js # http://localhost:5173/, Fast Refresh on save
76
77
  ```
77
78
 
78
79
  On the Swift side, `NativeApp().load()` runs the bundled `app.js` and
@@ -93,13 +94,19 @@ headless path, which is right here; `@swiftbrowser/react`'s `Host` (React DOM
93
94
  inside the tree) renders nothing, as `react-dom` is aliased to a stub.
94
95
 
95
96
  `fetch` sends the request over the bridge and `URLSession` performs it;
96
- bodies are whole (no streams, no `Blob`). `URL` is a small parser, enough for
97
- absolute and relative URLs and query strings, not the whole WHATWG algorithm.
97
+ bodies are whole (no streams), and may be a `Blob` or a `FormData` (sent as
98
+ multipart: a file upload works as written for the page). `URL` is a small
99
+ parser, enough for absolute and relative URLs and query strings, not the
100
+ whole WHATWG algorithm; `URL.createObjectURL` gives a `data:` URL. `WebSocket`
101
+ runs on `URLSessionWebSocketTask`, `crypto.subtle` digests (SHA-1 to
102
+ SHA-512) and signs HMACs on CryptoKit, `matchMedia` answers the
103
+ `prefers-color-scheme` queries from the host's environment, and
104
+ `navigator.vibrate` plays a haptic.
98
105
 
99
106
  ## Workers
100
107
 
101
108
  ```sh
102
- npx swiftbrowser-native build src/index.tsx --out ../MyApp/app.js --worker render=src/render.worker.ts
109
+ npx swiftbrowser-native build src/index.tsx --out ../ios/app.js --worker render=src/render.worker.ts
103
110
  ```
104
111
 
105
112
  ```ts
@@ -174,6 +181,87 @@ lock screen needs; for the audio to go on with the screen locked, the app's
174
181
  Xcode target also needs the `audio` background mode (Signing &
175
182
  Capabilities → Background Modes → Audio, AirPlay, and Picture in Picture).
176
183
 
184
+ ## Notifications
185
+
186
+ ```ts
187
+ import { onNotification, registerForPush } from '@swiftbrowser/native';
188
+
189
+ if ((await Notification.requestPermission()) === 'granted') {
190
+ const token = await registerForPush();
191
+ await api.post('/devices', { token });
192
+ }
193
+ useEffect(() => onNotification((n) => { if (n.event === 'opened') openPost(n.data.postId); }), []);
194
+ new Notification('Saved', { body: 'The draft is on the server', tag: 'draft', data: { draftId } });
195
+ navigator.setAppBadge(unread);
196
+ ```
197
+
198
+ The browser's `Notification` works in the native app over UserNotifications:
199
+ `Notification.permission` (read at launch and after each
200
+ `requestPermission`), `requestPermission()`, `new Notification(title, { body,
201
+ tag, data, silent, badge })` shown at once (`tag` is the notification's
202
+ identifier; a later one with the same tag replaces it), `close()`, and
203
+ `onclick` when the viewer opens it. `navigator.setAppBadge` and
204
+ `clearAppBadge` set the app badge.
205
+
206
+ `registerForPush()` registers with APNs and resolves with the device token as
207
+ hex, or rejects with the system's reason (the Xcode target needs the Push
208
+ Notifications capability, and the App file the delegate adaptor the project
209
+ `native init` writes has: `@UIApplicationDelegateAdaptor(NativeAppDelegate.self)`;
210
+ an app with a delegate of its own calls `NativeApp.didRegisterForRemoteNotifications(deviceToken:)`,
211
+ `didFailToRegisterForRemoteNotifications(error:)` and
212
+ `didReceiveRemoteNotification(userInfo:)` from it). `onNotification`
213
+ delivers what happens: `{ event: 'opened' | 'received', remote, id, title,
214
+ body, data, action? }`, with the push payload or the `Notification`'s `data`
215
+ as `data`. `opened` is the viewer tapping a notification (one that launched
216
+ the app waits for the first listener, like a URL); `received` is one that
217
+ arrived while the app is open (shown as it would be in the background) or a
218
+ silent push the app delegate was handed.
219
+
220
+ In the page (the round trip, or any browser) the same calls work with Web
221
+ Push: `Notification` is the browser's, `registerForPush({
222
+ applicationServerKey })` subscribes through the site's service worker with
223
+ the server's VAPID public key and resolves with the subscription's JSON as
224
+ the token, and the worker's pushes and clicks become `onNotification`
225
+ events. A server tells the two tokens apart by their shape and sends one
226
+ payload to both: APNs' (`aps.alert`, `aps.badge`), which the worker reads
227
+ too (docs/ops-protocol.md, "Push notifications").
228
+
229
+ ## Sharing, picking, the clipboard and signing in
230
+
231
+ `ShareLink`, `fileImporter`, the clipboard and the color chooser from
232
+ `@swiftbrowser/react` ask the browser for a share sheet, a file chooser, the
233
+ pasteboard and a color picker; in the native app the host answers instead,
234
+ with `UIActivityViewController`, the photo picker (for pictures and videos)
235
+ or the document picker, `UIPasteboard` and `UIColorPickerViewController`.
236
+ Nothing to write: `run` fills the web renderer's environment with what the
237
+ page has nothing for, so a screen written for the page shares and picks as
238
+ it did. Picked files are `File`s with their bytes.
239
+
240
+ ```ts
241
+ import { webAuthenticate, secureStorage } from '@swiftbrowser/native';
242
+
243
+ const callback = await webAuthenticate('https://x.example/oauth/authorize?…', { callbackScheme: 'myapp' });
244
+ secureStorage.setItem('session', new URL(callback).searchParams.get('token')!);
245
+ ```
246
+
247
+ `webAuthenticate(url, { callbackScheme, ephemeral })` is the system's
248
+ sign-in sheet (`ASWebAuthenticationSession`): it resolves with the callback
249
+ URL the sign-in ends with, and rejects with an `AbortError` when the viewer
250
+ closes it. In the page it runs on the shim's session (the popup flow of
251
+ docs/ops-protocol.md, "Signing in"). `secureStorage` has `localStorage`'s
252
+ shape over the Keychain, for what must not sit in plain text; in the page
253
+ it is `localStorage` under a prefix.
254
+
255
+ ## Undo
256
+
257
+ `useUndoManager()` from `@swiftbrowser/react` keeps its stack in
258
+ JavaScript; in the native app the window's `UndoManager` mirrors it (the
259
+ host's `undoState`, `Host/UndoBridge.swift`: one proxy action per side the
260
+ app can use, named as the app names it), so the shake, the three-finger
261
+ swipe, ⌘Z from a keyboard and the Edit menu undo and redo the app's
262
+ changes, as they do in a SwiftUI app. Nothing to write: `run` puts the
263
+ host in the web renderer's environment where the page's keyboard would be.
264
+
177
265
  ## The dev loop and Fast Refresh
178
266
 
179
267
  `swiftbrowser-native dev` serves the bundle in two halves and a manifest:
@@ -218,8 +306,8 @@ DOM through `@swiftbrowser/react` directly, real SwiftUI in the iOS app, and
218
306
  this: the iOS app's own views, in a page. `--base /path/` when the site is
219
307
  served under a path of another site, `--module <file>` for a module built
220
308
  from a checkout (`swift build --swift-sdk <wasm sdk> -c release --product
221
- NativeRoundTrip`), `--name <App>` for the site's app name (the folder
222
- holding `js/` by default), `--catalog <dir.xcassets>` (repeatable) for the
309
+ NativeRoundTrip`), `--name <App>` for the site's app name (the project's
310
+ folder by default), `--catalog <dir.xcassets>` (repeatable) for the
223
311
  app's named images and colors (the Xcode target's catalog, or one kept for
224
312
  the site: a `.symbolset` holding any SVG draws as a symbol there), and
225
313
  `--worker <name>=<entry>` (repeatable) for the app's workers, published
package/dist/blob.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `Blob`, `File` and `FormData` for the native app: bytes with a type, a
3
+ * named one, and a form whose entries `fetch` sends as multipart. A body is
4
+ * still whole (no streams); `URL.createObjectURL` gives a `data:` URL, which
5
+ * the host's image loader and `URLSession` both read, and
6
+ * `revokeObjectURL` has nothing to free.
7
+ */
8
+ export type BlobPartLike = string | ArrayBuffer | ArrayBufferView | SimpleBlob;
9
+ export interface BlobOptions {
10
+ type?: string;
11
+ }
12
+ export interface FileOptions extends BlobOptions {
13
+ lastModified?: number;
14
+ }
15
+ /** The browser's `Blob`: bytes and a MIME type. */
16
+ export declare class SimpleBlob {
17
+ private readonly data;
18
+ readonly type: string;
19
+ constructor(parts?: Iterable<BlobPartLike>, options?: BlobOptions);
20
+ get size(): number;
21
+ /** The bytes (a view; callers must not write into it). */
22
+ bytes(): Uint8Array;
23
+ slice(start?: number, end?: number, contentType?: string): SimpleBlob;
24
+ arrayBuffer(): Promise<ArrayBuffer>;
25
+ text(): Promise<string>;
26
+ get [Symbol.toStringTag](): string;
27
+ }
28
+ /** The browser's `File`: a `Blob` with a name. */
29
+ export declare class SimpleFile extends SimpleBlob {
30
+ readonly name: string;
31
+ readonly lastModified: number;
32
+ constructor(parts: Iterable<BlobPartLike>, name: string, options?: FileOptions);
33
+ get [Symbol.toStringTag](): string;
34
+ }
35
+ export type FormDataEntryValueLike = string | SimpleFile;
36
+ /** The browser's `FormData`, as far as a request body needs it. */
37
+ export declare class SimpleFormData {
38
+ private entries_;
39
+ private static value;
40
+ append(name: string, value: unknown, filename?: string): void;
41
+ set(name: string, value: unknown, filename?: string): void;
42
+ get(name: string): FormDataEntryValueLike | null;
43
+ getAll(name: string): FormDataEntryValueLike[];
44
+ has(name: string): boolean;
45
+ delete(name: string): void;
46
+ entries(): IterableIterator<[string, FormDataEntryValueLike]>;
47
+ keys(): IterableIterator<string>;
48
+ values(): IterableIterator<FormDataEntryValueLike>;
49
+ forEach(callback: (value: FormDataEntryValueLike, name: string, form: SimpleFormData) => void): void;
50
+ [Symbol.iterator](): IterableIterator<[string, FormDataEntryValueLike]>;
51
+ get [Symbol.toStringTag](): string;
52
+ }
53
+ /** A multipart/form-data body for the form, with the boundary `random` makes unique. */
54
+ export declare function encodeMultipart(form: SimpleFormData, random: (count: number) => Uint8Array): {
55
+ bytes: Uint8Array;
56
+ contentType: string;
57
+ };
58
+ /** `URL.createObjectURL`: a `data:` URL holding the blob. */
59
+ export declare function objectURL(blob: SimpleBlob): string;
60
+ //# sourceMappingURL=blob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD,mDAAmD;AACnD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,KAAK,GAAE,QAAQ,CAAC,YAAY,CAAM,EAAE,OAAO,GAAE,WAAgB;IAOzE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,0DAA0D;IAC1D,KAAK,IAAI,UAAU;IAInB,KAAK,CAAC,KAAK,SAAI,EAAE,GAAG,SAAY,EAAE,WAAW,SAAK,GAAG,UAAU;IAMzD,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAInC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAEjC;CACF;AAED,kDAAkD;AAClD,qBAAa,UAAW,SAAQ,UAAU;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB;IAMlF,IAAa,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAE1C;CACF;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,UAAU,CAAC;AAEzD,mEAAmE;AACnE,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA0C;IAE1D,OAAO,CAAC,MAAM,CAAC,KAAK;IAQpB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAI7D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAY1D,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI;IAIhD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,EAAE;IAI9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzB,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAI7D,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAIhC,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,CAAC;IAInD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAIpG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAIvE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAEjC;CACF;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAavI;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAElD"}
package/dist/blob.js ADDED
@@ -0,0 +1,153 @@
1
+ /**
2
+ * `Blob`, `File` and `FormData` for the native app: bytes with a type, a
3
+ * named one, and a form whose entries `fetch` sends as multipart. A body is
4
+ * still whole (no streams); `URL.createObjectURL` gives a `data:` URL, which
5
+ * the host's image loader and `URLSession` both read, and
6
+ * `revokeObjectURL` has nothing to free.
7
+ */
8
+ import { base64Encode, utf8Decode, utf8Encode } from './encoding';
9
+ function partBytes(part) {
10
+ if (typeof part === 'string')
11
+ return utf8Encode(part);
12
+ if (part instanceof SimpleBlob)
13
+ return part.bytes();
14
+ if (part instanceof ArrayBuffer)
15
+ return new Uint8Array(part.slice(0));
16
+ if (ArrayBuffer.isView(part))
17
+ return new Uint8Array(part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength));
18
+ return utf8Encode(String(part));
19
+ }
20
+ function concat(parts) {
21
+ const total = parts.reduce((sum, part) => sum + part.byteLength, 0);
22
+ const out = new Uint8Array(total);
23
+ let offset = 0;
24
+ for (const part of parts) {
25
+ out.set(part, offset);
26
+ offset += part.byteLength;
27
+ }
28
+ return out;
29
+ }
30
+ /** The browser's `Blob`: bytes and a MIME type. */
31
+ export class SimpleBlob {
32
+ data;
33
+ type;
34
+ constructor(parts = [], options = {}) {
35
+ this.data = concat([...parts].map(partBytes));
36
+ // As the browser does: lowercased, and empty when it is not printable ASCII.
37
+ const type = options.type ?? '';
38
+ this.type = /^[\x20-\x7e]*$/.test(type) ? type.toLowerCase() : '';
39
+ }
40
+ get size() {
41
+ return this.data.byteLength;
42
+ }
43
+ /** The bytes (a view; callers must not write into it). */
44
+ bytes() {
45
+ return this.data;
46
+ }
47
+ slice(start = 0, end = this.size, contentType = '') {
48
+ const from = start < 0 ? Math.max(this.size + start, 0) : Math.min(start, this.size);
49
+ const to = end < 0 ? Math.max(this.size + end, 0) : Math.min(end, this.size);
50
+ return new SimpleBlob([this.data.subarray(from, Math.max(from, to))], { type: contentType });
51
+ }
52
+ async arrayBuffer() {
53
+ return this.data.buffer.slice(this.data.byteOffset, this.data.byteOffset + this.data.byteLength);
54
+ }
55
+ async text() {
56
+ return utf8Decode(this.data);
57
+ }
58
+ get [Symbol.toStringTag]() {
59
+ return 'Blob';
60
+ }
61
+ }
62
+ /** The browser's `File`: a `Blob` with a name. */
63
+ export class SimpleFile extends SimpleBlob {
64
+ name;
65
+ lastModified;
66
+ constructor(parts, name, options = {}) {
67
+ super(parts, options);
68
+ this.name = String(name);
69
+ this.lastModified = options.lastModified ?? Date.now();
70
+ }
71
+ get [Symbol.toStringTag]() {
72
+ return 'File';
73
+ }
74
+ }
75
+ /** The browser's `FormData`, as far as a request body needs it. */
76
+ export class SimpleFormData {
77
+ entries_ = [];
78
+ static value(value, filename) {
79
+ if (value instanceof SimpleBlob) {
80
+ const name = filename ?? (value instanceof SimpleFile ? value.name : 'blob');
81
+ return value instanceof SimpleFile && filename === undefined ? value : new SimpleFile([value], name, { type: value.type });
82
+ }
83
+ return String(value);
84
+ }
85
+ append(name, value, filename) {
86
+ this.entries_.push([String(name), SimpleFormData.value(value, filename)]);
87
+ }
88
+ set(name, value, filename) {
89
+ const key = String(name);
90
+ const entry = [key, SimpleFormData.value(value, filename)];
91
+ const index = this.entries_.findIndex(([entryName]) => entryName === key);
92
+ if (index < 0) {
93
+ this.entries_.push(entry);
94
+ return;
95
+ }
96
+ this.entries_ = this.entries_.filter(([entryName], position) => position === index || entryName !== key);
97
+ this.entries_[index] = entry;
98
+ }
99
+ get(name) {
100
+ return this.entries_.find(([entryName]) => entryName === String(name))?.[1] ?? null;
101
+ }
102
+ getAll(name) {
103
+ return this.entries_.filter(([entryName]) => entryName === String(name)).map(([, value]) => value);
104
+ }
105
+ has(name) {
106
+ return this.entries_.some(([entryName]) => entryName === String(name));
107
+ }
108
+ delete(name) {
109
+ this.entries_ = this.entries_.filter(([entryName]) => entryName !== String(name));
110
+ }
111
+ *entries() {
112
+ yield* this.entries_;
113
+ }
114
+ *keys() {
115
+ for (const [name] of this.entries_)
116
+ yield name;
117
+ }
118
+ *values() {
119
+ for (const [, value] of this.entries_)
120
+ yield value;
121
+ }
122
+ forEach(callback) {
123
+ for (const [name, value] of this.entries_)
124
+ callback(value, name, this);
125
+ }
126
+ [Symbol.iterator]() {
127
+ return this.entries();
128
+ }
129
+ get [Symbol.toStringTag]() {
130
+ return 'FormData';
131
+ }
132
+ }
133
+ /** A multipart/form-data body for the form, with the boundary `random` makes unique. */
134
+ export function encodeMultipart(form, random) {
135
+ const boundary = `----SwiftBrowserFormBoundary${Array.from(random(16), (byte) => byte.toString(16).padStart(2, '0')).join('')}`;
136
+ const escape = (text) => text.replace(/\r/g, '%0D').replace(/\n/g, '%0A').replace(/"/g, '%22');
137
+ const parts = [];
138
+ for (const [name, value] of form.entries()) {
139
+ const head = [`--${boundary}`, `Content-Disposition: form-data; name="${escape(name)}"` + (typeof value === 'string' ? '' : `; filename="${escape(value.name)}"`)];
140
+ if (typeof value !== 'string')
141
+ head.push(`Content-Type: ${value.type || 'application/octet-stream'}`);
142
+ parts.push(utf8Encode(`${head.join('\r\n')}\r\n\r\n`));
143
+ parts.push(typeof value === 'string' ? utf8Encode(value) : value.bytes());
144
+ parts.push(utf8Encode('\r\n'));
145
+ }
146
+ parts.push(utf8Encode(`--${boundary}--\r\n`));
147
+ return { bytes: concat(parts), contentType: `multipart/form-data; boundary=${boundary}` };
148
+ }
149
+ /** `URL.createObjectURL`: a `data:` URL holding the blob. */
150
+ export function objectURL(blob) {
151
+ return `data:${blob.type || 'application/octet-stream'};base64,${base64Encode(blob.bytes())}`;
152
+ }
153
+ //# sourceMappingURL=blob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob.js","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"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"}
package/dist/bridge.d.ts CHANGED
@@ -3,7 +3,9 @@
3
3
  * (Native/Sources/SwiftBrowserNative/Host/HostBridge.swift). Every call is
4
4
  * synchronous; the ones that answer later do so by calling a global this
5
5
  * package defines (`__sbTimerFired`, `__sbFetchResult`, `__sbImageProbed`,
6
- * `__sbWorkerMessage`, `__sbOpenURL`, `__sbMediaSessionCommand`).
6
+ * `__sbWorkerMessage`, `__sbOpenURL`, `__sbMediaSessionCommand`,
7
+ * `__sbNotificationPermission`, `__sbPushRegistered`, `__sbNotification`,
8
+ * `__sbWebSocketEvent`, `__sbHostResponse`, `__sbUndoCommand`).
7
9
  */
8
10
  export interface NativeBridge {
9
11
  /** Applies a render pass's ops (a JSON array). Returns an error message, or nothing. */
@@ -43,6 +45,68 @@ export interface NativeBridge {
43
45
  * `__sbMediaSessionCommand(json)`. Hosts before 0.19 lack it.
44
46
  */
45
47
  mediaSession?(update: string): void;
48
+ /** The app listens: what came before it did (a tap that launched it) arrives at `__sbNotification(json)`. */
49
+ notificationsReady?(): void;
50
+ /** Answers `__sbNotificationPermission(id, 'default' | 'granted' | 'denied')`, after asking the viewer when `request` is set. */
51
+ notificationPermission?(id: number, request: boolean): void;
52
+ /** Shows `{ id, title, subtitle?, body?, data?, badge?, silent? }` now; returns what was wrong with it, or nothing. */
53
+ notificationShow?(json: string): string | null | undefined;
54
+ /** Closes the notifications with these identifiers (a JSON array). */
55
+ notificationClose?(json: string): void;
56
+ /** The app badge (0 clears it). */
57
+ setBadge?(count: number): void;
58
+ /**
59
+ * Registers for remote notifications; the device token (hex) or the
60
+ * failure answers `__sbPushRegistered(id, { token } | { error })`.
61
+ * `applicationServerKey` is for the page (the round trip's Web Push).
62
+ */
63
+ pushRegister?(id: number, applicationServerKey?: string): void;
64
+ wsOpen?(id: number, url: string, protocols: string[]): void;
65
+ /** `{ text }` or `{ binary }` (base64), as JSON. */
66
+ wsSend?(id: number, json: string): void;
67
+ wsClose?(id: number, code: number, reason: string): void;
68
+ /** The base64 digest of base64 `data` under `algorithm` (`SHA-256`, …), or nothing when the host cannot. */
69
+ digest?(algorithm: string, data: string): string | null | undefined;
70
+ /** The base64 HMAC of base64 `data` with base64 `key` under the hash `algorithm`, or nothing. */
71
+ hmac?(algorithm: string, key: string, data: string): string | null | undefined;
72
+ /** `navigator.vibrate`: a haptic (`impact`, `selection`, `success`, `warning`, `error`). Hosts before 0.20 lack it. */
73
+ haptic?(kind: string): void;
74
+ /**
75
+ * A host request of the web renderer's kinds (hostRequests.ts): `share`,
76
+ * `pickFiles`, `clipboard`, `pickColor` and `webAuth`, with the request's
77
+ * params as JSON; the answer arrives at `__sbHostResponse(id, { value } | { error })`.
78
+ * Hosts before 0.20 lack it.
79
+ */
80
+ hostRequest?(id: number, kind: string, json: string): void;
81
+ /**
82
+ * The app's undo manager's state (undo.ts): `{ canUndo, canRedo,
83
+ * undoActionName, redoActionName }` as JSON, which the host mirrors on the
84
+ * window's `UndoManager` so the system's undo reaches the app; the undo or
85
+ * redo the system asks for arrives at `__sbUndoCommand('undo' | 'redo')`.
86
+ * Hosts before 0.18 lack it.
87
+ */
88
+ undoState?(json: string): void;
89
+ /**
90
+ * `measureText` (@swiftbrowser/react): the size `text` in `font` (a Font
91
+ * JSON object over the body font) takes wrapped to `width` points (one
92
+ * line when null), from `NSAttributedString`'s bounding rect, synchronously:
93
+ * `{ width, height, lines }`, or nothing when the host cannot measure.
94
+ * Hosts before 0.21 lack it.
95
+ */
96
+ measureText?(text: string, font: string, width: number | null): {
97
+ width: number;
98
+ height: number;
99
+ lines: number;
100
+ } | null | undefined;
101
+ /**
102
+ * The app's standard directories as `file:` URLs, a JSON object
103
+ * `{ documents, applicationSupport, caches, temporary }` (hostRequests.ts
104
+ * `files`, Host/FilesBridge.swift). Hosts before 0.22 lack it.
105
+ */
106
+ appDirectories?(): string | null | undefined;
107
+ secureGet?(key: string): string | null;
108
+ secureSet?(key: string, value: string): void;
109
+ secureRemove?(key: string): void;
46
110
  /**
47
111
  * Starts worker `id` from `<name>.worker.js` in `engine` (`'context'`
48
112
  * when absent; hosts before 0.16 take no engine); returns an error
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,+BAA+B;IAC/B,GAAG,IAAI,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9D,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC;IAC9D;;;;;;OAMG;IACH,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,YAAY,IAAI,IAAI,CAAC;IACrB,sCAAsC;IACtC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,gDAAgD;IAChD,MAAM,IAAI,MAAM,CAAC;IACjB,+FAA+F;IAC/F,eAAe,CAAC,IAAI,MAAM,EAAE,CAAC;IAC7B;;;;;;OAMG;IACH,YAAY,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAMpC;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzF,0FAA0F;IAC1F,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,eAAe,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sEAAsE;IACtE,iBAAiB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjD,kEAAkE;AAClE,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAG1C;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uBAAuB;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,GAAE,OAAO,UAAuB,GAAG,YAAY,GAAG,SAAS,CAExF"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAwEA,kEAAkE;AAClE,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AA0BD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,IAAuB,UAAU;IAC5D,OAAQ,CAA8C,CAAC,UAAU,CAAC;AACpE,CAAC"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAiJA,kEAAkE;AAClE,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AA0BD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,IAAuB,UAAU;IAC5D,OAAQ,CAA8C,CAAC,UAAU,CAAC;AACpE,CAAC"}
package/dist/fetch.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * `fetch`, `Headers`, `Request`, `Response` and `AbortController` over the
3
3
  * bridge's `fetch` primitive (`URLSession` on the Swift side). Bodies cross
4
- * as base64; a `Response` reads them back as text, JSON or bytes. Streams
5
- * and `Blob` are not here: a body is whole.
4
+ * as base64; a `Response` reads them back as text, JSON, bytes or a `Blob`.
5
+ * A `Blob` or `FormData` body (blob.ts) is sent whole, the form as
6
+ * multipart; there are no streams.
6
7
  */
7
8
  import type { NativeBridge, NativeFetchResult } from './bridge';
9
+ import { SimpleBlob, SimpleFormData } from './blob';
8
10
  type HeadersInitLike = SimpleHeaders | Record<string, string> | [string, string][];
9
11
  export declare class SimpleHeaders {
10
12
  private map;
@@ -45,11 +47,12 @@ export declare class SimpleAbortController {
45
47
  readonly signal: SimpleAbortSignal;
46
48
  abort(reason?: unknown): void;
47
49
  }
48
- type BodyInitLike = string | ArrayBuffer | ArrayBufferView | SimpleURLSearchParamsLike | null | undefined;
50
+ type BodyInitLike = string | ArrayBuffer | ArrayBufferView | SimpleURLSearchParamsLike | SimpleBlob | SimpleFormData | null | undefined;
49
51
  interface SimpleURLSearchParamsLike {
50
52
  toString(): string;
51
53
  [Symbol.iterator](): IterableIterator<[string, string]>;
52
54
  }
55
+ export declare function setBodyRandomness(random: (count: number) => Uint8Array): void;
53
56
  declare class Body {
54
57
  protected bytes: Uint8Array | null;
55
58
  bodyUsed: boolean;
@@ -60,6 +63,9 @@ declare class Body {
60
63
  bytesArray(): Promise<Uint8Array>;
61
64
  text(): Promise<string>;
62
65
  json(): Promise<unknown>;
66
+ blob(): Promise<SimpleBlob>;
67
+ /** The body's content type, for `blob()`; a Request or Response reads its headers. */
68
+ protected contentType(): string;
63
69
  }
64
70
  export interface RequestInitLike {
65
71
  method?: string;
@@ -78,6 +84,7 @@ export declare class SimpleRequest extends Body {
78
84
  }, init?: RequestInitLike);
79
85
  /** @internal */
80
86
  rawBytes(): Uint8Array | null;
87
+ protected contentType(): string;
81
88
  clone(): SimpleRequest;
82
89
  }
83
90
  export interface ResponseInitLike {
@@ -95,6 +102,7 @@ export declare class SimpleResponse extends Body {
95
102
  readonly redirected = false;
96
103
  constructor(body?: BodyInitLike, init?: ResponseInitLike);
97
104
  get ok(): boolean;
105
+ protected contentType(): string;
98
106
  clone(): SimpleResponse;
99
107
  static json(data: unknown, init?: ResponseInitLike): SimpleResponse;
100
108
  static error(): SimpleResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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"}
package/dist/fetch.js CHANGED
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * `fetch`, `Headers`, `Request`, `Response` and `AbortController` over the
3
3
  * bridge's `fetch` primitive (`URLSession` on the Swift side). Bodies cross
4
- * as base64; a `Response` reads them back as text, JSON or bytes. Streams
5
- * and `Blob` are not here: a body is whole.
4
+ * as base64; a `Response` reads them back as text, JSON, bytes or a `Blob`.
5
+ * A `Blob` or `FormData` body (blob.ts) is sent whole, the form as
6
+ * multipart; there are no streams.
6
7
  */
8
+ import { encodeMultipart, SimpleBlob, SimpleFormData } from './blob';
7
9
  import { base64Decode, base64Encode, utf8Decode, utf8Encode } from './encoding';
8
10
  export class SimpleHeaders {
9
11
  map = new Map();
@@ -114,12 +116,21 @@ function timeoutError() {
114
116
  error.name = 'TimeoutError';
115
117
  return error;
116
118
  }
119
+ /** The multipart boundary's randomness: the bridge's bytes once the runtime is installed, a counter before. */
120
+ let randomBytes = (count) => Uint8Array.from({ length: count }, (_, i) => (i * 37 + 11) & 255);
121
+ export function setBodyRandomness(random) {
122
+ randomBytes = random;
123
+ }
117
124
  /** Bytes of a body, and the content type it implies when the caller set none. */
118
125
  function encodeBody(body) {
119
126
  if (body === null || body === undefined)
120
127
  return { bytes: null, contentType: null };
121
128
  if (typeof body === 'string')
122
129
  return { bytes: utf8Encode(body), contentType: 'text/plain;charset=UTF-8' };
130
+ if (body instanceof SimpleBlob)
131
+ return { bytes: body.bytes(), contentType: body.type || null };
132
+ if (body instanceof SimpleFormData)
133
+ return encodeMultipart(body, randomBytes);
123
134
  if (body instanceof ArrayBuffer)
124
135
  return { bytes: new Uint8Array(body), contentType: null };
125
136
  if (ArrayBuffer.isView(body))
@@ -158,6 +169,13 @@ class Body {
158
169
  async json() {
159
170
  return JSON.parse(utf8Decode(this.take()));
160
171
  }
172
+ async blob() {
173
+ return new SimpleBlob([this.take()], { type: this.contentType() });
174
+ }
175
+ /** The body's content type, for `blob()`; a Request or Response reads its headers. */
176
+ contentType() {
177
+ return '';
178
+ }
161
179
  }
162
180
  export class SimpleRequest extends Body {
163
181
  url;
@@ -179,6 +197,9 @@ export class SimpleRequest extends Body {
179
197
  rawBytes() {
180
198
  return this.bytes;
181
199
  }
200
+ contentType() {
201
+ return this.headers.get('content-type') ?? '';
202
+ }
182
203
  clone() {
183
204
  return new SimpleRequest(this, { body: this.bytes });
184
205
  }
@@ -203,6 +224,9 @@ export class SimpleResponse extends Body {
203
224
  get ok() {
204
225
  return this.status >= 200 && this.status < 300;
205
226
  }
227
+ contentType() {
228
+ return this.headers.get('content-type') ?? '';
229
+ }
206
230
  clone() {
207
231
  return new SimpleResponse(this.bytes, { status: this.status, statusText: this.statusText, headers: this.headers, url: this.url });
208
232
  }