From 7f1fcf33027c96510c79ee6fcfdc4ccafa29fb03 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Feb 2025 09:29:25 +0100 Subject: [PATCH 1/4] Update to latest ReScript alpha --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63ee09e..a55033b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "rescript": "^12.0.0-alpha.6" + "rescript": "^12.0.0-alpha.8" }, "devDependencies": { "@astrojs/starlight": "0.32.0", diff --git a/package.json b/package.json index 8559445..094c55b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "license": "MIT", "dependencies": { - "rescript": "^12.0.0-alpha.6" + "rescript": "^12.0.0-alpha.8" }, "devDependencies": { "@astrojs/starlight": "0.32.0", From fc7bb241a9cd453718c7c94f8eb0dfbcaf6508f4 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Feb 2025 09:30:27 +0100 Subject: [PATCH 2/4] Add service worker registration test --- src/ServiceWorkerAPI/ServiceWorkerContainer.res | 3 +-- tests/Global__test.js | 3 +++ tests/Global__test.res | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ServiceWorkerAPI/ServiceWorkerContainer.res b/src/ServiceWorkerAPI/ServiceWorkerContainer.res index c4c75a6..798aedb 100644 --- a/src/ServiceWorkerAPI/ServiceWorkerContainer.res +++ b/src/ServiceWorkerAPI/ServiceWorkerContainer.res @@ -1,4 +1,3 @@ -open EventAPI open ServiceWorkerAPI include EventTarget.Impl({ @@ -11,7 +10,7 @@ include EventTarget.Impl({ @send external register: ( serviceWorkerContainer, - ~scriptURL: string, + string, ~options: registrationOptions=?, ) => promise = "register" diff --git a/tests/Global__test.js b/tests/Global__test.js index 1a0a97e..0681ec4 100644 --- a/tests/Global__test.js +++ b/tests/Global__test.js @@ -25,9 +25,12 @@ removeEventListener("mousedown", prim => { capture: false }); +let registrationResult = await navigator.serviceWorker.register("/sw.js"); + export { response, response2, response3, + registrationResult, } /* response Not a pure module */ diff --git a/tests/Global__test.res b/tests/Global__test.res index 8fe15ca..8bc8ed5 100644 --- a/tests/Global__test.res +++ b/tests/Global__test.res @@ -29,3 +29,5 @@ let response3 = await fetch_withRequest( ) removeEventListener(Mousedown, MouseEvent.preventDefault, ~options={capture: false}) + +let registrationResult = await navigator.serviceWorker->ServiceWorkerContainer.register("/sw.js") From d0872d085705fadea14401e734953b1f6f24ea35 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Feb 2025 09:30:38 +0100 Subject: [PATCH 3/4] Add notification test --- tests/NotificationsAPI/Notification__test.js | 18 ++++++++++++++++++ tests/NotificationsAPI/Notification__test.res | 11 +++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/NotificationsAPI/Notification__test.js create mode 100644 tests/NotificationsAPI/Notification__test.res diff --git a/tests/NotificationsAPI/Notification__test.js b/tests/NotificationsAPI/Notification__test.js new file mode 100644 index 0000000..8e92699 --- /dev/null +++ b/tests/NotificationsAPI/Notification__test.js @@ -0,0 +1,18 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +Notification.requestPermission().then(notificationPermission => { + switch (notificationPermission) { + case "default" : + console.log("Permission default"); + return; + case "denied" : + console.log("Permission denied"); + return; + case "granted" : + console.log("Permission granted"); + return; + } +}); + +/* Not a pure module */ diff --git a/tests/NotificationsAPI/Notification__test.res b/tests/NotificationsAPI/Notification__test.res new file mode 100644 index 0000000..389e95e --- /dev/null +++ b/tests/NotificationsAPI/Notification__test.res @@ -0,0 +1,11 @@ +open WebAPI.NotificationAPI + +Notification.requestPermission() +->Promise.thenResolve(notificationPermission => { + switch notificationPermission { + | Granted => Console.log("Permission granted") + | Denied => Console.log("Permission denied") + | Default => Console.log("Permission default") + } +}) +->Promise.done From df5ae0d1b398ca7df4013e50b2fc5de6bb0a3f3c Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Feb 2025 11:31:28 +0100 Subject: [PATCH 4/4] Add bindings for push notifications using service worker --- src/DOMAPI.res | 5 +- src/EventAPI.res | 11 +++ src/EventAPI/ExtendableEvent.js | 15 ++++ src/EventAPI/ExtendableEvent.res | 20 ++++++ src/Global.res | 2 +- src/NotificationAPI.res | 25 ++++++- src/{PushManagerAPI.js => PushAPI.js} | 0 src/{PushManagerAPI.res => PushAPI.res} | 19 ++++- .../ApplicationServerKey.js} | 0 src/PushAPI/ApplicationServerKey.res | 4 ++ src/PushAPI/PushEvent.js | 7 ++ src/PushAPI/PushEvent.res | 5 ++ .../PushManager.js} | 0 .../PushManager.res | 2 +- .../PushMessageData.js} | 0 src/PushAPI/PushMessageData.res | 15 ++++ src/PushAPI/PushSubscription.js | 2 + .../PushSubscription.res | 2 +- src/ServiceWorkerAPI.res | 70 +++++++++++------- src/ServiceWorkerAPI/Cache.res | 2 +- src/ServiceWorkerAPI/Clients.js | 2 + src/ServiceWorkerAPI/Clients.res | 4 ++ .../ServiceWorkerGlobalScope.js | 7 ++ .../ServiceWorkerGlobalScope.res | 5 ++ src/WebWorkersAPI.js | 2 + src/WebWorkersAPI.res | 46 ++++++++++++ src/WebWorkersAPI/CacheStorage.js | 2 + .../CacheStorage.res | 2 +- src/WebWorkersAPI/WorkerGlobalScope.js | 15 ++++ src/WebWorkersAPI/WorkerGlobalScope.res | 45 ++++++++++++ tests/Global__test.js | 6 ++ tests/Global__test.res | 6 ++ .../IntersectionObserver__test.res | 17 +++-- tests/ServiceWorkerAPI/ServiceWorker__test.js | 72 +++++++++++++++++++ .../ServiceWorkerAPI/ServiceWorker__test.res | 56 +++++++++++++++ 35 files changed, 448 insertions(+), 45 deletions(-) create mode 100644 src/EventAPI/ExtendableEvent.js create mode 100644 src/EventAPI/ExtendableEvent.res rename src/{PushManagerAPI.js => PushAPI.js} (100%) rename src/{PushManagerAPI.res => PushAPI.res} (83%) rename src/{PushManagerAPI/PushManager.js => PushAPI/ApplicationServerKey.js} (100%) create mode 100644 src/PushAPI/ApplicationServerKey.res create mode 100644 src/PushAPI/PushEvent.js create mode 100644 src/PushAPI/PushEvent.res rename src/{PushManagerAPI/PushSubscription.js => PushAPI/PushManager.js} (100%) rename src/{PushManagerAPI => PushAPI}/PushManager.res (97%) rename src/{ServiceWorkerAPI/CacheStorage.js => PushAPI/PushMessageData.js} (100%) create mode 100644 src/PushAPI/PushMessageData.res create mode 100644 src/PushAPI/PushSubscription.js rename src/{PushManagerAPI => PushAPI}/PushSubscription.res (96%) create mode 100644 src/ServiceWorkerAPI/Clients.js create mode 100644 src/ServiceWorkerAPI/Clients.res create mode 100644 src/ServiceWorkerAPI/ServiceWorkerGlobalScope.js create mode 100644 src/ServiceWorkerAPI/ServiceWorkerGlobalScope.res create mode 100644 src/WebWorkersAPI.js create mode 100644 src/WebWorkersAPI.res create mode 100644 src/WebWorkersAPI/CacheStorage.js rename src/{ServiceWorkerAPI => WebWorkersAPI}/CacheStorage.res (98%) create mode 100644 src/WebWorkersAPI/WorkerGlobalScope.js create mode 100644 src/WebWorkersAPI/WorkerGlobalScope.res create mode 100644 tests/ServiceWorkerAPI/ServiceWorker__test.js create mode 100644 tests/ServiceWorkerAPI/ServiceWorker__test.res diff --git a/src/DOMAPI.res b/src/DOMAPI.res index 1366770..c03f038 100644 --- a/src/DOMAPI.res +++ b/src/DOMAPI.res @@ -10,17 +10,14 @@ open MediaCaptureAndStreamsAPI open MediaSessionAPI open PermissionsAPI open ScreenWakeLockAPI +open WebWorkersAPI open ServiceWorkerAPI open EncryptedMediaExtensionsAPI -open GamepadAPI open FileAPI -open WebMIDIAPI open HistoryAPI open VisualViewportAPI open WebSpeechAPI -open ViewTransitionsAPI open FileAndDirectoryEntriesAPI -open WebVTTAPI open RemotePlaybackAPI open CanvasAPI open StorageAPI diff --git a/src/EventAPI.res b/src/EventAPI.res index 6843e70..b076328 100644 --- a/src/EventAPI.res +++ b/src/EventAPI.res @@ -51,6 +51,7 @@ type eventType = | @as("mouseout") Mouseout | @as("mouseover") Mouseover | @as("mouseup") Mouseup + | @as("notificationclick") NotificationClick | @as("paste") Paste | @as("pause") Pause | @as("play") Play @@ -94,6 +95,7 @@ type eventType = | @as("pointercancel") Pointercancel | @as("pointerout") Pointerout | @as("pointerleave") Pointerleave + | @as("push") Push | @as("gotpointercapture") Gotpointercapture | @as("lostpointercapture") Lostpointercapture | @as("selectstart") Selectstart @@ -217,3 +219,12 @@ type eventInit = { mutable cancelable?: bool, mutable composed?: bool, } + +/** +The ExtendableEvent interface extends the lifetime of the install and activate events dispatched on the global scope as part of the service worker lifecycle. +[See ExtendableEvent on MDN](https://developer.mozilla.org/docs/Web/API/ExtendableEvent) + */ +@editor.completeFrom(ExtendableEvent) +type extendableEvent = { + ...event +} \ No newline at end of file diff --git a/src/EventAPI/ExtendableEvent.js b/src/EventAPI/ExtendableEvent.js new file mode 100644 index 0000000..0169077 --- /dev/null +++ b/src/EventAPI/ExtendableEvent.js @@ -0,0 +1,15 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Event$WebAPI from "./Event.js"; + +function Impl(T) { + Event$WebAPI.Impl({}); + return {}; +} + +Event$WebAPI.Impl({}); + +export { + Impl, +} +/* Not a pure module */ diff --git a/src/EventAPI/ExtendableEvent.res b/src/EventAPI/ExtendableEvent.res new file mode 100644 index 0000000..85277f0 --- /dev/null +++ b/src/EventAPI/ExtendableEvent.res @@ -0,0 +1,20 @@ +open EventAPI + +module Impl = ( + T: { + type t + }, +) => { + external asExtendableEvent: T.t => extendableEvent = "%identity" + + include Event.Impl({ + type t = T.t + }) + + @send + external waitUntil: (T.t, promise<'a>) => unit = "waitUntil" +} + +include Impl({ + type t = extendableEvent +}) diff --git a/src/Global.res b/src/Global.res index bd2d7d5..61d2b36 100644 --- a/src/Global.res +++ b/src/Global.res @@ -5,7 +5,7 @@ open WebSpeechAPI open IndexedDBAPI open WebCryptoAPI open PerformanceAPI -open ServiceWorkerAPI +open WebWorkersAPI open WebStorageAPI open CanvasAPI open FileAPI diff --git a/src/NotificationAPI.res b/src/NotificationAPI.res index 9e96ba4..78e446d 100644 --- a/src/NotificationAPI.res +++ b/src/NotificationAPI.res @@ -63,7 +63,17 @@ type notification = { /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/Notification/data) */ - data: JSON.t, + data?: JSON.t, +} + +/** + An array of actions to display in the notification, for which the default is an empty array. + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#actions) + */ +type notificationAction = { + action: string, + title: string, + icon?: string } type notificationOptions = { @@ -76,8 +86,21 @@ type notificationOptions = { mutable silent?: Null.t, mutable requireInteraction?: bool, mutable data?: JSON.t, + mutable actions?: array } type getNotificationOptions = {mutable tag?: string} type notificationPermissionCallback = notificationPermission => unit + +type notificationEvent = { + ...extendableEvent, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/NotificationEvent/action) + */ + action: string, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/NotificationEvent/notification) + */ + notification: notification, +} diff --git a/src/PushManagerAPI.js b/src/PushAPI.js similarity index 100% rename from src/PushManagerAPI.js rename to src/PushAPI.js diff --git a/src/PushManagerAPI.res b/src/PushAPI.res similarity index 83% rename from src/PushManagerAPI.res rename to src/PushAPI.res index 3314aff..76b1140 100644 --- a/src/PushManagerAPI.res +++ b/src/PushAPI.res @@ -1,6 +1,7 @@ @@warning("-30") open Prelude +open EventAPI type permissionState = | @as("denied") Denied @@ -23,6 +24,8 @@ type pushManager = { supportedContentEncodings: array, } +type applicationServerKey + /** [See PushSubscriptionOptions on MDN](https://developer.mozilla.org/docs/Web/API/PushSubscriptionOptions) */ @@ -34,7 +37,7 @@ type pushSubscriptionOptions = { /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushSubscriptionOptions/applicationServerKey) */ - applicationServerKey: Null.t, + applicationServerKey: applicationServerKey, } /** @@ -59,7 +62,7 @@ type pushSubscription = { type pushSubscriptionOptionsInit = { mutable userVisibleOnly?: bool, - mutable applicationServerKey?: Null.t, + mutable applicationServerKey?: applicationServerKey, } type pushSubscriptionJSON = { @@ -67,3 +70,15 @@ type pushSubscriptionJSON = { mutable expirationTime?: Null.t, mutable keys?: any, } + +@editor.completeFrom(PushMessageData) +type pushMessageData + +@editor.completeFrom(PushEvent) +type pushEvent = { + ...extendableEvent, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushEvent/data) + */ + data?: pushMessageData, +} \ No newline at end of file diff --git a/src/PushManagerAPI/PushManager.js b/src/PushAPI/ApplicationServerKey.js similarity index 100% rename from src/PushManagerAPI/PushManager.js rename to src/PushAPI/ApplicationServerKey.js diff --git a/src/PushAPI/ApplicationServerKey.res b/src/PushAPI/ApplicationServerKey.res new file mode 100644 index 0000000..78cfd95 --- /dev/null +++ b/src/PushAPI/ApplicationServerKey.res @@ -0,0 +1,4 @@ +open PushAPI + +external fromString: string => applicationServerKey = "%identity" +external fromUint8Array: Uint8Array.t => applicationServerKey = "%identity" diff --git a/src/PushAPI/PushEvent.js b/src/PushAPI/PushEvent.js new file mode 100644 index 0000000..8cf0cc5 --- /dev/null +++ b/src/PushAPI/PushEvent.js @@ -0,0 +1,7 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as ExtendableEvent$WebAPI from "../EventAPI/ExtendableEvent.js"; + +ExtendableEvent$WebAPI.Impl({}); + +/* Not a pure module */ diff --git a/src/PushAPI/PushEvent.res b/src/PushAPI/PushEvent.res new file mode 100644 index 0000000..f87f648 --- /dev/null +++ b/src/PushAPI/PushEvent.res @@ -0,0 +1,5 @@ +open PushAPI + +include ExtendableEvent.Impl({ + type t = pushEvent; +}); \ No newline at end of file diff --git a/src/PushManagerAPI/PushSubscription.js b/src/PushAPI/PushManager.js similarity index 100% rename from src/PushManagerAPI/PushSubscription.js rename to src/PushAPI/PushManager.js diff --git a/src/PushManagerAPI/PushManager.res b/src/PushAPI/PushManager.res similarity index 97% rename from src/PushManagerAPI/PushManager.res rename to src/PushAPI/PushManager.res index 7ff781b..7e2e445 100644 --- a/src/PushManagerAPI/PushManager.res +++ b/src/PushAPI/PushManager.res @@ -1,4 +1,4 @@ -open PushManagerAPI +open PushAPI /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushManager/subscribe) diff --git a/src/ServiceWorkerAPI/CacheStorage.js b/src/PushAPI/PushMessageData.js similarity index 100% rename from src/ServiceWorkerAPI/CacheStorage.js rename to src/PushAPI/PushMessageData.js diff --git a/src/PushAPI/PushMessageData.res b/src/PushAPI/PushMessageData.res new file mode 100644 index 0000000..acb6ec1 --- /dev/null +++ b/src/PushAPI/PushMessageData.res @@ -0,0 +1,15 @@ +open PushAPI + +/** +The json() method of the PushMessageData interface extracts push message data by parsing it as a JSON string and returning the result. +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushMessageData/json) +*/ +@send +external json: pushMessageData => JSON.t = "json" + +/** +The text() method of the PushMessageData interface extracts push message data as a plain text string. +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushMessageData/text) +*/ +@send +external text: pushMessageData => string = "text" \ No newline at end of file diff --git a/src/PushAPI/PushSubscription.js b/src/PushAPI/PushSubscription.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/PushAPI/PushSubscription.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/PushManagerAPI/PushSubscription.res b/src/PushAPI/PushSubscription.res similarity index 96% rename from src/PushManagerAPI/PushSubscription.res rename to src/PushAPI/PushSubscription.res index 2aca1eb..79b98b2 100644 --- a/src/PushManagerAPI/PushSubscription.res +++ b/src/PushAPI/PushSubscription.res @@ -1,4 +1,4 @@ -open PushManagerAPI +open PushAPI /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/PushSubscription/getKey) diff --git a/src/ServiceWorkerAPI.res b/src/ServiceWorkerAPI.res index 9742a8e..3826412 100644 --- a/src/ServiceWorkerAPI.res +++ b/src/ServiceWorkerAPI.res @@ -2,10 +2,8 @@ open Prelude open EventAPI -open PushManagerAPI -open NotificationAPI -open FetchAPI -open ChannelMessagingAPI +open PushAPI +open WebWorkersAPI type serviceWorkerState = | @as("activated") Activated @@ -101,20 +99,6 @@ type serviceWorkerContainer = { ready: promise, } -/** -The storage for Cache objects. -[See CacheStorage on MDN](https://developer.mozilla.org/docs/Web/API/CacheStorage) -*/ -@editor.completeFrom(CacheStorage) -type cacheStorage = {} - -/** -Provides a storage mechanism for Request / Response object pairs that are cached, for example as part of the ServiceWorker life cycle. Note that the Cache interface is exposed to windowed scopes as well as workers. You don't have to use it in conjunction with service workers, even though it is defined in the service worker spec. -[See Cache on MDN](https://developer.mozilla.org/docs/Web/API/Cache) -*/ -@editor.completeFrom(Cache) -type cache = {} - type navigationPreloadState = { mutable enabled?: bool, mutable headerValue?: string, @@ -126,15 +110,49 @@ type registrationOptions = { mutable updateViaCache?: serviceWorkerUpdateViaCache, } -type cacheQueryOptions = { - mutable ignoreSearch?: bool, - mutable ignoreMethod?: bool, - mutable ignoreVary?: bool, +type requestInfo = any + +/** +The Clients interface provides access to Client objects. Access it via self.clients within a service worker. +[See Clients on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Clients) + */ +@editor.completeFrom(Clients) +type clients + +/** +The ServiceWorkerGlobalScope interface of the Service Worker API represents the global execution context of a service worker. +[See ServiceWorkerGlobalScope on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope) + */ +@editor.completeFrom(ServiceWorkerGlobalScope) +type serviceWorkerGlobalScope = { + ...workerGlobalScope, + /** + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/clients) + */ + clients: clients, + /** + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/registration) + */ + registration: serviceWorkerRegistration, } -type multiCacheQueryOptions = { - ...cacheQueryOptions, - mutable cacheName?: string, +/** +The Client interface represents an executable context such as a Worker, or a SharedWorker. Window clients are represented by the more-specific WindowClient. +[See Client on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Client) +*/ +type client = { + /** + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Client/id) + */ + id: string, + /** [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Client/url) */ + url: string, } -type requestInfo = any +/** +The WindowClient interface of the ServiceWorker API represents the scope of a service worker client that is a document in a browsing context, controlled by an active worker. +[See WindowClient on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WindowClient) +*/ +type windowClient = { + ...client, +} \ No newline at end of file diff --git a/src/ServiceWorkerAPI/Cache.res b/src/ServiceWorkerAPI/Cache.res index b005765..95e5aa5 100644 --- a/src/ServiceWorkerAPI/Cache.res +++ b/src/ServiceWorkerAPI/Cache.res @@ -1,5 +1,5 @@ open FetchAPI -open ServiceWorkerAPI +open WebWorkersAPI /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/Cache/match) diff --git a/src/ServiceWorkerAPI/Clients.js b/src/ServiceWorkerAPI/Clients.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/ServiceWorkerAPI/Clients.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/ServiceWorkerAPI/Clients.res b/src/ServiceWorkerAPI/Clients.res new file mode 100644 index 0000000..cc35225 --- /dev/null +++ b/src/ServiceWorkerAPI/Clients.res @@ -0,0 +1,4 @@ +open ServiceWorkerAPI + +@send +external openWindow: (clients, string) => promise = "open" diff --git a/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.js b/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.js new file mode 100644 index 0000000..3e68475 --- /dev/null +++ b/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.js @@ -0,0 +1,7 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as WorkerGlobalScope$WebAPI from "../WebWorkersAPI/WorkerGlobalScope.js"; + +WorkerGlobalScope$WebAPI.Impl({}); + +/* Not a pure module */ diff --git a/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.res b/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.res new file mode 100644 index 0000000..07e7695 --- /dev/null +++ b/src/ServiceWorkerAPI/ServiceWorkerGlobalScope.res @@ -0,0 +1,5 @@ +open ServiceWorkerAPI + +include WorkerGlobalScope.Impl({ + type t = serviceWorkerGlobalScope +}) \ No newline at end of file diff --git a/src/WebWorkersAPI.js b/src/WebWorkersAPI.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/WebWorkersAPI.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/WebWorkersAPI.res b/src/WebWorkersAPI.res new file mode 100644 index 0000000..e7fb89c --- /dev/null +++ b/src/WebWorkersAPI.res @@ -0,0 +1,46 @@ +open EventAPI + +/** +Provides a storage mechanism for Request / Response object pairs that are cached, for example as part of the ServiceWorker life cycle. Note that the Cache interface is exposed to windowed scopes as well as workers. You don't have to use it in conjunction with service workers, even though it is defined in the service worker spec. +[See Cache on MDN](https://developer.mozilla.org/docs/Web/API/Cache) +*/ +@editor.completeFrom(Cache) +type cache = {} + +/** +The storage for Cache objects. +[See CacheStorage on MDN](https://developer.mozilla.org/docs/Web/API/CacheStorage) +*/ +@editor.completeFrom(CacheStorage) +type cacheStorage = {} + +type cacheQueryOptions = { + mutable ignoreSearch?: bool, + mutable ignoreMethod?: bool, + mutable ignoreVary?: bool, +} + +type multiCacheQueryOptions = { + ...cacheQueryOptions, + mutable cacheName?: string, +} + +/** +The WorkerGlobalScope interface of the Web Workers API is an interface representing the scope of any worker. +Workers have no browsing context; this scope contains the information usually conveyed by Window objects — +in this case event handlers, the console or the associated WorkerNavigator object. +Each WorkerGlobalScope has its own event loop. +[See WorkerGlobalScope on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope) +*/ +@editor.completeFrom(WorkerGlobalScope) +type workerGlobalScope = { + ...eventTarget, + /** + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/caches) + */ + caches: cacheStorage, + /** + [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/crossOriginIsolated) + */ + crossOriginIsolated: bool, +} diff --git a/src/WebWorkersAPI/CacheStorage.js b/src/WebWorkersAPI/CacheStorage.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/WebWorkersAPI/CacheStorage.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/ServiceWorkerAPI/CacheStorage.res b/src/WebWorkersAPI/CacheStorage.res similarity index 98% rename from src/ServiceWorkerAPI/CacheStorage.res rename to src/WebWorkersAPI/CacheStorage.res index 53cae45..e829b6f 100644 --- a/src/ServiceWorkerAPI/CacheStorage.res +++ b/src/WebWorkersAPI/CacheStorage.res @@ -1,5 +1,5 @@ open FetchAPI -open ServiceWorkerAPI +open WebWorkersAPI /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/CacheStorage/match) diff --git a/src/WebWorkersAPI/WorkerGlobalScope.js b/src/WebWorkersAPI/WorkerGlobalScope.js new file mode 100644 index 0000000..d309b02 --- /dev/null +++ b/src/WebWorkersAPI/WorkerGlobalScope.js @@ -0,0 +1,15 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as EventTarget$WebAPI from "../EventAPI/EventTarget.js"; + +function Impl(T) { + EventTarget$WebAPI.Impl({}); + return {}; +} + +EventTarget$WebAPI.Impl({}); + +export { + Impl, +} +/* Not a pure module */ diff --git a/src/WebWorkersAPI/WorkerGlobalScope.res b/src/WebWorkersAPI/WorkerGlobalScope.res new file mode 100644 index 0000000..dcf170d --- /dev/null +++ b/src/WebWorkersAPI/WorkerGlobalScope.res @@ -0,0 +1,45 @@ +open WebWorkersAPI +open FetchAPI + +module Impl = ( + T: { + type t + }, +) => { + include EventTarget.Impl({ + type t = T.t + }) + + /** +`fetch(workerGlobalScope, string, init)` + +The fetch() method of the WorkerGlobalScope interface starts the process of fetching a resource from the network, +returning a promise that is fulfilled once the response is available. + +```res +let response = await self->WorkerGlobalScope.fetch("https://rescript-lang.org") +``` + +[Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/fetch) +*/ +@send + external fetch: (T.t, string, ~init: requestInit=?) => promise = "fetch" + + /** +`fetch_withRequest(workerGlobalScope, request, init)` + +The fetch() method of the WorkerGlobalScope interface starts the process of fetching a resource from the network, +returning a promise that is fulfilled once the response is available. + +```res +let response = await self->WorkerGlobalScope.fetch(myRequest) +``` + +[Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/fetch) +*/ + external fetch_withRequest: (T.t, request, ~init: requestInit=?) => promise = "fetch" +} + +include Impl({ + type t = workerGlobalScope +}) diff --git a/tests/Global__test.js b/tests/Global__test.js index 0681ec4..35e6a4e 100644 --- a/tests/Global__test.js +++ b/tests/Global__test.js @@ -27,10 +27,16 @@ removeEventListener("mousedown", prim => { let registrationResult = await navigator.serviceWorker.register("/sw.js"); +let subscription = await registrationResult.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: "MyPublicKey" +}); + export { response, response2, response3, registrationResult, + subscription, } /* response Not a pure module */ diff --git a/tests/Global__test.res b/tests/Global__test.res index 8bc8ed5..eac151f 100644 --- a/tests/Global__test.res +++ b/tests/Global__test.res @@ -31,3 +31,9 @@ let response3 = await fetch_withRequest( removeEventListener(Mousedown, MouseEvent.preventDefault, ~options={capture: false}) let registrationResult = await navigator.serviceWorker->ServiceWorkerContainer.register("/sw.js") +let subscription = await registrationResult.pushManager->PushManager.subscribe( + ~options={ + userVisibleOnly: true, + applicationServerKey: ApplicationServerKey.fromString("MyPublicKey"), + }, +) diff --git a/tests/IntersectionObserverAPI/IntersectionObserver__test.res b/tests/IntersectionObserverAPI/IntersectionObserver__test.res index eeba8c8..051d82e 100644 --- a/tests/IntersectionObserverAPI/IntersectionObserver__test.res +++ b/tests/IntersectionObserverAPI/IntersectionObserver__test.res @@ -4,13 +4,16 @@ let observer = IntersectionObserver.make(~callback=(entry, observer) => { let root = Global.document->Document.querySelector("#root")->Null.getUnsafe -let observer2 = IntersectionObserver.make(~callback=(entry, observer) => { - Console.log2(entry, observer) -}, ~options={ - root: root->IntersectionObserverRoot.fromElement, - rootMargin: "10px", - threshold: [0.1], -}) +let observer2 = IntersectionObserver.make( + ~callback=(entry, observer) => { + Console.log2(entry, observer) + }, + ~options={ + root: root->IntersectionObserverRoot.fromElement, + rootMargin: "10px", + threshold: [0.1], + }, +) switch observer2.root->IntersectionObserverRoot.decode { | Element(_) => Console.log("Element") diff --git a/tests/ServiceWorkerAPI/ServiceWorker__test.js b/tests/ServiceWorkerAPI/ServiceWorker__test.js new file mode 100644 index 0000000..be7eb20 --- /dev/null +++ b/tests/ServiceWorkerAPI/ServiceWorker__test.js @@ -0,0 +1,72 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Option from "rescript/lib/es6/Option.js"; +import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; + +self.addEventListener("push", event => { + console.log("received push event"); + let data = event.data; + let match; + if (data !== undefined) { + let match$1 = Primitive_option.valFromOption(data).json(); + if (typeof match$1 === "object" && !Array.isArray(match$1)) { + let title = match$1.title; + if (typeof title === "string") { + let body = match$1.body; + match = typeof body === "string" ? [ + title, + body + ] : [ + "???", + "???" + ]; + } else { + match = [ + "???", + "???" + ]; + } + } else { + match = [ + "???", + "???" + ]; + } + } else { + match = [ + "???", + "???" + ]; + } + event.waitUntil(self.fetch("https://rescript-lang.org")); + self.registration.showNotification(match[0], { + body: match[1], + icon: "/icon.png", + data: 17, + actions: [ + { + action: "open", + title: "Open" + }, + { + action: "close", + title: "Close" + } + ] + }); +}); + +self.addEventListener("notificationclick", event => { + console.log("notification clicked: " + event.action); + event.notification.close(); + Option.forEach(Option.flatMap(event.notification.data, data => { + if (typeof data === "number") { + return data.toString(); + } + + }), id => { + self.clients.open("https://mywebsite.com/mydata/" + id); + }); +}); + +/* Not a pure module */ diff --git a/tests/ServiceWorkerAPI/ServiceWorker__test.res b/tests/ServiceWorkerAPI/ServiceWorker__test.res new file mode 100644 index 0000000..8d274a1 --- /dev/null +++ b/tests/ServiceWorkerAPI/ServiceWorker__test.res @@ -0,0 +1,56 @@ +open WebAPI.ServiceWorkerAPI + +external self: serviceWorkerGlobalScope = "self" + +self->ServiceWorkerGlobalScope.addEventListener(EventAPI.Push, (event: PushAPI.pushEvent) => { + Console.log("received push event") + + // Extract data + let (title, body) = switch event.data { + | Some(data) => + switch data->PushMessageData.json { + | JSON.Object(dict{"title": JSON.String(title), "body": JSON.String(body)}) => (title, body) + | _ => ("???", "???") + } + | None => ("???", "???") + } + + // Handle some data sync + event->PushEvent.waitUntil(self->ServiceWorkerGlobalScope.fetch("https://rescript-lang.org")) + + // Show notification + self.registration + ->ServiceWorkerRegistration.showNotification( + ~title, + ~options={ + body, + icon: "/icon.png", + actions: [{action: "open", title: "Open"}, {action: "close", title: "Close"}], + // For example the id of a new data entry + data: JSON.Number(17.), + }, + ) + ->Promise.done +}) + +self->ServiceWorkerGlobalScope.addEventListener(EventAPI.NotificationClick, ( + event: NotificationAPI.notificationEvent, +) => { + Console.log(`notification clicked: ${event.action}`) + // Close the notification + event.notification->Notification.close + + // Open a new window if that is relevant + event.notification.data + ->Option.flatMap(data => { + switch data { + | JSON.Number(id) => Some(Float.toString(id)) + | _ => None + } + }) + ->Option.forEach(id => { + self.clients + ->Clients.openWindow(`https://mywebsite.com/mydata/${id}`) + ->Promise.done + }) +})