@prosopo/ipinfo 0.4.20 → 0.4.22
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/.turbo/turbo-build$colon$cjs.log +6 -5
- package/.turbo/turbo-build$colon$tsc.log +9 -9
- package/.turbo/turbo-build.log +6 -5
- package/CHANGELOG.md +29 -0
- package/dist/IpInfoService.d.ts +2 -0
- package/dist/IpInfoService.d.ts.map +1 -1
- package/dist/IpInfoService.js +5 -0
- package/dist/IpInfoService.js.map +1 -1
- package/dist/cjs/IpInfoService.cjs +5 -0
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/lookupCache.cjs +53 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/lookupCache.d.ts +15 -0
- package/dist/lookupCache.d.ts.map +1 -0
- package/dist/lookupCache.js +52 -0
- package/dist/lookupCache.js.map +1 -0
- package/dist/tests/lookupCache.unit.test.d.ts +2 -0
- package/dist/tests/lookupCache.unit.test.d.ts.map +1 -0
- package/dist/tests/lookupCache.unit.test.js +99 -0
- package/dist/tests/lookupCache.unit.test.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -19,15 +19,16 @@ ViteCommonJSConfig: .
|
|
|
19
19
|
]
|
|
20
20
|
}
|
|
21
21
|
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
22
|
-
[36mvite v8.1.
|
|
22
|
+
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
23
23
|
Bundle build started
|
|
24
24
|
[2K
|
|
25
|
-
✓
|
|
25
|
+
✓ 6 modules transformed.
|
|
26
26
|
rendering chunks...
|
|
27
27
|
computing gzip size...
|
|
28
|
-
dist/cjs/index.cjs 0.
|
|
29
|
-
dist/cjs/
|
|
28
|
+
dist/cjs/index.cjs 0.66 kB │ gzip: 0.26 kB
|
|
29
|
+
dist/cjs/lookupCache.cjs 1.64 kB │ gzip: 0.78 kB
|
|
30
|
+
dist/cjs/IpInfoService.cjs 4.03 kB │ gzip: 1.47 kB
|
|
30
31
|
dist/cjs/backends/ipapi.cjs 4.11 kB │ gzip: 1.75 kB
|
|
31
32
|
dist/cjs/backends/maxmind.cjs 5.92 kB │ gzip: 1.89 kB
|
|
32
33
|
|
|
33
|
-
[32m✓ built in
|
|
34
|
+
[32m✓ built in 58ms[39m
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
$ tsc --build --verbose
|
|
2
|
-
|
|
2
|
+
5:07:53 PM - Projects in this build:
|
|
3
3
|
* ../../dev/config/tsconfig.json
|
|
4
4
|
* ../util/tsconfig.json
|
|
5
5
|
* ../logger/tsconfig.json
|
|
@@ -8,19 +8,19 @@ $ tsc --build --verbose
|
|
|
8
8
|
* ../types/tsconfig.json
|
|
9
9
|
* tsconfig.json
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
5:07:53 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
5:07:53 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
5:07:53 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
5:07:54 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
5:07:54 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
5:07:54 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
5:07:54 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
5:07:54 PM - Building project '/home/runner/work/captcha/captcha/packages/ipinfo/tsconfig.json'...
|
|
26
26
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -20,16 +20,17 @@ ViteEsmConfig: .
|
|
|
20
20
|
]
|
|
21
21
|
}
|
|
22
22
|
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
23
|
-
[36mvite v8.1.
|
|
23
|
+
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
24
24
|
Bundle build started
|
|
25
25
|
[2K
|
|
26
|
-
✓
|
|
26
|
+
✓ 6 modules transformed.
|
|
27
27
|
rendering chunks...
|
|
28
28
|
computing gzip size...
|
|
29
29
|
dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
30
|
-
dist/index.js 0.
|
|
31
|
-
dist/
|
|
30
|
+
dist/index.js 0.39 kB │ gzip: 0.19 kB
|
|
31
|
+
dist/lookupCache.js 1.60 kB │ gzip: 0.77 kB
|
|
32
|
+
dist/IpInfoService.js 3.93 kB │ gzip: 1.46 kB
|
|
32
33
|
dist/backends/ipapi.js 4.07 kB │ gzip: 1.75 kB
|
|
33
34
|
dist/backends/maxmind.js 5.91 kB │ gzip: 1.89 kB
|
|
34
35
|
|
|
35
|
-
[32m✓ built in
|
|
36
|
+
[32m✓ built in 50ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @prosopo/ipinfo
|
|
2
2
|
|
|
3
|
+
## 0.4.22
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- 46b97b7: Roll up the open Dependabot updates: express 5 (with `@types/express` 5), dotenv 18, undici 8, geolib 4, vitest 5, vite 8.1.6 everywhere, 17 minor and patch bumps (Babel, mongoose, i18next, ip-address, turbo and others), `@angular/router` in the Angular demo, and a GitHub Actions bump.
|
|
7
|
+
|
|
8
|
+
The whole vitest family moves to 5.0.4, including `@vitest/coverage-v8`, because `@vitest/browser-playwright` 5 only works with vitest 5. The `@types/express-serve-static-core` override moves to 5.1.3 to match `@types/express` 5.
|
|
9
|
+
|
|
10
|
+
`@prosopo/dotenv` now loads env files with `quiet: true`. Since dotenv 17, every load prints an "injected env" line to stderr unless told not to.
|
|
11
|
+
- 860948c: Server-side verify (what siteverify calls) now does far less waiting. A PoW verify used to make about 19 database and ip-lookup calls one after another; it now makes about 6, and a rejected verify fewer. Changes:
|
|
12
|
+
|
|
13
|
+
- The ip lookup that runs on every request is skipped on verify routes. Nothing on verify used it, and the caller there is the site's server, not the user.
|
|
14
|
+
- The session record is read once instead of twice, and the client record once instead of twice.
|
|
15
|
+
- DNS enrichment and the user's ip lookup run alongside the access-rule check instead of after it. The ip lookup is skipped once a check has already failed.
|
|
16
|
+
- The verify answers without waiting for its two bookkeeping writes, unless 500 are already waiting, so a slow database cannot pile them up in memory. The single-use claim is still made before anything else, so a token still verifies only once.
|
|
17
|
+
- Decision-machine artifacts are cached per process. They were cached per request, so every verify read them from Mongo. Saving or deleting a machine clears the cache.
|
|
18
|
+
- Client records are cached for 30 seconds and the cache is cleared by every client-record write in the process.
|
|
19
|
+
- Successful ip lookups are cached for 10 minutes, so an address is not looked up twice in one verify, or again at verify after the challenge looked it up.
|
|
20
|
+
- Updated dependencies [46b97b7]
|
|
21
|
+
- Updated dependencies [d2148c8]
|
|
22
|
+
- Updated dependencies [2bcf2fe]
|
|
23
|
+
- @prosopo/logger@2.1.5
|
|
24
|
+
- @prosopo/types@5.17.0
|
|
25
|
+
|
|
26
|
+
## 0.4.21
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- @prosopo/types@5.16.3
|
|
30
|
+
- @prosopo/logger@2.1.4
|
|
31
|
+
|
|
3
32
|
## 0.4.20
|
|
4
33
|
### Patch Changes
|
|
5
34
|
|
package/dist/IpInfoService.d.ts
CHANGED
|
@@ -11,10 +11,12 @@ export declare class IpInfoService implements IIpInfoService {
|
|
|
11
11
|
private maxmindBackend;
|
|
12
12
|
private ipapiBackend;
|
|
13
13
|
private config;
|
|
14
|
+
private readonly cache;
|
|
14
15
|
constructor(config: IpInfoServiceConfig, backends?: IpInfoBackends);
|
|
15
16
|
initialize(): Promise<void>;
|
|
16
17
|
isAvailable(): boolean;
|
|
17
18
|
country(ip: string): string | undefined;
|
|
18
19
|
lookup(ip: string): Promise<IPInfoResponse>;
|
|
20
|
+
private lookupUncached;
|
|
19
21
|
}
|
|
20
22
|
//# sourceMappingURL=IpInfoService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IpInfoService.d.ts","sourceRoot":"","sources":["../src/IpInfoService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"IpInfoService.d.ts","sourceRoot":"","sources":["../src/IpInfoService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA+BjD;AAQD,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B;AAED,qBAAa,aAAc,YAAW,cAAc;IACnD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;gBAEpC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC,EAAE,cAAc;IA6B5D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC,WAAW,IAAI,OAAO;IAsBtB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;YAMnC,cAAc;CA4C5B"}
|
package/dist/IpInfoService.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IpapiBackend } from "./backends/ipapi.js";
|
|
2
2
|
import { MaxMindBackend } from "./backends/maxmind.js";
|
|
3
|
+
import { LookupCache } from "./lookupCache.js";
|
|
3
4
|
//#region src/IpInfoService.ts
|
|
4
5
|
/**
|
|
5
6
|
* Returns true for loopback, link-local, and private-range IPs that will
|
|
@@ -22,6 +23,7 @@ var IpInfoService = class {
|
|
|
22
23
|
this.maxmindBackend = null;
|
|
23
24
|
this.ipapiBackend = null;
|
|
24
25
|
this.config = config;
|
|
26
|
+
this.cache = config.lookupCache ? new LookupCache(config.lookupCache) : void 0;
|
|
25
27
|
if (backends) {
|
|
26
28
|
this.maxmindBackend = backends.maxmind ?? null;
|
|
27
29
|
this.ipapiBackend = backends.ipapi ?? null;
|
|
@@ -72,6 +74,9 @@ var IpInfoService = class {
|
|
|
72
74
|
return this.maxmindBackend.countryCode(ip);
|
|
73
75
|
}
|
|
74
76
|
async lookup(ip) {
|
|
77
|
+
return this.cache ? this.cache.getOrLookup(ip, (address) => this.lookupUncached(address)) : this.lookupUncached(ip);
|
|
78
|
+
}
|
|
79
|
+
async lookupUncached(ip) {
|
|
75
80
|
if (isNonRoutable(ip)) return {
|
|
76
81
|
isValid: false,
|
|
77
82
|
error: "Non-routable IP address",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IpInfoService.js","sourceRoot":"","sources":["../src/IpInfoService.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"IpInfoService.js","sourceRoot":"","sources":["../src/IpInfoService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_ipapi = require("./backends/ipapi.cjs");
|
|
2
2
|
const require_maxmind = require("./backends/maxmind.cjs");
|
|
3
|
+
const require_lookupCache = require("./lookupCache.cjs");
|
|
3
4
|
//#region src/IpInfoService.ts
|
|
4
5
|
/**
|
|
5
6
|
* Returns true for loopback, link-local, and private-range IPs that will
|
|
@@ -22,6 +23,7 @@ var IpInfoService = class {
|
|
|
22
23
|
this.maxmindBackend = null;
|
|
23
24
|
this.ipapiBackend = null;
|
|
24
25
|
this.config = config;
|
|
26
|
+
this.cache = config.lookupCache ? new require_lookupCache.LookupCache(config.lookupCache) : void 0;
|
|
25
27
|
if (backends) {
|
|
26
28
|
this.maxmindBackend = backends.maxmind ?? null;
|
|
27
29
|
this.ipapiBackend = backends.ipapi ?? null;
|
|
@@ -72,6 +74,9 @@ var IpInfoService = class {
|
|
|
72
74
|
return this.maxmindBackend.countryCode(ip);
|
|
73
75
|
}
|
|
74
76
|
async lookup(ip) {
|
|
77
|
+
return this.cache ? this.cache.getOrLookup(ip, (address) => this.lookupUncached(address)) : this.lookupUncached(ip);
|
|
78
|
+
}
|
|
79
|
+
async lookupUncached(ip) {
|
|
75
80
|
if (isNonRoutable(ip)) return {
|
|
76
81
|
isValid: false,
|
|
77
82
|
error: "Non-routable IP address",
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_ipapi = require("./backends/ipapi.cjs");
|
|
3
3
|
const require_maxmind = require("./backends/maxmind.cjs");
|
|
4
|
+
const require_lookupCache = require("./lookupCache.cjs");
|
|
4
5
|
const require_IpInfoService = require("./IpInfoService.cjs");
|
|
6
|
+
exports.DEFAULT_LOOKUP_CACHE = require_lookupCache.DEFAULT_LOOKUP_CACHE;
|
|
5
7
|
exports.IpInfoService = require_IpInfoService.IpInfoService;
|
|
6
8
|
exports.IpapiBackend = require_ipapi.IpapiBackend;
|
|
9
|
+
exports.LookupCache = require_lookupCache.LookupCache;
|
|
7
10
|
exports.MaxMindBackend = require_maxmind.MaxMindBackend;
|
|
8
11
|
exports.isNonRoutable = require_IpInfoService.isNonRoutable;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/lookupCache.ts
|
|
2
|
+
/**
|
|
3
|
+
* The sidecar answers from a database that only changes on redeploy, so a
|
|
4
|
+
* few minutes of staleness costs nothing, while the same address is looked
|
|
5
|
+
* up repeatedly: by the challenge request and then its verify, and up to
|
|
6
|
+
* three times within one verify.
|
|
7
|
+
*/
|
|
8
|
+
var DEFAULT_LOOKUP_CACHE = {
|
|
9
|
+
ttlMs: 600 * 1e3,
|
|
10
|
+
maxEntries: 2e4
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Bounded LRU + TTL cache of successful lookups. Concurrent lookups of one
|
|
14
|
+
* address share a single call. Failed lookups are never stored, so a sidecar
|
|
15
|
+
* timeout is retried by the next caller rather than remembered.
|
|
16
|
+
*/
|
|
17
|
+
var LookupCache = class {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
21
|
+
this.inflight = /* @__PURE__ */ new Map();
|
|
22
|
+
}
|
|
23
|
+
async getOrLookup(ip, lookup) {
|
|
24
|
+
const entry = this.entries.get(ip);
|
|
25
|
+
if (entry && entry.expiresAt > Date.now()) {
|
|
26
|
+
this.entries.delete(ip);
|
|
27
|
+
this.entries.set(ip, entry);
|
|
28
|
+
return entry.value;
|
|
29
|
+
}
|
|
30
|
+
if (entry) this.entries.delete(ip);
|
|
31
|
+
const pending = this.inflight.get(ip);
|
|
32
|
+
if (pending) return pending;
|
|
33
|
+
const promise = lookup(ip).then((value) => {
|
|
34
|
+
if (value.isValid) this.store(ip, value);
|
|
35
|
+
return value;
|
|
36
|
+
}).finally(() => this.inflight.delete(ip));
|
|
37
|
+
this.inflight.set(ip, promise);
|
|
38
|
+
return promise;
|
|
39
|
+
}
|
|
40
|
+
store(ip, value) {
|
|
41
|
+
if (this.entries.size >= this.config.maxEntries) {
|
|
42
|
+
const oldest = this.entries.keys().next().value;
|
|
43
|
+
if (oldest !== void 0) this.entries.delete(oldest);
|
|
44
|
+
}
|
|
45
|
+
this.entries.set(ip, {
|
|
46
|
+
value,
|
|
47
|
+
expiresAt: Date.now() + this.config.ttlMs
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
exports.DEFAULT_LOOKUP_CACHE = DEFAULT_LOOKUP_CACHE;
|
|
53
|
+
exports.LookupCache = LookupCache;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,6 @@ export type { FetchFn, IpapiBackendConfig } from "./backends/ipapi.js";
|
|
|
5
5
|
export { MaxMindBackend } from "./backends/maxmind.js";
|
|
6
6
|
export type { MaxMindBackendConfig, OpenReader } from "./backends/maxmind.js";
|
|
7
7
|
export type { IIpInfoService, IpInfoServiceConfig } from "./types.js";
|
|
8
|
+
export { DEFAULT_LOOKUP_CACHE, LookupCache } from "./lookupCache.js";
|
|
9
|
+
export type { LookupCacheConfig } from "./lookupCache.js";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { IpapiBackend } from "./backends/ipapi.js";
|
|
3
3
|
import { MaxMindBackend } from "./backends/maxmind.js";
|
|
4
|
+
import { DEFAULT_LOOKUP_CACHE, LookupCache } from "./lookupCache.js";
|
|
4
5
|
import { IpInfoService, isNonRoutable } from "./IpInfoService.js";
|
|
5
|
-
export { IpInfoService, IpapiBackend, MaxMindBackend, isNonRoutable };
|
|
6
|
+
export { DEFAULT_LOOKUP_CACHE, IpInfoService, IpapiBackend, LookupCache, MaxMindBackend, isNonRoutable };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKlE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IPInfoResponse } from "@prosopo/types";
|
|
2
|
+
export type LookupCacheConfig = {
|
|
3
|
+
ttlMs: number;
|
|
4
|
+
maxEntries: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const DEFAULT_LOOKUP_CACHE: LookupCacheConfig;
|
|
7
|
+
export declare class LookupCache {
|
|
8
|
+
private readonly config;
|
|
9
|
+
private readonly entries;
|
|
10
|
+
private readonly inflight;
|
|
11
|
+
constructor(config: LookupCacheConfig);
|
|
12
|
+
getOrLookup(ip: string, lookup: (ip: string) => Promise<IPInfoResponse>): Promise<IPInfoResponse>;
|
|
13
|
+
private store;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=lookupCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookupCache.d.ts","sourceRoot":"","sources":["../src/lookupCache.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACnB,CAAC;AAQF,eAAO,MAAM,oBAAoB,EAAE,iBAGlC,CAAC;AASF,qBAAa,WAAW;IAIX,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8C;gBAE1C,MAAM,EAAE,iBAAiB;IAEhD,WAAW,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,GAC7C,OAAO,CAAC,cAAc,CAAC;IAsB1B,OAAO,CAAC,KAAK;CAOb"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/lookupCache.ts
|
|
2
|
+
/**
|
|
3
|
+
* The sidecar answers from a database that only changes on redeploy, so a
|
|
4
|
+
* few minutes of staleness costs nothing, while the same address is looked
|
|
5
|
+
* up repeatedly: by the challenge request and then its verify, and up to
|
|
6
|
+
* three times within one verify.
|
|
7
|
+
*/
|
|
8
|
+
var DEFAULT_LOOKUP_CACHE = {
|
|
9
|
+
ttlMs: 600 * 1e3,
|
|
10
|
+
maxEntries: 2e4
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Bounded LRU + TTL cache of successful lookups. Concurrent lookups of one
|
|
14
|
+
* address share a single call. Failed lookups are never stored, so a sidecar
|
|
15
|
+
* timeout is retried by the next caller rather than remembered.
|
|
16
|
+
*/
|
|
17
|
+
var LookupCache = class {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
21
|
+
this.inflight = /* @__PURE__ */ new Map();
|
|
22
|
+
}
|
|
23
|
+
async getOrLookup(ip, lookup) {
|
|
24
|
+
const entry = this.entries.get(ip);
|
|
25
|
+
if (entry && entry.expiresAt > Date.now()) {
|
|
26
|
+
this.entries.delete(ip);
|
|
27
|
+
this.entries.set(ip, entry);
|
|
28
|
+
return entry.value;
|
|
29
|
+
}
|
|
30
|
+
if (entry) this.entries.delete(ip);
|
|
31
|
+
const pending = this.inflight.get(ip);
|
|
32
|
+
if (pending) return pending;
|
|
33
|
+
const promise = lookup(ip).then((value) => {
|
|
34
|
+
if (value.isValid) this.store(ip, value);
|
|
35
|
+
return value;
|
|
36
|
+
}).finally(() => this.inflight.delete(ip));
|
|
37
|
+
this.inflight.set(ip, promise);
|
|
38
|
+
return promise;
|
|
39
|
+
}
|
|
40
|
+
store(ip, value) {
|
|
41
|
+
if (this.entries.size >= this.config.maxEntries) {
|
|
42
|
+
const oldest = this.entries.keys().next().value;
|
|
43
|
+
if (oldest !== void 0) this.entries.delete(oldest);
|
|
44
|
+
}
|
|
45
|
+
this.entries.set(ip, {
|
|
46
|
+
value,
|
|
47
|
+
expiresAt: Date.now() + this.config.ttlMs
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DEFAULT_LOOKUP_CACHE, LookupCache };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookupCache.js","sourceRoot":"","sources":["../src/lookupCache.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACtD,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IACrB,UAAU,EAAE,MAAM;CAClB,CAAC;AASF,MAAM,OAAO,WAAW;IAIvB,YAA6B,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;QAHrC,YAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;QACnC,aAAQ,GAAG,IAAI,GAAG,EAAmC,CAAC;IAEd,CAAC;IAE1D,KAAK,CAAC,WAAW,CAChB,EAAU,EACV,MAA+C;QAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC5B,OAAO,KAAK,CAAC,KAAK,CAAC;QACpB,CAAC;QACD,IAAI,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAE5B,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC;aACxB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,KAAK,CAAC,OAAO;gBAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACzC,OAAO,KAAK,CAAC;QACd,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,EAAU,EAAE,KAAqB;QAC9C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAChD,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5E,CAAC;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookupCache.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/lookupCache.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { IpInfoService } from "../IpInfoService.js";
|
|
3
|
+
import { LookupCache } from "../lookupCache.js";
|
|
4
|
+
const valid = (ip) => ({
|
|
5
|
+
isValid: true,
|
|
6
|
+
ip,
|
|
7
|
+
isVPN: false,
|
|
8
|
+
isTor: false,
|
|
9
|
+
isProxy: false,
|
|
10
|
+
isDatacenter: false,
|
|
11
|
+
isAbuser: false,
|
|
12
|
+
isMobile: false,
|
|
13
|
+
isSatellite: false,
|
|
14
|
+
isCrawler: false,
|
|
15
|
+
});
|
|
16
|
+
const failed = (ip) => ({
|
|
17
|
+
isValid: false,
|
|
18
|
+
error: "Request timed out after 700ms",
|
|
19
|
+
ip,
|
|
20
|
+
});
|
|
21
|
+
describe("LookupCache", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.useFakeTimers();
|
|
24
|
+
});
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
vi.useRealTimers();
|
|
27
|
+
});
|
|
28
|
+
it("answers a repeat lookup from the cache", async () => {
|
|
29
|
+
const cache = new LookupCache({ ttlMs: 1000, maxEntries: 10 });
|
|
30
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
31
|
+
await cache.getOrLookup("8.8.8.8", lookup);
|
|
32
|
+
const second = await cache.getOrLookup("8.8.8.8", lookup);
|
|
33
|
+
expect(second).toEqual(valid("8.8.8.8"));
|
|
34
|
+
expect(lookup).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
it("shares one call between concurrent lookups of the same address", async () => {
|
|
37
|
+
const cache = new LookupCache({ ttlMs: 1000, maxEntries: 10 });
|
|
38
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
39
|
+
await Promise.all([
|
|
40
|
+
cache.getOrLookup("8.8.8.8", lookup),
|
|
41
|
+
cache.getOrLookup("8.8.8.8", lookup),
|
|
42
|
+
cache.getOrLookup("8.8.8.8", lookup),
|
|
43
|
+
]);
|
|
44
|
+
expect(lookup).toHaveBeenCalledTimes(1);
|
|
45
|
+
});
|
|
46
|
+
it("looks up again once the entry has expired", async () => {
|
|
47
|
+
const cache = new LookupCache({ ttlMs: 1000, maxEntries: 10 });
|
|
48
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
49
|
+
await cache.getOrLookup("8.8.8.8", lookup);
|
|
50
|
+
vi.advanceTimersByTime(1001);
|
|
51
|
+
await cache.getOrLookup("8.8.8.8", lookup);
|
|
52
|
+
expect(lookup).toHaveBeenCalledTimes(2);
|
|
53
|
+
});
|
|
54
|
+
it("does not remember a failed lookup", async () => {
|
|
55
|
+
const cache = new LookupCache({ ttlMs: 1000, maxEntries: 10 });
|
|
56
|
+
const lookup = vi
|
|
57
|
+
.fn()
|
|
58
|
+
.mockResolvedValueOnce(failed("8.8.8.8"))
|
|
59
|
+
.mockResolvedValueOnce(valid("8.8.8.8"));
|
|
60
|
+
const first = await cache.getOrLookup("8.8.8.8", lookup);
|
|
61
|
+
const second = await cache.getOrLookup("8.8.8.8", lookup);
|
|
62
|
+
expect(first.isValid).toBe(false);
|
|
63
|
+
expect(second.isValid).toBe(true);
|
|
64
|
+
expect(lookup).toHaveBeenCalledTimes(2);
|
|
65
|
+
});
|
|
66
|
+
it("evicts the least recently used address when full", async () => {
|
|
67
|
+
const cache = new LookupCache({ ttlMs: 1000, maxEntries: 2 });
|
|
68
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
69
|
+
await cache.getOrLookup("1.1.1.1", lookup);
|
|
70
|
+
await cache.getOrLookup("2.2.2.2", lookup);
|
|
71
|
+
await cache.getOrLookup("1.1.1.1", lookup);
|
|
72
|
+
await cache.getOrLookup("3.3.3.3", lookup);
|
|
73
|
+
lookup.mockClear();
|
|
74
|
+
await cache.getOrLookup("1.1.1.1", lookup);
|
|
75
|
+
await cache.getOrLookup("2.2.2.2", lookup);
|
|
76
|
+
expect(lookup.mock.calls).toEqual([["2.2.2.2"]]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("IpInfoService lookup cache", () => {
|
|
80
|
+
const ipapiReturning = (lookup) => ({
|
|
81
|
+
isAvailable: () => true,
|
|
82
|
+
lookup,
|
|
83
|
+
});
|
|
84
|
+
it("asks the sidecar once for an address looked up twice", async () => {
|
|
85
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
86
|
+
const service = new IpInfoService({ lookupCache: { ttlMs: 60_000, maxEntries: 10 } }, { ipapi: ipapiReturning(lookup) });
|
|
87
|
+
await service.lookup("8.8.8.8");
|
|
88
|
+
await service.lookup("8.8.8.8");
|
|
89
|
+
expect(lookup).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
it("asks the sidecar every time when no cache is configured", async () => {
|
|
92
|
+
const lookup = vi.fn((ip) => Promise.resolve(valid(ip)));
|
|
93
|
+
const service = new IpInfoService({}, { ipapi: ipapiReturning(lookup) });
|
|
94
|
+
await service.lookup("8.8.8.8");
|
|
95
|
+
await service.lookup("8.8.8.8");
|
|
96
|
+
expect(lookup).toHaveBeenCalledTimes(2);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
//# sourceMappingURL=lookupCache.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookupCache.unit.test.js","sourceRoot":"","sources":["../../src/tests/lookupCache.unit.test.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "@prosopo/logger";
|
|
2
2
|
import type { IPInfoResponse } from "@prosopo/types";
|
|
3
|
+
import type { LookupCacheConfig } from "./lookupCache.js";
|
|
3
4
|
export interface IIpInfoService {
|
|
4
5
|
initialize(): Promise<void>;
|
|
5
6
|
lookup(ip: string): Promise<IPInfoResponse>;
|
|
@@ -12,5 +13,6 @@ export interface IpInfoServiceConfig {
|
|
|
12
13
|
ipapiUrl?: string;
|
|
13
14
|
ipapiKey?: string;
|
|
14
15
|
logger?: Logger;
|
|
16
|
+
lookupCache?: LookupCacheConfig;
|
|
15
17
|
}
|
|
16
18
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAM5C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACxC,WAAW,IAAI,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,iBAAiB,CAAC;CAChC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/ipinfo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
4
4
|
"description": "IP information service with MaxMind and ipapi.is backends",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -17,18 +17,18 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@maxmind/geoip2-node": "7.1.0",
|
|
20
|
-
"@prosopo/logger": "2.1.
|
|
21
|
-
"@prosopo/types": "5.
|
|
20
|
+
"@prosopo/logger": "2.1.5",
|
|
21
|
+
"@prosopo/types": "5.17.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@prosopo/config": "3.
|
|
24
|
+
"@prosopo/config": "3.5.0",
|
|
25
25
|
"@types/node": "22.10.2",
|
|
26
|
-
"@vitest/coverage-v8": "
|
|
26
|
+
"@vitest/coverage-v8": "5.0.4",
|
|
27
27
|
"del-cli": "6.0.0",
|
|
28
28
|
"tslib": "2.7.0",
|
|
29
29
|
"typescript": "5.6.2",
|
|
30
|
-
"vite": "8.1.
|
|
31
|
-
"vitest": "
|
|
30
|
+
"vite": "8.1.6",
|
|
31
|
+
"vitest": "5.0.4"
|
|
32
32
|
},
|
|
33
33
|
"license": "Apache-2.0",
|
|
34
34
|
"repository": {
|