From 80fd9daed79eb612c3c323fa25e1eb01062d56f4 Mon Sep 17 00:00:00 2001 From: tristancaron Date: Mon, 23 Mar 2015 20:23:45 +0100 Subject: [PATCH 1/5] Service Worker Api --- service_worker_api/service_worker_api-test.ts | 188 ++++ service_worker_api/service_worker_api.d.ts | 896 ++++++++++++++++++ 2 files changed, 1084 insertions(+) create mode 100644 service_worker_api/service_worker_api-test.ts create mode 100644 service_worker_api/service_worker_api.d.ts diff --git a/service_worker_api/service_worker_api-test.ts b/service_worker_api/service_worker_api-test.ts new file mode 100644 index 0000000000..67ce58cd40 --- /dev/null +++ b/service_worker_api/service_worker_api-test.ts @@ -0,0 +1,188 @@ +/// + +var OFFLINE_CACHE = "cache_test"; +var OFFLINE_URL = "localhost"; + +self.addEventListener('fetch', function(event: FetchEvent) { + if (event.request.method === 'GET' && + event.request.headers.get('accept').indexOf('text/html') !== -1) { + console.log('Handling fetch event for', event.request.url); + event.respondWith( + self.fetch(event.request).catch(function(e) { + console.error('Fetch failed; returning offline page instead.', e); + return self.caches.open(OFFLINE_CACHE).then(function(cache: Cache) { + return cache.match(OFFLINE_URL); + }); + }) + ); + } +}); + +self.caches.open('v1').then(function(cache: Cache) { + cache.matchAll('/images/').then(function(response: Array) { + response.forEach(function(element, index, array) { + cache.delete(element); + + }); + }); + +}); + +self.addEventListener('install', function(event: InstallEvent) { + event.waitUntil( + self.caches.open('v1').then(function(cache: Cache) { + return cache.add('/sw-test/index.html'); + }) + ); +}); + +self.addEventListener('install', function(event: InstallEvent) { + event.waitUntil( + self.caches.open('v1').then(function(cache) { + return cache.addAll( + '/sw-test/', + '/sw-test/index.html', + '/sw-test/style.css', + '/sw-test/app.js', + '/sw-test/image-list.js', + '/sw-test/star-wars-logo.jpg', + '/sw-test/gallery/', + '/sw-test/gallery/bountyHunters.jpg', + '/sw-test/gallery/myLittleVader.jpg', + '/sw-test/gallery/snowTroopers.jpg' + ); + }) + ); +}); + +self.addEventListener('fetch', function(event: FetchEvent) { + var cachedResponse = self.caches.match(event.request).catch(function() { + return self.fetch(event.request).then(function(response: Response) { + return self.caches.open('v1').then(function(cache) { + cache.put(event.request, response.clone()); + return response; + }); + }); + }).catch(function() { + return self.caches.match('/sw-test/gallery/myLittleVader.jpg'); + }); + + event.respondWith(cachedResponse); +}); + +self.caches.open('v1').then(function(cache) { + cache.match('/images/image.png').then(function(response) { + cache.delete(response); + }); +}); + +self.caches.open('v1').then(function(cache: Cache) { + cache.keys().then(function(response) { + response.forEach(function(element, index, array) { + cache.delete(element); + }); + }); +}); + +self.caches.has('v1').then(function() { + self.caches.delete('v1').then(function() { + + }); +}); + +self.addEventListener('activate', function(event: ExtendableEvent) { + var cacheWhitelist = ['v2']; + + event.waitUntil( + self.caches.keys().then(function(keyList) { + for(var i = 0; i < keyList.length; i++) { + if (cacheWhitelist.indexOf(keyList[i]) === -1) { + return self.caches.delete(keyList[i]); + } + } + }) + ); +}); + +function sendMessage(message) { + return new Promise(function(resolve, reject) { + var messageChannel = new MessageChannel(); + messageChannel.port1.onmessage = function(event) { + if (event.data.error) { + reject(event.data.error); + } else { + resolve(event.data); + } + }; + navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]); + }); +} + +self.clients.matchAll({type: "test"}).then(function(clients) { + for(var i = 0 ; i < clients.length ; i++) { + if(clients[i].url === 'index.html') { + self.clients.openWindow(clients[i].url); + // or do something else involving the matching client + } + } +}); + +self.addEventListener('activate', function(e: ExtendableEvent) { + e.waitUntil(self.clients.claim()); +}); + +navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(function(registration) { + // At this point, registration has taken place. + // The service worker will not handle requests until this page and any + // other instances of this page (in other tabs, etc.) have been + // closed/reloaded. + var serviceWorker; + if (registration.installing) { + serviceWorker = registration.installing; + } else if (registration.waiting) { + serviceWorker = registration.waiting; + } else if (registration.active) { + serviceWorker = registration.active; + } + if (serviceWorker) { + console.log(serviceWorker.state); + serviceWorker.addEventListener('statechange', function(e) { + console.log(e.target.state); + }); + } +}).catch(function(error) { + // Something went wrong during registration. The service-worker.js file + // might be unavailable or contain a syntax error. + +}); + +navigator.serviceWorker.getRegistration('/app').then(function(registration: ServiceWorkerRegistration) { + +}); + +navigator.serviceWorker.getRegistrations().then(function(registrations: Array) { + +}); + +self.registration.unregister(); + +self.addEventListener('install', function(event: ExtendableEvent) { + event.waitUntil(self.skipWaiting()); +}); + +self.addEventListener('notificationclick', function(event: NotificationEvent) { + console.log('On notification click: ', event.notification.tag); + event.notification.close(); + + // This looks to see if the current is already open and + // focuses if it is + event.waitUntil(self.clients.matchAll({ + type: "window" + }).then(function(clientList) { + for (var i = 0; i < clientList.length; i++) { + var client = clientList[i]; + } + if (self.clients.openWindow) + return self.clients.openWindow('/'); + })); +}); \ No newline at end of file diff --git a/service_worker_api/service_worker_api.d.ts b/service_worker_api/service_worker_api.d.ts new file mode 100644 index 0000000000..f9b2981463 --- /dev/null +++ b/service_worker_api/service_worker_api.d.ts @@ -0,0 +1,896 @@ +// Type definitions for service_worker_api +// Project: https://developer.mozilla.org/fr/docs/Web/API/ServiceWorker_API +// Definitions by: Tristan Caron +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +/** + * Provides methods relating to the body of the response/request, allowing you + * to declare what its content type is and how it should be handled. + */ +interface Body { + /** + * Contains a Boolean that indicates whether the body has been read. + * @readonly + */ + bodyUsed: boolean; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with an ArrayBuffer. + */ + arrayBuffer(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a Blob. + */ + blob(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a FormData object. + */ + formData(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a JSON object. + */ + json(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a USVString (text). + */ + text(): Promise; + +} + +/** + * Represents response/request headers, allowing you to query them and take + * different actions depending on the results. + */ +interface Header { + new(): Header; + + /** + * Appends a new value onto an existing header inside a Headers object, or + * adds the header if it does not already exist. + * + * @param name The name of the HTTP header you want to add to the Headers + * object. + * @param value The value of the HTTP header you want to add. + */ + append(name: string, value: string): void; + + /** + * Deletes a header from a Headers object. + * + * @param name The name of the HTTP header you want to delete from the + * Headers object. + */ + delete(name: string): void; + + /** + * Returns the first value of a given header from within a Headers object. + * + * @param name The name of the HTTP header whose value you want to retrieve + * from the Headers object. If the given name is not the name of an + * HTTP header, this method throws a TypeError. + */ + get(name: string): string; + + /** + * Returns an array of all the values of a header within a Headers object + * with a given name. + * + * @param name The name of the HTTP header whose values you want to retrieve + * from the Headers object. If the given name is not the name of an + * HTTP header, this method throws a TypeError. + */ + getAll(name:string): Array; + + /** + * Returns a boolean stating whether a Headers object contains a + * certain header. + * + * @param name The name of the HTTP header you want to test for. If the + * given name is not the name of an HTTP header, this method throws + * a TypeError. + */ + has(name: string): boolean; + + /** + * Sets a new value for an existing header inside a Headers object, or + * adds the header if it does not already exist. + * + * @param name The name of the HTTP header you want to set to a new value. + * If the given name is not the name of an HTTP header, this method throws + * a TypeError. + * @param value The new value you want to set. + */ + set(name: string, value: string): void; +} + +/** + * Represents the response to a request. + */ +interface Response extends Body { + new(): Response; + + /** + * Contains the type of the response (e.g., basic, cors). + * @readonly + */ + type: string; + + /** + * Contains the URL of the response. + * @readonly + */ + url: string; + + /** + * Contains a boolean stating whether this is the final URL of the response. + */ + useFinalURL: boolean; + + /** + * Contains the status code of the response (e.g., 200 for a success). + * @readonly + */ + status: number; + + /** + * Contains a boolean stating whether the response was successful + * (status in the range 200-299) or not. + * @readonly + */ + ok: boolean; + + /** + * Contains the status message corresponding to the status code + * (e.g., OK for 200). + * @readonly + */ + statusText: string; + + /** + * Contains the Headers object associated with the response. + * @readonly + */ + headers: Header; + + /** + * Creates a clone of a Response object. + */ + clone(): Response; + + /** + * Returns a new Response object associated with a network error. + */ + error(): Response; + + /** + * Creates a new response with a different URL. + */ + redirect(): Response; +} + +/** + * Represents a resource request. + */ +interface Request extends Body { + new(): Request; + + /** + * Contains the request's method (GET, POST, etc.). + * @readonly + */ + method: string; + + /** + * Contains the URL of the request. + * @readonly + */ + url: string; + + /** + * Contains the associated Headers object of the request. + * @readonly + */ + headers: Header; + + /** + * Contains the context of the request (e.g., audio, image, iframe, etc.). + * @readonly + */ + context: string; + + /** + * Contains the referrer of the request (e.g., client). + * @readonly + */ + referrer: string; + + /** + * Contains the mode of the request (e.g., cors, no-cors, same-origin). + * @readonly + */ + mode: string; + + /** + * Contains the credentials of the request (e.g., omit, same-origin). + * @readonly + */ + credentials: string; + + /** + * Contains the cache mode of the request (e.g., default, reload, no-cache). + * @readonly + */ + cache: string; + + /** + * Creates a copy of the current Request object. + */ + clone(): Request; +} + +/** + * An CacheOptions object allowing you to set specific control options for the + * matching done in the match operation. + * + * @property [ignoreSearch] A Boolean that specifies whether the matching + * process should ignore the query string in the url. If set to true, + * the ?value=bar part of http://foo.com/?value=bar would be ignored when + * performing a match. It defaults to false. + * + * @property [ignoreMethod] A Boolean that, when set to true, prevents matching + * operations from validating the Request http method (normally only GET + * and HEAD are allowed.) It defaults to false. + * + * @property [ignoreVary] A Boolean that when set to true tells the matching + * operation not to perform VARY header matching — i.e. if the URL matches you + * will get a match regardless of the Response object having a VARY header or + * not. It defaults to false. + * + * @property [cacheName] A DOMString that represents a specific cache to search + * within. Note that this option is ignored by Cache.match(). + */ +interface CacheOptions { + ignoreSearch?: boolean; + ignoreMethod?: boolean; + ignoreVary?: boolean; + cacheName?: string; +} + +/** + * Represents the storage for Request / Response object pairs that are cached as + * part of the ServiceWorker life cycle. + */ +interface Cache { + /** + * Returns a Promise that resolves to the response associated with the first + * matching request in the Cache object. + * + * @param request The Request you are attempting to find in the Cache. + * @param {CacheOptions} options + */ + match(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to an array of all matching requests in + * the Cache object. + * + * @param request The Request you are attempting to find in the Cache. + * @param {CacheOptions} options + */ + matchAll(request: Request | string, options?: CacheOptions): Promise>; + + /** + * Returns a Promise that resolves to a new Cache entry whose key + * is the request. + * + * @param request The Request you want to add to the cache. + */ + add(request: Request | string): Promise; + + /** + * Returns a Promise that resolves to a new array of Cache entries whose + * keys are the requests. + * + * @param request An array of Request objects you want to add to the cache. + */ + addAll(...request: Array): Promise; + + /** + * Adds additional key/value pairs to the current Cache object. + * + * @param request The Request you want to add to the cache. + * @param response The response you want to match up to the request. + */ + put(request: Request, response: Response): Promise; + + /** + * Finds the Cache entry whose key is the request, and if found, deletes the + * Cache entry and returns a Promise that resolves to true. If no Cache + * entry is found, it returns false. + * + * @param request The Request you are looking to delete. + * @param {CacheOptions} options + */ + delete(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to an array of Cache keys. + * + * @param request The Request want to return, if a specific key is desired. + * @param {CacheOptions} options + */ + keys(request?: Request, options?: CacheOptions): Promise>; +} + +/** + * Represents the storage for Cache objects. It provides a master directory of + * all the named caches that a ServiceWorker can access and maintains a mapping + * of string names to corresponding Cache objects. + */ +interface CacheStorage { + /** + * Checks if a given Request is a key in any of the Cache objects that the + * CacheStorage object tracks and returns a Promise that resolves + * to that match. + * + * @param request The Request you are looking for a match for in the CacheStorage. + * @param {CacheOptions} options + */ + match(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to true if a Cache object matching + * the cacheName exists. + * + * @param cacheName The Request you are looking for a match for in the + * CacheStorage. + */ + has(cacheName: string): Promise; + + /** + * Returns a Promise that resolves to the Cache object matching + * the cacheName. + * + * @param cacheName The name of the cache you want to open. + */ + open(cacheName: string): Promise; + + /** + * Finds the Cache object matching the cacheName, and if found, deletes the + * Cache object and returns a Promise that resolves to true. If no + * Cache object is found, it returns false. + * + * @param cacheName The name of the cache you want to delete. + */ + delete(cacheName: string): Promise; + + /** + * Returns a Promise that will resolve with an array containing strings + * corresponding to all of the named Cache objects tracked by the + * CacheStorage. Use this method to iterate over a list of all the + * Cache objects. + */ + keys(): Promise>; +} + +/** + * Represents the scope of a service worker client. A service worker client is + * either a document in a browser context or a SharedWorker, which is controlled + * by an active worker. + */ +interface ServiceWorkerClient { + /** + * Allows a service worker client to send a message to a ServiceWorker. + * + * @param message The message to send to the service worker. + * @param [transfer] A transferable object such as, for example, a reference + * to a port. + */ + postMessage(message: string, transfer?: Object): void; + + /** + * Indicates the type of browsing context of the current client. + * This value can be one of auxiliary, top-level, nested, or none. + * @readonly + */ + frameType: string; + + /** + * Returns the id of the Client object. + * @readonly + */ + id: string; + + /** + * The URL of the current service worker client. + * @readonly + */ + url: string; +} + +interface WindowClient extends ServiceWorkerClient { + /** + * Gives user input focus to the current client. + */ + focus(): Promise; + + /** + * A boolean that indicates whether the current client has focus. + * @readonly + */ + focused: boolean; + + /** + * Indicates the visibility of the current client. This value can be one of + * hidden, visible, prerender, or unloaded. + * @readonly + */ + visibilityState: string; +} + +interface ServiceWorkerClientsMatchOptions { + includeUncontrolled?: boolean; + type?: string; +} + +/** + * Represents a container for a list of Client objects; the main way to access + * the active service worker clients at the current origin. + */ +interface ServiceWorkerClients { + /** + * Gets a list of service worker clients and returns them in a Promise. + * Include the options parameter to return all service worker clients whose + * origin is the same as the associated service worker's origin. If options + * are not included, the method returns only the service worker clients + * controlled by the service worker. + * + * @param options + */ + matchAll(options: ServiceWorkerClientsMatchOptions): Promise>; + + /** + * Opens a service worker Client in a new browser window. + * + * @param url A string representing the URL of the client you want to open + * in the window. + */ + openWindow(url: string): Promise; + + /** + * Allows an active Service Worker to set itself as the active worker for a + * client page when the worker and the page are in the same scope. + */ + claim(): Promise; +} + +/** + * Extends the lifetime of the install and activate events dispatched on the + * ServiceWorkerGlobalScope as part of the service worker lifecycle. This + * ensures that any functional events (like FetchEvent) are not dispatched to + * the ServiceWorker until it upgrades database schemas, deletes outdated cache + * entries, etc. + */ +interface ExtendableEvent extends Event { + /** + * Extends the lifetime of the event. + * It is intended to be called in the install EventHandler for the + * installing worker and on the active EventHandler for the active worker. + * + * @param all + */ + waitUntil(all: any): any; +} + +/** + * The parameter passed into the ServiceWorkerGlobalScope.onfetch handler, + * FetchEvent represents a fetch action that is dispatched on the + * ServiceWorkerGlobalScope of a ServiceWorker. It contains information about + * the request and resulting response, and provides the FetchEvent.respondWith() + * method, which allows us to provide an arbitrary response back to the + * controlled page. + */ +interface FetchEvent extends Event { + /** + * Returns a Boolean that is true if the event was dispatched with the + * user's intention for the page to reload, and false otherwise. Typically, + * pressing the refresh button in a browser is a reload, while clicking a + * link and pressing the back button is not. + * @readonly + */ + isReload: boolean; + + /** + * Returns the Request that triggered the event handler. + * @readonly + */ + request: Request; + + /** + * Returns the Client that the current service worker is controlling. + * @readonly + */ + client: ServiceWorkerClient; + + /** + * Resolves by returning a Response or a network error to Fetch. + * + * @param any + */ + respondWith(any): Response; +} + +/** + * Represents a service worker. Multiple browsing contexts (e.g. pages, workers, + * etc.) can be associated with the same ServiceWorker object. + */ +interface ServiceWorker extends Worker { + /** + * Returns the ServiceWorker serialized script URL defined as part of + * ServiceWorkerRegistration. The URL must be on the same origin as the + * document that registers the ServiceWorker. + * @readonly + */ + scriptURL: string; + + /** + * Returns the state of the service worker. It returns one of the following + * values: installing, installed, activating, activated, or redundant. + * @readonly + */ + state: string; + + /** + * An EventListener property called whenever an event of type statechange + * is fired; it is basically fired anytime the ServiceWorker.state changes. + * + * @param [statechangeevent] + */ + onstatechange: (statechangeevent?: Event) => void; +} + +/** + * The PushSubscription interface provides a subcription's URL endpoint and + * subscription ID. + */ +interface PushSubscription { + /** + * The endpoint associated with the push subscription. + * @readonly + */ + endpoint: any; + + /** + * The subscription ID associated with the push subscription. + * @readonly + */ + subscriptionId: any; +} + +/** + * The PushManager interface provides a way to receive notifications from + * third-party servers as well as request URLs for push notifications. + * This interface has replaced functionality offered by the obsolete + * PushRegistrationManager. + */ +interface PushManager { + /** + * Returns a promise that resolves to a PushSubscription with details of a + * new push subscription. + */ + subscribe(): Promise; + + /** + * Returns a promise that resolves to a PushSubscription details of + * the retrieved push subscription. + */ + getSubscription(): Promise; + + /** + * Returns a promise that resolves to the PushPermissionStatus of the + * requesting webapp, which will be one of granted, denied, or default. + */ + hasPermission(): Promise; +} + +/** + * Represents a service worker registration. + */ +interface ServiceWorkerRegistration extends EventTarget { + /** + * Returns a unique identifier for a service worker registration. + * This must be on the same origin as the document that registers + * the ServiceWorker. + * @readonly + */ + scope: any; + + /** + * Returns a service worker whose state is installing. This is initially + * set to null. + * @readonly + */ + installing: ServiceWorker; + + /** + * Returns a service worker whose state is installed. This is initially + * set to null. + * @readonly + */ + waiting: ServiceWorker; + + /** + * Returns a service worker whose state is either activating or activated. + * This is initially set to null. An active worker will control a + * ServiceWorkerClient if the client's URL falls within the scope of the + * registration (the scope option set when ServiceWorkerContainer.register + * is first called). + * @readonly + */ + active: ServiceWorker; + + /** + * Returns an interface to for managing push subscriptions, including + * subcribing, getting an anctive subscription, and accessing push + * permission status. + * @readonly + */ + pushManager: PushManager; + + /** + * An EventListener property called whenever an event of type updatefound + * is fired; it is fired any time the ServiceWorkerRegistration.installing + * property acquires a new service worker. + */ + onupdatefound: () => void; + + /** + * Allows you to update a service worker. + */ + update(); + + /** + * Unregisters the service worker registration and returns a promise + * (see Promise). The service worker will finish any ongoing operations + * before it is unregistered. + */ + unregister(): Promise; +} + +interface ServiceWorkerRegisterOptions { + scope: string; +} + +/** + * Provides an object representing the service worker as an overall unit in the + * network ecosystem, including facilities to register, unregister and update + * service workers, and access the state of service workers + * and their registrations. + */ +interface ServiceWorkerContainer { + /** + * Returns a ServiceWorker object if its state is activated (the same object + * returned by ServiceWorkerRegistration.active). This property returns null + * if the request is a force refresh (Shift + refresh) or if there is no + * active worker. + * @readonly + */ + controller: ServiceWorker; + + /** + * Defines whether a service worker is ready to control a page or not. + * It returns a Promise that will never reject, which resolves to a + * ServiceWorkerRegistration with an ServiceWorkerRegistration.active worker. + * @readonly + */ + ready: Promise; + + /** + * An event handler fired whenever a controllerchange event occurs — when + * the document's associated ServiceWorkerRegistration acquires a new + * ServiceWorkerRegistration.active worker. + * + * @param [controllerchangeevent] + */ + oncontrollerchange: (controllerchangeevent?: Event) => void; + + /** + * An event handler fired whenever an error event occurs in the associated + * service workers. + * + * @param [errorevent] + */ + onerror: (errorevent?: ErrorEvent) => void; + + /** + * An event handler fired whenever a message event occurs — when incoming + * messages are received to the ServiceWorkerContainer object (e.g. via a + * MessagePort.postMessage() call.) + * + * @param [messageevent] + */ + onmessage: (messageevent?: MessageEvent) => void; + + /** + * Creates or updates a ServiceWorkerRegistration for the given scriptURL. + * + * @param scriptURL The URL of the service worker script. + * @param [options] An options object to provide options upon registration. + * Currently available options are: scope: A USVString representing a URL + * that defines a service worker's registration scope; what range of URLs a + * service worker can control. This is usually a relative URL, and it + * defaults to '/' when not specified. + */ + register(scriptURL: string, options?: ServiceWorkerRegisterOptions): Promise; + + /** + * Gets a ServiceWorkerRegistration object whose scope URL matches the + * provided document URL. If the method can't return a + * ServiceWorkerRegistration, it returns a Promise. + * + * @param [scope] A unique identifier for a service worker registration — the + * scope URL of the registration object you want to return. This is usually + * a relative URL. + */ + getRegistration(scope?: string): Promise; + + /** + * Returns all ServiceWorkerRegistrations associated with a + * ServiceWorkerContainer in an array. If the method can't return + * ServiceWorkerRegistrations, it returns a Promise. + */ + getRegistrations(): Promise>; +} + +/** + * The parameter passed into the oninstall handler, the InstallEvent interface + * represents an install action that is dispatched on the + * ServiceWorkerGlobalScope of a ServiceWorker. As a child of ExtendableEvent, + * it ensures that functional events such as FetchEvent are not dispatched + * during installation. + */ +interface InstallEvent extends ExtendableEvent { + /** + * Returns the ServiceWorker that is currently actively controlling the page. + * @readonly + */ + activeWorker: ServiceWorker; +} + +interface ServiceWorkerGlobalScope { + /** + * Contains the Clients object associated with the service worker. + * @readonly + */ + clients: ServiceWorkerClients; + + /** + * Contains the ServiceWorkerRegistration object that represents the + * service worker's registration. + * @readonly + */ + registration: ServiceWorkerRegistration; + + /** + * An event handler fired whenever an activate event occurs — when a + * ServiceWorkerRegistration acquires a new ServiceWorkerRegistration.active + * worker. + * + * @param [activateevent] + */ + onactivate: (activateevent?: ExtendableEvent) => void; + + /** + * Not defined in the spec yet, but it looks like this will be fired when + * the device is nearly out of storage space, prompting the UA to start + * claiming back some space from web apps that are using client-side storage, + * and the current app is targeted. + * + * @param [beforeevictedevent] + */ + onbeforeevicted: (beforeevictedevent?: Event) => void; + + /** + * Not defined in the spec yet, but it looks like this will be fired when + * the device is out of storage space, and the UA claims back some space + * from the current app. + * + * @param [evictedevent] + */ + onevicted: (evictedevent?: Event) => void; + + /** + * An event handler fired whenever a fetch event occurs — when a fetch() + * is called. + * + * @param [fetchevent] + */ + onfetch: (fetchevent?: FetchEvent) => void; + + /** + * An event handler fired whenever an install event occurs — when a + * ServiceWorkerRegistration acquires a new + * ServiceWorkerRegistration.installing worker. + * + * @param [installevent] + */ + oninstall: (installevent?: InstallEvent) => void; + + /** + * An event handler fired whenever a message event occurs — when incoming + * messages are received. Controlled pages can use the + * MessagePort.postMessage() method to send messages to service workers. + * The service worker can optionally send a response back via the + * MessagePort exposed in event.data.port, corresponding to the controlled + * page. + * + * @param [messageevent] + */ + onmessage: (messageevent?: MessageEvent) => void; + + /** + * An event handler fired whenever a notificationclick event occurs — when + * a user clicks on a displayed notification. + * + * @param [notificationclickevent] + */ + onnotificationclick: (notificationclickevent?: NotificationEvent) => void; + + /** + * An event handler fired whenever a push event occurs — when a server + * push notification is received. + * + * @param [onpushevent] + */ + onpush: (onpushevent?: Event) => void; + + /** + * An event handler fired whenever a pushsubscriptionchange event occurs — + * when a push subscription has been invalidated, or is about to be + * invalidated (e.g. when a push service sets an expiration time). + * + * @param [pushsubscriptionchangeevent] + */ + onpushsubscriptionchange: (pushsubscriptionchangeevent?: Event) => void; + + /** + * Allows the current service worker registration to progress from waiting + * to active state while service worker clients are using it. + */ + skipWaiting(): Promise; + + /** + * TODO GlobalFetch + * @param url + * @param init + */ + fetch(url: string | Request, init?: Object): Promise; +} + +interface Navigator { + /** + * Returns a ServiceWorkerContainer object, which provides access to + * registration, removal, upgrade, and communication with the ServiceWorker + * objects for the associated document. + */ + serviceWorker: ServiceWorkerContainer; +} + +interface Window extends ServiceWorkerGlobalScope { + caches: CacheStorage; +} + +interface NotificationEvent extends Event, ExtendableEvent { + notification: any; +} \ No newline at end of file From 8164f9d8b9123bf8c71f555276ef826d7a0a9d37 Mon Sep 17 00:00:00 2001 From: tristancaron Date: Mon, 23 Mar 2015 20:25:42 +0100 Subject: [PATCH 2/5] Revert "Service Worker Api" This reverts commit 80fd9daed79eb612c3c323fa25e1eb01062d56f4. --- service_worker_api/service_worker_api-test.ts | 188 ---- service_worker_api/service_worker_api.d.ts | 896 ------------------ 2 files changed, 1084 deletions(-) delete mode 100644 service_worker_api/service_worker_api-test.ts delete mode 100644 service_worker_api/service_worker_api.d.ts diff --git a/service_worker_api/service_worker_api-test.ts b/service_worker_api/service_worker_api-test.ts deleted file mode 100644 index 67ce58cd40..0000000000 --- a/service_worker_api/service_worker_api-test.ts +++ /dev/null @@ -1,188 +0,0 @@ -/// - -var OFFLINE_CACHE = "cache_test"; -var OFFLINE_URL = "localhost"; - -self.addEventListener('fetch', function(event: FetchEvent) { - if (event.request.method === 'GET' && - event.request.headers.get('accept').indexOf('text/html') !== -1) { - console.log('Handling fetch event for', event.request.url); - event.respondWith( - self.fetch(event.request).catch(function(e) { - console.error('Fetch failed; returning offline page instead.', e); - return self.caches.open(OFFLINE_CACHE).then(function(cache: Cache) { - return cache.match(OFFLINE_URL); - }); - }) - ); - } -}); - -self.caches.open('v1').then(function(cache: Cache) { - cache.matchAll('/images/').then(function(response: Array) { - response.forEach(function(element, index, array) { - cache.delete(element); - - }); - }); - -}); - -self.addEventListener('install', function(event: InstallEvent) { - event.waitUntil( - self.caches.open('v1').then(function(cache: Cache) { - return cache.add('/sw-test/index.html'); - }) - ); -}); - -self.addEventListener('install', function(event: InstallEvent) { - event.waitUntil( - self.caches.open('v1').then(function(cache) { - return cache.addAll( - '/sw-test/', - '/sw-test/index.html', - '/sw-test/style.css', - '/sw-test/app.js', - '/sw-test/image-list.js', - '/sw-test/star-wars-logo.jpg', - '/sw-test/gallery/', - '/sw-test/gallery/bountyHunters.jpg', - '/sw-test/gallery/myLittleVader.jpg', - '/sw-test/gallery/snowTroopers.jpg' - ); - }) - ); -}); - -self.addEventListener('fetch', function(event: FetchEvent) { - var cachedResponse = self.caches.match(event.request).catch(function() { - return self.fetch(event.request).then(function(response: Response) { - return self.caches.open('v1').then(function(cache) { - cache.put(event.request, response.clone()); - return response; - }); - }); - }).catch(function() { - return self.caches.match('/sw-test/gallery/myLittleVader.jpg'); - }); - - event.respondWith(cachedResponse); -}); - -self.caches.open('v1').then(function(cache) { - cache.match('/images/image.png').then(function(response) { - cache.delete(response); - }); -}); - -self.caches.open('v1').then(function(cache: Cache) { - cache.keys().then(function(response) { - response.forEach(function(element, index, array) { - cache.delete(element); - }); - }); -}); - -self.caches.has('v1').then(function() { - self.caches.delete('v1').then(function() { - - }); -}); - -self.addEventListener('activate', function(event: ExtendableEvent) { - var cacheWhitelist = ['v2']; - - event.waitUntil( - self.caches.keys().then(function(keyList) { - for(var i = 0; i < keyList.length; i++) { - if (cacheWhitelist.indexOf(keyList[i]) === -1) { - return self.caches.delete(keyList[i]); - } - } - }) - ); -}); - -function sendMessage(message) { - return new Promise(function(resolve, reject) { - var messageChannel = new MessageChannel(); - messageChannel.port1.onmessage = function(event) { - if (event.data.error) { - reject(event.data.error); - } else { - resolve(event.data); - } - }; - navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]); - }); -} - -self.clients.matchAll({type: "test"}).then(function(clients) { - for(var i = 0 ; i < clients.length ; i++) { - if(clients[i].url === 'index.html') { - self.clients.openWindow(clients[i].url); - // or do something else involving the matching client - } - } -}); - -self.addEventListener('activate', function(e: ExtendableEvent) { - e.waitUntil(self.clients.claim()); -}); - -navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(function(registration) { - // At this point, registration has taken place. - // The service worker will not handle requests until this page and any - // other instances of this page (in other tabs, etc.) have been - // closed/reloaded. - var serviceWorker; - if (registration.installing) { - serviceWorker = registration.installing; - } else if (registration.waiting) { - serviceWorker = registration.waiting; - } else if (registration.active) { - serviceWorker = registration.active; - } - if (serviceWorker) { - console.log(serviceWorker.state); - serviceWorker.addEventListener('statechange', function(e) { - console.log(e.target.state); - }); - } -}).catch(function(error) { - // Something went wrong during registration. The service-worker.js file - // might be unavailable or contain a syntax error. - -}); - -navigator.serviceWorker.getRegistration('/app').then(function(registration: ServiceWorkerRegistration) { - -}); - -navigator.serviceWorker.getRegistrations().then(function(registrations: Array) { - -}); - -self.registration.unregister(); - -self.addEventListener('install', function(event: ExtendableEvent) { - event.waitUntil(self.skipWaiting()); -}); - -self.addEventListener('notificationclick', function(event: NotificationEvent) { - console.log('On notification click: ', event.notification.tag); - event.notification.close(); - - // This looks to see if the current is already open and - // focuses if it is - event.waitUntil(self.clients.matchAll({ - type: "window" - }).then(function(clientList) { - for (var i = 0; i < clientList.length; i++) { - var client = clientList[i]; - } - if (self.clients.openWindow) - return self.clients.openWindow('/'); - })); -}); \ No newline at end of file diff --git a/service_worker_api/service_worker_api.d.ts b/service_worker_api/service_worker_api.d.ts deleted file mode 100644 index f9b2981463..0000000000 --- a/service_worker_api/service_worker_api.d.ts +++ /dev/null @@ -1,896 +0,0 @@ -// Type definitions for service_worker_api -// Project: https://developer.mozilla.org/fr/docs/Web/API/ServiceWorker_API -// Definitions by: Tristan Caron -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -/// - -/** - * Provides methods relating to the body of the response/request, allowing you - * to declare what its content type is and how it should be handled. - */ -interface Body { - /** - * Contains a Boolean that indicates whether the body has been read. - * @readonly - */ - bodyUsed: boolean; - - /** - * Takes a Response stream and reads it to completion. - * It returns a promise that resolves with an ArrayBuffer. - */ - arrayBuffer(): Promise; - - /** - * Takes a Response stream and reads it to completion. - * It returns a promise that resolves with a Blob. - */ - blob(): Promise; - - /** - * Takes a Response stream and reads it to completion. - * It returns a promise that resolves with a FormData object. - */ - formData(): Promise; - - /** - * Takes a Response stream and reads it to completion. - * It returns a promise that resolves with a JSON object. - */ - json(): Promise; - - /** - * Takes a Response stream and reads it to completion. - * It returns a promise that resolves with a USVString (text). - */ - text(): Promise; - -} - -/** - * Represents response/request headers, allowing you to query them and take - * different actions depending on the results. - */ -interface Header { - new(): Header; - - /** - * Appends a new value onto an existing header inside a Headers object, or - * adds the header if it does not already exist. - * - * @param name The name of the HTTP header you want to add to the Headers - * object. - * @param value The value of the HTTP header you want to add. - */ - append(name: string, value: string): void; - - /** - * Deletes a header from a Headers object. - * - * @param name The name of the HTTP header you want to delete from the - * Headers object. - */ - delete(name: string): void; - - /** - * Returns the first value of a given header from within a Headers object. - * - * @param name The name of the HTTP header whose value you want to retrieve - * from the Headers object. If the given name is not the name of an - * HTTP header, this method throws a TypeError. - */ - get(name: string): string; - - /** - * Returns an array of all the values of a header within a Headers object - * with a given name. - * - * @param name The name of the HTTP header whose values you want to retrieve - * from the Headers object. If the given name is not the name of an - * HTTP header, this method throws a TypeError. - */ - getAll(name:string): Array; - - /** - * Returns a boolean stating whether a Headers object contains a - * certain header. - * - * @param name The name of the HTTP header you want to test for. If the - * given name is not the name of an HTTP header, this method throws - * a TypeError. - */ - has(name: string): boolean; - - /** - * Sets a new value for an existing header inside a Headers object, or - * adds the header if it does not already exist. - * - * @param name The name of the HTTP header you want to set to a new value. - * If the given name is not the name of an HTTP header, this method throws - * a TypeError. - * @param value The new value you want to set. - */ - set(name: string, value: string): void; -} - -/** - * Represents the response to a request. - */ -interface Response extends Body { - new(): Response; - - /** - * Contains the type of the response (e.g., basic, cors). - * @readonly - */ - type: string; - - /** - * Contains the URL of the response. - * @readonly - */ - url: string; - - /** - * Contains a boolean stating whether this is the final URL of the response. - */ - useFinalURL: boolean; - - /** - * Contains the status code of the response (e.g., 200 for a success). - * @readonly - */ - status: number; - - /** - * Contains a boolean stating whether the response was successful - * (status in the range 200-299) or not. - * @readonly - */ - ok: boolean; - - /** - * Contains the status message corresponding to the status code - * (e.g., OK for 200). - * @readonly - */ - statusText: string; - - /** - * Contains the Headers object associated with the response. - * @readonly - */ - headers: Header; - - /** - * Creates a clone of a Response object. - */ - clone(): Response; - - /** - * Returns a new Response object associated with a network error. - */ - error(): Response; - - /** - * Creates a new response with a different URL. - */ - redirect(): Response; -} - -/** - * Represents a resource request. - */ -interface Request extends Body { - new(): Request; - - /** - * Contains the request's method (GET, POST, etc.). - * @readonly - */ - method: string; - - /** - * Contains the URL of the request. - * @readonly - */ - url: string; - - /** - * Contains the associated Headers object of the request. - * @readonly - */ - headers: Header; - - /** - * Contains the context of the request (e.g., audio, image, iframe, etc.). - * @readonly - */ - context: string; - - /** - * Contains the referrer of the request (e.g., client). - * @readonly - */ - referrer: string; - - /** - * Contains the mode of the request (e.g., cors, no-cors, same-origin). - * @readonly - */ - mode: string; - - /** - * Contains the credentials of the request (e.g., omit, same-origin). - * @readonly - */ - credentials: string; - - /** - * Contains the cache mode of the request (e.g., default, reload, no-cache). - * @readonly - */ - cache: string; - - /** - * Creates a copy of the current Request object. - */ - clone(): Request; -} - -/** - * An CacheOptions object allowing you to set specific control options for the - * matching done in the match operation. - * - * @property [ignoreSearch] A Boolean that specifies whether the matching - * process should ignore the query string in the url. If set to true, - * the ?value=bar part of http://foo.com/?value=bar would be ignored when - * performing a match. It defaults to false. - * - * @property [ignoreMethod] A Boolean that, when set to true, prevents matching - * operations from validating the Request http method (normally only GET - * and HEAD are allowed.) It defaults to false. - * - * @property [ignoreVary] A Boolean that when set to true tells the matching - * operation not to perform VARY header matching — i.e. if the URL matches you - * will get a match regardless of the Response object having a VARY header or - * not. It defaults to false. - * - * @property [cacheName] A DOMString that represents a specific cache to search - * within. Note that this option is ignored by Cache.match(). - */ -interface CacheOptions { - ignoreSearch?: boolean; - ignoreMethod?: boolean; - ignoreVary?: boolean; - cacheName?: string; -} - -/** - * Represents the storage for Request / Response object pairs that are cached as - * part of the ServiceWorker life cycle. - */ -interface Cache { - /** - * Returns a Promise that resolves to the response associated with the first - * matching request in the Cache object. - * - * @param request The Request you are attempting to find in the Cache. - * @param {CacheOptions} options - */ - match(request: Request | string, options?: CacheOptions): Promise; - - /** - * Returns a Promise that resolves to an array of all matching requests in - * the Cache object. - * - * @param request The Request you are attempting to find in the Cache. - * @param {CacheOptions} options - */ - matchAll(request: Request | string, options?: CacheOptions): Promise>; - - /** - * Returns a Promise that resolves to a new Cache entry whose key - * is the request. - * - * @param request The Request you want to add to the cache. - */ - add(request: Request | string): Promise; - - /** - * Returns a Promise that resolves to a new array of Cache entries whose - * keys are the requests. - * - * @param request An array of Request objects you want to add to the cache. - */ - addAll(...request: Array): Promise; - - /** - * Adds additional key/value pairs to the current Cache object. - * - * @param request The Request you want to add to the cache. - * @param response The response you want to match up to the request. - */ - put(request: Request, response: Response): Promise; - - /** - * Finds the Cache entry whose key is the request, and if found, deletes the - * Cache entry and returns a Promise that resolves to true. If no Cache - * entry is found, it returns false. - * - * @param request The Request you are looking to delete. - * @param {CacheOptions} options - */ - delete(request: Request | string, options?: CacheOptions): Promise; - - /** - * Returns a Promise that resolves to an array of Cache keys. - * - * @param request The Request want to return, if a specific key is desired. - * @param {CacheOptions} options - */ - keys(request?: Request, options?: CacheOptions): Promise>; -} - -/** - * Represents the storage for Cache objects. It provides a master directory of - * all the named caches that a ServiceWorker can access and maintains a mapping - * of string names to corresponding Cache objects. - */ -interface CacheStorage { - /** - * Checks if a given Request is a key in any of the Cache objects that the - * CacheStorage object tracks and returns a Promise that resolves - * to that match. - * - * @param request The Request you are looking for a match for in the CacheStorage. - * @param {CacheOptions} options - */ - match(request: Request | string, options?: CacheOptions): Promise; - - /** - * Returns a Promise that resolves to true if a Cache object matching - * the cacheName exists. - * - * @param cacheName The Request you are looking for a match for in the - * CacheStorage. - */ - has(cacheName: string): Promise; - - /** - * Returns a Promise that resolves to the Cache object matching - * the cacheName. - * - * @param cacheName The name of the cache you want to open. - */ - open(cacheName: string): Promise; - - /** - * Finds the Cache object matching the cacheName, and if found, deletes the - * Cache object and returns a Promise that resolves to true. If no - * Cache object is found, it returns false. - * - * @param cacheName The name of the cache you want to delete. - */ - delete(cacheName: string): Promise; - - /** - * Returns a Promise that will resolve with an array containing strings - * corresponding to all of the named Cache objects tracked by the - * CacheStorage. Use this method to iterate over a list of all the - * Cache objects. - */ - keys(): Promise>; -} - -/** - * Represents the scope of a service worker client. A service worker client is - * either a document in a browser context or a SharedWorker, which is controlled - * by an active worker. - */ -interface ServiceWorkerClient { - /** - * Allows a service worker client to send a message to a ServiceWorker. - * - * @param message The message to send to the service worker. - * @param [transfer] A transferable object such as, for example, a reference - * to a port. - */ - postMessage(message: string, transfer?: Object): void; - - /** - * Indicates the type of browsing context of the current client. - * This value can be one of auxiliary, top-level, nested, or none. - * @readonly - */ - frameType: string; - - /** - * Returns the id of the Client object. - * @readonly - */ - id: string; - - /** - * The URL of the current service worker client. - * @readonly - */ - url: string; -} - -interface WindowClient extends ServiceWorkerClient { - /** - * Gives user input focus to the current client. - */ - focus(): Promise; - - /** - * A boolean that indicates whether the current client has focus. - * @readonly - */ - focused: boolean; - - /** - * Indicates the visibility of the current client. This value can be one of - * hidden, visible, prerender, or unloaded. - * @readonly - */ - visibilityState: string; -} - -interface ServiceWorkerClientsMatchOptions { - includeUncontrolled?: boolean; - type?: string; -} - -/** - * Represents a container for a list of Client objects; the main way to access - * the active service worker clients at the current origin. - */ -interface ServiceWorkerClients { - /** - * Gets a list of service worker clients and returns them in a Promise. - * Include the options parameter to return all service worker clients whose - * origin is the same as the associated service worker's origin. If options - * are not included, the method returns only the service worker clients - * controlled by the service worker. - * - * @param options - */ - matchAll(options: ServiceWorkerClientsMatchOptions): Promise>; - - /** - * Opens a service worker Client in a new browser window. - * - * @param url A string representing the URL of the client you want to open - * in the window. - */ - openWindow(url: string): Promise; - - /** - * Allows an active Service Worker to set itself as the active worker for a - * client page when the worker and the page are in the same scope. - */ - claim(): Promise; -} - -/** - * Extends the lifetime of the install and activate events dispatched on the - * ServiceWorkerGlobalScope as part of the service worker lifecycle. This - * ensures that any functional events (like FetchEvent) are not dispatched to - * the ServiceWorker until it upgrades database schemas, deletes outdated cache - * entries, etc. - */ -interface ExtendableEvent extends Event { - /** - * Extends the lifetime of the event. - * It is intended to be called in the install EventHandler for the - * installing worker and on the active EventHandler for the active worker. - * - * @param all - */ - waitUntil(all: any): any; -} - -/** - * The parameter passed into the ServiceWorkerGlobalScope.onfetch handler, - * FetchEvent represents a fetch action that is dispatched on the - * ServiceWorkerGlobalScope of a ServiceWorker. It contains information about - * the request and resulting response, and provides the FetchEvent.respondWith() - * method, which allows us to provide an arbitrary response back to the - * controlled page. - */ -interface FetchEvent extends Event { - /** - * Returns a Boolean that is true if the event was dispatched with the - * user's intention for the page to reload, and false otherwise. Typically, - * pressing the refresh button in a browser is a reload, while clicking a - * link and pressing the back button is not. - * @readonly - */ - isReload: boolean; - - /** - * Returns the Request that triggered the event handler. - * @readonly - */ - request: Request; - - /** - * Returns the Client that the current service worker is controlling. - * @readonly - */ - client: ServiceWorkerClient; - - /** - * Resolves by returning a Response or a network error to Fetch. - * - * @param any - */ - respondWith(any): Response; -} - -/** - * Represents a service worker. Multiple browsing contexts (e.g. pages, workers, - * etc.) can be associated with the same ServiceWorker object. - */ -interface ServiceWorker extends Worker { - /** - * Returns the ServiceWorker serialized script URL defined as part of - * ServiceWorkerRegistration. The URL must be on the same origin as the - * document that registers the ServiceWorker. - * @readonly - */ - scriptURL: string; - - /** - * Returns the state of the service worker. It returns one of the following - * values: installing, installed, activating, activated, or redundant. - * @readonly - */ - state: string; - - /** - * An EventListener property called whenever an event of type statechange - * is fired; it is basically fired anytime the ServiceWorker.state changes. - * - * @param [statechangeevent] - */ - onstatechange: (statechangeevent?: Event) => void; -} - -/** - * The PushSubscription interface provides a subcription's URL endpoint and - * subscription ID. - */ -interface PushSubscription { - /** - * The endpoint associated with the push subscription. - * @readonly - */ - endpoint: any; - - /** - * The subscription ID associated with the push subscription. - * @readonly - */ - subscriptionId: any; -} - -/** - * The PushManager interface provides a way to receive notifications from - * third-party servers as well as request URLs for push notifications. - * This interface has replaced functionality offered by the obsolete - * PushRegistrationManager. - */ -interface PushManager { - /** - * Returns a promise that resolves to a PushSubscription with details of a - * new push subscription. - */ - subscribe(): Promise; - - /** - * Returns a promise that resolves to a PushSubscription details of - * the retrieved push subscription. - */ - getSubscription(): Promise; - - /** - * Returns a promise that resolves to the PushPermissionStatus of the - * requesting webapp, which will be one of granted, denied, or default. - */ - hasPermission(): Promise; -} - -/** - * Represents a service worker registration. - */ -interface ServiceWorkerRegistration extends EventTarget { - /** - * Returns a unique identifier for a service worker registration. - * This must be on the same origin as the document that registers - * the ServiceWorker. - * @readonly - */ - scope: any; - - /** - * Returns a service worker whose state is installing. This is initially - * set to null. - * @readonly - */ - installing: ServiceWorker; - - /** - * Returns a service worker whose state is installed. This is initially - * set to null. - * @readonly - */ - waiting: ServiceWorker; - - /** - * Returns a service worker whose state is either activating or activated. - * This is initially set to null. An active worker will control a - * ServiceWorkerClient if the client's URL falls within the scope of the - * registration (the scope option set when ServiceWorkerContainer.register - * is first called). - * @readonly - */ - active: ServiceWorker; - - /** - * Returns an interface to for managing push subscriptions, including - * subcribing, getting an anctive subscription, and accessing push - * permission status. - * @readonly - */ - pushManager: PushManager; - - /** - * An EventListener property called whenever an event of type updatefound - * is fired; it is fired any time the ServiceWorkerRegistration.installing - * property acquires a new service worker. - */ - onupdatefound: () => void; - - /** - * Allows you to update a service worker. - */ - update(); - - /** - * Unregisters the service worker registration and returns a promise - * (see Promise). The service worker will finish any ongoing operations - * before it is unregistered. - */ - unregister(): Promise; -} - -interface ServiceWorkerRegisterOptions { - scope: string; -} - -/** - * Provides an object representing the service worker as an overall unit in the - * network ecosystem, including facilities to register, unregister and update - * service workers, and access the state of service workers - * and their registrations. - */ -interface ServiceWorkerContainer { - /** - * Returns a ServiceWorker object if its state is activated (the same object - * returned by ServiceWorkerRegistration.active). This property returns null - * if the request is a force refresh (Shift + refresh) or if there is no - * active worker. - * @readonly - */ - controller: ServiceWorker; - - /** - * Defines whether a service worker is ready to control a page or not. - * It returns a Promise that will never reject, which resolves to a - * ServiceWorkerRegistration with an ServiceWorkerRegistration.active worker. - * @readonly - */ - ready: Promise; - - /** - * An event handler fired whenever a controllerchange event occurs — when - * the document's associated ServiceWorkerRegistration acquires a new - * ServiceWorkerRegistration.active worker. - * - * @param [controllerchangeevent] - */ - oncontrollerchange: (controllerchangeevent?: Event) => void; - - /** - * An event handler fired whenever an error event occurs in the associated - * service workers. - * - * @param [errorevent] - */ - onerror: (errorevent?: ErrorEvent) => void; - - /** - * An event handler fired whenever a message event occurs — when incoming - * messages are received to the ServiceWorkerContainer object (e.g. via a - * MessagePort.postMessage() call.) - * - * @param [messageevent] - */ - onmessage: (messageevent?: MessageEvent) => void; - - /** - * Creates or updates a ServiceWorkerRegistration for the given scriptURL. - * - * @param scriptURL The URL of the service worker script. - * @param [options] An options object to provide options upon registration. - * Currently available options are: scope: A USVString representing a URL - * that defines a service worker's registration scope; what range of URLs a - * service worker can control. This is usually a relative URL, and it - * defaults to '/' when not specified. - */ - register(scriptURL: string, options?: ServiceWorkerRegisterOptions): Promise; - - /** - * Gets a ServiceWorkerRegistration object whose scope URL matches the - * provided document URL. If the method can't return a - * ServiceWorkerRegistration, it returns a Promise. - * - * @param [scope] A unique identifier for a service worker registration — the - * scope URL of the registration object you want to return. This is usually - * a relative URL. - */ - getRegistration(scope?: string): Promise; - - /** - * Returns all ServiceWorkerRegistrations associated with a - * ServiceWorkerContainer in an array. If the method can't return - * ServiceWorkerRegistrations, it returns a Promise. - */ - getRegistrations(): Promise>; -} - -/** - * The parameter passed into the oninstall handler, the InstallEvent interface - * represents an install action that is dispatched on the - * ServiceWorkerGlobalScope of a ServiceWorker. As a child of ExtendableEvent, - * it ensures that functional events such as FetchEvent are not dispatched - * during installation. - */ -interface InstallEvent extends ExtendableEvent { - /** - * Returns the ServiceWorker that is currently actively controlling the page. - * @readonly - */ - activeWorker: ServiceWorker; -} - -interface ServiceWorkerGlobalScope { - /** - * Contains the Clients object associated with the service worker. - * @readonly - */ - clients: ServiceWorkerClients; - - /** - * Contains the ServiceWorkerRegistration object that represents the - * service worker's registration. - * @readonly - */ - registration: ServiceWorkerRegistration; - - /** - * An event handler fired whenever an activate event occurs — when a - * ServiceWorkerRegistration acquires a new ServiceWorkerRegistration.active - * worker. - * - * @param [activateevent] - */ - onactivate: (activateevent?: ExtendableEvent) => void; - - /** - * Not defined in the spec yet, but it looks like this will be fired when - * the device is nearly out of storage space, prompting the UA to start - * claiming back some space from web apps that are using client-side storage, - * and the current app is targeted. - * - * @param [beforeevictedevent] - */ - onbeforeevicted: (beforeevictedevent?: Event) => void; - - /** - * Not defined in the spec yet, but it looks like this will be fired when - * the device is out of storage space, and the UA claims back some space - * from the current app. - * - * @param [evictedevent] - */ - onevicted: (evictedevent?: Event) => void; - - /** - * An event handler fired whenever a fetch event occurs — when a fetch() - * is called. - * - * @param [fetchevent] - */ - onfetch: (fetchevent?: FetchEvent) => void; - - /** - * An event handler fired whenever an install event occurs — when a - * ServiceWorkerRegistration acquires a new - * ServiceWorkerRegistration.installing worker. - * - * @param [installevent] - */ - oninstall: (installevent?: InstallEvent) => void; - - /** - * An event handler fired whenever a message event occurs — when incoming - * messages are received. Controlled pages can use the - * MessagePort.postMessage() method to send messages to service workers. - * The service worker can optionally send a response back via the - * MessagePort exposed in event.data.port, corresponding to the controlled - * page. - * - * @param [messageevent] - */ - onmessage: (messageevent?: MessageEvent) => void; - - /** - * An event handler fired whenever a notificationclick event occurs — when - * a user clicks on a displayed notification. - * - * @param [notificationclickevent] - */ - onnotificationclick: (notificationclickevent?: NotificationEvent) => void; - - /** - * An event handler fired whenever a push event occurs — when a server - * push notification is received. - * - * @param [onpushevent] - */ - onpush: (onpushevent?: Event) => void; - - /** - * An event handler fired whenever a pushsubscriptionchange event occurs — - * when a push subscription has been invalidated, or is about to be - * invalidated (e.g. when a push service sets an expiration time). - * - * @param [pushsubscriptionchangeevent] - */ - onpushsubscriptionchange: (pushsubscriptionchangeevent?: Event) => void; - - /** - * Allows the current service worker registration to progress from waiting - * to active state while service worker clients are using it. - */ - skipWaiting(): Promise; - - /** - * TODO GlobalFetch - * @param url - * @param init - */ - fetch(url: string | Request, init?: Object): Promise; -} - -interface Navigator { - /** - * Returns a ServiceWorkerContainer object, which provides access to - * registration, removal, upgrade, and communication with the ServiceWorker - * objects for the associated document. - */ - serviceWorker: ServiceWorkerContainer; -} - -interface Window extends ServiceWorkerGlobalScope { - caches: CacheStorage; -} - -interface NotificationEvent extends Event, ExtendableEvent { - notification: any; -} \ No newline at end of file From 9c55d70b9b91c4a7d95a0993313e9e5e8541890a Mon Sep 17 00:00:00 2001 From: tristancaron Date: Mon, 23 Mar 2015 20:26:39 +0100 Subject: [PATCH 3/5] Revert "Revert "Service Worker Api"" This reverts commit 8164f9d8b9123bf8c71f555276ef826d7a0a9d37. --- service_worker_api/service_worker_api-test.ts | 188 ++++ service_worker_api/service_worker_api.d.ts | 896 ++++++++++++++++++ 2 files changed, 1084 insertions(+) create mode 100644 service_worker_api/service_worker_api-test.ts create mode 100644 service_worker_api/service_worker_api.d.ts diff --git a/service_worker_api/service_worker_api-test.ts b/service_worker_api/service_worker_api-test.ts new file mode 100644 index 0000000000..67ce58cd40 --- /dev/null +++ b/service_worker_api/service_worker_api-test.ts @@ -0,0 +1,188 @@ +/// + +var OFFLINE_CACHE = "cache_test"; +var OFFLINE_URL = "localhost"; + +self.addEventListener('fetch', function(event: FetchEvent) { + if (event.request.method === 'GET' && + event.request.headers.get('accept').indexOf('text/html') !== -1) { + console.log('Handling fetch event for', event.request.url); + event.respondWith( + self.fetch(event.request).catch(function(e) { + console.error('Fetch failed; returning offline page instead.', e); + return self.caches.open(OFFLINE_CACHE).then(function(cache: Cache) { + return cache.match(OFFLINE_URL); + }); + }) + ); + } +}); + +self.caches.open('v1').then(function(cache: Cache) { + cache.matchAll('/images/').then(function(response: Array) { + response.forEach(function(element, index, array) { + cache.delete(element); + + }); + }); + +}); + +self.addEventListener('install', function(event: InstallEvent) { + event.waitUntil( + self.caches.open('v1').then(function(cache: Cache) { + return cache.add('/sw-test/index.html'); + }) + ); +}); + +self.addEventListener('install', function(event: InstallEvent) { + event.waitUntil( + self.caches.open('v1').then(function(cache) { + return cache.addAll( + '/sw-test/', + '/sw-test/index.html', + '/sw-test/style.css', + '/sw-test/app.js', + '/sw-test/image-list.js', + '/sw-test/star-wars-logo.jpg', + '/sw-test/gallery/', + '/sw-test/gallery/bountyHunters.jpg', + '/sw-test/gallery/myLittleVader.jpg', + '/sw-test/gallery/snowTroopers.jpg' + ); + }) + ); +}); + +self.addEventListener('fetch', function(event: FetchEvent) { + var cachedResponse = self.caches.match(event.request).catch(function() { + return self.fetch(event.request).then(function(response: Response) { + return self.caches.open('v1').then(function(cache) { + cache.put(event.request, response.clone()); + return response; + }); + }); + }).catch(function() { + return self.caches.match('/sw-test/gallery/myLittleVader.jpg'); + }); + + event.respondWith(cachedResponse); +}); + +self.caches.open('v1').then(function(cache) { + cache.match('/images/image.png').then(function(response) { + cache.delete(response); + }); +}); + +self.caches.open('v1').then(function(cache: Cache) { + cache.keys().then(function(response) { + response.forEach(function(element, index, array) { + cache.delete(element); + }); + }); +}); + +self.caches.has('v1').then(function() { + self.caches.delete('v1').then(function() { + + }); +}); + +self.addEventListener('activate', function(event: ExtendableEvent) { + var cacheWhitelist = ['v2']; + + event.waitUntil( + self.caches.keys().then(function(keyList) { + for(var i = 0; i < keyList.length; i++) { + if (cacheWhitelist.indexOf(keyList[i]) === -1) { + return self.caches.delete(keyList[i]); + } + } + }) + ); +}); + +function sendMessage(message) { + return new Promise(function(resolve, reject) { + var messageChannel = new MessageChannel(); + messageChannel.port1.onmessage = function(event) { + if (event.data.error) { + reject(event.data.error); + } else { + resolve(event.data); + } + }; + navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]); + }); +} + +self.clients.matchAll({type: "test"}).then(function(clients) { + for(var i = 0 ; i < clients.length ; i++) { + if(clients[i].url === 'index.html') { + self.clients.openWindow(clients[i].url); + // or do something else involving the matching client + } + } +}); + +self.addEventListener('activate', function(e: ExtendableEvent) { + e.waitUntil(self.clients.claim()); +}); + +navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(function(registration) { + // At this point, registration has taken place. + // The service worker will not handle requests until this page and any + // other instances of this page (in other tabs, etc.) have been + // closed/reloaded. + var serviceWorker; + if (registration.installing) { + serviceWorker = registration.installing; + } else if (registration.waiting) { + serviceWorker = registration.waiting; + } else if (registration.active) { + serviceWorker = registration.active; + } + if (serviceWorker) { + console.log(serviceWorker.state); + serviceWorker.addEventListener('statechange', function(e) { + console.log(e.target.state); + }); + } +}).catch(function(error) { + // Something went wrong during registration. The service-worker.js file + // might be unavailable or contain a syntax error. + +}); + +navigator.serviceWorker.getRegistration('/app').then(function(registration: ServiceWorkerRegistration) { + +}); + +navigator.serviceWorker.getRegistrations().then(function(registrations: Array) { + +}); + +self.registration.unregister(); + +self.addEventListener('install', function(event: ExtendableEvent) { + event.waitUntil(self.skipWaiting()); +}); + +self.addEventListener('notificationclick', function(event: NotificationEvent) { + console.log('On notification click: ', event.notification.tag); + event.notification.close(); + + // This looks to see if the current is already open and + // focuses if it is + event.waitUntil(self.clients.matchAll({ + type: "window" + }).then(function(clientList) { + for (var i = 0; i < clientList.length; i++) { + var client = clientList[i]; + } + if (self.clients.openWindow) + return self.clients.openWindow('/'); + })); +}); \ No newline at end of file diff --git a/service_worker_api/service_worker_api.d.ts b/service_worker_api/service_worker_api.d.ts new file mode 100644 index 0000000000..f9b2981463 --- /dev/null +++ b/service_worker_api/service_worker_api.d.ts @@ -0,0 +1,896 @@ +// Type definitions for service_worker_api +// Project: https://developer.mozilla.org/fr/docs/Web/API/ServiceWorker_API +// Definitions by: Tristan Caron +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +/** + * Provides methods relating to the body of the response/request, allowing you + * to declare what its content type is and how it should be handled. + */ +interface Body { + /** + * Contains a Boolean that indicates whether the body has been read. + * @readonly + */ + bodyUsed: boolean; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with an ArrayBuffer. + */ + arrayBuffer(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a Blob. + */ + blob(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a FormData object. + */ + formData(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a JSON object. + */ + json(): Promise; + + /** + * Takes a Response stream and reads it to completion. + * It returns a promise that resolves with a USVString (text). + */ + text(): Promise; + +} + +/** + * Represents response/request headers, allowing you to query them and take + * different actions depending on the results. + */ +interface Header { + new(): Header; + + /** + * Appends a new value onto an existing header inside a Headers object, or + * adds the header if it does not already exist. + * + * @param name The name of the HTTP header you want to add to the Headers + * object. + * @param value The value of the HTTP header you want to add. + */ + append(name: string, value: string): void; + + /** + * Deletes a header from a Headers object. + * + * @param name The name of the HTTP header you want to delete from the + * Headers object. + */ + delete(name: string): void; + + /** + * Returns the first value of a given header from within a Headers object. + * + * @param name The name of the HTTP header whose value you want to retrieve + * from the Headers object. If the given name is not the name of an + * HTTP header, this method throws a TypeError. + */ + get(name: string): string; + + /** + * Returns an array of all the values of a header within a Headers object + * with a given name. + * + * @param name The name of the HTTP header whose values you want to retrieve + * from the Headers object. If the given name is not the name of an + * HTTP header, this method throws a TypeError. + */ + getAll(name:string): Array; + + /** + * Returns a boolean stating whether a Headers object contains a + * certain header. + * + * @param name The name of the HTTP header you want to test for. If the + * given name is not the name of an HTTP header, this method throws + * a TypeError. + */ + has(name: string): boolean; + + /** + * Sets a new value for an existing header inside a Headers object, or + * adds the header if it does not already exist. + * + * @param name The name of the HTTP header you want to set to a new value. + * If the given name is not the name of an HTTP header, this method throws + * a TypeError. + * @param value The new value you want to set. + */ + set(name: string, value: string): void; +} + +/** + * Represents the response to a request. + */ +interface Response extends Body { + new(): Response; + + /** + * Contains the type of the response (e.g., basic, cors). + * @readonly + */ + type: string; + + /** + * Contains the URL of the response. + * @readonly + */ + url: string; + + /** + * Contains a boolean stating whether this is the final URL of the response. + */ + useFinalURL: boolean; + + /** + * Contains the status code of the response (e.g., 200 for a success). + * @readonly + */ + status: number; + + /** + * Contains a boolean stating whether the response was successful + * (status in the range 200-299) or not. + * @readonly + */ + ok: boolean; + + /** + * Contains the status message corresponding to the status code + * (e.g., OK for 200). + * @readonly + */ + statusText: string; + + /** + * Contains the Headers object associated with the response. + * @readonly + */ + headers: Header; + + /** + * Creates a clone of a Response object. + */ + clone(): Response; + + /** + * Returns a new Response object associated with a network error. + */ + error(): Response; + + /** + * Creates a new response with a different URL. + */ + redirect(): Response; +} + +/** + * Represents a resource request. + */ +interface Request extends Body { + new(): Request; + + /** + * Contains the request's method (GET, POST, etc.). + * @readonly + */ + method: string; + + /** + * Contains the URL of the request. + * @readonly + */ + url: string; + + /** + * Contains the associated Headers object of the request. + * @readonly + */ + headers: Header; + + /** + * Contains the context of the request (e.g., audio, image, iframe, etc.). + * @readonly + */ + context: string; + + /** + * Contains the referrer of the request (e.g., client). + * @readonly + */ + referrer: string; + + /** + * Contains the mode of the request (e.g., cors, no-cors, same-origin). + * @readonly + */ + mode: string; + + /** + * Contains the credentials of the request (e.g., omit, same-origin). + * @readonly + */ + credentials: string; + + /** + * Contains the cache mode of the request (e.g., default, reload, no-cache). + * @readonly + */ + cache: string; + + /** + * Creates a copy of the current Request object. + */ + clone(): Request; +} + +/** + * An CacheOptions object allowing you to set specific control options for the + * matching done in the match operation. + * + * @property [ignoreSearch] A Boolean that specifies whether the matching + * process should ignore the query string in the url. If set to true, + * the ?value=bar part of http://foo.com/?value=bar would be ignored when + * performing a match. It defaults to false. + * + * @property [ignoreMethod] A Boolean that, when set to true, prevents matching + * operations from validating the Request http method (normally only GET + * and HEAD are allowed.) It defaults to false. + * + * @property [ignoreVary] A Boolean that when set to true tells the matching + * operation not to perform VARY header matching — i.e. if the URL matches you + * will get a match regardless of the Response object having a VARY header or + * not. It defaults to false. + * + * @property [cacheName] A DOMString that represents a specific cache to search + * within. Note that this option is ignored by Cache.match(). + */ +interface CacheOptions { + ignoreSearch?: boolean; + ignoreMethod?: boolean; + ignoreVary?: boolean; + cacheName?: string; +} + +/** + * Represents the storage for Request / Response object pairs that are cached as + * part of the ServiceWorker life cycle. + */ +interface Cache { + /** + * Returns a Promise that resolves to the response associated with the first + * matching request in the Cache object. + * + * @param request The Request you are attempting to find in the Cache. + * @param {CacheOptions} options + */ + match(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to an array of all matching requests in + * the Cache object. + * + * @param request The Request you are attempting to find in the Cache. + * @param {CacheOptions} options + */ + matchAll(request: Request | string, options?: CacheOptions): Promise>; + + /** + * Returns a Promise that resolves to a new Cache entry whose key + * is the request. + * + * @param request The Request you want to add to the cache. + */ + add(request: Request | string): Promise; + + /** + * Returns a Promise that resolves to a new array of Cache entries whose + * keys are the requests. + * + * @param request An array of Request objects you want to add to the cache. + */ + addAll(...request: Array): Promise; + + /** + * Adds additional key/value pairs to the current Cache object. + * + * @param request The Request you want to add to the cache. + * @param response The response you want to match up to the request. + */ + put(request: Request, response: Response): Promise; + + /** + * Finds the Cache entry whose key is the request, and if found, deletes the + * Cache entry and returns a Promise that resolves to true. If no Cache + * entry is found, it returns false. + * + * @param request The Request you are looking to delete. + * @param {CacheOptions} options + */ + delete(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to an array of Cache keys. + * + * @param request The Request want to return, if a specific key is desired. + * @param {CacheOptions} options + */ + keys(request?: Request, options?: CacheOptions): Promise>; +} + +/** + * Represents the storage for Cache objects. It provides a master directory of + * all the named caches that a ServiceWorker can access and maintains a mapping + * of string names to corresponding Cache objects. + */ +interface CacheStorage { + /** + * Checks if a given Request is a key in any of the Cache objects that the + * CacheStorage object tracks and returns a Promise that resolves + * to that match. + * + * @param request The Request you are looking for a match for in the CacheStorage. + * @param {CacheOptions} options + */ + match(request: Request | string, options?: CacheOptions): Promise; + + /** + * Returns a Promise that resolves to true if a Cache object matching + * the cacheName exists. + * + * @param cacheName The Request you are looking for a match for in the + * CacheStorage. + */ + has(cacheName: string): Promise; + + /** + * Returns a Promise that resolves to the Cache object matching + * the cacheName. + * + * @param cacheName The name of the cache you want to open. + */ + open(cacheName: string): Promise; + + /** + * Finds the Cache object matching the cacheName, and if found, deletes the + * Cache object and returns a Promise that resolves to true. If no + * Cache object is found, it returns false. + * + * @param cacheName The name of the cache you want to delete. + */ + delete(cacheName: string): Promise; + + /** + * Returns a Promise that will resolve with an array containing strings + * corresponding to all of the named Cache objects tracked by the + * CacheStorage. Use this method to iterate over a list of all the + * Cache objects. + */ + keys(): Promise>; +} + +/** + * Represents the scope of a service worker client. A service worker client is + * either a document in a browser context or a SharedWorker, which is controlled + * by an active worker. + */ +interface ServiceWorkerClient { + /** + * Allows a service worker client to send a message to a ServiceWorker. + * + * @param message The message to send to the service worker. + * @param [transfer] A transferable object such as, for example, a reference + * to a port. + */ + postMessage(message: string, transfer?: Object): void; + + /** + * Indicates the type of browsing context of the current client. + * This value can be one of auxiliary, top-level, nested, or none. + * @readonly + */ + frameType: string; + + /** + * Returns the id of the Client object. + * @readonly + */ + id: string; + + /** + * The URL of the current service worker client. + * @readonly + */ + url: string; +} + +interface WindowClient extends ServiceWorkerClient { + /** + * Gives user input focus to the current client. + */ + focus(): Promise; + + /** + * A boolean that indicates whether the current client has focus. + * @readonly + */ + focused: boolean; + + /** + * Indicates the visibility of the current client. This value can be one of + * hidden, visible, prerender, or unloaded. + * @readonly + */ + visibilityState: string; +} + +interface ServiceWorkerClientsMatchOptions { + includeUncontrolled?: boolean; + type?: string; +} + +/** + * Represents a container for a list of Client objects; the main way to access + * the active service worker clients at the current origin. + */ +interface ServiceWorkerClients { + /** + * Gets a list of service worker clients and returns them in a Promise. + * Include the options parameter to return all service worker clients whose + * origin is the same as the associated service worker's origin. If options + * are not included, the method returns only the service worker clients + * controlled by the service worker. + * + * @param options + */ + matchAll(options: ServiceWorkerClientsMatchOptions): Promise>; + + /** + * Opens a service worker Client in a new browser window. + * + * @param url A string representing the URL of the client you want to open + * in the window. + */ + openWindow(url: string): Promise; + + /** + * Allows an active Service Worker to set itself as the active worker for a + * client page when the worker and the page are in the same scope. + */ + claim(): Promise; +} + +/** + * Extends the lifetime of the install and activate events dispatched on the + * ServiceWorkerGlobalScope as part of the service worker lifecycle. This + * ensures that any functional events (like FetchEvent) are not dispatched to + * the ServiceWorker until it upgrades database schemas, deletes outdated cache + * entries, etc. + */ +interface ExtendableEvent extends Event { + /** + * Extends the lifetime of the event. + * It is intended to be called in the install EventHandler for the + * installing worker and on the active EventHandler for the active worker. + * + * @param all + */ + waitUntil(all: any): any; +} + +/** + * The parameter passed into the ServiceWorkerGlobalScope.onfetch handler, + * FetchEvent represents a fetch action that is dispatched on the + * ServiceWorkerGlobalScope of a ServiceWorker. It contains information about + * the request and resulting response, and provides the FetchEvent.respondWith() + * method, which allows us to provide an arbitrary response back to the + * controlled page. + */ +interface FetchEvent extends Event { + /** + * Returns a Boolean that is true if the event was dispatched with the + * user's intention for the page to reload, and false otherwise. Typically, + * pressing the refresh button in a browser is a reload, while clicking a + * link and pressing the back button is not. + * @readonly + */ + isReload: boolean; + + /** + * Returns the Request that triggered the event handler. + * @readonly + */ + request: Request; + + /** + * Returns the Client that the current service worker is controlling. + * @readonly + */ + client: ServiceWorkerClient; + + /** + * Resolves by returning a Response or a network error to Fetch. + * + * @param any + */ + respondWith(any): Response; +} + +/** + * Represents a service worker. Multiple browsing contexts (e.g. pages, workers, + * etc.) can be associated with the same ServiceWorker object. + */ +interface ServiceWorker extends Worker { + /** + * Returns the ServiceWorker serialized script URL defined as part of + * ServiceWorkerRegistration. The URL must be on the same origin as the + * document that registers the ServiceWorker. + * @readonly + */ + scriptURL: string; + + /** + * Returns the state of the service worker. It returns one of the following + * values: installing, installed, activating, activated, or redundant. + * @readonly + */ + state: string; + + /** + * An EventListener property called whenever an event of type statechange + * is fired; it is basically fired anytime the ServiceWorker.state changes. + * + * @param [statechangeevent] + */ + onstatechange: (statechangeevent?: Event) => void; +} + +/** + * The PushSubscription interface provides a subcription's URL endpoint and + * subscription ID. + */ +interface PushSubscription { + /** + * The endpoint associated with the push subscription. + * @readonly + */ + endpoint: any; + + /** + * The subscription ID associated with the push subscription. + * @readonly + */ + subscriptionId: any; +} + +/** + * The PushManager interface provides a way to receive notifications from + * third-party servers as well as request URLs for push notifications. + * This interface has replaced functionality offered by the obsolete + * PushRegistrationManager. + */ +interface PushManager { + /** + * Returns a promise that resolves to a PushSubscription with details of a + * new push subscription. + */ + subscribe(): Promise; + + /** + * Returns a promise that resolves to a PushSubscription details of + * the retrieved push subscription. + */ + getSubscription(): Promise; + + /** + * Returns a promise that resolves to the PushPermissionStatus of the + * requesting webapp, which will be one of granted, denied, or default. + */ + hasPermission(): Promise; +} + +/** + * Represents a service worker registration. + */ +interface ServiceWorkerRegistration extends EventTarget { + /** + * Returns a unique identifier for a service worker registration. + * This must be on the same origin as the document that registers + * the ServiceWorker. + * @readonly + */ + scope: any; + + /** + * Returns a service worker whose state is installing. This is initially + * set to null. + * @readonly + */ + installing: ServiceWorker; + + /** + * Returns a service worker whose state is installed. This is initially + * set to null. + * @readonly + */ + waiting: ServiceWorker; + + /** + * Returns a service worker whose state is either activating or activated. + * This is initially set to null. An active worker will control a + * ServiceWorkerClient if the client's URL falls within the scope of the + * registration (the scope option set when ServiceWorkerContainer.register + * is first called). + * @readonly + */ + active: ServiceWorker; + + /** + * Returns an interface to for managing push subscriptions, including + * subcribing, getting an anctive subscription, and accessing push + * permission status. + * @readonly + */ + pushManager: PushManager; + + /** + * An EventListener property called whenever an event of type updatefound + * is fired; it is fired any time the ServiceWorkerRegistration.installing + * property acquires a new service worker. + */ + onupdatefound: () => void; + + /** + * Allows you to update a service worker. + */ + update(); + + /** + * Unregisters the service worker registration and returns a promise + * (see Promise). The service worker will finish any ongoing operations + * before it is unregistered. + */ + unregister(): Promise; +} + +interface ServiceWorkerRegisterOptions { + scope: string; +} + +/** + * Provides an object representing the service worker as an overall unit in the + * network ecosystem, including facilities to register, unregister and update + * service workers, and access the state of service workers + * and their registrations. + */ +interface ServiceWorkerContainer { + /** + * Returns a ServiceWorker object if its state is activated (the same object + * returned by ServiceWorkerRegistration.active). This property returns null + * if the request is a force refresh (Shift + refresh) or if there is no + * active worker. + * @readonly + */ + controller: ServiceWorker; + + /** + * Defines whether a service worker is ready to control a page or not. + * It returns a Promise that will never reject, which resolves to a + * ServiceWorkerRegistration with an ServiceWorkerRegistration.active worker. + * @readonly + */ + ready: Promise; + + /** + * An event handler fired whenever a controllerchange event occurs — when + * the document's associated ServiceWorkerRegistration acquires a new + * ServiceWorkerRegistration.active worker. + * + * @param [controllerchangeevent] + */ + oncontrollerchange: (controllerchangeevent?: Event) => void; + + /** + * An event handler fired whenever an error event occurs in the associated + * service workers. + * + * @param [errorevent] + */ + onerror: (errorevent?: ErrorEvent) => void; + + /** + * An event handler fired whenever a message event occurs — when incoming + * messages are received to the ServiceWorkerContainer object (e.g. via a + * MessagePort.postMessage() call.) + * + * @param [messageevent] + */ + onmessage: (messageevent?: MessageEvent) => void; + + /** + * Creates or updates a ServiceWorkerRegistration for the given scriptURL. + * + * @param scriptURL The URL of the service worker script. + * @param [options] An options object to provide options upon registration. + * Currently available options are: scope: A USVString representing a URL + * that defines a service worker's registration scope; what range of URLs a + * service worker can control. This is usually a relative URL, and it + * defaults to '/' when not specified. + */ + register(scriptURL: string, options?: ServiceWorkerRegisterOptions): Promise; + + /** + * Gets a ServiceWorkerRegistration object whose scope URL matches the + * provided document URL. If the method can't return a + * ServiceWorkerRegistration, it returns a Promise. + * + * @param [scope] A unique identifier for a service worker registration — the + * scope URL of the registration object you want to return. This is usually + * a relative URL. + */ + getRegistration(scope?: string): Promise; + + /** + * Returns all ServiceWorkerRegistrations associated with a + * ServiceWorkerContainer in an array. If the method can't return + * ServiceWorkerRegistrations, it returns a Promise. + */ + getRegistrations(): Promise>; +} + +/** + * The parameter passed into the oninstall handler, the InstallEvent interface + * represents an install action that is dispatched on the + * ServiceWorkerGlobalScope of a ServiceWorker. As a child of ExtendableEvent, + * it ensures that functional events such as FetchEvent are not dispatched + * during installation. + */ +interface InstallEvent extends ExtendableEvent { + /** + * Returns the ServiceWorker that is currently actively controlling the page. + * @readonly + */ + activeWorker: ServiceWorker; +} + +interface ServiceWorkerGlobalScope { + /** + * Contains the Clients object associated with the service worker. + * @readonly + */ + clients: ServiceWorkerClients; + + /** + * Contains the ServiceWorkerRegistration object that represents the + * service worker's registration. + * @readonly + */ + registration: ServiceWorkerRegistration; + + /** + * An event handler fired whenever an activate event occurs — when a + * ServiceWorkerRegistration acquires a new ServiceWorkerRegistration.active + * worker. + * + * @param [activateevent] + */ + onactivate: (activateevent?: ExtendableEvent) => void; + + /** + * Not defined in the spec yet, but it looks like this will be fired when + * the device is nearly out of storage space, prompting the UA to start + * claiming back some space from web apps that are using client-side storage, + * and the current app is targeted. + * + * @param [beforeevictedevent] + */ + onbeforeevicted: (beforeevictedevent?: Event) => void; + + /** + * Not defined in the spec yet, but it looks like this will be fired when + * the device is out of storage space, and the UA claims back some space + * from the current app. + * + * @param [evictedevent] + */ + onevicted: (evictedevent?: Event) => void; + + /** + * An event handler fired whenever a fetch event occurs — when a fetch() + * is called. + * + * @param [fetchevent] + */ + onfetch: (fetchevent?: FetchEvent) => void; + + /** + * An event handler fired whenever an install event occurs — when a + * ServiceWorkerRegistration acquires a new + * ServiceWorkerRegistration.installing worker. + * + * @param [installevent] + */ + oninstall: (installevent?: InstallEvent) => void; + + /** + * An event handler fired whenever a message event occurs — when incoming + * messages are received. Controlled pages can use the + * MessagePort.postMessage() method to send messages to service workers. + * The service worker can optionally send a response back via the + * MessagePort exposed in event.data.port, corresponding to the controlled + * page. + * + * @param [messageevent] + */ + onmessage: (messageevent?: MessageEvent) => void; + + /** + * An event handler fired whenever a notificationclick event occurs — when + * a user clicks on a displayed notification. + * + * @param [notificationclickevent] + */ + onnotificationclick: (notificationclickevent?: NotificationEvent) => void; + + /** + * An event handler fired whenever a push event occurs — when a server + * push notification is received. + * + * @param [onpushevent] + */ + onpush: (onpushevent?: Event) => void; + + /** + * An event handler fired whenever a pushsubscriptionchange event occurs — + * when a push subscription has been invalidated, or is about to be + * invalidated (e.g. when a push service sets an expiration time). + * + * @param [pushsubscriptionchangeevent] + */ + onpushsubscriptionchange: (pushsubscriptionchangeevent?: Event) => void; + + /** + * Allows the current service worker registration to progress from waiting + * to active state while service worker clients are using it. + */ + skipWaiting(): Promise; + + /** + * TODO GlobalFetch + * @param url + * @param init + */ + fetch(url: string | Request, init?: Object): Promise; +} + +interface Navigator { + /** + * Returns a ServiceWorkerContainer object, which provides access to + * registration, removal, upgrade, and communication with the ServiceWorker + * objects for the associated document. + */ + serviceWorker: ServiceWorkerContainer; +} + +interface Window extends ServiceWorkerGlobalScope { + caches: CacheStorage; +} + +interface NotificationEvent extends Event, ExtendableEvent { + notification: any; +} \ No newline at end of file From 1e6428c3474fa9174a1d218be30ac350e0a48f6e Mon Sep 17 00:00:00 2001 From: tristancaron Date: Mon, 23 Mar 2015 21:10:09 +0100 Subject: [PATCH 4/5] Service Worker API --- service_worker_api/service_worker_api-test.ts | 6 +++--- service_worker_api/service_worker_api.d.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/service_worker_api/service_worker_api-test.ts b/service_worker_api/service_worker_api-test.ts index 67ce58cd40..a28446a382 100644 --- a/service_worker_api/service_worker_api-test.ts +++ b/service_worker_api/service_worker_api-test.ts @@ -104,7 +104,7 @@ self.addEventListener('activate', function(event: ExtendableEvent) { ); }); -function sendMessage(message) { +function sendMessage(message: string) { return new Promise(function(resolve, reject) { var messageChannel = new MessageChannel(); messageChannel.port1.onmessage = function(event) { @@ -136,7 +136,7 @@ navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(functi // The service worker will not handle requests until this page and any // other instances of this page (in other tabs, etc.) have been // closed/reloaded. - var serviceWorker; + var serviceWorker: ServiceWorkerRegistration; if (registration.installing) { serviceWorker = registration.installing; } else if (registration.waiting) { @@ -146,7 +146,7 @@ navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(functi } if (serviceWorker) { console.log(serviceWorker.state); - serviceWorker.addEventListener('statechange', function(e) { + serviceWorker.addEventListener('statechange', function(e: Event) { console.log(e.target.state); }); } diff --git a/service_worker_api/service_worker_api.d.ts b/service_worker_api/service_worker_api.d.ts index f9b2981463..3851d0ec10 100644 --- a/service_worker_api/service_worker_api.d.ts +++ b/service_worker_api/service_worker_api.d.ts @@ -1,6 +1,6 @@ // Type definitions for service_worker_api // Project: https://developer.mozilla.org/fr/docs/Web/API/ServiceWorker_API -// Definitions by: Tristan Caron +// Definitions by: Tristan Caron // Definitions: https://github.com/borisyankov/DefinitelyTyped /// @@ -526,9 +526,9 @@ interface FetchEvent extends Event { /** * Resolves by returning a Response or a network error to Fetch. * - * @param any + * @param all */ - respondWith(any): Response; + respondWith(all: any): Response; } /** @@ -658,7 +658,7 @@ interface ServiceWorkerRegistration extends EventTarget { /** * Allows you to update a service worker. */ - update(); + update(): void; /** * Unregisters the service worker registration and returns a promise From d12ab0b655fbe42f35d257773fb23219d608d252 Mon Sep 17 00:00:00 2001 From: tristancaron Date: Mon, 23 Mar 2015 21:19:54 +0100 Subject: [PATCH 5/5] Service Worker API --- service_worker_api/service_worker_api-test.ts | 4 ++-- service_worker_api/service_worker_api.d.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/service_worker_api/service_worker_api-test.ts b/service_worker_api/service_worker_api-test.ts index a28446a382..e144880ba1 100644 --- a/service_worker_api/service_worker_api-test.ts +++ b/service_worker_api/service_worker_api-test.ts @@ -136,7 +136,7 @@ navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(functi // The service worker will not handle requests until this page and any // other instances of this page (in other tabs, etc.) have been // closed/reloaded. - var serviceWorker: ServiceWorkerRegistration; + var serviceWorker: ServiceWorker; if (registration.installing) { serviceWorker = registration.installing; } else if (registration.waiting) { @@ -146,7 +146,7 @@ navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(functi } if (serviceWorker) { console.log(serviceWorker.state); - serviceWorker.addEventListener('statechange', function(e: Event) { + serviceWorker.addEventListener('statechange', function(e: any) { console.log(e.target.state); }); } diff --git a/service_worker_api/service_worker_api.d.ts b/service_worker_api/service_worker_api.d.ts index 3851d0ec10..77c80b6706 100644 --- a/service_worker_api/service_worker_api.d.ts +++ b/service_worker_api/service_worker_api.d.ts @@ -557,7 +557,7 @@ interface ServiceWorker extends Worker { * * @param [statechangeevent] */ - onstatechange: (statechangeevent?: Event) => void; + onstatechange: (statechangeevent?: any) => void; } /**