@ovineko/spa-guard-fastify 0.0.1-alpha-24 → 0.0.1-alpha-26
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/README.md +100 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +27 -1
- package/package.json +9 -5
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# @ovineko/spa-guard-fastify
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ovineko/spa-guard-fastify)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
Fastify plugin for spa-guard beacon endpoint and HTML cache handler with ETag/304 support.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @ovineko/spa-guard-fastify @ovineko/spa-guard-node fastify fastify-plugin
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Beacon endpoint
|
|
17
|
+
|
|
18
|
+
Register the plugin to receive beacon data posted by the spa-guard client runtime:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import Fastify from "fastify";
|
|
22
|
+
import { fastifySPAGuard } from "@ovineko/spa-guard-fastify";
|
|
23
|
+
|
|
24
|
+
const app = Fastify();
|
|
25
|
+
|
|
26
|
+
app.addContentTypeParser("text/plain", { parseAs: "string" }, (_req, body, done) => {
|
|
27
|
+
done(null, body);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
app.register(fastifySPAGuard, {
|
|
31
|
+
path: "/api/beacon",
|
|
32
|
+
onBeacon: async (beacon, request, reply) => {
|
|
33
|
+
request.log.info({ beacon }, "SPA Guard beacon received");
|
|
34
|
+
// optionally suppress default log
|
|
35
|
+
return { skipDefaultLog: true };
|
|
36
|
+
},
|
|
37
|
+
onUnknownBeacon: async (body, request) => {
|
|
38
|
+
request.log.warn({ body }, "Unknown beacon format");
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await app.listen({ port: 3000 });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### HTML cache handler
|
|
46
|
+
|
|
47
|
+
Serve your SPA's `index.html` with ETag/304 and compression negotiation:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createReadStream } from "node:fs";
|
|
51
|
+
import { spaGuardFastifyHandler } from "@ovineko/spa-guard-fastify";
|
|
52
|
+
import { createHtmlCache } from "@ovineko/spa-guard-node";
|
|
53
|
+
|
|
54
|
+
const handlerOptions = {};
|
|
55
|
+
|
|
56
|
+
app.get("/*", async (request, reply) => {
|
|
57
|
+
return spaGuardFastifyHandler(request, reply, {
|
|
58
|
+
...handlerOptions,
|
|
59
|
+
getHtml: () => ({ html: "<html>...</html>" }),
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## API
|
|
65
|
+
|
|
66
|
+
### `fastifySPAGuard` (Fastify plugin)
|
|
67
|
+
|
|
68
|
+
Registers a `POST` route at `options.path` to receive beacon payloads.
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
|
|
72
|
+
- `path` (required) - Route path for the beacon endpoint, e.g. `"/api/beacon"`
|
|
73
|
+
- `onBeacon(beacon, request, reply)` - Called with parsed beacon data. Return `{ skipDefaultLog: true }` to suppress default logging.
|
|
74
|
+
- `onUnknownBeacon(body, request, reply)` - Called when beacon fails schema validation. Return `{ skipDefaultLog: true }` to suppress default warning.
|
|
75
|
+
|
|
76
|
+
### `spaGuardFastifyHandler(request, reply, options)`
|
|
77
|
+
|
|
78
|
+
Fastify request handler that serves HTML with ETag/304 and content-encoding negotiation.
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
|
|
82
|
+
- `cache` - Pre-built `HtmlCache` instance
|
|
83
|
+
- `getHtml()` - Async factory returning `CreateHtmlCacheOptions`; cache is created lazily on first request
|
|
84
|
+
|
|
85
|
+
### Exported types
|
|
86
|
+
|
|
87
|
+
- `FastifySPAGuardOptions`
|
|
88
|
+
- `SpaGuardHandlerOptions`
|
|
89
|
+
- `BeaconHandlerResult`
|
|
90
|
+
- `BeaconError`
|
|
91
|
+
|
|
92
|
+
## Related packages
|
|
93
|
+
|
|
94
|
+
- [@ovineko/spa-guard](../spa-guard/README.md) - Core package
|
|
95
|
+
- [@ovineko/spa-guard-node](../node/README.md) - Node.js HTML cache
|
|
96
|
+
- [@ovineko/spa-guard-vite](../vite/README.md) - Vite build plugin
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FastifyPluginAsync, FastifyReply, FastifyRequest } from "fastify";
|
|
2
|
+
import type { CreateHtmlCacheOptions, HtmlCache } from "@ovineko/spa-guard-node";
|
|
2
3
|
import type { BeaconSchema } from "@ovineko/spa-guard/schema";
|
|
3
4
|
export { BeaconError } from "@ovineko/spa-guard";
|
|
4
5
|
export interface BeaconHandlerResult {
|
|
@@ -31,3 +32,10 @@ export interface FastifySPAGuardOptions {
|
|
|
31
32
|
path: string;
|
|
32
33
|
}
|
|
33
34
|
export declare const fastifySPAGuard: FastifyPluginAsync<FastifySPAGuardOptions>;
|
|
35
|
+
export interface SpaGuardHandlerOptions {
|
|
36
|
+
/** @internal Promise used to deduplicate concurrent lazy cache creation */
|
|
37
|
+
_cachePromise?: Promise<HtmlCache>;
|
|
38
|
+
cache?: HtmlCache;
|
|
39
|
+
getHtml?: (() => CreateHtmlCacheOptions) | (() => Promise<CreateHtmlCacheOptions>);
|
|
40
|
+
}
|
|
41
|
+
export declare function spaGuardFastifyHandler(request: FastifyRequest, reply: FastifyReply, options: SpaGuardHandlerOptions): Promise<FastifyReply>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { createHtmlCache } from "@ovineko/spa-guard-node";
|
|
2
3
|
import fp from "fastify-plugin";
|
|
3
4
|
import { BeaconError } from "@ovineko/spa-guard";
|
|
4
5
|
import { logMessage } from "@ovineko/spa-guard/_internal";
|
|
@@ -82,7 +83,32 @@ var fastifySPAGuard = fp(fastifySPAGuardPlugin, {
|
|
|
82
83
|
fastify: "5.x || 4.x",
|
|
83
84
|
name: `${name}/fastify`
|
|
84
85
|
});
|
|
86
|
+
async function spaGuardFastifyHandler(request, reply, options) {
|
|
87
|
+
const { getHtml } = options;
|
|
88
|
+
if (!options.cache && !getHtml) {
|
|
89
|
+
throw new Error("spaGuardFastifyHandler requires either 'cache' or 'getHtml' option");
|
|
90
|
+
}
|
|
91
|
+
if (!options.cache && getHtml) {
|
|
92
|
+
options._cachePromise ??= (async () => createHtmlCache(await getHtml()))().catch(
|
|
93
|
+
(error) => {
|
|
94
|
+
options._cachePromise = void 0;
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
options.cache = await options._cachePromise;
|
|
99
|
+
}
|
|
100
|
+
const cache = options.cache;
|
|
101
|
+
const acceptEncoding = request.headers["accept-encoding"];
|
|
102
|
+
const acceptLanguage = request.headers["accept-language"];
|
|
103
|
+
const ifNoneMatch = request.headers["if-none-match"];
|
|
104
|
+
const response = cache.get({ acceptEncoding, acceptLanguage, ifNoneMatch });
|
|
105
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
106
|
+
reply.header(key, value);
|
|
107
|
+
}
|
|
108
|
+
return reply.status(response.statusCode).send(response.body);
|
|
109
|
+
}
|
|
85
110
|
export {
|
|
86
111
|
BeaconError,
|
|
87
|
-
fastifySPAGuard
|
|
112
|
+
fastifySPAGuard,
|
|
113
|
+
spaGuardFastifyHandler
|
|
88
114
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ovineko/spa-guard-fastify",
|
|
3
|
-
"version": "0.0.1-alpha-
|
|
4
|
-
"description": "Fastify plugin for spa-guard beacon endpoint",
|
|
3
|
+
"version": "0.0.1-alpha-26",
|
|
4
|
+
"description": "Fastify plugin for spa-guard beacon endpoint and HTML cache handler with ETag/304",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spa",
|
|
7
7
|
"fastify",
|
|
8
8
|
"beacon",
|
|
9
|
-
"monitoring"
|
|
9
|
+
"monitoring",
|
|
10
|
+
"etag",
|
|
11
|
+
"cache",
|
|
12
|
+
"html"
|
|
10
13
|
],
|
|
11
14
|
"homepage": "https://github.com/ovineko/ovineko/tree/main/spa-guard/fastify",
|
|
12
15
|
"bugs": {
|
|
@@ -31,11 +34,12 @@
|
|
|
31
34
|
"dist"
|
|
32
35
|
],
|
|
33
36
|
"dependencies": {
|
|
34
|
-
"@ovineko/spa-guard": "0.0.1-alpha-
|
|
37
|
+
"@ovineko/spa-guard": "0.0.1-alpha-26"
|
|
35
38
|
},
|
|
36
39
|
"peerDependencies": {
|
|
37
40
|
"fastify": "^5 || ^4",
|
|
38
|
-
"fastify-plugin": "^5 || ^4"
|
|
41
|
+
"fastify-plugin": "^5 || ^4",
|
|
42
|
+
"@ovineko/spa-guard-node": "0.0.1-alpha-26"
|
|
39
43
|
},
|
|
40
44
|
"engines": {
|
|
41
45
|
"node": ">=22.15.0"
|