BREAKING CHANGE(typedserver): Migrate to new push.rocks packages and async smartfs API; replace smartchok with smartwatch; update deps and service worker handling

This commit is contained in:
2025-12-02 09:16:42 +00:00
parent bce84c6838
commit 8557c769fa
11 changed files with 1478 additions and 1072 deletions

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@api.global/typedserver',
version: '3.0.80',
version: '4.0.0',
description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.'
}

View File

@@ -73,7 +73,7 @@ export class TypedServer {
// instance
public options: IServerOptions;
public server: servertools.Server;
public smartchokInstance: plugins.smartchok.Smartchok;
public smartwatchInstance: plugins.smartwatch.Smartwatch;
public serveDirHashSubject = new plugins.smartrx.rxjs.ReplaySubject<string>(1);
public serveHash: string = '000000';
public typedsocket: plugins.typedsocket.TypedSocket;
@@ -104,7 +104,8 @@ export class TypedServer {
case 'devtools':
res.setHeader('Content-Type', 'text/javascript');
res.status(200);
res.write(plugins.smartfile.fs.toStringSync(paths.injectBundlePath));
const devtoolsContent = await plugins.fsInstance.file(paths.injectBundlePath).encoding('utf8').read();
res.write(devtoolsContent);
res.end();
break;
case 'reloadcheck':
@@ -192,9 +193,9 @@ export class TypedServer {
if (this.options.watch && this.options.serveDir) {
try {
this.smartchokInstance = new plugins.smartchok.Smartchok([this.options.serveDir]);
await this.smartchokInstance.start();
(await this.smartchokInstance.getObservableFor('change')).subscribe(async () => {
this.smartwatchInstance = new plugins.smartwatch.Smartwatch([this.options.serveDir]);
await this.smartwatchInstance.start();
(await this.smartwatchInstance.getObservableFor('change')).subscribe(async () => {
await this.createServeDirHash();
this.reload();
});
@@ -284,8 +285,8 @@ export class TypedServer {
}
// Stop file watcher
if (this.smartchokInstance) {
tasks.push(stopWithErrorHandling(() => this.smartchokInstance.stop(), 'file watcher'));
if (this.smartwatchInstance) {
tasks.push(stopWithErrorHandling(() => this.smartwatchInstance.stop(), 'file watcher'));
}
await Promise.all(tasks);
@@ -296,10 +297,13 @@ export class TypedServer {
*/
public async createServeDirHash() {
try {
const serveDirHash = await plugins.smartfile.fs.fileTreeToHash(this.options.serveDir, '**/*');
this.serveHash = serveDirHash;
console.log('Current ServeDir hash: ' + serveDirHash);
this.serveDirHashSubject.next(serveDirHash);
const serveDirHash = await plugins.fsInstance
.directory(this.options.serveDir)
.recursive()
.treeHash();
this.serveHash = serveDirHash.slice(0, 12);
console.log('Current ServeDir hash: ' + this.serveHash);
this.serveDirHashSubject.next(this.serveHash);
} catch (error) {
console.error('Failed to create serve directory hash:', error);
// Use a timestamp-based hash as fallback

View File

@@ -3,7 +3,6 @@ import * as http from 'http';
import * as https from 'https';
import * as net from 'net';
import * as path from 'path';
import * as stream from 'stream';
import * as zlib from 'zlib';
export { http, https, net, path, zlib };
@@ -22,10 +21,11 @@ export { typedrequest, typedrequestInterfaces, typedsocket };
// @pushrocks scope
import * as lik from '@push.rocks/lik';
import * as smartchok from '@push.rocks/smartchok';
import * as smartwatch from '@push.rocks/smartwatch';
import * as smartdelay from '@push.rocks/smartdelay';
import * as smartfeed from '@push.rocks/smartfeed';
import * as smartfile from '@push.rocks/smartfile';
import * as smartfs from '@push.rocks/smartfs';
import * as smartjson from '@push.rocks/smartjson';
import * as smartmanifest from '@push.rocks/smartmanifest';
import * as smartmime from '@push.rocks/smartmime';
@@ -40,10 +40,11 @@ import * as smarttime from '@push.rocks/smarttime';
export {
lik,
smartchok,
smartwatch,
smartdelay,
smartfeed,
smartfile,
smartfs,
smartjson,
smartmanifest,
smartmime,
@@ -57,6 +58,9 @@ export {
smartrx,
};
// Create a ready-to-use smartfs instance with Node.js provider
export const fsInstance = new smartfs.SmartFs(new smartfs.SmartFsProviderNode());
// express
import bodyParser from 'body-parser';
import cors from 'cors';

View File

@@ -92,7 +92,7 @@ export class HandlerStatic extends Handler {
// lets actually care about serving, if security checks pass
let fileBuffer: Buffer;
try {
fileBuffer = plugins.smartfile.fs.toBufferSync(joinedPath);
fileBuffer = await plugins.fsInstance.file(joinedPath).read() as Buffer;
usedPath = joinedPath;
} catch (err) {
// try serving index.html instead
@@ -101,7 +101,7 @@ export class HandlerStatic extends Handler {
console.log(`serving default path ${defaultPath} instead of ${joinedPath}`);
try {
parsedPath = plugins.path.parse(defaultPath);
fileBuffer = plugins.smartfile.fs.toBufferSync(defaultPath);
fileBuffer = await plugins.fsInstance.file(defaultPath).read() as Buffer;
usedPath = defaultPath;
} catch (err) {
res.writeHead(500);

View File

@@ -6,17 +6,32 @@ import { Handler } from './classes.handler.js';
import type { TypedServer } from '../classes.typedserver.js';
import { HandlerTypedRouter } from './classes.handlertypedrouter.js';
const swBundleJs: string = plugins.smartfile.fs.toStringSync(
plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js')
);
const swBundleJsMap: string = plugins.smartfile.fs.toStringSync(
plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js.map')
);
// Lazy-loaded service worker bundle content
let swBundleJs: string | null = null;
let swBundleJsMap: string | null = null;
const loadServiceWorkerBundle = async (): Promise<void> => {
if (swBundleJs === null) {
swBundleJs = await plugins.fsInstance
.file(plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js'))
.encoding('utf8')
.read() as string;
}
if (swBundleJsMap === null) {
swBundleJsMap = await plugins.fsInstance
.file(plugins.path.join(paths.serviceworkerBundleDir, './serviceworker.bundle.js.map'))
.encoding('utf8')
.read() as string;
}
};
let swVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response'] =
null;
const serviceworkerHandler = new Handler(
'GET',
async (req, res) => {
await loadServiceWorkerBundle();
if (req.path === '/serviceworker.bundle.js') {
res.status(200);
res.set('Content-Type', 'text/javascript');