fix(core): update
This commit is contained in:
parent
1c5e2845d1
commit
b6d0843e3e
@ -13,7 +13,8 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run build && tstest test/",
|
"test": "npm run build && tstest test/",
|
||||||
"build": "tsbuild tsfolders --web --allowimplicitany --skiplibcheck && tsbundle --from ./ts_web_inject/index.ts --to ./dist_ts_web_inject/bundle.js",
|
"build": "tsbuild tsfolders --web --allowimplicitany --skiplibcheck && npm run bundle",
|
||||||
|
"bundle": "tsbundle --from ./ts_web_inject/index.ts --to ./dist_ts_web_inject/bundle.js && tsbundle --from ./ts_web_serviceworker/index.ts --to ./dist_ts_web_serviceworker/serviceworker.bundle.js",
|
||||||
"interfaces": "tsbuild interfaces --web --allowimplicitany --skiplibcheck",
|
"interfaces": "tsbuild interfaces --web --allowimplicitany --skiplibcheck",
|
||||||
"docs": "tsdoc aidoc"
|
"docs": "tsdoc aidoc"
|
||||||
},
|
},
|
||||||
@ -74,6 +75,7 @@
|
|||||||
"@push.rocks/smartmanifest": "^2.0.2",
|
"@push.rocks/smartmanifest": "^2.0.2",
|
||||||
"@push.rocks/smartmatch": "^2.0.0",
|
"@push.rocks/smartmatch": "^2.0.0",
|
||||||
"@push.rocks/smartmime": "^1.0.5",
|
"@push.rocks/smartmime": "^1.0.5",
|
||||||
|
"@push.rocks/smartntml": "^2.0.4",
|
||||||
"@push.rocks/smartopen": "^2.0.0",
|
"@push.rocks/smartopen": "^2.0.0",
|
||||||
"@push.rocks/smartpath": "^5.0.18",
|
"@push.rocks/smartpath": "^5.0.18",
|
||||||
"@push.rocks/smartpromise": "^4.0.2",
|
"@push.rocks/smartpromise": "^4.0.2",
|
||||||
|
6833
pnpm-lock.yaml
6833
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@api.global/typedserver',
|
name: '@api.global/typedserver',
|
||||||
version: '3.0.34',
|
version: '3.0.35',
|
||||||
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.'
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as plugins from './plugins.js';
|
import * as plugins from './plugins.js';
|
||||||
import * as paths from './typedserver.paths.js';
|
import * as paths from './paths.js';
|
||||||
import * as interfaces from '../dist_ts_interfaces/index.js';
|
import * as interfaces from '../dist_ts_interfaces/index.js';
|
||||||
import * as servertools from './servertools/index.js';
|
import * as servertools from './servertools/index.js';
|
||||||
import { type TCompressionMethod } from './servertools/classes.compressor.js';
|
import { type TCompressionMethod } from './servertools/classes.compressor.js';
|
||||||
@ -103,7 +103,7 @@ export class TypedServer {
|
|||||||
case 'devtools':
|
case 'devtools':
|
||||||
res.setHeader('Content-Type', 'text/javascript');
|
res.setHeader('Content-Type', 'text/javascript');
|
||||||
res.status(200);
|
res.status(200);
|
||||||
res.write(plugins.smartfile.fs.toStringSync(paths.bundlePath));
|
res.write(plugins.smartfile.fs.toStringSync(paths.injectBundlePath));
|
||||||
res.end();
|
res.end();
|
||||||
break;
|
break;
|
||||||
case 'reloadcheck':
|
case 'reloadcheck':
|
@ -4,7 +4,12 @@ import * as servertools from './servertools/index.js';
|
|||||||
|
|
||||||
export { servertools };
|
export { servertools };
|
||||||
|
|
||||||
export * from './typedserver.classes.typedserver.js';
|
export * from './classes.typedserver.js';
|
||||||
// Type helpers
|
// Type helpers
|
||||||
export type Request = plugins.express.Request;
|
export type Request = plugins.express.Request;
|
||||||
export type Response = plugins.express.Response;
|
export type Response = plugins.express.Response;
|
||||||
|
|
||||||
|
|
||||||
|
// lets export utilityservers
|
||||||
|
import * as utilityservers from './utilityservers/index.js';
|
||||||
|
export { utilityservers };
|
||||||
|
8
ts/infohtml/00_commitinfo_data.ts
Normal file
8
ts/infohtml/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @pushrocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@losslessone_private/lole-infohtml',
|
||||||
|
version: '1.0.39',
|
||||||
|
description: 'html for displaying infos at lossless'
|
||||||
|
}
|
44
ts/infohtml/index.ts
Normal file
44
ts/infohtml/index.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import * as plugins from './infohtml.plugins.js';
|
||||||
|
|
||||||
|
import { simpleInfo } from './template.js';
|
||||||
|
|
||||||
|
export interface IHtmlInfoOptions {
|
||||||
|
text: string;
|
||||||
|
heading?: string;
|
||||||
|
title?: string;
|
||||||
|
sentryMessage?: string;
|
||||||
|
sentryDsn?: string;
|
||||||
|
redirectTo?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InfoHtml {
|
||||||
|
// STATIC
|
||||||
|
public static async fromSimpleText(textArg: string) {
|
||||||
|
const infohtmlInstance = new InfoHtml({
|
||||||
|
text: textArg,
|
||||||
|
heading: null,
|
||||||
|
});
|
||||||
|
await infohtmlInstance.init();
|
||||||
|
return infohtmlInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async fromOptions(optionsArg: IHtmlInfoOptions) {
|
||||||
|
const infohtmlInstance = new InfoHtml(optionsArg);
|
||||||
|
await infohtmlInstance.init();
|
||||||
|
return infohtmlInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public options: IHtmlInfoOptions;
|
||||||
|
public smartntmlInstance: plugins.smartntml.Smartntml;
|
||||||
|
public htmlString: string;
|
||||||
|
constructor(optionsArg: IHtmlInfoOptions) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async init() {
|
||||||
|
this.smartntmlInstance = new plugins.smartntml.Smartntml();
|
||||||
|
this.htmlString = await simpleInfo(this.smartntmlInstance, this.options);
|
||||||
|
return this.htmlString;
|
||||||
|
}
|
||||||
|
}
|
3
ts/infohtml/infohtml.plugins.ts
Normal file
3
ts/infohtml/infohtml.plugins.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import * as smartntml from '@push.rocks/smartntml';
|
||||||
|
|
||||||
|
export { smartntml };
|
160
ts/infohtml/template.ts
Normal file
160
ts/infohtml/template.ts
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import * as plugins from './infohtml.plugins.js';
|
||||||
|
import { type IHtmlInfoOptions } from './index.js';
|
||||||
|
|
||||||
|
export const simpleInfo = async (
|
||||||
|
smartntmlInstanceArg: plugins.smartntml.Smartntml,
|
||||||
|
optionsArg: IHtmlInfoOptions
|
||||||
|
) => {
|
||||||
|
const html = plugins.smartntml.deesElement.html;
|
||||||
|
const htmlTemplate = await plugins.smartntml.deesElement.html`
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>${optionsArg.title}</title>
|
||||||
|
<script>
|
||||||
|
setTimeout(() => {
|
||||||
|
const redirectUrl = '${optionsArg.redirectTo}';
|
||||||
|
if (redirectUrl) {
|
||||||
|
window.location = redirectUrl;
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
background: #000000;
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
min-height: 100vh;
|
||||||
|
min-width: 100vw;
|
||||||
|
border: 1px solid #e4002b;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 150px;
|
||||||
|
padding-top: 70px;
|
||||||
|
margin: 0px auto 30px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .maintext {
|
||||||
|
margin: 10px;
|
||||||
|
color: #ffffff;
|
||||||
|
background: #333;
|
||||||
|
display: block;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .maintext h1 {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .addontext {
|
||||||
|
margin: 10px;
|
||||||
|
color: #ffffff;
|
||||||
|
background: #222;
|
||||||
|
display: block;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .text h1 {
|
||||||
|
margin: 0px;
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .text ul {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legal {
|
||||||
|
color: #fff;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0px;
|
||||||
|
width: 100vw;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi"
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
src="https://browser.sentry-cdn.com/5.4.0/bundle.min.js"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
<script>
|
||||||
|
if (optionsArg.sentryDsn && optionsArg.sentryMessage) {
|
||||||
|
Sentry.init({
|
||||||
|
dsn: '${optionsArg.sentryDsn}',
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
Sentry.setExtra('location', window.location.href);
|
||||||
|
Sentry.captureMessage('${optionsArg.sentryMessage} @ ' + window.location.host);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="logo">
|
||||||
|
<img src="https://assetbroker.lossless.one/brandfiles/lossless/svg-minimal-bright.svg" />
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
${(() => {
|
||||||
|
const returnArray: plugins.smartntml.deesElement.TemplateResult[] = [];
|
||||||
|
if (optionsArg.heading) {
|
||||||
|
returnArray.push(html`
|
||||||
|
<div class="maintext">
|
||||||
|
<h1>${optionsArg.heading}</h1>
|
||||||
|
${optionsArg.text}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
returnArray.push(html` <div class="maintext">${optionsArg.text}</div> `);
|
||||||
|
}
|
||||||
|
if (optionsArg.sentryDsn && optionsArg.sentryMessage) {
|
||||||
|
returnArray.push(
|
||||||
|
html`<div class="addontext">
|
||||||
|
We recorded this event. Should you continue to see this page against your
|
||||||
|
expectations, feel free to mail us at
|
||||||
|
<a href="mailto:hello@lossless.com">hello@lossless.com</a>
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (optionsArg.redirectTo) {
|
||||||
|
returnArray.push(
|
||||||
|
html`<div class="addontext">
|
||||||
|
We will redirect you to ${optionsArg.redirectTo} in a few seconds.
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return returnArray;
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
<div class="legal">
|
||||||
|
<a href="https://lossless.com">Lossless GmbH</a> / © 2014-${new Date().getFullYear()}
|
||||||
|
/ <a href="https://lossless.gmbh">Legal Info</a> /
|
||||||
|
<a href="https://lossless.gmbh">Privacy Policy</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
return smartntmlInstanceArg.renderTemplateResult(htmlTemplate);
|
||||||
|
};
|
@ -4,4 +4,8 @@ export const packageDir = plugins.path.join(
|
|||||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||||
'../'
|
'../'
|
||||||
);
|
);
|
||||||
export const distBundleDir = plugins.path.join(packageDir, './dist_bundle');
|
|
||||||
|
export const injectBundleDir = plugins.path.join(packageDir, './dist_ts_web_inject');
|
||||||
|
export const injectBundlePath = plugins.path.join(injectBundleDir, './bundle.js');
|
||||||
|
|
||||||
|
export const serviceworkerBundleDir = plugins.path.join(packageDir, './dist_ts_web_serviceworker');
|
@ -9,7 +9,7 @@ import { setupRobots } from './tools.robots.js';
|
|||||||
import { setupManifest } from './tools.manifest.js';
|
import { setupManifest } from './tools.manifest.js';
|
||||||
import { Sitemap } from './classes.sitemap.js';
|
import { Sitemap } from './classes.sitemap.js';
|
||||||
import { Feed } from './classes.feed.js';
|
import { Feed } from './classes.feed.js';
|
||||||
import { type IServerOptions } from '../typedserver.classes.typedserver.js';
|
import { type IServerOptions } from '../classes.typedserver.js';
|
||||||
export type TServerStatus = 'initiated' | 'running' | 'stopped';
|
export type TServerStatus = 'initiated' | 'running' | 'stopped';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,3 +4,9 @@ export * from './classes.handler.js';
|
|||||||
export * from './classes.handlerstatic.js';
|
export * from './classes.handlerstatic.js';
|
||||||
export * from './classes.handlerproxy.js';
|
export * from './classes.handlerproxy.js';
|
||||||
export * from './classes.handlertypedrouter.js';
|
export * from './classes.handlertypedrouter.js';
|
||||||
|
export * from './classes.compressor.js';
|
||||||
|
import * as serviceworker from './tools.serviceworker.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
serviceworker,
|
||||||
|
}
|
||||||
|
@ -3,28 +3,28 @@ import * as paths from '../paths.js';
|
|||||||
|
|
||||||
import * as interfaces from '../../dist_ts_interfaces/index.js'
|
import * as interfaces from '../../dist_ts_interfaces/index.js'
|
||||||
import { Handler } from './classes.handler.js';
|
import { Handler } from './classes.handler.js';
|
||||||
import type { TypedServer } from '../typedserver.classes.typedserver.js';
|
import type { TypedServer } from '../classes.typedserver.js';
|
||||||
import { HandlerTypedRouter } from './classes.handlertypedrouter.js';
|
import { HandlerTypedRouter } from './classes.handlertypedrouter.js';
|
||||||
|
|
||||||
const lswJS: string = plugins.smartfile.fs.toStringSync(
|
const swBundleJs: string = plugins.smartfile.fs.toStringSync(
|
||||||
plugins.path.join(paths.distBundleDir, './lsw.js')
|
plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js')
|
||||||
);
|
);
|
||||||
const lswJSMeta: string = plugins.smartfile.fs.toStringSync(
|
const swBundleJsMap: string = plugins.smartfile.fs.toStringSync(
|
||||||
plugins.path.join(paths.distBundleDir, './lsw.js.map')
|
plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js.map')
|
||||||
);
|
);
|
||||||
let lswVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'] =
|
let swVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'] =
|
||||||
null;
|
null;
|
||||||
const serviceworkerHandler = new Handler(
|
const serviceworkerHandler = new Handler(
|
||||||
'GET',
|
'GET',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
if (req.path === '/lsw.js') {
|
if (req.path === '/serviceworker.bundle.js') {
|
||||||
res.status(200);
|
res.status(200);
|
||||||
res.set('Content-Type', 'text/javascript');
|
res.set('Content-Type', 'text/javascript');
|
||||||
res.write(lswJS + '\n' + `/** appSemVer: ${lswVersionInfo?.appSemVer || 'not set'} */`);
|
res.write(swBundleJs + '\n' + `/** appSemVer: ${swVersionInfo?.appSemVer || 'not set'} */`);
|
||||||
} else if (req.path === '/lsw.js.map') {
|
} else if (req.path === '/serviceworker.bundle.js.map') {
|
||||||
res.status(200);
|
res.status(200);
|
||||||
res.set('Content-Type', 'application/json');
|
res.set('Content-Type', 'application/json');
|
||||||
res.write(lswJSMeta);
|
res.write(swBundleJsMap);
|
||||||
}
|
}
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
@ -32,13 +32,13 @@ const serviceworkerHandler = new Handler(
|
|||||||
|
|
||||||
export const addServiceWorkerRoute = (
|
export const addServiceWorkerRoute = (
|
||||||
typedserverInstance: TypedServer,
|
typedserverInstance: TypedServer,
|
||||||
lswData: () => interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response']
|
swDataFunc: () => interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response']
|
||||||
) => {
|
) => {
|
||||||
// lets the version info as unique string;
|
// lets the version info as unique string;
|
||||||
lswVersionInfo = lswData();
|
swVersionInfo = swDataFunc();
|
||||||
|
|
||||||
// the basic stuff
|
// the basic stuff
|
||||||
typedserverInstance.server.addRoute('/lsw.js*', serviceworkerHandler);
|
typedserverInstance.server.addRoute('/serviceworker.js*', serviceworkerHandler);
|
||||||
|
|
||||||
// the typed stuff
|
// the typed stuff
|
||||||
const typedrouter = new plugins.typedrequest.TypedRouter();
|
const typedrouter = new plugins.typedrequest.TypedRouter();
|
||||||
@ -47,14 +47,14 @@ export const addServiceWorkerRoute = (
|
|||||||
new plugins.typedrequest.TypedHandler<interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo>(
|
new plugins.typedrequest.TypedHandler<interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo>(
|
||||||
'serviceworker_versionInfo',
|
'serviceworker_versionInfo',
|
||||||
async (req) => {
|
async (req) => {
|
||||||
const versionInfoResponse = lswData();
|
const versionInfoResponse = swDataFunc();
|
||||||
return versionInfoResponse;
|
return versionInfoResponse;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
typedserverInstance.server.addRoute(
|
typedserverInstance.server.addRoute(
|
||||||
'/lsw-typedrequest',
|
'/sw-typedrequest',
|
||||||
new HandlerTypedRouter(typedrouter)
|
new HandlerTypedRouter(typedrouter)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import * as plugins from './plugins.js';
|
|
||||||
|
|
||||||
export const packageDir = plugins.path.join(
|
|
||||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
|
||||||
'../'
|
|
||||||
);
|
|
||||||
|
|
||||||
export const bundlePath = plugins.path.join(packageDir, './dist_ts_web_inject/bundle.js');
|
|
51
ts/utilityservers/classes.serviceserver.ts
Normal file
51
ts/utilityservers/classes.serviceserver.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { TypedServer } from '../classes.typedserver.js';
|
||||||
|
import * as servertools from '../servertools/index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
|
||||||
|
export interface ILoleServiceServerConstructorOptions {
|
||||||
|
addCustomRoutes?: (serverArg: servertools.Server) => Promise<any>;
|
||||||
|
serviceName: string;
|
||||||
|
serviceVersion: string;
|
||||||
|
serviceDomain: string;
|
||||||
|
port?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the main service server
|
||||||
|
export class ServiceServer {
|
||||||
|
public options: ILoleServiceServerConstructorOptions;
|
||||||
|
public typedServer: TypedServer;
|
||||||
|
|
||||||
|
constructor(optionsArg: ILoleServiceServerConstructorOptions) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start() {
|
||||||
|
console.log('starting lole-serviceserver...')
|
||||||
|
this.typedServer = new TypedServer({
|
||||||
|
cors: true,
|
||||||
|
domain: this.options.serviceDomain,
|
||||||
|
forceSsl: false,
|
||||||
|
port: this.options.port || 3000,
|
||||||
|
robots: true,
|
||||||
|
defaultAnswer: async () => {
|
||||||
|
const InfoHtml = (await import('../infohtml/index.js')).InfoHtml;
|
||||||
|
return (
|
||||||
|
await InfoHtml.fromSimpleText(
|
||||||
|
`${this.options.serviceName} (version ${this.options.serviceVersion})`
|
||||||
|
)
|
||||||
|
).htmlString;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets add any custom routes
|
||||||
|
if (this.options.addCustomRoutes) {
|
||||||
|
await this.options.addCustomRoutes(this.typedServer.server);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.typedServer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async stop() {
|
||||||
|
await this.typedServer.stop();
|
||||||
|
}
|
||||||
|
}
|
137
ts/utilityservers/classes.websiteserver.ts
Normal file
137
ts/utilityservers/classes.websiteserver.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
||||||
|
import { type IServerOptions, TypedServer } from '../classes.typedserver.js';
|
||||||
|
import type { Request, Response } from '../index.js';
|
||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
import * as servertools from '../servertools/index.js';
|
||||||
|
|
||||||
|
export interface IUtilityWebsiteServerConstructorOptions {
|
||||||
|
addCustomRoutes?: (serverArg: servertools.Server) => Promise<any>;
|
||||||
|
appSemVer?: string;
|
||||||
|
domain: string;
|
||||||
|
serveDir: string;
|
||||||
|
feedMetadata: IServerOptions['feedMetadata'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the utility website server implements a best practice server for websites
|
||||||
|
* It supports:
|
||||||
|
* * live reload
|
||||||
|
* * compression
|
||||||
|
* * serviceworker
|
||||||
|
* * pwa manifest
|
||||||
|
*/
|
||||||
|
export class UtilityWebsiteServer {
|
||||||
|
public options: IUtilityWebsiteServerConstructorOptions;
|
||||||
|
public typedserver: TypedServer;
|
||||||
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||||
|
|
||||||
|
constructor(optionsArg: IUtilityWebsiteServerConstructorOptions) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public async start(portArg = 3000) {
|
||||||
|
this.typedserver = new TypedServer({
|
||||||
|
cors: true,
|
||||||
|
injectReload: true,
|
||||||
|
watch: true,
|
||||||
|
serveDir: this.options.serveDir,
|
||||||
|
enableCompression: true,
|
||||||
|
preferredCompressionMethod: 'gzip',
|
||||||
|
domain: this.options.domain,
|
||||||
|
forceSsl: false,
|
||||||
|
manifest: {
|
||||||
|
name: this.options.domain,
|
||||||
|
short_name: this.options.domain,
|
||||||
|
start_url: '/',
|
||||||
|
display_override: ['window-controls-overlay'],
|
||||||
|
lang: 'en',
|
||||||
|
background_color: '#000000',
|
||||||
|
scope: '/',
|
||||||
|
},
|
||||||
|
port: portArg,
|
||||||
|
|
||||||
|
// features
|
||||||
|
robots: true,
|
||||||
|
sitemap: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let lswData: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'] =
|
||||||
|
{
|
||||||
|
appHash: 'xxxxxx',
|
||||||
|
appSemVer: this.options.appSemVer || 'x.x.x',
|
||||||
|
};
|
||||||
|
|
||||||
|
// -> /lsw* - anything regarding serviceworker
|
||||||
|
servertools.serviceworker.addServiceWorkerRoute(this.typedserver, () => {
|
||||||
|
return lswData;
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets add ads.txt
|
||||||
|
this.typedserver.server.addRoute(
|
||||||
|
'/ads.txt',
|
||||||
|
new servertools.Handler('GET', async (req, res) => {
|
||||||
|
res.type('txt/plain');
|
||||||
|
const adsTxt =
|
||||||
|
['google.com, pub-4104137977476459, DIRECT, f08c47fec0942fa0'].join('\n') + '\n';
|
||||||
|
res.write(adsTxt);
|
||||||
|
res.end();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.typedserver.server.addRoute(
|
||||||
|
'/assetbroker/manifest/:manifestAsset',
|
||||||
|
new servertools.Handler('GET', async (req, res) => {
|
||||||
|
let manifestAssetName = req.params.manifestAsset;
|
||||||
|
if (manifestAssetName === 'favicon.png') {
|
||||||
|
manifestAssetName = `favicon_${this.options.domain
|
||||||
|
.replace('.', '')
|
||||||
|
.replace('losslesscom', 'lossless')}@2x_transparent.png`;
|
||||||
|
}
|
||||||
|
const fullOriginAssetUrl = `https://assetbroker.lossless.one/brandfiles/00general/${manifestAssetName}`;
|
||||||
|
console.log(`Getting ${manifestAssetName} from ${fullOriginAssetUrl}`);
|
||||||
|
const dataBuffer: Buffer = (await plugins.smartrequest.getBinary(fullOriginAssetUrl)).body;
|
||||||
|
res.type('.png');
|
||||||
|
res.write(dataBuffer);
|
||||||
|
res.end();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// lets add any custom routes
|
||||||
|
if (this.options.addCustomRoutes) {
|
||||||
|
await this.options.addCustomRoutes(this.typedserver.server);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -> /* - serve the files
|
||||||
|
this.typedserver.serveDirHashSubject.subscribe((appHash: string) => {
|
||||||
|
lswData = {
|
||||||
|
appHash,
|
||||||
|
appSemVer: '1.0.0',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets setup the typedrouter chain
|
||||||
|
this.typedserver.typedrouter.addTypedRouter(this.typedrouter);
|
||||||
|
|
||||||
|
// lets start everything
|
||||||
|
console.log('routes are all set. Startin up now!');
|
||||||
|
await this.typedserver.start();
|
||||||
|
console.log('typedserver started!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async stop() {
|
||||||
|
await this.typedserver.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allows you to hanlde requests from other server instances without the need to listen for yourself
|
||||||
|
* note smartexpress allows you start the instance wuith passing >>false<< as second parameter to .start();
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
public async handleRequest(req: Request, res: Response) {
|
||||||
|
await this.typedserver.server.handleReqRes(req, res);
|
||||||
|
}
|
||||||
|
}
|
0
ts/utilityservers/index.ts
Normal file
0
ts/utilityservers/index.ts
Normal file
@ -61,7 +61,7 @@ export class UpdateManager {
|
|||||||
public async getVersionInfoFromServer() {
|
public async getVersionInfoFromServer() {
|
||||||
const getAppHashRequest = new plugins.typedrequest.TypedRequest<
|
const getAppHashRequest = new plugins.typedrequest.TypedRequest<
|
||||||
interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo
|
interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo
|
||||||
>('/lsw-typedrequest', 'serviceworker_versionInfo');
|
>('/sw-typedrequest', 'serviceworker_versionInfo');
|
||||||
const result = await getAppHashRequest.fire({});
|
const result = await getAppHashRequest.fire({});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user