fix(core): update
This commit is contained in:
parent
84e214d087
commit
1644cbbfad
@ -58,6 +58,7 @@
|
|||||||
"@api.global/typedrequest": "^3.0.23",
|
"@api.global/typedrequest": "^3.0.23",
|
||||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||||
"@api.global/typedsocket": "^3.0.1",
|
"@api.global/typedsocket": "^3.0.1",
|
||||||
|
"@cloudflare/workers-types": "^4.20240502.0",
|
||||||
"@design.estate/dees-comms": "^1.0.24",
|
"@design.estate/dees-comms": "^1.0.24",
|
||||||
"@push.rocks/lik": "^6.0.15",
|
"@push.rocks/lik": "^6.0.15",
|
||||||
"@push.rocks/smartchok": "^1.0.34",
|
"@push.rocks/smartchok": "^1.0.34",
|
||||||
@ -68,7 +69,9 @@
|
|||||||
"@push.rocks/smartjson": "^5.0.19",
|
"@push.rocks/smartjson": "^5.0.19",
|
||||||
"@push.rocks/smartlog": "^3.0.3",
|
"@push.rocks/smartlog": "^3.0.3",
|
||||||
"@push.rocks/smartlog-destination-devtools": "^1.0.10",
|
"@push.rocks/smartlog-destination-devtools": "^1.0.10",
|
||||||
|
"@push.rocks/smartlog-interfaces": "^3.0.0",
|
||||||
"@push.rocks/smartmanifest": "^2.0.2",
|
"@push.rocks/smartmanifest": "^2.0.2",
|
||||||
|
"@push.rocks/smartmatch": "^2.0.0",
|
||||||
"@push.rocks/smartmime": "^1.0.5",
|
"@push.rocks/smartmime": "^1.0.5",
|
||||||
"@push.rocks/smartopen": "^2.0.0",
|
"@push.rocks/smartopen": "^2.0.0",
|
||||||
"@push.rocks/smartpath": "^5.0.18",
|
"@push.rocks/smartpath": "^5.0.18",
|
||||||
|
@ -14,6 +14,9 @@ dependencies:
|
|||||||
'@api.global/typedsocket':
|
'@api.global/typedsocket':
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: 3.0.1
|
version: 3.0.1
|
||||||
|
'@cloudflare/workers-types':
|
||||||
|
specifier: ^4.20240502.0
|
||||||
|
version: 4.20240502.0
|
||||||
'@design.estate/dees-comms':
|
'@design.estate/dees-comms':
|
||||||
specifier: ^1.0.24
|
specifier: ^1.0.24
|
||||||
version: 1.0.24
|
version: 1.0.24
|
||||||
@ -44,9 +47,15 @@ dependencies:
|
|||||||
'@push.rocks/smartlog-destination-devtools':
|
'@push.rocks/smartlog-destination-devtools':
|
||||||
specifier: ^1.0.10
|
specifier: ^1.0.10
|
||||||
version: 1.0.10
|
version: 1.0.10
|
||||||
|
'@push.rocks/smartlog-interfaces':
|
||||||
|
specifier: ^3.0.0
|
||||||
|
version: 3.0.0
|
||||||
'@push.rocks/smartmanifest':
|
'@push.rocks/smartmanifest':
|
||||||
specifier: ^2.0.2
|
specifier: ^2.0.2
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
|
'@push.rocks/smartmatch':
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0
|
||||||
'@push.rocks/smartmime':
|
'@push.rocks/smartmime':
|
||||||
specifier: ^1.0.5
|
specifier: ^1.0.5
|
||||||
version: 1.0.6
|
version: 1.0.6
|
||||||
@ -232,6 +241,10 @@ packages:
|
|||||||
regenerator-runtime: 0.14.1
|
regenerator-runtime: 0.14.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@cloudflare/workers-types@4.20240502.0:
|
||||||
|
resolution: {integrity: sha512-OB1jIyPOzyOcuZFHWhsQnkRLN6u8+jmU9X3T4KZlGgn3Ivw8pBiswhLOp+yFeChR3Y4/5+V0hPFRko5SReordg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@cspotcode/source-map-support@0.8.1:
|
/@cspotcode/source-map-support@0.8.1:
|
||||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@api.global/typedserver',
|
name: '@api.global/typedserver',
|
||||||
version: '3.0.31',
|
version: '3.0.32',
|
||||||
description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.'
|
description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.'
|
||||||
}
|
}
|
||||||
|
8
ts_edgeworker/00_commitinfo_data.ts
Normal file
8
ts_edgeworker/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @pushrocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: 'cloudflare-workers',
|
||||||
|
version: '1.0.192',
|
||||||
|
description: 'cloudflare-workers'
|
||||||
|
}
|
83
ts_edgeworker/analytics/analyzer.ts
Normal file
83
ts_edgeworker/analytics/analyzer.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
import type { EdgeWorker } from '../classes.edgeworker.js';
|
||||||
|
import type { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { SmartlogDestination } from './smartlog.js';
|
||||||
|
|
||||||
|
export interface IAnalyticsData {
|
||||||
|
requestAgent: string;
|
||||||
|
requestUrl: string;
|
||||||
|
requestMethod: string;
|
||||||
|
requestStartTime: number;
|
||||||
|
responseStatus: number;
|
||||||
|
responseEndTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Analyzer {
|
||||||
|
cworkerEventRef: WorkerEvent;
|
||||||
|
|
||||||
|
public data: IAnalyticsData = {
|
||||||
|
requestAgent: 'unknown',
|
||||||
|
requestMethod: 'unknown',
|
||||||
|
requestUrl: 'unknown',
|
||||||
|
requestStartTime: 0,
|
||||||
|
responseStatus: 0,
|
||||||
|
responseEndTime: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public finishedDeferred = plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
constructor(cworkerEventRefArg: WorkerEvent) {
|
||||||
|
this.cworkerEventRef = cworkerEventRefArg;
|
||||||
|
this.smartlog.addLogDestination(new SmartlogDestination(this.cworkerEventRef.options.edgeWorkerRef));
|
||||||
|
}
|
||||||
|
public smartlog = new plugins.smartlog.Smartlog({
|
||||||
|
logContext: {
|
||||||
|
environment: 'production',
|
||||||
|
runtime: "cloudflare_workers",
|
||||||
|
zone: 'servezone',
|
||||||
|
company: 'Lossless GmbH',
|
||||||
|
companyunit: 'Lossless Cloud',
|
||||||
|
containerName: 'cloudflare_workers'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
public setRequestData (optionsArg: {
|
||||||
|
requestAgent: string;
|
||||||
|
requestUrl: string;
|
||||||
|
requestMethod: string;
|
||||||
|
}) {
|
||||||
|
this.data = {
|
||||||
|
...this.data,
|
||||||
|
...{
|
||||||
|
requestAgent: optionsArg.requestAgent,
|
||||||
|
requestUrl: optionsArg.requestUrl,
|
||||||
|
requestMethod: optionsArg.requestMethod,
|
||||||
|
requestStartTime: Date.now()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public setResponseData(optionsArg: {
|
||||||
|
responseStatus: number,
|
||||||
|
responseEndTime: number,
|
||||||
|
}) {
|
||||||
|
this.data = {
|
||||||
|
...this.data,
|
||||||
|
...{
|
||||||
|
responseStatus: optionsArg.responseStatus,
|
||||||
|
responseEndTime: optionsArg.responseEndTime
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.sendLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendLogs() {
|
||||||
|
await this.smartlog.log('info', `
|
||||||
|
Got a ${this.data.requestMethod} request from ${this.data.requestAgent} to
|
||||||
|
${this.data.requestUrl}
|
||||||
|
that took ${this.data.responseEndTime - this.data.requestStartTime}ms to resolve with status ${this.data.responseStatus}.`, this.data);
|
||||||
|
this.finishedDeferred.resolve();
|
||||||
|
}
|
||||||
|
}
|
26
ts_edgeworker/analytics/smartlog.ts
Normal file
26
ts_edgeworker/analytics/smartlog.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import * as smartlogInterfaces from '@push.rocks/smartlog-interfaces';
|
||||||
|
import type { EdgeWorker } from '../classes.edgeworker.js';
|
||||||
|
|
||||||
|
export class SmartlogDestination implements smartlogInterfaces.ILogDestination {
|
||||||
|
public edgeWorkerRef: EdgeWorker;
|
||||||
|
|
||||||
|
constructor(edgeworkerRefArg: EdgeWorker) {
|
||||||
|
this.edgeWorkerRef = edgeworkerRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleLog(logPackageArg: smartlogInterfaces.ILogPackage) {
|
||||||
|
if (this.edgeWorkerRef.options.smartlogConfig) {
|
||||||
|
const requestBody: smartlogInterfaces.ILogPackageAuthenticated = {
|
||||||
|
auth: this.edgeWorkerRef.options.smartlogConfig.token,
|
||||||
|
logPackage: logPackageArg,
|
||||||
|
};
|
||||||
|
await fetch(this.edgeWorkerRef.options.smartlogConfig.endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(requestBody),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
ts_edgeworker/classes.domainrouter.ts
Normal file
67
ts_edgeworker/classes.domainrouter.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import * as interfaces from './interfaces/index.js';
|
||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import { WorkerEvent } from './classes.workerevent.js';
|
||||||
|
|
||||||
|
import * as domainInstructions from './domaininstructions/index.js';
|
||||||
|
|
||||||
|
export class DomainRouter {
|
||||||
|
private smartmatches: plugins.smartmatch.SmartMatch[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
for (const key of Object.keys(domainInstructions.instructionObject)) {
|
||||||
|
this.smartmatches.push(new plugins.smartmatch.SmartMatch(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param cworkerevent
|
||||||
|
*/
|
||||||
|
public routeToResponder(cworkerevent: WorkerEvent) {
|
||||||
|
const match = this.smartmatches.find(smartmatchArg => {
|
||||||
|
return smartmatchArg.match(cworkerevent.request.url);
|
||||||
|
});
|
||||||
|
cworkerevent.responderInstruction = match
|
||||||
|
? domainInstructions.instructionObject[match.wildcard]
|
||||||
|
: {
|
||||||
|
type: 'cache'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rendertronRouter
|
||||||
|
*/
|
||||||
|
public checkWetherReRouteToRendertron(cworkerevent: WorkerEvent) {
|
||||||
|
let needsRendertron = false;
|
||||||
|
for (const botAgentIdentifier of domainInstructions.botUserAgents) {
|
||||||
|
if (needsRendertron) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
cworkerevent.request.headers.get('user-agent') &&
|
||||||
|
cworkerevent.request.headers.get('user-agent').toLowerCase().includes(botAgentIdentifier.toLowerCase()) &&
|
||||||
|
!cworkerevent.request.url.includes('lossless.one')
|
||||||
|
) {
|
||||||
|
needsRendertron = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needsRendertron) {
|
||||||
|
cworkerevent.routedThroughRendertron = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check wether this is a preflight request that should be handled
|
||||||
|
*/
|
||||||
|
public checkWetherIsPreflight (cworkerevent: WorkerEvent) {
|
||||||
|
if (
|
||||||
|
cworkerevent.request.method === 'OPTIONS' &&
|
||||||
|
cworkerevent.request.headers.get('Origin') !== null &&
|
||||||
|
cworkerevent.request.headers.get('Access-Control-Request-Method') !== null &&
|
||||||
|
cworkerevent.request.headers.get('Access-Control-Request-Headers') !== null
|
||||||
|
) {
|
||||||
|
cworkerevent.isPreflight = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
73
ts_edgeworker/classes.edgeworker.ts
Normal file
73
ts_edgeworker/classes.edgeworker.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// imports
|
||||||
|
import { WorkerEvent } from './classes.workerevent.js';
|
||||||
|
import { DomainRouter } from './classes.domainrouter.js';
|
||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as responders from './responders/index.js';
|
||||||
|
|
||||||
|
export interface IEdgeWorkerOptions {
|
||||||
|
smartlogConfig?: {
|
||||||
|
endpoint: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EdgeWorker {
|
||||||
|
public options: IEdgeWorkerOptions;
|
||||||
|
domainRouter: DomainRouter;
|
||||||
|
|
||||||
|
constructor(optionsArg: IEdgeWorkerOptions = {}) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
this.domainRouter = new DomainRouter();
|
||||||
|
addEventListener('fetch', this.fetchFunction as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async fetchFunction (eventArg: plugins.cloudflareTypes.FetchEvent) {
|
||||||
|
if (new URL(eventArg.request.url).pathname.startsWith('/socket.io')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cworkerEvent = new WorkerEvent({
|
||||||
|
edgeWorkerRef: this,
|
||||||
|
event: eventArg,
|
||||||
|
passThroughOnException: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets answer basic reuest things
|
||||||
|
responders.timeoutResponder(cworkerEvent);
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.urlFormattingResponder(cworkerEvent);
|
||||||
|
|
||||||
|
// lets route the domain
|
||||||
|
this.domainRouter.routeToResponder(cworkerEvent);
|
||||||
|
this.domainRouter.checkWetherReRouteToRendertron(cworkerEvent);
|
||||||
|
this.domainRouter.checkWetherIsPreflight(cworkerEvent);
|
||||||
|
|
||||||
|
// guardresponder
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.guardResponder(cworkerEvent);
|
||||||
|
|
||||||
|
// lets process all requests that need rendertron
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.rendertronResponder(cworkerEvent);
|
||||||
|
|
||||||
|
// lets process all requests that are preflight requests
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.preflightResponder(cworkerEvent);
|
||||||
|
|
||||||
|
switch (cworkerEvent.responderInstruction.type) {
|
||||||
|
case 'cache':
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.cacheResponder(cworkerEvent);
|
||||||
|
break;
|
||||||
|
case 'origin':
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.originResponder(cworkerEvent);
|
||||||
|
break;
|
||||||
|
case 'redirect':
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.adsTxtResponder(cworkerEvent);
|
||||||
|
break;
|
||||||
|
case 'static':
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.staticResponder(cworkerEvent);
|
||||||
|
break;
|
||||||
|
case 'ads.txt':
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.adsTxtResponder(cworkerEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// cworkerEvent.hasResponse ? null : await responders.kvResponder(cworkerEvent);
|
||||||
|
cworkerEvent.hasResponse ? null : await responders.errorResponder(cworkerEvent);
|
||||||
|
};
|
||||||
|
}
|
37
ts_edgeworker/classes.kvhandler.ts
Normal file
37
ts_edgeworker/classes.kvhandler.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import * as interfaces from './interfaces/index.js';
|
||||||
|
import * as plugins from './plugins.js';
|
||||||
|
|
||||||
|
declare var lokv: plugins.cloudflareTypes.KVNamespace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an abstraction for the workerd KV store
|
||||||
|
*/
|
||||||
|
export class KVHandler {
|
||||||
|
private getSafeIdentifier(urlString: string) {
|
||||||
|
return encodeURI(urlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFromKv(keyIdentifier: string) {
|
||||||
|
const key = this.getSafeIdentifier(keyIdentifier);
|
||||||
|
const valueString = await lokv.get(key);
|
||||||
|
return valueString;
|
||||||
|
}
|
||||||
|
|
||||||
|
async putInKv(keyIdentifier: string, valueForStorage: string) {
|
||||||
|
const key = this.getSafeIdentifier(keyIdentifier);
|
||||||
|
const value = valueForStorage;
|
||||||
|
await lokv.put(key, value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deletes a key/value from the cache
|
||||||
|
* @param keyIdentifier
|
||||||
|
*/
|
||||||
|
async deleteInKv(keyIdentifier: string) {
|
||||||
|
const cacheKey = this.getSafeIdentifier(keyIdentifier);
|
||||||
|
await lokv.delete(cacheKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const kvHandlerInstance = new KVHandler();
|
46
ts_edgeworker/classes.responsekv.ts
Normal file
46
ts_edgeworker/classes.responsekv.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import { kvHandlerInstance } from './classes.kvhandler.js';
|
||||||
|
|
||||||
|
declare var lokv: plugins.cloudflareTypes.KVNamespace;
|
||||||
|
|
||||||
|
interface IKVResponseObject {
|
||||||
|
headers: { [key: string]: string };
|
||||||
|
version: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResponseKv {
|
||||||
|
public async storeResponse(urlIdentifier: string, responseArg: any) {
|
||||||
|
const headers: { [key: string]: string } = {};
|
||||||
|
for (const kv of responseArg.headers.entries()) {
|
||||||
|
headers[kv[0]] = kv[1];
|
||||||
|
}
|
||||||
|
const kvResponseForStorage: IKVResponseObject = {
|
||||||
|
headers,
|
||||||
|
version: '1.0.0',
|
||||||
|
body: await responseArg.text()
|
||||||
|
};
|
||||||
|
await kvHandlerInstance.putInKv(urlIdentifier, JSON.stringify(kvResponseForStorage));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getResponse(urlIdentifier: string): Promise<Response> {
|
||||||
|
const kvValue = await kvHandlerInstance.getFromKv(urlIdentifier);
|
||||||
|
if (kvValue) {
|
||||||
|
let kvResponse: IKVResponseObject;
|
||||||
|
try {
|
||||||
|
kvResponse = JSON.parse(kvValue);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const headers = new Headers();
|
||||||
|
for (const key of Object.keys(kvResponse.headers)) {
|
||||||
|
headers.append(key, kvResponse.headers[key]);
|
||||||
|
}
|
||||||
|
headers.append('SERVEZONE_ROUTE', 'CLOUDFLARE_EDGE_LOKV');
|
||||||
|
return new Response(kvResponse.body, { headers: headers });
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
ts_edgeworker/classes.workerevent.ts
Normal file
102
ts_edgeworker/classes.workerevent.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import * as interfaces from './interfaces/index.js';
|
||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as helpers from './helpers/index.js';
|
||||||
|
import { DomainRouter } from './classes.domainrouter.js';
|
||||||
|
import { Analyzer } from './analytics/analyzer.js';
|
||||||
|
import type { EdgeWorker } from './classes.edgeworker.js';
|
||||||
|
|
||||||
|
export interface ICworkerEventOptions {
|
||||||
|
event: plugins.cloudflareTypes.FetchEvent
|
||||||
|
edgeWorkerRef: EdgeWorker;
|
||||||
|
passThroughOnException?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class WorkerEvent {
|
||||||
|
public options: ICworkerEventOptions;
|
||||||
|
|
||||||
|
public analyzer: Analyzer;
|
||||||
|
private responseDeferred: plugins.smartpromise.Deferred<any>;
|
||||||
|
private waitUntilDeferred: plugins.smartpromise.Deferred<any>;
|
||||||
|
|
||||||
|
private response: Response = null;
|
||||||
|
private waitList = [];
|
||||||
|
|
||||||
|
// routing settings
|
||||||
|
public responderInstruction: interfaces.IResponderInstruction;
|
||||||
|
public routedThroughRendertron: boolean = false;
|
||||||
|
public isPreflight: boolean = false;
|
||||||
|
|
||||||
|
public request: plugins.cloudflareTypes.Request;
|
||||||
|
|
||||||
|
public parsedUrl: URL;
|
||||||
|
|
||||||
|
constructor(optionsArg: ICworkerEventOptions) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
|
||||||
|
// lets create an Analyzer for this request
|
||||||
|
this.analyzer = new Analyzer(this);
|
||||||
|
|
||||||
|
// lets make sure we always answer
|
||||||
|
this.options.passThroughOnException ? this.options.event.passThroughOnException() : null;
|
||||||
|
|
||||||
|
// lets set up some better asnyc behaviour
|
||||||
|
this.waitUntilDeferred = plugins.smartpromise.defer();
|
||||||
|
this.responseDeferred = plugins.smartpromise.defer();
|
||||||
|
this.addToWaitList(this.analyzer.finishedDeferred.promise);
|
||||||
|
|
||||||
|
// lets entangle the event with this class instance
|
||||||
|
this.request = this.options.event.request;
|
||||||
|
|
||||||
|
// lets start with analytics
|
||||||
|
this.analyzer.setRequestData({
|
||||||
|
requestAgent: this.request.headers.get('user-agent'),
|
||||||
|
requestMethod: this.request.method,
|
||||||
|
requestUrl: this.request.url
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.options.event.respondWith(this.responseDeferred.promise);
|
||||||
|
this.options.event.waitUntil(this.waitUntilDeferred.promise);
|
||||||
|
|
||||||
|
// lets parse the url
|
||||||
|
this.parsedUrl = new URL(this.request.url);
|
||||||
|
|
||||||
|
// lets check the waitlist
|
||||||
|
this.checkWaitList();
|
||||||
|
console.log(`Got request for ${this.request.url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasResponse () {
|
||||||
|
let returnValue: boolean;
|
||||||
|
this.response ? returnValue = true : returnValue = false;
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addToWaitList(promiseArg: Promise<any>) {
|
||||||
|
this.waitList.push(promiseArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkWaitList() {
|
||||||
|
await this.responseDeferred.promise;
|
||||||
|
const currentWaitList = this.waitList;
|
||||||
|
this.waitList = [];
|
||||||
|
await Promise.all(currentWaitList);
|
||||||
|
if (this.waitList.length > 0) {
|
||||||
|
this.checkWaitList();
|
||||||
|
} else {
|
||||||
|
this.waitUntilDeferred.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setResponse (responseArg: Response) {
|
||||||
|
this.response = responseArg;
|
||||||
|
this.responseDeferred.resolve(responseArg);
|
||||||
|
this.analyzer.setResponseData({
|
||||||
|
responseStatus: this.response.status,
|
||||||
|
responseEndTime: Date.now()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
36
ts_edgeworker/domaininstructions/botuseragents.ts
Normal file
36
ts_edgeworker/domaininstructions/botuseragents.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export const botUserAgents = [
|
||||||
|
// Baidu
|
||||||
|
'baiduspider',
|
||||||
|
'embedly',
|
||||||
|
|
||||||
|
// Facebook
|
||||||
|
'facebookexternalhit',
|
||||||
|
|
||||||
|
// Ghost
|
||||||
|
'Ghost',
|
||||||
|
|
||||||
|
// Microsoft
|
||||||
|
'bingbot',
|
||||||
|
'BingPreview',
|
||||||
|
'linkedinbot',
|
||||||
|
'MissinglettrBot',
|
||||||
|
'msnbot',
|
||||||
|
'outbrain',
|
||||||
|
'pinterest',
|
||||||
|
'quora link preview',
|
||||||
|
'rogerbot',
|
||||||
|
'showyoubot',
|
||||||
|
'slackbot',
|
||||||
|
'TelegramBot',
|
||||||
|
|
||||||
|
// Twitter
|
||||||
|
'twitterbot',
|
||||||
|
'vkShare',
|
||||||
|
'W3C_Validator',
|
||||||
|
|
||||||
|
// WhatsApp
|
||||||
|
'whatsapp',
|
||||||
|
|
||||||
|
// woorank
|
||||||
|
'woorank'
|
||||||
|
];
|
7
ts_edgeworker/domaininstructions/domaininstructions.ts
Normal file
7
ts_edgeworker/domaininstructions/domaininstructions.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
|
||||||
|
export const instructionObject: { [key: string]: interfaces.IResponderInstruction } = {
|
||||||
|
'*/ads.txt': {
|
||||||
|
type: 'ads.txt',
|
||||||
|
}
|
||||||
|
};
|
2
ts_edgeworker/domaininstructions/index.ts
Normal file
2
ts_edgeworker/domaininstructions/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './botuseragents.js';
|
||||||
|
export * from './domaininstructions.js';
|
9
ts_edgeworker/helpers/checks.ts
Normal file
9
ts_edgeworker/helpers/checks.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
declare var lokv: plugins.cloudflareTypes.KVNamespace;
|
||||||
|
export const checkLokv = () => {
|
||||||
|
if (!lokv) {
|
||||||
|
throw new Error('lokv not defined!');
|
||||||
|
} else {
|
||||||
|
console.log('lokv present!');
|
||||||
|
}
|
||||||
|
};
|
1
ts_edgeworker/helpers/index.ts
Normal file
1
ts_edgeworker/helpers/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './checks.js';
|
1
ts_edgeworker/index.ts
Normal file
1
ts_edgeworker/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './classes.edgeworker.js';
|
9
ts_edgeworker/interfaces/custom.ts
Normal file
9
ts_edgeworker/interfaces/custom.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { WorkerEvent } from "../classes.workerevent.js";
|
||||||
|
|
||||||
|
export interface IResponderInstruction {
|
||||||
|
type: 'origin' | 'cache' | 'static' | 'redirect' | 'ads.txt';
|
||||||
|
cacheClientSideForMin?: number;
|
||||||
|
redirectUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TRequestResponser = (workerEventArg: WorkerEvent) => Promise<void>;
|
1
ts_edgeworker/interfaces/index.ts
Normal file
1
ts_edgeworker/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './custom.js';
|
21
ts_edgeworker/plugins.ts
Normal file
21
ts_edgeworker/plugins.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// @pushrocks scope
|
||||||
|
import * as smartdelay from '@push.rocks/smartdelay';
|
||||||
|
import * as smartlog from '@push.rocks/smartlog';
|
||||||
|
import * as smartlogInterfaces from '@push.rocks/smartlog-interfaces';
|
||||||
|
import * as smartmatch from '@push.rocks/smartmatch';
|
||||||
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
|
|
||||||
|
export {
|
||||||
|
smartdelay,
|
||||||
|
smartlog,
|
||||||
|
smartlogInterfaces,
|
||||||
|
smartmatch,
|
||||||
|
smartpromise
|
||||||
|
};
|
||||||
|
|
||||||
|
// cloudflarea
|
||||||
|
import * as cloudflareTypes from '@cloudflare/workers-types';
|
||||||
|
|
||||||
|
export {
|
||||||
|
cloudflareTypes
|
||||||
|
}
|
14
ts_edgeworker/responders/adstxt.responder.ts
Normal file
14
ts_edgeworker/responders/adstxt.responder.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const adsTxtResponder: interfaces.TRequestResponser = async (cWorkerEventArg: WorkerEvent) => {
|
||||||
|
if (cWorkerEventArg.responderInstruction.type === 'ads.txt') {
|
||||||
|
const response = new Response('google.com, pub-4104137977476459, DIRECT, f08c47fec0942fa0\n', {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain; charset=utf-8'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
cWorkerEventArg.setResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
92
ts_edgeworker/responders/cache.responder.ts
Normal file
92
ts_edgeworker/responders/cache.responder.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
import { kvHandlerInstance } from '../classes.kvhandler.js';
|
||||||
|
|
||||||
|
declare const fetch: plugins.cloudflareTypes.Fetcher['fetch'];
|
||||||
|
|
||||||
|
declare var caches: any;
|
||||||
|
export const cacheResponder: interfaces.TRequestResponser = async (cworkerEventArg: WorkerEvent) => {
|
||||||
|
const host = cworkerEventArg.request.headers.get('Host');
|
||||||
|
const appHashKey = `${host.toLowerCase()}_appHash`;
|
||||||
|
const appHash = await kvHandlerInstance.getFromKv(appHashKey);
|
||||||
|
|
||||||
|
const cache = caches.default;
|
||||||
|
let response: Response = await cache.match(cworkerEventArg.request);
|
||||||
|
|
||||||
|
if (
|
||||||
|
response &&
|
||||||
|
response.headers.get('appHash') &&
|
||||||
|
response.headers.get('appHash') !== appHash
|
||||||
|
) {
|
||||||
|
response = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
cworkerEventArg.setResponse(response);
|
||||||
|
} else {
|
||||||
|
response = await handleNewRequest(cworkerEventArg.request);
|
||||||
|
if (response) {
|
||||||
|
cworkerEventArg.addToWaitList(new Promise<void>(async (resolve, reject) => {
|
||||||
|
const newAppHash = response.headers.get('appHash');
|
||||||
|
if (newAppHash) {
|
||||||
|
await kvHandlerInstance.putInKv(appHashKey, newAppHash);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
cworkerEventArg.addToWaitList(buildCacheResponse(cache, cworkerEventArg.request, response));
|
||||||
|
cworkerEventArg.setResponse(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Request} originalRequest
|
||||||
|
*/
|
||||||
|
const handleNewRequest = async (originalRequest: plugins.cloudflareTypes.Request): Promise<Response> => {
|
||||||
|
console.log('answering from origin');
|
||||||
|
const originResponse: any = await fetch(
|
||||||
|
originalRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// lets capture status
|
||||||
|
if (originResponse.status > 399) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseClientPassThroughStream = new TransformStream();
|
||||||
|
originResponse.body.pipeTo(responseClientPassThroughStream.writable);
|
||||||
|
|
||||||
|
// build response for client
|
||||||
|
const clientHeaders = new Headers();
|
||||||
|
for (const kv of originResponse.headers.entries()) {
|
||||||
|
clientHeaders.append(kv[0], kv[1]);
|
||||||
|
}
|
||||||
|
clientHeaders.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_ORIGIN_INITIAL');
|
||||||
|
const responseForClient = new Response(responseClientPassThroughStream.readable, {
|
||||||
|
...originResponse,
|
||||||
|
headers: clientHeaders
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets return the responses
|
||||||
|
return responseForClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildCacheResponse = async (cache, matchRequest: plugins.cloudflareTypes.Request, originResponse: any) => {
|
||||||
|
const cacheHeaders = new Headers();
|
||||||
|
for (const kv of originResponse.headers.entries()) {
|
||||||
|
cacheHeaders.append(kv[0], kv[1]);
|
||||||
|
}
|
||||||
|
cacheHeaders.delete('SERVEZONE_ROUTE');
|
||||||
|
cacheHeaders.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_CACHE');
|
||||||
|
cacheHeaders.delete('Cache-Control');
|
||||||
|
cacheHeaders.append('Cache-Control', 'public, max-age=60');
|
||||||
|
cacheHeaders.delete('Expires');
|
||||||
|
cacheHeaders.append('Expires', new Date(Date.now() + 60 * 1000).toUTCString());
|
||||||
|
|
||||||
|
const responseForCache = new Response(await originResponse.clone().body, {
|
||||||
|
...originResponse,
|
||||||
|
headers: cacheHeaders
|
||||||
|
});
|
||||||
|
await cache.put(matchRequest, responseForCache);
|
||||||
|
};
|
6
ts_edgeworker/responders/error.responder.ts
Normal file
6
ts_edgeworker/responders/error.responder.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
export const errorResponder: interfaces.TRequestResponser = async (cWorkerEvent: WorkerEvent) => {
|
||||||
|
const errorResponse = await fetch('https://nullresolve.lossless.one/status/firewall');
|
||||||
|
cWorkerEvent.setResponse(errorResponse);
|
||||||
|
};
|
8
ts_edgeworker/responders/guard.responder.ts
Normal file
8
ts_edgeworker/responders/guard.responder.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
export const guardResponder: interfaces.TRequestResponser = async (cWorkerEvent: WorkerEvent) => {
|
||||||
|
if (cWorkerEvent.parsedUrl.pathname.endsWith('.map')) {
|
||||||
|
const errorResponse = await fetch('https://nullresolve.lossless.one/status/firewall');
|
||||||
|
cWorkerEvent.setResponse(errorResponse);
|
||||||
|
}
|
||||||
|
};
|
12
ts_edgeworker/responders/index.ts
Normal file
12
ts_edgeworker/responders/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export * from './adstxt.responder.js';
|
||||||
|
export * from './cache.responder.js';
|
||||||
|
export * from './urlformatting.responder.js';
|
||||||
|
export * from './error.responder.js';
|
||||||
|
export * from './guard.responder.js';
|
||||||
|
export * from './kv.responder.js';
|
||||||
|
export * from './origin.responder.js';
|
||||||
|
export * from './preflight.responder.js';
|
||||||
|
export * from './redirect.reponder.js';
|
||||||
|
export * from './rendertron.responder.js';
|
||||||
|
export * from './static.responder.js';
|
||||||
|
export * from './timeout.responder.js';
|
34
ts_edgeworker/responders/kv.responder.ts
Normal file
34
ts_edgeworker/responders/kv.responder.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
import { ResponseKv } from '../classes.responsekv.js';
|
||||||
|
|
||||||
|
declare const fetch: plugins.cloudflareTypes.Fetcher['fetch'];
|
||||||
|
|
||||||
|
export const kvResponder: interfaces.TRequestResponser = async (cworkerEventArg: WorkerEvent) => {
|
||||||
|
const responseKvInstance = new ResponseKv();
|
||||||
|
let response = await responseKvInstance.getResponse(cworkerEventArg.request.url);
|
||||||
|
if (response) {
|
||||||
|
console.log('Got response from KV');
|
||||||
|
} else {
|
||||||
|
response = await handleNewRequest(cworkerEventArg.request, responseKvInstance);
|
||||||
|
}
|
||||||
|
cworkerEventArg.setResponse(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNewRequest = async (request: plugins.cloudflareTypes.Request, responseKvInstance: ResponseKv) => {
|
||||||
|
const originResponse: any = await fetch(request);
|
||||||
|
// build response for cache
|
||||||
|
const cacheHeaders = new Headers();
|
||||||
|
for (const kv of originResponse.headers.entries()) {
|
||||||
|
cacheHeaders.append(kv[0], kv[1]);
|
||||||
|
}
|
||||||
|
cacheHeaders.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_KVRESPONSE');
|
||||||
|
cacheHeaders.append('Cache-Control', 'max-age=600');
|
||||||
|
const responseForKV = new Response(await originResponse.body, {
|
||||||
|
...originResponse,
|
||||||
|
headers: cacheHeaders
|
||||||
|
});
|
||||||
|
await responseKvInstance.storeResponse(request.url, responseForKV.clone());
|
||||||
|
return responseForKV.clone();
|
||||||
|
};
|
31
ts_edgeworker/responders/origin.responder.ts
Normal file
31
ts_edgeworker/responders/origin.responder.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
declare const fetch: plugins.cloudflareTypes.Fetcher['fetch'];
|
||||||
|
|
||||||
|
export const originResponder: interfaces.TRequestResponser = async (eventArg: WorkerEvent) => {
|
||||||
|
const originResponse: any = await fetch(eventArg.request);
|
||||||
|
// lets capture status
|
||||||
|
if (originResponse.status > 399) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
for (const kv of originResponse.headers.entries()) {
|
||||||
|
headers.append(kv[0], kv[1]);
|
||||||
|
}
|
||||||
|
headers.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_FASTORIGIN');
|
||||||
|
|
||||||
|
const responsePassThroughStream = new TransformStream();
|
||||||
|
originResponse.body.pipeTo(responsePassThroughStream.writable);
|
||||||
|
|
||||||
|
// response
|
||||||
|
|
||||||
|
const responseForClient = new Response(responsePassThroughStream.readable, {
|
||||||
|
...originResponse,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
eventArg.setResponse(responseForClient);
|
||||||
|
};
|
18
ts_edgeworker/responders/preflight.responder.ts
Normal file
18
ts_edgeworker/responders/preflight.responder.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const preflightResponder: interfaces.TRequestResponser = async (eventArg: WorkerEvent) => {
|
||||||
|
if (eventArg.isPreflight) {
|
||||||
|
const corsHeaders = new Headers();
|
||||||
|
corsHeaders.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_PREFLIGHT');
|
||||||
|
corsHeaders.append('Access-Control-Allow-Origin', '*');
|
||||||
|
corsHeaders.append('Access-Control-Allow-Methods', '*');
|
||||||
|
corsHeaders.append('Access-Control-Allow-Headers', '*');
|
||||||
|
|
||||||
|
eventArg.setResponse(
|
||||||
|
new Response(null, {
|
||||||
|
headers: corsHeaders,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
9
ts_edgeworker/responders/redirect.reponder.ts
Normal file
9
ts_edgeworker/responders/redirect.reponder.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const redirectResponder: interfaces.TRequestResponser = async (cWorkerEventArg: WorkerEvent) => {
|
||||||
|
if (cWorkerEventArg.responderInstruction.type === 'redirect') {
|
||||||
|
cWorkerEventArg.setResponse(Response.redirect(cWorkerEventArg.responderInstruction.redirectUrl, 302));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
22
ts_edgeworker/responders/rendertron.responder.ts
Normal file
22
ts_edgeworker/responders/rendertron.responder.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const rendertronResponder = async (cworkerevent: WorkerEvent) => {
|
||||||
|
if (cworkerevent.routedThroughRendertron) {
|
||||||
|
const oldHeaders: any = cworkerevent.request.headers;
|
||||||
|
const rendertronHeaders = new Headers();
|
||||||
|
for (const kv of oldHeaders.entries()) {
|
||||||
|
const headerName = kv[0];
|
||||||
|
const headerValue = headerName === 'user-agent' ? 'Lossless Rendertron' : kv[1];
|
||||||
|
rendertronHeaders.append(headerName, headerValue);
|
||||||
|
}
|
||||||
|
const rendertronRequest = new Request(
|
||||||
|
`https://rendertron.lossless.one/render/${cworkerevent.request.url}`,
|
||||||
|
{
|
||||||
|
method: cworkerevent.request.method,
|
||||||
|
headers: rendertronHeaders
|
||||||
|
}
|
||||||
|
);
|
||||||
|
cworkerevent.setResponse(await fetch(rendertronRequest));
|
||||||
|
}
|
||||||
|
};
|
31
ts_edgeworker/responders/static.responder.ts
Normal file
31
ts_edgeworker/responders/static.responder.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const staticResponder: interfaces.TRequestResponser = async (cWorkerEventArg: WorkerEvent) => {
|
||||||
|
if (cWorkerEventArg.responderInstruction.type === 'static') {
|
||||||
|
const originResponse: any = await fetch(
|
||||||
|
`https://statichost.lossless.one/resolve?url=${encodeURI(cWorkerEventArg.request.url)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const cacheHeaders = new Headers();
|
||||||
|
for (const kv of originResponse.headers.entries()) {
|
||||||
|
cacheHeaders.append(kv[0], kv[1]);
|
||||||
|
}
|
||||||
|
cacheHeaders.delete('SERVEZONE_ROUTE');
|
||||||
|
cacheHeaders.append('SERVEZONE_ROUTE', 'LOSSLESS_EDGE_STATICHOST');
|
||||||
|
|
||||||
|
if (cWorkerEventArg.responderInstruction.cacheClientSideForMin) {
|
||||||
|
cacheHeaders.delete('Cache-Control');
|
||||||
|
cacheHeaders.append('Cache-Control', `public, max-age=${cWorkerEventArg.responderInstruction.cacheClientSideForMin * 60}`);
|
||||||
|
cacheHeaders.delete('Expires');
|
||||||
|
cacheHeaders.append('Expires', new Date(Date.now() + cWorkerEventArg.responderInstruction.cacheClientSideForMin * 1000).toUTCString());
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseForClient = new Response(await originResponse.clone().body, {
|
||||||
|
...originResponse,
|
||||||
|
headers: cacheHeaders
|
||||||
|
});
|
||||||
|
|
||||||
|
cWorkerEventArg.setResponse(responseForClient);
|
||||||
|
}
|
||||||
|
};
|
23
ts_edgeworker/responders/timeout.responder.ts
Normal file
23
ts_edgeworker/responders/timeout.responder.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const timeoutResponder: interfaces.TRequestResponser = async (cWorkerEvent: WorkerEvent) => {
|
||||||
|
await plugins.smartdelay.delayFor(10000);
|
||||||
|
if (cWorkerEvent.routedThroughRendertron) {
|
||||||
|
await plugins.smartdelay.delayFor(10000);
|
||||||
|
}
|
||||||
|
if (!cWorkerEvent.hasResponse) {
|
||||||
|
const errorResponse = await fetch(
|
||||||
|
`https://nullresolve.lossless.one/custom?title=${encodeURI(
|
||||||
|
`Lossless Network: Request Cancellation!`
|
||||||
|
)}&heading=${encodeURI(`Error: Request Cancellation`)}&text=${encodeURI(
|
||||||
|
`Lossless Network could not decide how to respond to this request within 5 seconds. Therefore it timed out and has been canceled.
|
||||||
|
<p>requestUrl: ${cWorkerEvent.request.url}<br>
|
||||||
|
requestTime: ${Date.now()}<br>
|
||||||
|
referenceNumber: xxxxxx</p>`
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
cWorkerEvent.setResponse(errorResponse);
|
||||||
|
}
|
||||||
|
};
|
21
ts_edgeworker/responders/urlformatting.responder.ts
Normal file
21
ts_edgeworker/responders/urlformatting.responder.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { WorkerEvent } from '../classes.workerevent.js';
|
||||||
|
|
||||||
|
export const urlFormattingResponder: interfaces.TRequestResponser = async (eventArg: WorkerEvent) => {
|
||||||
|
let shouldCorrect = false;
|
||||||
|
const correctedUrl = new URL(eventArg.request.url);
|
||||||
|
if (eventArg.parsedUrl.hostname.startsWith('www.')) {
|
||||||
|
shouldCorrect = true;
|
||||||
|
correctedUrl.hostname = eventArg.parsedUrl.hostname.substring(
|
||||||
|
4,
|
||||||
|
eventArg.parsedUrl.hostname.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (eventArg.parsedUrl.protocol.startsWith('http:')) {
|
||||||
|
shouldCorrect = true;
|
||||||
|
correctedUrl.protocol = 'https:';
|
||||||
|
}
|
||||||
|
if (shouldCorrect) {
|
||||||
|
eventArg.setResponse(Response.redirect(`${correctedUrl.protocol}//${correctedUrl.host}${correctedUrl.pathname}${correctedUrl.search}`, 301));
|
||||||
|
}
|
||||||
|
};
|
7
ts_edgeworker/versionhandler.ts
Normal file
7
ts_edgeworker/versionhandler.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import * as interfaces from './interfaces/index.js';
|
||||||
|
|
||||||
|
export class VersionHandler {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const versionHandlerInstance = new VersionHandler();
|
@ -11,13 +11,14 @@ import { logger } from './serviceworker.logging.js';
|
|||||||
import { UpdateManager } from './serviceworker.classes.updatemanager.js';
|
import { UpdateManager } from './serviceworker.classes.updatemanager.js';
|
||||||
import { NetworkManager } from './serviceworker.classes.networkmanager.js';
|
import { NetworkManager } from './serviceworker.classes.networkmanager.js';
|
||||||
import { TaskManager } from './serviceworker.classes.taskmanager.js';
|
import { TaskManager } from './serviceworker.classes.taskmanager.js';
|
||||||
|
import { ServiceworkerBackend } from './classes.backend.js';
|
||||||
|
|
||||||
export class LosslessServiceWorker {
|
export class LosslessServiceWorker {
|
||||||
// STATIC
|
// STATIC
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public serviceWindowRef: interfaces.ServiceWindow;
|
public serviceWindowRef: interfaces.ServiceWindow;
|
||||||
public leleServiceWorkerBackend: plugins.leleServiceworker.LosslessServiceworkerBackend;
|
public leleServiceWorkerBackend: ServiceworkerBackend;
|
||||||
|
|
||||||
public cacheManager: CacheManager;
|
public cacheManager: CacheManager;
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ export class LosslessServiceWorker {
|
|||||||
constructor(selfArg: interfaces.ServiceWindow) {
|
constructor(selfArg: interfaces.ServiceWindow) {
|
||||||
logger.log('info', `Service worker instantiating at ${Date.now()}`);
|
logger.log('info', `Service worker instantiating at ${Date.now()}`);
|
||||||
this.serviceWindowRef = selfArg;
|
this.serviceWindowRef = selfArg;
|
||||||
this.leleServiceWorkerBackend = plugins.leleServiceworker.getServiceWorkerBackend({
|
this.leleServiceWorkerBackend = new ServiceworkerBackend({
|
||||||
self: selfArg,
|
self: selfArg,
|
||||||
purgeCache: async (reqArg) => {
|
purgeCache: async (reqArg) => {
|
||||||
await this.cacheManager.cleanCaches(),
|
await this.cacheManager.cleanCaches(),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import * as plugins from './plugins.js';
|
import * as plugins from './plugins.js';
|
||||||
|
import * as interfaces from '../dist_ts_interfaces/index.js';
|
||||||
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
import { LosslessServiceWorker } from './serviceworker.classes.serviceworker.js';
|
||||||
import { logger } from './serviceworker.logging.js';
|
import { logger } from './serviceworker.logging.js';
|
||||||
import { CacheManager } from './serviceworker.classes.cachemanager.js';
|
import { CacheManager } from './serviceworker.classes.cachemanager.js';
|
||||||
|
|
||||||
export class UpdateManager {
|
export class UpdateManager {
|
||||||
public lastUpdateCheck: number = 0;
|
public lastUpdateCheck: number = 0;
|
||||||
public lastVersionInfo: plugins.lointServiceworker.IRequest_Serviceworker_Backend_VersionInfo['response'];
|
public lastVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'];
|
||||||
|
|
||||||
public serviceworkerRef: LosslessServiceWorker;
|
public serviceworkerRef: LosslessServiceWorker;
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ export class UpdateManager {
|
|||||||
*/
|
*/
|
||||||
public async getVersionInfoFromServer() {
|
public async getVersionInfoFromServer() {
|
||||||
const getAppHashRequest = new plugins.typedrequest.TypedRequest<
|
const getAppHashRequest = new plugins.typedrequest.TypedRequest<
|
||||||
plugins.lointServiceworker.IRequest_Serviceworker_Backend_VersionInfo
|
interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo
|
||||||
>('/lsw-typedrequest', 'serviceworker_versionInfo');
|
>('/lsw-typedrequest', 'serviceworker_versionInfo');
|
||||||
const result = await getAppHashRequest.fire({});
|
const result = await getAppHashRequest.fire({});
|
||||||
return result;
|
return result;
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
import * as plugins from '../lele-serviceworker.plugins.js';
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user