rust-node-cache 0.1.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/LICENSE +21 -0
- package/README.md +390 -0
- package/binding.d.ts +54 -0
- package/binding.js +315 -0
- package/dist/express.d.mts +34 -0
- package/dist/express.d.ts +34 -0
- package/dist/express.js +58 -0
- package/dist/express.js.map +1 -0
- package/dist/express.mjs +33 -0
- package/dist/express.mjs.map +1 -0
- package/dist/fastify.d.mts +33 -0
- package/dist/fastify.d.ts +33 -0
- package/dist/fastify.js +73 -0
- package/dist/fastify.js.map +1 -0
- package/dist/fastify.mjs +48 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/index.d.mts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +56 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nestjs.d.mts +46 -0
- package/dist/nestjs.d.ts +46 -0
- package/dist/nestjs.js +61 -0
- package/dist/nestjs.js.map +1 -0
- package/dist/nestjs.mjs +36 -0
- package/dist/nestjs.mjs.map +1 -0
- package/package.json +109 -0
- package/rust-node-cache.darwin-arm64.node +0 -0
- package/rust-node-cache.darwin-x64.node +0 -0
- package/rust-node-cache.linux-arm64-gnu.node +0 -0
- package/rust-node-cache.linux-x64-gnu.node +0 -0
- package/rust-node-cache.win32-x64-msvc.node +0 -0
package/binding.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'rust-node-cache.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./rust-node-cache.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('rust-node-cache-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'rust-node-cache.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./rust-node-cache.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('rust-node-cache-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'rust-node-cache.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./rust-node-cache.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('rust-node-cache-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'rust-node-cache.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./rust-node-cache.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('rust-node-cache-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'rust-node-cache.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./rust-node-cache.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('rust-node-cache-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'rust-node-cache.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./rust-node-cache.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('rust-node-cache-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'rust-node-cache.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./rust-node-cache.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('rust-node-cache-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'rust-node-cache.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./rust-node-cache.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('rust-node-cache-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'rust-node-cache.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./rust-node-cache.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('rust-node-cache-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'rust-node-cache.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./rust-node-cache.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('rust-node-cache-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'rust-node-cache.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./rust-node-cache.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('rust-node-cache-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'rust-node-cache.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./rust-node-cache.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('rust-node-cache-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'rust-node-cache.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./rust-node-cache.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('rust-node-cache-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'rust-node-cache.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./rust-node-cache.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('rust-node-cache-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'rust-node-cache.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./rust-node-cache.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('rust-node-cache-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'rust-node-cache.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./rust-node-cache.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('rust-node-cache-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'rust-node-cache.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./rust-node-cache.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('rust-node-cache-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'rust-node-cache.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./rust-node-cache.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('rust-node-cache-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { Cache } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.Cache = Cache
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { Cache } from './index.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Integração com Express: cache de respostas JSON.
|
|
6
|
+
*
|
|
7
|
+
* Uso:
|
|
8
|
+
* import { Cache } from "rust-node-cache";
|
|
9
|
+
* import { cacheMiddleware } from "rust-node-cache/express";
|
|
10
|
+
*
|
|
11
|
+
* const cache = new Cache();
|
|
12
|
+
* app.get("/users/:id", cacheMiddleware({ cache, ttlSeconds: 60 }), handler);
|
|
13
|
+
*
|
|
14
|
+
* O middleware intercepta `res.json`: num HIT responde direto do cache; num
|
|
15
|
+
* MISS deixa o handler rodar e guarda o corpo da resposta (apenas em 2xx).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface CacheMiddlewareOptions {
|
|
19
|
+
/** Instância de cache a usar. */
|
|
20
|
+
cache: Cache;
|
|
21
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
22
|
+
ttlSeconds?: number;
|
|
23
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
24
|
+
methods?: string[];
|
|
25
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
26
|
+
keyGenerator?: (req: Request) => string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Cria um middleware Express que cacheia respostas JSON. Adiciona o cabeçalho
|
|
30
|
+
* `X-Cache: HIT|MISS` para facilitar a observabilidade.
|
|
31
|
+
*/
|
|
32
|
+
declare function cacheMiddleware(options: CacheMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
33
|
+
|
|
34
|
+
export { type CacheMiddlewareOptions, cacheMiddleware };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { Cache } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Integração com Express: cache de respostas JSON.
|
|
6
|
+
*
|
|
7
|
+
* Uso:
|
|
8
|
+
* import { Cache } from "rust-node-cache";
|
|
9
|
+
* import { cacheMiddleware } from "rust-node-cache/express";
|
|
10
|
+
*
|
|
11
|
+
* const cache = new Cache();
|
|
12
|
+
* app.get("/users/:id", cacheMiddleware({ cache, ttlSeconds: 60 }), handler);
|
|
13
|
+
*
|
|
14
|
+
* O middleware intercepta `res.json`: num HIT responde direto do cache; num
|
|
15
|
+
* MISS deixa o handler rodar e guarda o corpo da resposta (apenas em 2xx).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface CacheMiddlewareOptions {
|
|
19
|
+
/** Instância de cache a usar. */
|
|
20
|
+
cache: Cache;
|
|
21
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
22
|
+
ttlSeconds?: number;
|
|
23
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
24
|
+
methods?: string[];
|
|
25
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
26
|
+
keyGenerator?: (req: Request) => string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Cria um middleware Express que cacheia respostas JSON. Adiciona o cabeçalho
|
|
30
|
+
* `X-Cache: HIT|MISS` para facilitar a observabilidade.
|
|
31
|
+
*/
|
|
32
|
+
declare function cacheMiddleware(options: CacheMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
33
|
+
|
|
34
|
+
export { type CacheMiddlewareOptions, cacheMiddleware };
|
package/dist/express.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// js/express.ts
|
|
21
|
+
var express_exports = {};
|
|
22
|
+
__export(express_exports, {
|
|
23
|
+
cacheMiddleware: () => cacheMiddleware
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(express_exports);
|
|
26
|
+
function cacheMiddleware(options) {
|
|
27
|
+
const { cache } = options;
|
|
28
|
+
const ttlSeconds = options.ttlSeconds;
|
|
29
|
+
const methods = options.methods ?? ["GET"];
|
|
30
|
+
const keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.originalUrl}`);
|
|
31
|
+
return function rustNodeCache(req, res, next) {
|
|
32
|
+
if (!methods.includes(req.method)) {
|
|
33
|
+
next();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const key = keyGenerator(req);
|
|
37
|
+
const cached = cache.get(key);
|
|
38
|
+
if (cached !== null) {
|
|
39
|
+
res.setHeader("X-Cache", "HIT");
|
|
40
|
+
res.json(cached);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
res.setHeader("X-Cache", "MISS");
|
|
44
|
+
const originalJson = res.json.bind(res);
|
|
45
|
+
res.json = (body) => {
|
|
46
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
47
|
+
cache.set(key, body, ttlSeconds ? { ttlSeconds } : void 0);
|
|
48
|
+
}
|
|
49
|
+
return originalJson(body);
|
|
50
|
+
};
|
|
51
|
+
next();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
55
|
+
0 && (module.exports = {
|
|
56
|
+
cacheMiddleware
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/express.ts"],"sourcesContent":["/**\n * Integração com Express: cache de respostas JSON.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { cacheMiddleware } from \"rust-node-cache/express\";\n *\n * const cache = new Cache();\n * app.get(\"/users/:id\", cacheMiddleware({ cache, ttlSeconds: 60 }), handler);\n *\n * O middleware intercepta `res.json`: num HIT responde direto do cache; num\n * MISS deixa o handler rodar e guarda o corpo da resposta (apenas em 2xx).\n */\n\nimport type { Request, Response, NextFunction } from \"express\";\nimport type { Cache } from \"./index\";\n\nexport interface CacheMiddlewareOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: Request) => string;\n}\n\n/**\n * Cria um middleware Express que cacheia respostas JSON. Adiciona o cabeçalho\n * `X-Cache: HIT|MISS` para facilitar a observabilidade.\n */\nexport function cacheMiddleware(options: CacheMiddlewareOptions) {\n const { cache } = options;\n const ttlSeconds = options.ttlSeconds;\n const methods = options.methods ?? [\"GET\"];\n const keyGenerator =\n options.keyGenerator ?? ((req: Request) => `${req.method}:${req.originalUrl}`);\n\n return function rustNodeCache(\n req: Request,\n res: Response,\n next: NextFunction,\n ): void {\n if (!methods.includes(req.method)) {\n next();\n return;\n }\n\n const key = keyGenerator(req);\n const cached = cache.get(key);\n if (cached !== null) {\n res.setHeader(\"X-Cache\", \"HIT\");\n res.json(cached);\n return;\n }\n\n res.setHeader(\"X-Cache\", \"MISS\");\n const originalJson = res.json.bind(res);\n res.json = (body: unknown): Response => {\n // Só guardamos respostas bem-sucedidas (2xx).\n if (res.statusCode >= 200 && res.statusCode < 300) {\n cache.set(key, body, ttlSeconds ? { ttlSeconds } : undefined);\n }\n return originalJson(body);\n };\n\n next();\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCO,SAAS,gBAAgB,SAAiC;AAC/D,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,aAAa,QAAQ;AAC3B,QAAM,UAAU,QAAQ,WAAW,CAAC,KAAK;AACzC,QAAM,eACJ,QAAQ,iBAAiB,CAAC,QAAiB,GAAG,IAAI,MAAM,IAAI,IAAI,WAAW;AAE7E,SAAO,SAAS,cACd,KACA,KACA,MACM;AACN,QAAI,CAAC,QAAQ,SAAS,IAAI,MAAM,GAAG;AACjC,WAAK;AACL;AAAA,IACF;AAEA,UAAM,MAAM,aAAa,GAAG;AAC5B,UAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,QAAI,WAAW,MAAM;AACnB,UAAI,UAAU,WAAW,KAAK;AAC9B,UAAI,KAAK,MAAM;AACf;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,MAAM;AAC/B,UAAM,eAAe,IAAI,KAAK,KAAK,GAAG;AACtC,QAAI,OAAO,CAAC,SAA4B;AAEtC,UAAI,IAAI,cAAc,OAAO,IAAI,aAAa,KAAK;AACjD,cAAM,IAAI,KAAK,MAAM,aAAa,EAAE,WAAW,IAAI,MAAS;AAAA,MAC9D;AACA,aAAO,aAAa,IAAI;AAAA,IAC1B;AAEA,SAAK;AAAA,EACP;AACF;","names":[]}
|
package/dist/express.mjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// js/express.ts
|
|
2
|
+
function cacheMiddleware(options) {
|
|
3
|
+
const { cache } = options;
|
|
4
|
+
const ttlSeconds = options.ttlSeconds;
|
|
5
|
+
const methods = options.methods ?? ["GET"];
|
|
6
|
+
const keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.originalUrl}`);
|
|
7
|
+
return function rustNodeCache(req, res, next) {
|
|
8
|
+
if (!methods.includes(req.method)) {
|
|
9
|
+
next();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const key = keyGenerator(req);
|
|
13
|
+
const cached = cache.get(key);
|
|
14
|
+
if (cached !== null) {
|
|
15
|
+
res.setHeader("X-Cache", "HIT");
|
|
16
|
+
res.json(cached);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
res.setHeader("X-Cache", "MISS");
|
|
20
|
+
const originalJson = res.json.bind(res);
|
|
21
|
+
res.json = (body) => {
|
|
22
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
23
|
+
cache.set(key, body, ttlSeconds ? { ttlSeconds } : void 0);
|
|
24
|
+
}
|
|
25
|
+
return originalJson(body);
|
|
26
|
+
};
|
|
27
|
+
next();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
cacheMiddleware
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=express.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/express.ts"],"sourcesContent":["/**\n * Integração com Express: cache de respostas JSON.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { cacheMiddleware } from \"rust-node-cache/express\";\n *\n * const cache = new Cache();\n * app.get(\"/users/:id\", cacheMiddleware({ cache, ttlSeconds: 60 }), handler);\n *\n * O middleware intercepta `res.json`: num HIT responde direto do cache; num\n * MISS deixa o handler rodar e guarda o corpo da resposta (apenas em 2xx).\n */\n\nimport type { Request, Response, NextFunction } from \"express\";\nimport type { Cache } from \"./index\";\n\nexport interface CacheMiddlewareOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: Request) => string;\n}\n\n/**\n * Cria um middleware Express que cacheia respostas JSON. Adiciona o cabeçalho\n * `X-Cache: HIT|MISS` para facilitar a observabilidade.\n */\nexport function cacheMiddleware(options: CacheMiddlewareOptions) {\n const { cache } = options;\n const ttlSeconds = options.ttlSeconds;\n const methods = options.methods ?? [\"GET\"];\n const keyGenerator =\n options.keyGenerator ?? ((req: Request) => `${req.method}:${req.originalUrl}`);\n\n return function rustNodeCache(\n req: Request,\n res: Response,\n next: NextFunction,\n ): void {\n if (!methods.includes(req.method)) {\n next();\n return;\n }\n\n const key = keyGenerator(req);\n const cached = cache.get(key);\n if (cached !== null) {\n res.setHeader(\"X-Cache\", \"HIT\");\n res.json(cached);\n return;\n }\n\n res.setHeader(\"X-Cache\", \"MISS\");\n const originalJson = res.json.bind(res);\n res.json = (body: unknown): Response => {\n // Só guardamos respostas bem-sucedidas (2xx).\n if (res.statusCode >= 200 && res.statusCode < 300) {\n cache.set(key, body, ttlSeconds ? { ttlSeconds } : undefined);\n }\n return originalJson(body);\n };\n\n next();\n };\n}\n"],"mappings":";AAgCO,SAAS,gBAAgB,SAAiC;AAC/D,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,aAAa,QAAQ;AAC3B,QAAM,UAAU,QAAQ,WAAW,CAAC,KAAK;AACzC,QAAM,eACJ,QAAQ,iBAAiB,CAAC,QAAiB,GAAG,IAAI,MAAM,IAAI,IAAI,WAAW;AAE7E,SAAO,SAAS,cACd,KACA,KACA,MACM;AACN,QAAI,CAAC,QAAQ,SAAS,IAAI,MAAM,GAAG;AACjC,WAAK;AACL;AAAA,IACF;AAEA,UAAM,MAAM,aAAa,GAAG;AAC5B,UAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,QAAI,WAAW,MAAM;AACnB,UAAI,UAAU,WAAW,KAAK;AAC9B,UAAI,KAAK,MAAM;AACf;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,MAAM;AAC/B,UAAM,eAAe,IAAI,KAAK,KAAK,GAAG;AACtC,QAAI,OAAO,CAAC,SAA4B;AAEtC,UAAI,IAAI,cAAc,OAAO,IAAI,aAAa,KAAK;AACjD,cAAM,IAAI,KAAK,MAAM,aAAa,EAAE,WAAW,IAAI,MAAS;AAAA,MAC9D;AACA,aAAO,aAAa,IAAI;AAAA,IAC1B;AAEA,SAAK;AAAA,EACP;AACF;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FastifyRequest, FastifyInstance } from 'fastify';
|
|
2
|
+
import { Cache } from './index.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Integração com Fastify: cache de respostas JSON via plugin.
|
|
6
|
+
*
|
|
7
|
+
* Uso:
|
|
8
|
+
* import { Cache } from "rust-node-cache";
|
|
9
|
+
* import { cachePlugin } from "rust-node-cache/fastify";
|
|
10
|
+
*
|
|
11
|
+
* const cache = new Cache();
|
|
12
|
+
* fastify.register(cachePlugin, { cache, ttlSeconds: 60 });
|
|
13
|
+
*
|
|
14
|
+
* Fluxo: o hook `onRequest` checa o cache e, num HIT, responde imediatamente
|
|
15
|
+
* (curto-circuito). Num MISS, o hook `onSend` guarda o payload serializado.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface CachePluginOptions {
|
|
19
|
+
/** Instância de cache a usar. */
|
|
20
|
+
cache: Cache;
|
|
21
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
22
|
+
ttlSeconds?: number;
|
|
23
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
24
|
+
methods?: string[];
|
|
25
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
26
|
+
keyGenerator?: (req: FastifyRequest) => string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Plugin Fastify que cacheia respostas JSON. Use com `fastify.register`.
|
|
30
|
+
*/
|
|
31
|
+
declare function cachePlugin(fastify: FastifyInstance, options: CachePluginOptions): Promise<void>;
|
|
32
|
+
|
|
33
|
+
export { type CachePluginOptions, cachePlugin };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FastifyRequest, FastifyInstance } from 'fastify';
|
|
2
|
+
import { Cache } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Integração com Fastify: cache de respostas JSON via plugin.
|
|
6
|
+
*
|
|
7
|
+
* Uso:
|
|
8
|
+
* import { Cache } from "rust-node-cache";
|
|
9
|
+
* import { cachePlugin } from "rust-node-cache/fastify";
|
|
10
|
+
*
|
|
11
|
+
* const cache = new Cache();
|
|
12
|
+
* fastify.register(cachePlugin, { cache, ttlSeconds: 60 });
|
|
13
|
+
*
|
|
14
|
+
* Fluxo: o hook `onRequest` checa o cache e, num HIT, responde imediatamente
|
|
15
|
+
* (curto-circuito). Num MISS, o hook `onSend` guarda o payload serializado.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface CachePluginOptions {
|
|
19
|
+
/** Instância de cache a usar. */
|
|
20
|
+
cache: Cache;
|
|
21
|
+
/** TTL aplicado às respostas guardadas (em segundos). */
|
|
22
|
+
ttlSeconds?: number;
|
|
23
|
+
/** Métodos HTTP elegíveis para cache. Padrão: `["GET"]`. */
|
|
24
|
+
methods?: string[];
|
|
25
|
+
/** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */
|
|
26
|
+
keyGenerator?: (req: FastifyRequest) => string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Plugin Fastify que cacheia respostas JSON. Use com `fastify.register`.
|
|
30
|
+
*/
|
|
31
|
+
declare function cachePlugin(fastify: FastifyInstance, options: CachePluginOptions): Promise<void>;
|
|
32
|
+
|
|
33
|
+
export { type CachePluginOptions, cachePlugin };
|
package/dist/fastify.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// js/fastify.ts
|
|
21
|
+
var fastify_exports = {};
|
|
22
|
+
__export(fastify_exports, {
|
|
23
|
+
cachePlugin: () => cachePlugin
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(fastify_exports);
|
|
26
|
+
var CACHE_KEY = /* @__PURE__ */ Symbol("rustNodeCacheKey");
|
|
27
|
+
async function cachePlugin(fastify, options) {
|
|
28
|
+
const { cache } = options;
|
|
29
|
+
const ttlSeconds = options.ttlSeconds;
|
|
30
|
+
const methods = options.methods ?? ["GET"];
|
|
31
|
+
const keyGenerator = options.keyGenerator ?? ((req) => `${req.method}:${req.url}`);
|
|
32
|
+
fastify.addHook(
|
|
33
|
+
"onRequest",
|
|
34
|
+
(request, reply, done) => {
|
|
35
|
+
if (!methods.includes(request.method)) {
|
|
36
|
+
done();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const key = keyGenerator(request);
|
|
40
|
+
const cached = cache.get(key);
|
|
41
|
+
if (cached !== null) {
|
|
42
|
+
reply.header("X-Cache", "HIT");
|
|
43
|
+
reply.send(cached);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
reply.header("X-Cache", "MISS");
|
|
47
|
+
request[CACHE_KEY] = key;
|
|
48
|
+
done();
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
fastify.addHook(
|
|
52
|
+
"onSend",
|
|
53
|
+
(request, reply, payload, done) => {
|
|
54
|
+
const key = request[CACHE_KEY];
|
|
55
|
+
if (key && typeof payload === "string" && reply.statusCode >= 200 && reply.statusCode < 300) {
|
|
56
|
+
try {
|
|
57
|
+
cache.set(
|
|
58
|
+
key,
|
|
59
|
+
JSON.parse(payload),
|
|
60
|
+
ttlSeconds ? { ttlSeconds } : void 0
|
|
61
|
+
);
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
done(null, payload);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
+
0 && (module.exports = {
|
|
71
|
+
cachePlugin
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../js/fastify.ts"],"sourcesContent":["/**\n * Integração com Fastify: cache de respostas JSON via plugin.\n *\n * Uso:\n * import { Cache } from \"rust-node-cache\";\n * import { cachePlugin } from \"rust-node-cache/fastify\";\n *\n * const cache = new Cache();\n * fastify.register(cachePlugin, { cache, ttlSeconds: 60 });\n *\n * Fluxo: o hook `onRequest` checa o cache e, num HIT, responde imediatamente\n * (curto-circuito). Num MISS, o hook `onSend` guarda o payload serializado.\n */\n\nimport type {\n FastifyInstance,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport type { Cache } from \"./index\";\n\nexport interface CachePluginOptions {\n /** Instância de cache a usar. */\n cache: Cache;\n /** TTL aplicado às respostas guardadas (em segundos). */\n ttlSeconds?: number;\n /** Métodos HTTP elegíveis para cache. Padrão: `[\"GET\"]`. */\n methods?: string[];\n /** Gera a chave de cache a partir da requisição. Padrão: `METHOD:url`. */\n keyGenerator?: (req: FastifyRequest) => string;\n}\n\n// Guardamos a chave calculada na própria request entre os hooks.\nconst CACHE_KEY = Symbol(\"rustNodeCacheKey\");\n\n/**\n * Plugin Fastify que cacheia respostas JSON. Use com `fastify.register`.\n */\nexport async function cachePlugin(\n fastify: FastifyInstance,\n options: CachePluginOptions,\n): Promise<void> {\n const { cache } = options;\n const ttlSeconds = options.ttlSeconds;\n const methods = options.methods ?? [\"GET\"];\n const keyGenerator =\n options.keyGenerator ?? ((req: FastifyRequest) => `${req.method}:${req.url}`);\n\n fastify.addHook(\n \"onRequest\",\n (request: FastifyRequest, reply: FastifyReply, done: () => void) => {\n if (!methods.includes(request.method)) {\n done();\n return;\n }\n\n const key = keyGenerator(request);\n const cached = cache.get(key);\n if (cached !== null) {\n reply.header(\"X-Cache\", \"HIT\");\n reply.send(cached);\n return; // não chama done(): a resposta já foi enviada.\n }\n\n reply.header(\"X-Cache\", \"MISS\");\n (request as unknown as Record<symbol, string>)[CACHE_KEY] = key;\n done();\n },\n );\n\n fastify.addHook(\n \"onSend\",\n (\n request: FastifyRequest,\n reply: FastifyReply,\n payload: unknown,\n done: (err: Error | null, value?: unknown) => void,\n ) => {\n const key = (request as unknown as Record<symbol, string | undefined>)[\n CACHE_KEY\n ];\n if (\n key &&\n typeof payload === \"string\" &&\n reply.statusCode >= 200 &&\n reply.statusCode < 300\n ) {\n try {\n cache.set(\n key,\n JSON.parse(payload),\n ttlSeconds ? { ttlSeconds } : undefined,\n );\n } catch {\n // payload não-JSON: simplesmente não cacheia.\n }\n }\n done(null, payload);\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCA,IAAM,YAAY,uBAAO,kBAAkB;AAK3C,eAAsB,YACpB,SACA,SACe;AACf,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,aAAa,QAAQ;AAC3B,QAAM,UAAU,QAAQ,WAAW,CAAC,KAAK;AACzC,QAAM,eACJ,QAAQ,iBAAiB,CAAC,QAAwB,GAAG,IAAI,MAAM,IAAI,IAAI,GAAG;AAE5E,UAAQ;AAAA,IACN;AAAA,IACA,CAAC,SAAyB,OAAqB,SAAqB;AAClE,UAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,GAAG;AACrC,aAAK;AACL;AAAA,MACF;AAEA,YAAM,MAAM,aAAa,OAAO;AAChC,YAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,UAAI,WAAW,MAAM;AACnB,cAAM,OAAO,WAAW,KAAK;AAC7B,cAAM,KAAK,MAAM;AACjB;AAAA,MACF;AAEA,YAAM,OAAO,WAAW,MAAM;AAC9B,MAAC,QAA8C,SAAS,IAAI;AAC5D,WAAK;AAAA,IACP;AAAA,EACF;AAEA,UAAQ;AAAA,IACN;AAAA,IACA,CACE,SACA,OACA,SACA,SACG;AACH,YAAM,MAAO,QACX,SACF;AACA,UACE,OACA,OAAO,YAAY,YACnB,MAAM,cAAc,OACpB,MAAM,aAAa,KACnB;AACA,YAAI;AACF,gBAAM;AAAA,YACJ;AAAA,YACA,KAAK,MAAM,OAAO;AAAA,YAClB,aAAa,EAAE,WAAW,IAAI;AAAA,UAChC;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AACA,WAAK,MAAM,OAAO;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
|