@feasibleone/blong-gogo 1.26.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +4 -2
- package/src/Gateway.ts +8 -0
- package/src/Watch.ts +2 -1
- package/src/favicon.ico +0 -0
- package/src/jwt.ts +2 -1
- package/src/load.ts +15 -11
- package/src/mle.ts +4 -4
- package/src/public.ts +9 -0
- package/src/static.ts +35 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.27.0](https://github.com/feasibleone/blong/compare/blong-gogo-v1.26.0...blong-gogo-v1.27.0) (2026-07-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* compress static assets ([a0a376d](https://github.com/feasibleone/blong/commit/a0a376dc141a8b3041ad0c83895bd3de5675c2e2))
|
|
9
|
+
* static routes ([b544ca3](https://github.com/feasibleone/blong/commit/b544ca3b4c3ed858457c93f21b8523147c30bf59))
|
|
10
|
+
|
|
3
11
|
## [1.26.0](https://github.com/feasibleone/blong/compare/blong-gogo-v1.25.1...blong-gogo-v1.26.0) (2026-07-14)
|
|
4
12
|
|
|
5
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feasibleone/blong-gogo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "git+https://github.com/feasibleone/blong.git"
|
|
6
6
|
},
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"@fastify/cookie": "^11.0.2",
|
|
26
26
|
"@fastify/cors": "^11.2.0",
|
|
27
27
|
"@fastify/deepmerge": "^3.2.1",
|
|
28
|
+
"@fastify/helmet": "^13.1.0",
|
|
29
|
+
"@fastify/static": "^10.1.0",
|
|
28
30
|
"@fastify/swagger": "^9.7.0",
|
|
29
31
|
"@fastify/swagger-ui": "^5.2.5",
|
|
30
32
|
"@fastify/type-provider-typebox": "^6.1.0",
|
|
@@ -84,7 +86,7 @@
|
|
|
84
86
|
"playwright": "^1.60.0",
|
|
85
87
|
"tap": "^21.6.3",
|
|
86
88
|
"typescript": "^6.0.3",
|
|
87
|
-
"@feasibleone/blong-dev": "1.1.
|
|
89
|
+
"@feasibleone/blong-dev": "1.1.1"
|
|
88
90
|
},
|
|
89
91
|
"scripts": {
|
|
90
92
|
"browser-check": "node scripts/browser-compat-check.mjs",
|
package/src/Gateway.ts
CHANGED
|
@@ -83,6 +83,9 @@ interface IConfig extends IConfigMLE {
|
|
|
83
83
|
cache: object;
|
|
84
84
|
audience: string;
|
|
85
85
|
};
|
|
86
|
+
static?: {
|
|
87
|
+
root: string;
|
|
88
|
+
};
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
function operationParams(
|
|
@@ -610,6 +613,11 @@ export default class Gateway extends Internal implements IGateway {
|
|
|
610
613
|
methodId: methodId,
|
|
611
614
|
methodParts: methodParts,
|
|
612
615
|
});
|
|
616
|
+
if (this.#config.static)
|
|
617
|
+
await this.#server.register(
|
|
618
|
+
(await import('./static.ts')).default,
|
|
619
|
+
this.#config.static,
|
|
620
|
+
);
|
|
613
621
|
if (this.#config.cors)
|
|
614
622
|
await this.#server.register((await import('./cors.ts')).default, this.#config.cors);
|
|
615
623
|
if (this.#config.sign || this.#config.encrypt) {
|
package/src/Watch.ts
CHANGED
|
@@ -195,7 +195,8 @@ export default class Watch extends Internal implements IWatch {
|
|
|
195
195
|
},
|
|
196
196
|
[[] as string[], [] as string[]],
|
|
197
197
|
);
|
|
198
|
-
const
|
|
198
|
+
const codeGen = '@sinclair/typebox-codegen';
|
|
199
|
+
const {Formatter, TypeScriptToTypeBox} = await import(/* @vite-ignore */ codeGen);
|
|
199
200
|
if (schema.length)
|
|
200
201
|
this.#platform.writeFileSync(
|
|
201
202
|
this.#platform.join(dir, '~.schema.ts'),
|
package/src/favicon.ico
ADDED
|
Binary file
|
package/src/jwt.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {type Errors, type ILocal} from '@feasibleone/blong/types';
|
|
|
5
5
|
import type {FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest} from 'fastify';
|
|
6
6
|
import fp from 'fastify-plugin';
|
|
7
7
|
import {LRUCache} from 'lru-cache';
|
|
8
|
+
import isPublic from './public.ts';
|
|
8
9
|
|
|
9
10
|
import {type IGatewayCodec} from './GatewayCodec.ts';
|
|
10
11
|
|
|
@@ -65,7 +66,7 @@ export default fp<{
|
|
|
65
66
|
'preValidation',
|
|
66
67
|
function (request: FastifyRequest, reply: FastifyReply, done: (err?: Error) => void) {
|
|
67
68
|
const auth = request.routeOptions.config.auth;
|
|
68
|
-
if (auth !== false && !request.originalUrl
|
|
69
|
+
if (auth !== false && !isPublic(request.originalUrl)) {
|
|
69
70
|
if (auth === 'login') {
|
|
70
71
|
request.auth = {credentials: {mlek: 'header', mlsk: 'header'}};
|
|
71
72
|
done();
|
package/src/load.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {methodParts} from './lib.ts';
|
|
|
25
25
|
import layerProxy from './layerProxy.ts';
|
|
26
26
|
import RealmImpl, {type IRealm} from './Realm.ts';
|
|
27
27
|
import type {IWatch} from './Watch.ts';
|
|
28
|
+
const extension = '.ts';
|
|
28
29
|
|
|
29
30
|
const LAYER_FILE = 'layer' as const;
|
|
30
31
|
|
|
@@ -444,6 +445,7 @@ export default async function loadRealm<T extends TSchema>(
|
|
|
444
445
|
},
|
|
445
446
|
gateway: {
|
|
446
447
|
port: 0,
|
|
448
|
+
static: {},
|
|
447
449
|
// Static development keys, so sessions survive server hot-reloads
|
|
448
450
|
/* cSpell:disable */
|
|
449
451
|
sign: {
|
|
@@ -487,7 +489,7 @@ export default async function loadRealm<T extends TSchema>(
|
|
|
487
489
|
load: () =>
|
|
488
490
|
rootKind === 'browser' && globalThis.window
|
|
489
491
|
? import('./BrowserLog.ts')
|
|
490
|
-
: import('./Log
|
|
492
|
+
: import(/* vite-ignore */ './Log' + extension),
|
|
491
493
|
},
|
|
492
494
|
{
|
|
493
495
|
name: 'apiSchema',
|
|
@@ -551,27 +553,27 @@ export default async function loadRealm<T extends TSchema>(
|
|
|
551
553
|
{
|
|
552
554
|
name: 'remote',
|
|
553
555
|
deps: ['log', 'local'],
|
|
554
|
-
load: () => import('./RpcClient
|
|
556
|
+
load: () => import(/* @vite-ignore */ './RpcClient' + extension),
|
|
555
557
|
},
|
|
556
558
|
{
|
|
557
559
|
name: 'rpcServer',
|
|
558
560
|
deps: ['log'],
|
|
559
|
-
load: () => import('./RpcServer
|
|
561
|
+
load: () => import(/* @vite-ignore */ './RpcServer' + extension),
|
|
560
562
|
},
|
|
561
563
|
{
|
|
562
564
|
name: 'gateway',
|
|
563
565
|
deps: ['log'],
|
|
564
|
-
load: () => import('./Gateway
|
|
566
|
+
load: () => import(/* @vite-ignore */ './Gateway' + extension),
|
|
565
567
|
},
|
|
566
568
|
{
|
|
567
569
|
name: 'restFs',
|
|
568
570
|
deps: ['log', 'gateway'],
|
|
569
|
-
load: () => import('./RestFs
|
|
571
|
+
load: () => import(/* @vite-ignore */ './RestFs' + extension),
|
|
570
572
|
},
|
|
571
573
|
{
|
|
572
574
|
name: 'systemDebug',
|
|
573
575
|
deps: ['log', 'gateway', 'registry', 'rpcServer'],
|
|
574
|
-
load: () => import('./SystemDebug
|
|
576
|
+
load: () => import(/* @vite-ignore */ './SystemDebug' + extension),
|
|
575
577
|
},
|
|
576
578
|
{
|
|
577
579
|
name: 'registry',
|
|
@@ -585,22 +587,22 @@ export default async function loadRealm<T extends TSchema>(
|
|
|
585
587
|
'watch',
|
|
586
588
|
'apiSchema',
|
|
587
589
|
],
|
|
588
|
-
load: () => import('./Registry
|
|
590
|
+
load: () => import(/* @vite-ignore */ './Registry' + extension),
|
|
589
591
|
},
|
|
590
592
|
{
|
|
591
593
|
name: 'codec',
|
|
592
594
|
deps: ['log'],
|
|
593
|
-
load: () => import('./codec/server
|
|
595
|
+
load: () => import(/* @vite-ignore */ './codec/server' + extension),
|
|
594
596
|
},
|
|
595
597
|
{
|
|
596
598
|
name: 'orchestrator',
|
|
597
599
|
deps: ['log'],
|
|
598
|
-
load: () => import('./orchestrator/index
|
|
600
|
+
load: () => import(/* @vite-ignore */ './orchestrator/index' + extension),
|
|
599
601
|
},
|
|
600
602
|
{
|
|
601
603
|
name: 'adapter',
|
|
602
604
|
deps: ['log'],
|
|
603
|
-
load: () => import('./adapter/server
|
|
605
|
+
load: () => import(/* @vite-ignore */ './adapter/server' + extension),
|
|
604
606
|
},
|
|
605
607
|
]),
|
|
606
608
|
]).map(({name, load}) => {
|
|
@@ -777,7 +779,9 @@ export default async function loadRealm<T extends TSchema>(
|
|
|
777
779
|
platformApi.join(destUrl, 'package.json'),
|
|
778
780
|
)
|
|
779
781
|
) {
|
|
780
|
-
const {createRealm} = await import(
|
|
782
|
+
const {createRealm} = await import(
|
|
783
|
+
/* @vite-ignore */ './kopi' + extension
|
|
784
|
+
);
|
|
781
785
|
await createRealm(destUrl, logger);
|
|
782
786
|
const mod = await import(/* @vite-ignore */ fileName);
|
|
783
787
|
return mod.default ?? mod;
|
package/src/mle.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type {FastifyInstance, FastifyRequest} from 'fastify';
|
|
|
2
2
|
import fp from 'fastify-plugin';
|
|
3
3
|
|
|
4
4
|
import jose from './jose.ts';
|
|
5
|
+
import isPublic from './public.ts';
|
|
5
6
|
|
|
6
7
|
export type IConfig = Parameters<typeof jose>[0] & {public: {sign: unknown; encrypt: unknown}};
|
|
7
8
|
|
|
@@ -14,6 +15,7 @@ export default fp<IConfig>(async function mlePlugin(fastify: FastifyInstance, co
|
|
|
14
15
|
fastify.addHook(
|
|
15
16
|
'preValidation',
|
|
16
17
|
async (request: FastifyRequest<{Body: {jsonrpc?: string}}>, reply) => {
|
|
18
|
+
if (isPublic(request.originalUrl)) return;
|
|
17
19
|
if (
|
|
18
20
|
request.routeOptions.config.auth &&
|
|
19
21
|
request.headers['content-type'] === 'application/json'
|
|
@@ -95,6 +97,7 @@ export default fp<IConfig>(async function mlePlugin(fastify: FastifyInstance, co
|
|
|
95
97
|
checkpoints?: unknown;
|
|
96
98
|
},
|
|
97
99
|
) => {
|
|
100
|
+
if (isPublic(request.originalUrl)) return payload;
|
|
98
101
|
if (payload instanceof Error) return payload;
|
|
99
102
|
const mlek =
|
|
100
103
|
request.auth?.credentials?.mlek ||
|
|
@@ -108,10 +111,7 @@ export default fp<IConfig>(async function mlePlugin(fastify: FastifyInstance, co
|
|
|
108
111
|
const encrypt: (message: object) => unknown = message =>
|
|
109
112
|
request.routeOptions.config.mle === false
|
|
110
113
|
? message
|
|
111
|
-
: mle.signEncrypt(
|
|
112
|
-
message,
|
|
113
|
-
mlek as {type: string},
|
|
114
|
-
);
|
|
114
|
+
: mle.signEncrypt(message, mlek as {type: string});
|
|
115
115
|
const where = payload.jsonrpc
|
|
116
116
|
? payload
|
|
117
117
|
: {
|
package/src/public.ts
ADDED
package/src/static.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import helmet from '@fastify/helmet';
|
|
2
|
+
import fastifyStatic from '@fastify/static';
|
|
3
|
+
import type {FastifyInstance} from 'fastify';
|
|
4
|
+
import fp from 'fastify-plugin';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
export type IConfig = {
|
|
8
|
+
root: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default fp<IConfig>(async function staticPlugin(fastify: FastifyInstance, config: IConfig) {
|
|
12
|
+
await fastify.register(helmet, {
|
|
13
|
+
contentSecurityPolicy: false, // Prevents helmet from wasting bytes on images/scripts/JSON
|
|
14
|
+
});
|
|
15
|
+
fastify.get('/favicon.ico', async (_request, reply) => {
|
|
16
|
+
return reply.sendFile('favicon.ico', import.meta.dirname);
|
|
17
|
+
});
|
|
18
|
+
fastify.register(fastifyStatic, {
|
|
19
|
+
root: config.root ?? path.join(process.cwd(), 'dist'),
|
|
20
|
+
prefix: '/s',
|
|
21
|
+
redirect: true,
|
|
22
|
+
preCompressed: true,
|
|
23
|
+
cacheControl: true,
|
|
24
|
+
maxAge: '1y',
|
|
25
|
+
immutable: true,
|
|
26
|
+
setHeaders: (res, filePath) => {
|
|
27
|
+
if (filePath.endsWith('.html')) {
|
|
28
|
+
res.header(
|
|
29
|
+
'Content-Security-Policy',
|
|
30
|
+
"default-src 'self';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline'",
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
});
|