fix(core): update
This commit is contained in:
parent
fedb37ee16
commit
d225a9584f
31
package.json
31
package.json
@ -2,13 +2,19 @@
|
||||
"name": "@api.global/typedserver",
|
||||
"version": "3.0.29",
|
||||
"description": "A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./dist_ts/index.js",
|
||||
"./ts": "./dist_ts/index.js",
|
||||
"./ts_web_inject": "./dist_ts_web_inject/index.js",
|
||||
"./ts_web_serviceworker": "./dist_web_serviceworker",
|
||||
"./ts_web_serviceworker_client": "./dist_web_serviceworker_client"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && tstest test/",
|
||||
"build": "tsbuild --web --allowimplicitany --skiplibcheck && tsbundle --from ./ts_web/index.ts --to ./dist_ts_web/bundle.js",
|
||||
"buildDocs": "tsdoc"
|
||||
"build": "tsbuild tsfolders --web --allowimplicitany --skiplibcheck && tsbundle --from ./ts_web/index.ts --to ./dist_ts_web/bundle.js",
|
||||
"interfaces": "tsbuild interfaces --web --allowimplicitany --skiplibcheck",
|
||||
"docs": "tsdoc aidoc"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -49,11 +55,12 @@
|
||||
],
|
||||
"homepage": "https://github.com/pushrocks/easyserve",
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest": "^3.0.21",
|
||||
"@api.global/typedrequest-interfaces": "^3.0.18",
|
||||
"@api.global/typedrequest": "^3.0.23",
|
||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||
"@api.global/typedsocket": "^3.0.1",
|
||||
"@design.estate/dees-comms": "^1.0.24",
|
||||
"@push.rocks/lik": "^6.0.15",
|
||||
"@push.rocks/smartchok": "^1.0.33",
|
||||
"@push.rocks/smartchok": "^1.0.34",
|
||||
"@push.rocks/smartdelay": "^3.0.5",
|
||||
"@push.rocks/smartenv": "^5.0.12",
|
||||
"@push.rocks/smartfeed": "^1.0.11",
|
||||
@ -64,13 +71,15 @@
|
||||
"@push.rocks/smartmanifest": "^2.0.2",
|
||||
"@push.rocks/smartmime": "^1.0.5",
|
||||
"@push.rocks/smartopen": "^2.0.0",
|
||||
"@push.rocks/smartpath": "^5.0.14",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@push.rocks/smartpromise": "^4.0.2",
|
||||
"@push.rocks/smartrequest": "^2.0.22",
|
||||
"@push.rocks/smartrx": "^3.0.7",
|
||||
"@push.rocks/smartsitemap": "^2.0.3",
|
||||
"@push.rocks/smartstream": "^3.0.34",
|
||||
"@push.rocks/smartstream": "^3.0.35",
|
||||
"@push.rocks/smarttime": "^4.0.6",
|
||||
"@push.rocks/taskbuffer": "^3.1.7",
|
||||
"@push.rocks/webrequest": "^3.0.37",
|
||||
"@push.rocks/webstore": "^2.0.14",
|
||||
"@tsclass/tsclass": "^4.0.54",
|
||||
"@types/express": "^4.17.21",
|
||||
@ -81,12 +90,12 @@
|
||||
"lit": "^3.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.1.72",
|
||||
"@git.zone/tsbuild": "^2.1.75",
|
||||
"@git.zone/tsbundle": "^2.0.15",
|
||||
"@git.zone/tsrun": "^1.2.44",
|
||||
"@git.zone/tstest": "^1.0.90",
|
||||
"@push.rocks/tapbundle": "^5.0.23",
|
||||
"@types/node": "^20.12.7"
|
||||
"@types/node": "^20.12.11"
|
||||
},
|
||||
"private": false,
|
||||
"browserslist": [
|
||||
|
896
pnpm-lock.yaml
generated
896
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@api.global/typedserver',
|
||||
version: '3.0.29',
|
||||
version: '3.0.30',
|
||||
description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.'
|
||||
}
|
||||
|
7
ts/paths.ts
Normal file
7
ts/paths.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export const packageDir = plugins.path.join(
|
||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||
'../'
|
||||
);
|
||||
export const distBundleDir = plugins.path.join(packageDir, './dist_bundle');
|
@ -1,7 +1,7 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { Handler } from './classes.handler.js';
|
||||
|
||||
import * as interfaces from '../interfaces/index.js';
|
||||
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
||||
|
||||
export class HandlerProxy extends Handler {
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as interfaces from '../interfaces/index.js';
|
||||
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
||||
|
||||
import { Handler } from './classes.handler.js';
|
||||
import { Compressor, type TCompressionMethod, type ICompressionResult } from './classes.compressor.js';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { Handler } from './classes.handler.js';
|
||||
|
||||
import * as interfaces from '../interfaces/index.js';
|
||||
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
||||
|
||||
export class HandlerTypedRouter extends Handler {
|
||||
/**
|
||||
|
60
ts/servertools/tools.serviceworker.ts
Normal file
60
ts/servertools/tools.serviceworker.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as paths from '../paths.js';
|
||||
|
||||
import * as interfaces from '../../dist_ts_interfaces/index.js'
|
||||
import { Handler } from './classes.handler.js';
|
||||
import type { TypedServer } from '../typedserver.classes.typedserver.js';
|
||||
import { HandlerTypedRouter } from './classes.handlertypedrouter.js';
|
||||
|
||||
const lswJS: string = plugins.smartfile.fs.toStringSync(
|
||||
plugins.path.join(paths.distBundleDir, './lsw.js')
|
||||
);
|
||||
const lswJSMeta: string = plugins.smartfile.fs.toStringSync(
|
||||
plugins.path.join(paths.distBundleDir, './lsw.js.map')
|
||||
);
|
||||
let lswVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'] =
|
||||
null;
|
||||
const serviceworkerHandler = new Handler(
|
||||
'GET',
|
||||
async (req, res) => {
|
||||
if (req.path === '/lsw.js') {
|
||||
res.status(200);
|
||||
res.set('Content-Type', 'text/javascript');
|
||||
res.write(lswJS + '\n' + `/** appSemVer: ${lswVersionInfo?.appSemVer || 'not set'} */`);
|
||||
} else if (req.path === '/lsw.js.map') {
|
||||
res.status(200);
|
||||
res.set('Content-Type', 'application/json');
|
||||
res.write(lswJSMeta);
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
);
|
||||
|
||||
export const addServiceWorkerRoute = (
|
||||
typedserverInstance: TypedServer,
|
||||
lswData: () => interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response']
|
||||
) => {
|
||||
// lets the version info as unique string;
|
||||
lswVersionInfo = lswData();
|
||||
|
||||
// the basic stuff
|
||||
typedserverInstance.server.addRoute('/lsw.js*', serviceworkerHandler);
|
||||
|
||||
// the typed stuff
|
||||
const typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
|
||||
typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo>(
|
||||
'serviceworker_versionInfo',
|
||||
async (req) => {
|
||||
const versionInfoResponse = lswData();
|
||||
return versionInfoResponse;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
typedserverInstance.server.addRoute(
|
||||
'/lsw-typedrequest',
|
||||
new HandlerTypedRouter(typedrouter)
|
||||
);
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as paths from './typedserver.paths.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import * as interfaces from '../dist_ts_interfaces/index.js';
|
||||
import * as servertools from './servertools/index.js';
|
||||
import { type TCompressionMethod } from './servertools/classes.compressor.js';
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
export * from './requestmodifier.js';
|
||||
export * from './responsemodifier.js';
|
||||
export * from './typedrequests.js';
|
||||
|
||||
import * as serviceworker from './serviceworker.js';
|
||||
|
||||
export {
|
||||
serviceworker,
|
||||
}
|
5
ts_interfaces/plugins.ts
Normal file
5
ts_interfaces/plugins.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
|
||||
|
||||
export {
|
||||
typedrequestInterfaces,
|
||||
}
|
127
ts_interfaces/serviceworker.ts
Normal file
127
ts_interfaces/serviceworker.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export interface CacheStorage {
|
||||
keys: () => Promise<string[]>;
|
||||
match: any;
|
||||
open: any;
|
||||
delete: any;
|
||||
}
|
||||
export declare var caches: CacheStorage;
|
||||
|
||||
|
||||
// =============================
|
||||
// Interfaces for communication
|
||||
// =============================
|
||||
|
||||
export interface IMessage_Serviceworker_Client_UpdateInfo
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IMessage_Serviceworker_Client_UpdateInfo
|
||||
> {
|
||||
method: 'serviceworker_newVersion';
|
||||
request: {
|
||||
appVersion: string;
|
||||
appHash: string;
|
||||
};
|
||||
response: {};
|
||||
}
|
||||
|
||||
export interface IMessage_Serviceworker_Client_RequestReload
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IMessage_Serviceworker_Client_RequestReload
|
||||
> {
|
||||
method: 'serviceworker_requestReload';
|
||||
request: {};
|
||||
response: {};
|
||||
}
|
||||
|
||||
export interface IRequest_Serviceworker_Backend_VersionInfo
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Serviceworker_Backend_VersionInfo
|
||||
> {
|
||||
method: 'serviceworker_versionInfo';
|
||||
request: {};
|
||||
response: {
|
||||
appHash: string;
|
||||
appSemVer: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ===============
|
||||
// web
|
||||
// ===============
|
||||
/**
|
||||
* purges the service workers cache
|
||||
*/
|
||||
export interface IRequest_PurgeServiceWorkerCache extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_PurgeServiceWorkerCache
|
||||
> {
|
||||
method: 'purgeServiceWorkerCache';
|
||||
request: {};
|
||||
response: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the info in all connected tabs
|
||||
*/
|
||||
export interface IMessage_Serviceworker_Client_UpdateInfo
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IMessage_Serviceworker_Client_UpdateInfo
|
||||
> {
|
||||
method: 'serviceworker_newVersion';
|
||||
request: {
|
||||
appVersion: string;
|
||||
appHash: string;
|
||||
};
|
||||
response: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* requests all clients to reload
|
||||
*/
|
||||
export interface IMessage_Serviceworker_Client_RequestReload
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IMessage_Serviceworker_Client_RequestReload
|
||||
> {
|
||||
method: 'serviceworker_requestReload';
|
||||
request: {};
|
||||
response: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* updates version infos
|
||||
*/
|
||||
export interface IRequest_Serviceworker_Backend_VersionInfo
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Serviceworker_Backend_VersionInfo
|
||||
> {
|
||||
method: 'serviceworker_versionInfo';
|
||||
request: {};
|
||||
response: {
|
||||
appHash: string;
|
||||
appSemVer: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ensures a stable connection between clients and the serviceworker
|
||||
*/
|
||||
export interface IRequest_Client_Serviceworker_ConnectionPolling
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Client_Serviceworker_ConnectionPolling
|
||||
> {
|
||||
method: 'broadcastConnectionPolling',
|
||||
request: {
|
||||
tabId: string;
|
||||
},
|
||||
response: {
|
||||
serviceworkerId: string;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import * as plugins from './typedserver_web.plugins.js';
|
||||
import * as interfaces from '../ts/interfaces/index.js';
|
||||
import * as interfaces from '../ts_interfaces/index.js';
|
||||
import { logger } from './typedserver_web.logger.js';
|
||||
logger.log('info', `TypedServer-Devtools initialized!`);
|
||||
|
8
ts_web_serviceworker/00_commitinfo_data.ts
Normal file
8
ts_web_serviceworker/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@losslessone_private/lole-serviceworker',
|
||||
version: '1.0.206',
|
||||
description: 'serviceworker implementation for lossless websites'
|
||||
}
|
53
ts_web_serviceworker/classes.backend.ts
Normal file
53
ts_web_serviceworker/classes.backend.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as interfaces from '../dist_ts_interfaces/index.js';
|
||||
|
||||
/**
|
||||
* This class is meant to be used only on the backend side
|
||||
*/
|
||||
export class ServiceworkerBackend {
|
||||
public deesComms = new plugins.deesComms.DeesComms();
|
||||
|
||||
constructor(optionsArg: {
|
||||
self: any;
|
||||
purgeCache: (reqArg: interfaces.serviceworker.IRequest_PurgeServiceWorkerCache['request']) => Promise<interfaces.serviceworker.IRequest_PurgeServiceWorkerCache['response']>;
|
||||
}) {
|
||||
|
||||
// lets handle wakestuff
|
||||
optionsArg.self.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.type === 'wakeUpCall') {
|
||||
console.log('sw-backend: got wake up call');
|
||||
}
|
||||
});
|
||||
this.deesComms.createTypedHandler<interfaces.serviceworker.IRequest_Client_Serviceworker_ConnectionPolling>('broadcastConnectionPolling', async reqArg => {
|
||||
return {
|
||||
serviceworkerId: '123'
|
||||
};
|
||||
})
|
||||
|
||||
this.deesComms.createTypedHandler<interfaces.serviceworker.IRequest_PurgeServiceWorkerCache>('purgeServiceWorkerCache', async reqArg => {
|
||||
console.log(`Executing purge cache in serviceworker backend.`)
|
||||
return await optionsArg.purgeCache?.(reqArg);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* reloads all clients
|
||||
*/
|
||||
public async triggerReloadAll() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* display notification
|
||||
*/
|
||||
public async addNotification(notificationArg: {
|
||||
title: string;
|
||||
body: string;
|
||||
}) {
|
||||
|
||||
}
|
||||
|
||||
public async alert(alertText: string) {
|
||||
|
||||
}
|
||||
}
|
20
ts_web_serviceworker/env.ts
Normal file
20
ts_web_serviceworker/env.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export * from '../dist_ts_interfaces/index.js';
|
||||
|
||||
// =============================
|
||||
// Interfaces for the service worker
|
||||
// =============================
|
||||
// tslint:disable-next-line: interface-name
|
||||
export interface ServiceEvent extends Event {
|
||||
request: any;
|
||||
respondWith: any;
|
||||
waitUntil: any;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: interface-name
|
||||
export interface ServiceWindow extends Window {
|
||||
addEventListener: any;
|
||||
location: any;
|
||||
skipWaiting: any;
|
||||
clients: any;
|
||||
}
|
||||
declare var self: Window;
|
8
ts_web_serviceworker/index.ts
Normal file
8
ts_web_serviceworker/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// TypeScript declatations
|
||||
import * as env from './env.js';
|
||||
declare var self: env.ServiceWindow;
|
||||
|
||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||
|
||||
const losslessServiceWorkerInstance = new LosslessServiceWorker(self);
|
||||
|
25
ts_web_serviceworker/plugins.ts
Normal file
25
ts_web_serviceworker/plugins.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// @losslessone_private scope
|
||||
import * as interfaces from '../dist_ts_interfaces/index.js';
|
||||
|
||||
export { interfaces };
|
||||
|
||||
// @apiglobal scope
|
||||
import * as typedrequest from '@api.global/typedrequest';
|
||||
|
||||
export { typedrequest };
|
||||
|
||||
// @pushrocks scope
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
import * as webrequest from '@push.rocks/webrequest';
|
||||
import * as webstore from '@push.rocks/webstore';
|
||||
import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||
|
||||
export { smartdelay, smartpromise, webrequest, webstore, taskbuffer };
|
||||
|
||||
// @design.estate scope
|
||||
import * as deesComms from '@design.estate/dees-comms';
|
||||
|
||||
export {
|
||||
deesComms,
|
||||
}
|
224
ts_web_serviceworker/serviceworker.classes.cachemanager.ts
Normal file
224
ts_web_serviceworker/serviceworker.classes.cachemanager.ts
Normal file
@ -0,0 +1,224 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as interfaces from './env.js';
|
||||
import { logger } from './serviceworker.logging.js';
|
||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||
|
||||
export class CacheManager {
|
||||
public losslessServiceWorkerRef: LosslessServiceWorker;
|
||||
|
||||
public usedCacheNames = {
|
||||
runtimeCacheName: 'runtime'
|
||||
};
|
||||
|
||||
constructor(losslessServiceWorkerRefArg: LosslessServiceWorker) {
|
||||
this.losslessServiceWorkerRef = losslessServiceWorkerRefArg;
|
||||
this._setupCache();
|
||||
}
|
||||
|
||||
private _setupCache = () => {
|
||||
const createMatchRequest = (requestArg: Request) => {
|
||||
// lets create a matchRequest
|
||||
let matchRequest: Request;
|
||||
if (requestArg.url.startsWith(this.losslessServiceWorkerRef.serviceWindowRef.location.origin)) {
|
||||
// internal request
|
||||
matchRequest = requestArg;
|
||||
} else {
|
||||
matchRequest = new Request(requestArg.url, {
|
||||
...requestArg.clone(),
|
||||
mode: 'cors'
|
||||
});
|
||||
}
|
||||
return matchRequest;
|
||||
};
|
||||
|
||||
/**
|
||||
* creates a 500 response
|
||||
*/
|
||||
const create500Response = async (requestArg: Request, responseArg: Response) => {
|
||||
return new Response(
|
||||
`
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.note {
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
border-bottom: 1px solid #e4002b;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="note">
|
||||
<strong>serviceworker running, but status 500</strong><br>
|
||||
</div>
|
||||
serviceworker is unable to fetch this request<br>
|
||||
Here is some info about the request/response pair:<br>
|
||||
<br>
|
||||
requestUrl: ${requestArg.url}<br>
|
||||
responseType: ${responseArg.type}<br>
|
||||
responseBody: ${await responseArg.clone().text()}<br>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "text/html"
|
||||
},
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// A list of local resources we always want to be cached.
|
||||
this.losslessServiceWorkerRef.serviceWindowRef.addEventListener('fetch', async (fetchEventArg: any) => {
|
||||
// Lets block scopes we don't want to be passing through the serviceworker
|
||||
const parsedUrl = new URL(fetchEventArg.request.url)
|
||||
if (
|
||||
parsedUrl.hostname.includes('paddle.com')
|
||||
|| parsedUrl.hostname.includes('paypal.com')
|
||||
|| parsedUrl.hostname.includes('reception.lossless.one')
|
||||
|| parsedUrl.pathname.startsWith('/socket.io')
|
||||
) {
|
||||
logger.log('note',`serviceworker not active for ${parsedUrl.toString()}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// lets continue for the rest
|
||||
const done = plugins.smartpromise.defer<Response>();
|
||||
fetchEventArg.respondWith(done.promise);
|
||||
const originalRequest: Request = fetchEventArg.request;
|
||||
|
||||
if (
|
||||
(originalRequest.method === 'GET' &&
|
||||
(originalRequest.url.startsWith(this.losslessServiceWorkerRef.serviceWindowRef.location.origin) &&
|
||||
!originalRequest.url.includes('/api/') &&
|
||||
!originalRequest.url.includes('smartserve/reloadcheck'))) ||
|
||||
originalRequest.url.includes('https://assetbroker.lossless.one/public') ||
|
||||
originalRequest.url.includes('https://assetbroker.lossless.one/brandfiles') ||
|
||||
originalRequest.url.includes('https://assetbroker.lossless.one/websites') ||
|
||||
originalRequest.url.includes('https://unpkg.com') ||
|
||||
originalRequest.url.includes('https://fonts.googleapis.com') ||
|
||||
originalRequest.url.includes('https://fonts.gstatic.com')
|
||||
) {
|
||||
|
||||
// lets see if things need to be updated
|
||||
// not waiting here
|
||||
this.losslessServiceWorkerRef.updateManager.checkUpdate(this);
|
||||
|
||||
// this code block is executed for local requests
|
||||
const matchRequest = createMatchRequest(originalRequest);
|
||||
const cachedResponse = await caches.match(matchRequest);
|
||||
if (cachedResponse) {
|
||||
logger.log('ok', `CACHED: found cached response for ${matchRequest.url}`);
|
||||
done.resolve(cachedResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// in case there is no cached response
|
||||
logger.log('info', `NOTYETCACHED: trying to cache ${matchRequest.url}`);
|
||||
const newResponse: Response = await fetch(matchRequest).catch(async err => {
|
||||
return await create500Response(matchRequest, new Response(err.message));
|
||||
});
|
||||
|
||||
// fill cache
|
||||
// Put a copy of the response in the runtime cache.
|
||||
if (newResponse.status > 299 || newResponse.type === 'opaque') {
|
||||
logger.log(
|
||||
'error',
|
||||
`NOTCACHED: can't cache response for ${matchRequest.url} due to status ${
|
||||
newResponse.status
|
||||
} and type ${newResponse.type}`
|
||||
);
|
||||
done.resolve(await create500Response(matchRequest, newResponse));
|
||||
} else {
|
||||
const cache = await caches.open(this.usedCacheNames.runtimeCacheName);
|
||||
const responseToPutToCache = newResponse.clone();
|
||||
const headers = new Headers();
|
||||
responseToPutToCache.headers.forEach((value, key) => {
|
||||
if (
|
||||
value !== 'Cache-Control'
|
||||
&& value !== 'cache-control'
|
||||
&& value !== 'Expires'
|
||||
&& value !== 'expires'
|
||||
&& value !== 'Pragma'
|
||||
&& value !== 'pragma'
|
||||
) {
|
||||
headers.set(key, value);
|
||||
}
|
||||
});
|
||||
headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
headers.set('Pragma', 'no-cache');
|
||||
headers.set('Expires', '0');
|
||||
await cache.put(matchRequest, new Response(responseToPutToCache.body, {
|
||||
...responseToPutToCache,
|
||||
headers
|
||||
}));
|
||||
logger.log(
|
||||
'ok',
|
||||
`NOWCACHED: cached response for ${matchRequest.url} for subsequent requests!`
|
||||
);
|
||||
done.resolve(newResponse);
|
||||
}
|
||||
} else {
|
||||
// this code block is executed for remote requests
|
||||
logger.log(
|
||||
'ok',
|
||||
`NOTCACHED: not caching any responses for ${
|
||||
originalRequest.url
|
||||
}. Fetching from origin now...`
|
||||
);
|
||||
done.resolve(
|
||||
await fetch(originalRequest).catch(async err => {
|
||||
return await create500Response(originalRequest, new Response(err.message));
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* update caches
|
||||
* @param reasonArg
|
||||
*/
|
||||
|
||||
/**
|
||||
* cleans all caches
|
||||
* should only be run when running a new service worker
|
||||
* @param reasonArg
|
||||
*/
|
||||
public cleanCaches = async (reasonArg = 'no reason given') => {
|
||||
logger.log('info', `MAJOR CACHEEVENT: cleaning caches now! Reason: ${reasonArg}`);
|
||||
const cacheNames = await caches.keys();
|
||||
|
||||
const deletePromises = cacheNames.map(cacheToDelete => {
|
||||
const deletePromise = caches.delete(cacheToDelete);
|
||||
deletePromise.then(() => {
|
||||
logger.log('ok', `Deleted cache ${cacheToDelete}`);
|
||||
});
|
||||
return deletePromise;
|
||||
});
|
||||
await Promise.all(deletePromises);
|
||||
}
|
||||
|
||||
/**
|
||||
* revalidate cache
|
||||
*/
|
||||
public async revalidateCache() {
|
||||
const runtimeCache = await caches.open(this.usedCacheNames.runtimeCacheName);
|
||||
const cacheKeys = await runtimeCache.keys();
|
||||
for (const requestArg of cacheKeys) {
|
||||
const cachedResponse = runtimeCache.match(requestArg);
|
||||
|
||||
// lets get a new response for comparison
|
||||
const clonedRequest = requestArg.clone();
|
||||
const response = await plugins.smartpromise.timeoutWrap(fetch(clonedRequest), 1000);
|
||||
if (response && response.status >= 200 && response.status < 300) {
|
||||
await runtimeCache.delete(requestArg);
|
||||
await runtimeCache.put(requestArg, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
ts_web_serviceworker/serviceworker.classes.networkmanager.ts
Normal file
33
ts_web_serviceworker/serviceworker.classes.networkmanager.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||
|
||||
export class NetworkManager {
|
||||
public serviceWorkerRef: LosslessServiceWorker;
|
||||
public webRequest: plugins.webrequest.WebRequest;
|
||||
|
||||
public previousState: string;
|
||||
|
||||
constructor(serviceWorkerRefArg: LosslessServiceWorker) {
|
||||
this.serviceWorkerRef = serviceWorkerRefArg;
|
||||
this.webRequest = new plugins.webrequest.WebRequest();
|
||||
this.getConnection()?.addEventListener('change', () => {
|
||||
this.updateConnectionStatus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the connection
|
||||
*/
|
||||
public getConnection() {
|
||||
const navigatorLocal: any = self.navigator;
|
||||
return navigatorLocal?.connection;
|
||||
}
|
||||
|
||||
public getEffectiveType() {
|
||||
return this.getConnection()?.effectiveType || '4g';
|
||||
}
|
||||
|
||||
public updateConnectionStatus() {
|
||||
console.log(`Connection type changed from ${this.previousState} to ${this.getEffectiveType()}`);
|
||||
}
|
||||
}
|
75
ts_web_serviceworker/serviceworker.classes.serviceworker.ts
Normal file
75
ts_web_serviceworker/serviceworker.classes.serviceworker.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as interfaces from './env.js';
|
||||
|
||||
// imports
|
||||
import { CacheManager } from './serviceworker.classes.cachemanager.js';
|
||||
import { Deferred } from '@push.rocks/smartpromise';
|
||||
|
||||
import { logger } from './serviceworker.logging.js';
|
||||
|
||||
// imported classes
|
||||
import { UpdateManager } from './serviceworker.classes.updatemanager.js';
|
||||
import { NetworkManager } from './serviceworker.classes.networkmanager.js';
|
||||
import { TaskManager } from './serviceworker.classes.taskmanager.js';
|
||||
|
||||
export class LosslessServiceWorker {
|
||||
// STATIC
|
||||
|
||||
// INSTANCE
|
||||
public serviceWindowRef: interfaces.ServiceWindow;
|
||||
public leleServiceWorkerBackend: plugins.leleServiceworker.LosslessServiceworkerBackend;
|
||||
|
||||
public cacheManager: CacheManager;
|
||||
|
||||
public updateManager: UpdateManager;
|
||||
public networkManager: NetworkManager;
|
||||
public taskManager: TaskManager;
|
||||
public store: plugins.webstore.WebStore;
|
||||
|
||||
constructor(selfArg: interfaces.ServiceWindow) {
|
||||
logger.log('info', `Service worker instantiating at ${Date.now()}`);
|
||||
this.serviceWindowRef = selfArg;
|
||||
this.leleServiceWorkerBackend = plugins.leleServiceworker.getServiceWorkerBackend({
|
||||
self: selfArg,
|
||||
purgeCache: async (reqArg) => {
|
||||
await this.cacheManager.cleanCaches(),
|
||||
logger.log('info', `cleaned caches in serviceworker as per request from frontend.`);
|
||||
return {}
|
||||
}
|
||||
});
|
||||
|
||||
this.updateManager = new UpdateManager(this);
|
||||
this.networkManager = new NetworkManager(this);
|
||||
this.taskManager = new TaskManager(this);
|
||||
|
||||
this.cacheManager = new CacheManager(this);
|
||||
|
||||
this.store = new plugins.webstore.WebStore({
|
||||
dbName: 'losslessServiceworker',
|
||||
storeName: 'losslessServiceworker',
|
||||
});
|
||||
|
||||
// =================================
|
||||
// Installation and Activation
|
||||
// =================================
|
||||
this.serviceWindowRef.addEventListener('install', async (event: interfaces.ServiceEvent) => {
|
||||
const done = new Deferred();
|
||||
event.waitUntil(done.promise);
|
||||
// its important to not go async before event.waitUntil
|
||||
done.resolve();
|
||||
logger.log('success', `service worker installed! TimeStamp = ${new Date().toISOString()}`);
|
||||
selfArg.skipWaiting();
|
||||
logger.log('note', `Called skip waiting!`);
|
||||
});
|
||||
|
||||
this.serviceWindowRef.addEventListener('activate', async (event: interfaces.ServiceEvent) => {
|
||||
const done = new Deferred();
|
||||
event.waitUntil(done.promise);
|
||||
|
||||
// its important to not go async before event.waitUntil
|
||||
await selfArg.clients.claim();
|
||||
await this.cacheManager.cleanCaches('new service worker loaded! :)');
|
||||
done.resolve();
|
||||
});
|
||||
}
|
||||
}
|
15
ts_web_serviceworker/serviceworker.classes.taskmanager.ts
Normal file
15
ts_web_serviceworker/serviceworker.classes.taskmanager.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||
|
||||
/**
|
||||
* Taskmanager
|
||||
* should use times allocated by browser
|
||||
*/
|
||||
export class TaskManager {
|
||||
public serviceworkerRef: LosslessServiceWorker;
|
||||
|
||||
constructor(serviceWorkerRefArg: LosslessServiceWorker) {
|
||||
this.serviceworkerRef = serviceWorkerRefArg;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
import * as plugins from './plugins.js';
|
90
ts_web_serviceworker/serviceworker.classes.updatemanager.ts
Normal file
90
ts_web_serviceworker/serviceworker.classes.updatemanager.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||
import { logger } from './serviceworker.logging.js';
|
||||
import { CacheManager } from './serviceworker.classes.cachemanager.js';
|
||||
|
||||
export class UpdateManager {
|
||||
public lastUpdateCheck: number = 0;
|
||||
public lastVersionInfo: plugins.lointServiceworker.IRequest_Serviceworker_Backend_VersionInfo['response'];
|
||||
|
||||
public serviceworkerRef: LosslessServiceWorker;
|
||||
|
||||
constructor(serviceWorkerRefArg: LosslessServiceWorker) {
|
||||
this.serviceworkerRef = serviceWorkerRefArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks wether an update is needed
|
||||
*/
|
||||
public async checkUpdate(cacheManager: CacheManager): Promise<boolean> {
|
||||
const lswVersionInfoKey = 'versionInfo';
|
||||
if (!this.lastVersionInfo && !(await this.serviceworkerRef.store.check(lswVersionInfoKey))) {
|
||||
this.lastVersionInfo = {
|
||||
appHash: '',
|
||||
appSemVer: 'v0.0.0',
|
||||
};
|
||||
} else if (
|
||||
!this.lastVersionInfo &&
|
||||
(await this.serviceworkerRef.store.check(lswVersionInfoKey))
|
||||
) {
|
||||
this.lastVersionInfo = await this.serviceworkerRef.store.get(lswVersionInfoKey);
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const millisSinceLastCheck = now - this.lastUpdateCheck;
|
||||
if (millisSinceLastCheck < 100000) {
|
||||
// TODO account for being offline
|
||||
return false;
|
||||
}
|
||||
logger.log('info', 'checking for update of the app by comparing app hashes...');
|
||||
this.lastUpdateCheck = now;
|
||||
const currentVersionInfo = await this.getVersionInfoFromServer();
|
||||
logger.log('info', `old versionInfo: ${JSON.stringify(this.lastVersionInfo)}`);
|
||||
logger.log('info', `current versionInfo: ${JSON.stringify(currentVersionInfo)}`);
|
||||
const needsUpdate = this.lastVersionInfo.appHash !== currentVersionInfo.appHash ? true : false;
|
||||
if (needsUpdate) {
|
||||
logger.log('info', 'Caches need to be updated');
|
||||
logger.log('info', 'starting a debounced update task');
|
||||
this.performAsyncUpdateDebouncedTask.trigger();
|
||||
this.lastVersionInfo = currentVersionInfo;
|
||||
await this.serviceworkerRef.store.set(lswVersionInfoKey, this.lastVersionInfo);
|
||||
} else {
|
||||
logger.log('ok', 'caches are still valid, performing revalidation in a bit...');
|
||||
this.performAsyncCacheRevalidationDebouncedTask.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the apphash from the server
|
||||
*/
|
||||
public async getVersionInfoFromServer() {
|
||||
const getAppHashRequest = new plugins.typedrequest.TypedRequest<
|
||||
plugins.lointServiceworker.IRequest_Serviceworker_Backend_VersionInfo
|
||||
>('/lsw-typedrequest', 'serviceworker_versionInfo');
|
||||
const result = await getAppHashRequest.fire({});
|
||||
return result;
|
||||
}
|
||||
|
||||
// tasks
|
||||
/**
|
||||
* this task is executed once we know that there is a new version available
|
||||
*/
|
||||
public performAsyncUpdateDebouncedTask = new plugins.taskbuffer.TaskDebounced({
|
||||
name: 'performAsyncUpdate',
|
||||
taskFunction: async () => {
|
||||
logger.log('info', 'trying to update PWA with serviceworker');
|
||||
await this.serviceworkerRef.cacheManager.cleanCaches('a new app version has been communicated by the server.');
|
||||
// lets notify all current clients about the update
|
||||
await this.serviceworkerRef.leleServiceWorkerBackend.triggerReloadAll();
|
||||
},
|
||||
debounceTimeInMillis: 2000,
|
||||
});
|
||||
|
||||
public performAsyncCacheRevalidationDebouncedTask = new plugins.taskbuffer.TaskDebounced({
|
||||
name: 'performAsyncCacheRevalidation',
|
||||
taskFunction: async () => {
|
||||
await this.serviceworkerRef.cacheManager.revalidateCache();
|
||||
},
|
||||
debounceTimeInMillis: 6000
|
||||
});
|
||||
}
|
17
ts_web_serviceworker/serviceworker.logging.ts
Normal file
17
ts_web_serviceworker/serviceworker.logging.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import { SmartlogDestinationDevtools } from '@push.rocks/smartlog-destination-devtools';
|
||||
|
||||
export const logger = new smartlog.Smartlog({
|
||||
logContext: {
|
||||
company: 'Lossless GmbH',
|
||||
companyunit: 'Lossless Cloud',
|
||||
containerName: 'web',
|
||||
environment: 'production',
|
||||
runtime: 'chrome',
|
||||
zone: 'servezone'
|
||||
},
|
||||
minimumLogLevel: 'info'
|
||||
});
|
||||
|
||||
logger.addLogDestination(new SmartlogDestinationDevtools());
|
||||
logger.log('note', 'serviceworker console initialized!');
|
8
ts_web_serviceworker_client/00_commitinfo_data.ts
Normal file
8
ts_web_serviceworker_client/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@losslessone_private/lele-serviceworker',
|
||||
version: '1.0.58',
|
||||
description: 'the mainthread of the serviceworker'
|
||||
}
|
24
ts_web_serviceworker_client/index.ts
Normal file
24
ts_web_serviceworker_client/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// types
|
||||
import type * as interfaces from './interfaces/index.js';
|
||||
export type {
|
||||
interfaces
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// imports
|
||||
// ====================================
|
||||
|
||||
import { logger } from './serviceworker.logging.js';
|
||||
logger.log('note', 'mainthread console initialized!');
|
||||
|
||||
import { LosslessServiceworker } from './lele-serviceworker.classes.serviceworker.js';
|
||||
|
||||
export type {
|
||||
LosslessServiceworker
|
||||
}
|
||||
|
||||
export const getServiceWorker = async () => {
|
||||
const losslessServiceWorkerInstance = await LosslessServiceworker.createServiceWorker(); // lets setup the service worker
|
||||
logger.log('ok', 'service worker ready!'); // and wait for it to be ready
|
||||
return losslessServiceWorkerInstance;
|
||||
};
|
2
ts_web_serviceworker_client/interfaces/index.ts
Normal file
2
ts_web_serviceworker_client/interfaces/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import * as plugins from '../lele-serviceworker.plugins.js';
|
||||
|
@ -0,0 +1,58 @@
|
||||
import * as plugins from './lele-serviceworker.plugins.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import { logger } from './serviceworker.logging.js';
|
||||
|
||||
/**
|
||||
* MessageManager implements two ways of serviceworker communication
|
||||
* * the serviceWorker method
|
||||
* * the deesComms method using BroadcastChannel
|
||||
*/
|
||||
export class ActionManager {
|
||||
public deesComms = new plugins.deesComms.DeesComms();
|
||||
|
||||
constructor() {
|
||||
// lets define handlers on the client/tab side
|
||||
this.deesComms.createTypedHandler<interfaces.IMessage_Serviceworker_Client_UpdateInfo>('serviceworker_newVersion', async req => {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 200);
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
public async waitForServiceWorkerConnection () {
|
||||
console.log('waiting for service worker connection...')
|
||||
const tr = this.deesComms.createTypedRequest<interfaces.IRequest_Client_Serviceworker_ConnectionPolling>('broadcastConnectionPolling');
|
||||
let connected = false;
|
||||
while (!connected) {
|
||||
tr.fire({
|
||||
tabId: '123'
|
||||
}).then(response => {
|
||||
if (response.serviceworkerId) {
|
||||
console.log('connected to serviceworker!');
|
||||
connected = true;
|
||||
}
|
||||
}).catch();
|
||||
await plugins.smartdelay.delayFor(777);
|
||||
if (!connected) {
|
||||
// lets wake it up.
|
||||
navigator.serviceWorker.controller.postMessage({
|
||||
type: 'wakeUpCall',
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log('ok, got serviceworker connection.')
|
||||
}
|
||||
|
||||
public async purgeServiceWorkerCache () {
|
||||
const tr = this.deesComms.createTypedRequest<interfaces.IRequest_PurgeServiceWorkerCache>('purgeServiceWorkerCache');
|
||||
const response = await tr.fire({});
|
||||
return response;
|
||||
}
|
||||
|
||||
public async getVersionInfo () {
|
||||
const tr = this.deesComms.createTypedRequest<interfaces.IRequest_Serviceworker_Backend_VersionInfo>('serviceworker_versionInfo');
|
||||
const response = await tr.fire({});
|
||||
return response;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import * as plugins from './lele-serviceworker.plugins.js';
|
||||
import { LosslessServiceworker } from './lele-serviceworker.classes.serviceworker.js';
|
||||
|
||||
export class GlobalSW {
|
||||
losslessSw: LosslessServiceworker;
|
||||
constructor(losslessServiceWorkerInstanceArg: LosslessServiceworker) {
|
||||
this.losslessSw = losslessServiceWorkerInstanceArg;
|
||||
globalThis.globalSw = this;
|
||||
};
|
||||
|
||||
/**
|
||||
* purges the cache of the app's serviceworker
|
||||
* @returns
|
||||
*/
|
||||
public async purgeCache() {
|
||||
await this.losslessSw.actionManager.waitForServiceWorkerConnection();
|
||||
console.log(`purgeCache() was executed via globalThis.globalSw`);
|
||||
const result = await this.losslessSw.actionManager.purgeServiceWorkerCache();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* attempts to reload the app
|
||||
*/
|
||||
public async reloadApp() {
|
||||
await this.purgeCache();
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import * as plugins from './lele-serviceworker.plugins.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import { logger } from "./serviceworker.logging.js";
|
||||
|
||||
export class NotificationManager {
|
||||
|
||||
constructor() {
|
||||
// this.askPermission();
|
||||
}
|
||||
|
||||
public askPermission () {
|
||||
Notification.requestPermission((status) => {
|
||||
console.log('Notification permission status:', status);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
import * as plugins from './lele-serviceworker.plugins.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import { logger } from "./serviceworker.logging.js";
|
||||
import { NotificationManager } from './lele-serviceworker.classes.notificationmanager.js';
|
||||
import { ActionManager } from './lele-serviceworker.classes.actionmanager.js';
|
||||
import { GlobalSW } from './lele-serviceworker.classes.globalsw.js'
|
||||
|
||||
export class LosslessServiceworker {
|
||||
// STATIC
|
||||
public static async createServiceWorker(): Promise<LosslessServiceworker> {
|
||||
if ('serviceWorker' in navigator) {
|
||||
try {
|
||||
logger.log('info', 'trying to register serviceworker');
|
||||
// this is some magic for Parcel to not pick up the serviceworker
|
||||
const serviceworkerInNavigator: ServiceWorkerContainer = navigator.serviceWorker;
|
||||
const swRegistration: ServiceWorkerRegistration = await serviceworkerInNavigator.register('/lsw.js', {
|
||||
scope: '/',
|
||||
updateViaCache: 'none'
|
||||
});
|
||||
plugins.smartdelay.delayFor(2000).then(async () => {
|
||||
swRegistration.onupdatefound = () => {
|
||||
logger.log('info', 'update found for service worker!');
|
||||
logger.log('warn', 'trying to find convenient time to update');
|
||||
};
|
||||
while(true) {
|
||||
await plugins.smartdelay.delayFor(60000);
|
||||
swRegistration.update();
|
||||
}
|
||||
});
|
||||
logger.log('ok', 'serviceworker registered');
|
||||
await navigator.serviceWorker.ready;
|
||||
logger.log('ok', 'serviceworker is ready!');
|
||||
await this.waitForController();
|
||||
const losslessServiceWorkerInstance = new LosslessServiceworker();
|
||||
return losslessServiceWorkerInstance;
|
||||
} catch (err) {
|
||||
// sentry integration here
|
||||
console.log(err);
|
||||
console.log(err.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async waitForController() {
|
||||
const done = new plugins.smartpromise.Deferred();
|
||||
const checkReady = () => {
|
||||
if(navigator.serviceWorker.controller) {
|
||||
logger.log('ok', 'controller is ready');
|
||||
done.resolve();
|
||||
} else {
|
||||
logger.log('warn', 'controller not ready');
|
||||
}
|
||||
};
|
||||
navigator.serviceWorker.oncontrollerchange = checkReady;
|
||||
checkReady();
|
||||
await done.promise;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public notificationManager: NotificationManager;
|
||||
public actionManager: ActionManager;
|
||||
public globalSw: GlobalSW;
|
||||
|
||||
constructor() {
|
||||
this.notificationManager = new NotificationManager();
|
||||
this.actionManager = new ActionManager();
|
||||
this.globalSw = new GlobalSW(this);
|
||||
}
|
||||
}
|
22
ts_web_serviceworker_client/lele-serviceworker.plugins.ts
Normal file
22
ts_web_serviceworker_client/lele-serviceworker.plugins.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// @apiglobal scope
|
||||
import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
|
||||
|
||||
export { typedrequestInterfaces };
|
||||
|
||||
// designestate
|
||||
import * as deesComms from '@design.estate/dees-comms';
|
||||
|
||||
export {
|
||||
deesComms
|
||||
};
|
||||
|
||||
// @pushrocks scope
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
import * as webstore from '@push.rocks/webstore';
|
||||
|
||||
export {
|
||||
smartdelay,
|
||||
smartpromise,
|
||||
webstore
|
||||
};
|
16
ts_web_serviceworker_client/serviceworker.logging.ts
Normal file
16
ts_web_serviceworker_client/serviceworker.logging.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import { SmartlogDestinationDevtools } from '@push.rocks/smartlog-destination-devtools';
|
||||
|
||||
export const logger = new smartlog.Smartlog({
|
||||
logContext: {
|
||||
company: 'Lossless GmbH',
|
||||
companyunit: 'Lossless Cloud',
|
||||
containerName: 'web',
|
||||
environment: 'production',
|
||||
runtime: 'chrome',
|
||||
zone: 'servezone'
|
||||
},
|
||||
minimumLogLevel: 'info'
|
||||
});
|
||||
|
||||
logger.addLogDestination(new SmartlogDestinationDevtools());
|
Loading…
Reference in New Issue
Block a user