@ipgeotrace/fastify 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/README.md +89 -0
- package/dist/index.cjs +50 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# @ipgeotrace/fastify
|
|
2
|
+
|
|
3
|
+
Fastify plugin for [IPGeoTrace](https://ipgeotrace.com). Resolves the caller's location once per
|
|
4
|
+
request and hands it to you on `request.geo`. Built on [`@ipgeotrace/client`](../client) — the
|
|
5
|
+
secret key stays server-side.
|
|
6
|
+
|
|
7
|
+
Sign up and grab your API key at [ipgeotrace.com](https://ipgeotrace.com).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm add @ipgeotrace/fastify fastify
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import Fastify from 'fastify';
|
|
19
|
+
import { ipgeotrace, getGeo } from '@ipgeotrace/fastify';
|
|
20
|
+
|
|
21
|
+
const app = Fastify({ trustProxy: true }); // so request.ip reads X-Forwarded-For behind a proxy
|
|
22
|
+
|
|
23
|
+
await app.register(ipgeotrace, { apiKey: process.env.IPGEOTRACE_API_KEY! });
|
|
24
|
+
|
|
25
|
+
app.get('/checkout', (request, reply) => {
|
|
26
|
+
const geo = getGeo(request);
|
|
27
|
+
const currency = geo.status === 'resolved' ? geo.value?.country?.currency ?? 'USD' : 'USD';
|
|
28
|
+
reply.send({ currency });
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The plugin is registered app-wide (wrapped with `fastify-plugin`), so `request.geo` is available in
|
|
33
|
+
every route.
|
|
34
|
+
|
|
35
|
+
`request.geo` (and `getGeo(request)`) is a `GeoLookup` whose `status` tells you exactly what
|
|
36
|
+
happened:
|
|
37
|
+
|
|
38
|
+
- `resolved` — `value` carries the data.
|
|
39
|
+
- `skipped` — the caller's IP was missing, private, loopback, or link-local, so no API call was made.
|
|
40
|
+
- `failed` — `error` carries the reason (`rate_limited`, `quota_exceeded`, …).
|
|
41
|
+
- `not_attempted` — the plugin opted out for this request (`shouldResolve` returned false).
|
|
42
|
+
|
|
43
|
+
`getGeo()` is always safe to call and returns `not_attempted` when the plugin never ran.
|
|
44
|
+
|
|
45
|
+
## Skipping requests
|
|
46
|
+
|
|
47
|
+
Health checks and internal endpoints should not spend lookups. Opt them out with `shouldResolve`:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
await app.register(ipgeotrace, {
|
|
51
|
+
apiKey: process.env.IPGEOTRACE_API_KEY!,
|
|
52
|
+
shouldResolve: (request) => !request.url.startsWith('/health') && !request.url.startsWith('/internal'),
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Private, loopback, and link-local addresses (including IPv4-mapped IPv6) are detected locally and
|
|
57
|
+
skipped without an API call or quota usage.
|
|
58
|
+
|
|
59
|
+
## Choosing the caller's IP
|
|
60
|
+
|
|
61
|
+
By default the plugin uses `request.ip`, which respects Fastify's `trustProxy` setting. For full
|
|
62
|
+
control, supply your own selector:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
await app.register(ipgeotrace, {
|
|
66
|
+
apiKey: process.env.IPGEOTRACE_API_KEY!,
|
|
67
|
+
ipSelector: (request) => (request.headers['cf-connecting-ip'] as string) ?? request.ip,
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
Pass client options through `clientOptions`, or share a pre-built client across your app:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { IpGeoTraceClient } from '@ipgeotrace/client';
|
|
77
|
+
|
|
78
|
+
// inline client options
|
|
79
|
+
await app.register(ipgeotrace, {
|
|
80
|
+
apiKey: process.env.IPGEOTRACE_API_KEY!,
|
|
81
|
+
clientOptions: { cache: true, cacheTtlMs: 6 * 60 * 60_000, timeoutMs: 3_000 },
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// or bring your own client (also usable directly in services)
|
|
85
|
+
const client = new IpGeoTraceClient({ apiKey: process.env.IPGEOTRACE_API_KEY!, cache: true });
|
|
86
|
+
await app.register(ipgeotrace, { client });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See the [`@ipgeotrace/client` README](../client) for caching, retries, timeouts, and batch lookups.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var client = require('@ipgeotrace/client');
|
|
4
|
+
var fp = require('fastify-plugin');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var fp__default = /*#__PURE__*/_interopDefault(fp);
|
|
9
|
+
|
|
10
|
+
// src/plugin.ts
|
|
11
|
+
var plugin = async (fastify, options) => {
|
|
12
|
+
const client$1 = resolveClient(options);
|
|
13
|
+
const shouldResolve = options.shouldResolve ?? (() => true);
|
|
14
|
+
const ipSelector = options.ipSelector ?? ((req) => req.ip);
|
|
15
|
+
if (!fastify.hasRequestDecorator("geo")) {
|
|
16
|
+
fastify.decorateRequest("geo", void 0);
|
|
17
|
+
}
|
|
18
|
+
fastify.addHook("onRequest", async (req) => {
|
|
19
|
+
if (!shouldResolve(req)) {
|
|
20
|
+
req.geo = { status: "not_attempted" };
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const ip = ipSelector(req);
|
|
24
|
+
if (!ip || client.isPrivateOrReservedIp(ip)) {
|
|
25
|
+
req.geo = { status: "skipped" };
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const result = await client$1.resolve(ip);
|
|
29
|
+
req.geo = result.ok ? { status: "resolved", value: result.value } : { status: "failed", error: result.error };
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
var ipgeotrace = fp__default.default(plugin, {
|
|
33
|
+
fastify: ">=4.26.0 <6.0.0",
|
|
34
|
+
name: "@ipgeotrace/fastify"
|
|
35
|
+
});
|
|
36
|
+
function getGeo(req) {
|
|
37
|
+
return req.geo ?? { status: "not_attempted" };
|
|
38
|
+
}
|
|
39
|
+
function resolveClient(options) {
|
|
40
|
+
if (options.client) return options.client;
|
|
41
|
+
if (!options.apiKey) {
|
|
42
|
+
throw new Error("IPGeoTrace: pass either a client or an apiKey to the fastify plugin.");
|
|
43
|
+
}
|
|
44
|
+
return new client.IpGeoTraceClient({ apiKey: options.apiKey, ...options.clientOptions });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
exports.getGeo = getGeo;
|
|
48
|
+
exports.ipgeotrace = ipgeotrace;
|
|
49
|
+
//# sourceMappingURL=index.cjs.map
|
|
50
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":["client","isPrivateOrReservedIp","fp","IpGeoTraceClient"],"mappings":";;;;;;;;;;AAKA,IAAM,MAAA,GAAsD,OAAO,OAAA,EAAS,OAAA,KAAY;AACtF,EAAA,MAAMA,QAAA,GAAS,cAAc,OAAO,CAAA;AACpC,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,aAAA,KAAkB,MAAM,IAAA,CAAA;AACtD,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,UAAA,KAAe,CAAC,QAAwB,GAAA,CAAI,EAAA,CAAA;AAEvE,EAAA,IAAI,CAAC,OAAA,CAAQ,mBAAA,CAAoB,KAAK,CAAA,EAAG;AACvC,IAAA,OAAA,CAAQ,eAAA,CAAgB,OAAO,MAAS,CAAA;AAAA,EAC1C;AAEA,EAAA,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAa,OAAO,GAAA,KAAwB;AAC1D,IAAA,IAAI,CAAC,aAAA,CAAc,GAAG,CAAA,EAAG;AACvB,MAAA,GAAA,CAAI,GAAA,GAAM,EAAE,MAAA,EAAQ,eAAA,EAAgB;AACpC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,EAAA,GAAK,WAAW,GAAG,CAAA;AACzB,IAAA,IAAI,CAAC,EAAA,IAAMC,4BAAA,CAAsB,EAAE,CAAA,EAAG;AACpC,MAAA,GAAA,CAAI,GAAA,GAAM,EAAE,MAAA,EAAQ,SAAA,EAAU;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,MAAMD,QAAA,CAAO,OAAA,CAAQ,EAAE,CAAA;AACtC,IAAA,GAAA,CAAI,GAAA,GAAM,MAAA,CAAO,EAAA,GACb,EAAE,QAAQ,UAAA,EAAY,KAAA,EAAO,MAAA,CAAO,KAAA,KACpC,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,OAAO,KAAA,EAAM;AAAA,EAC9C,CAAC,CAAA;AACH,CAAA;AAEO,IAAM,UAAA,GAAaE,oBAAG,MAAA,EAAQ;AAAA,EACnC,OAAA,EAAS,iBAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAC;AAEM,SAAS,OAAO,GAAA,EAAgC;AACrD,EAAA,OAAO,GAAA,CAAI,GAAA,IAAO,EAAE,MAAA,EAAQ,eAAA,EAAgB;AAC9C;AAEA,SAAS,cAAc,OAAA,EAAoD;AACzE,EAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAO,OAAA,CAAQ,MAAA;AACnC,EAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,IAAA,MAAM,IAAI,MAAM,sEAAsE,CAAA;AAAA,EACxF;AACA,EAAA,OAAO,IAAIC,wBAAiB,EAAE,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAG,OAAA,CAAQ,aAAA,EAAe,CAAA;AAClF","file":"index.cjs","sourcesContent":["import { IpGeoTraceClient, isPrivateOrReservedIp, type GeoLookup } from '@ipgeotrace/client';\nimport type { FastifyPluginAsync, FastifyRequest } from 'fastify';\nimport fp from 'fastify-plugin';\nimport type { IpGeoTracePluginOptions } from './types.js';\n\nconst plugin: FastifyPluginAsync<IpGeoTracePluginOptions> = async (fastify, options) => {\n const client = resolveClient(options);\n const shouldResolve = options.shouldResolve ?? (() => true);\n const ipSelector = options.ipSelector ?? ((req: FastifyRequest) => req.ip);\n\n if (!fastify.hasRequestDecorator('geo')) {\n fastify.decorateRequest('geo', undefined);\n }\n\n fastify.addHook('onRequest', async (req: FastifyRequest) => {\n if (!shouldResolve(req)) {\n req.geo = { status: 'not_attempted' };\n return;\n }\n\n const ip = ipSelector(req);\n if (!ip || isPrivateOrReservedIp(ip)) {\n req.geo = { status: 'skipped' };\n return;\n }\n\n const result = await client.resolve(ip);\n req.geo = result.ok\n ? { status: 'resolved', value: result.value }\n : { status: 'failed', error: result.error };\n });\n};\n\nexport const ipgeotrace = fp(plugin, {\n fastify: '>=4.26.0 <6.0.0',\n name: '@ipgeotrace/fastify',\n});\n\nexport function getGeo(req: FastifyRequest): GeoLookup {\n return req.geo ?? { status: 'not_attempted' };\n}\n\nfunction resolveClient(options: IpGeoTracePluginOptions): IpGeoTraceClient {\n if (options.client) return options.client;\n if (!options.apiKey) {\n throw new Error('IPGeoTrace: pass either a client or an apiKey to the fastify plugin.');\n }\n return new IpGeoTraceClient({ apiKey: options.apiKey, ...options.clientOptions });\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GeoLookup, IpGeoTraceClient, IpGeoTraceClientOptions } from '@ipgeotrace/client';
|
|
2
|
+
export { GeoError, GeoLookup, GeoLookupStatus, GeoResponse } from '@ipgeotrace/client';
|
|
3
|
+
import { FastifyRequest, FastifyPluginAsync } from 'fastify';
|
|
4
|
+
|
|
5
|
+
interface IpGeoTracePluginOptions {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
client?: IpGeoTraceClient;
|
|
8
|
+
clientOptions?: Omit<IpGeoTraceClientOptions, 'apiKey'>;
|
|
9
|
+
shouldResolve?: (req: FastifyRequest) => boolean;
|
|
10
|
+
ipSelector?: (req: FastifyRequest) => string | undefined;
|
|
11
|
+
}
|
|
12
|
+
declare module 'fastify' {
|
|
13
|
+
interface FastifyRequest {
|
|
14
|
+
geo?: GeoLookup;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const ipgeotrace: FastifyPluginAsync<IpGeoTracePluginOptions>;
|
|
19
|
+
declare function getGeo(req: FastifyRequest): GeoLookup;
|
|
20
|
+
|
|
21
|
+
export { type IpGeoTracePluginOptions, getGeo, ipgeotrace };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GeoLookup, IpGeoTraceClient, IpGeoTraceClientOptions } from '@ipgeotrace/client';
|
|
2
|
+
export { GeoError, GeoLookup, GeoLookupStatus, GeoResponse } from '@ipgeotrace/client';
|
|
3
|
+
import { FastifyRequest, FastifyPluginAsync } from 'fastify';
|
|
4
|
+
|
|
5
|
+
interface IpGeoTracePluginOptions {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
client?: IpGeoTraceClient;
|
|
8
|
+
clientOptions?: Omit<IpGeoTraceClientOptions, 'apiKey'>;
|
|
9
|
+
shouldResolve?: (req: FastifyRequest) => boolean;
|
|
10
|
+
ipSelector?: (req: FastifyRequest) => string | undefined;
|
|
11
|
+
}
|
|
12
|
+
declare module 'fastify' {
|
|
13
|
+
interface FastifyRequest {
|
|
14
|
+
geo?: GeoLookup;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const ipgeotrace: FastifyPluginAsync<IpGeoTracePluginOptions>;
|
|
19
|
+
declare function getGeo(req: FastifyRequest): GeoLookup;
|
|
20
|
+
|
|
21
|
+
export { type IpGeoTracePluginOptions, getGeo, ipgeotrace };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isPrivateOrReservedIp, IpGeoTraceClient } from '@ipgeotrace/client';
|
|
2
|
+
import fp from 'fastify-plugin';
|
|
3
|
+
|
|
4
|
+
// src/plugin.ts
|
|
5
|
+
var plugin = async (fastify, options) => {
|
|
6
|
+
const client = resolveClient(options);
|
|
7
|
+
const shouldResolve = options.shouldResolve ?? (() => true);
|
|
8
|
+
const ipSelector = options.ipSelector ?? ((req) => req.ip);
|
|
9
|
+
if (!fastify.hasRequestDecorator("geo")) {
|
|
10
|
+
fastify.decorateRequest("geo", void 0);
|
|
11
|
+
}
|
|
12
|
+
fastify.addHook("onRequest", async (req) => {
|
|
13
|
+
if (!shouldResolve(req)) {
|
|
14
|
+
req.geo = { status: "not_attempted" };
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const ip = ipSelector(req);
|
|
18
|
+
if (!ip || isPrivateOrReservedIp(ip)) {
|
|
19
|
+
req.geo = { status: "skipped" };
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const result = await client.resolve(ip);
|
|
23
|
+
req.geo = result.ok ? { status: "resolved", value: result.value } : { status: "failed", error: result.error };
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
var ipgeotrace = fp(plugin, {
|
|
27
|
+
fastify: ">=4.26.0 <6.0.0",
|
|
28
|
+
name: "@ipgeotrace/fastify"
|
|
29
|
+
});
|
|
30
|
+
function getGeo(req) {
|
|
31
|
+
return req.geo ?? { status: "not_attempted" };
|
|
32
|
+
}
|
|
33
|
+
function resolveClient(options) {
|
|
34
|
+
if (options.client) return options.client;
|
|
35
|
+
if (!options.apiKey) {
|
|
36
|
+
throw new Error("IPGeoTrace: pass either a client or an apiKey to the fastify plugin.");
|
|
37
|
+
}
|
|
38
|
+
return new IpGeoTraceClient({ apiKey: options.apiKey, ...options.clientOptions });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { getGeo, ipgeotrace };
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":[],"mappings":";;;;AAKA,IAAM,MAAA,GAAsD,OAAO,OAAA,EAAS,OAAA,KAAY;AACtF,EAAA,MAAM,MAAA,GAAS,cAAc,OAAO,CAAA;AACpC,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,aAAA,KAAkB,MAAM,IAAA,CAAA;AACtD,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,UAAA,KAAe,CAAC,QAAwB,GAAA,CAAI,EAAA,CAAA;AAEvE,EAAA,IAAI,CAAC,OAAA,CAAQ,mBAAA,CAAoB,KAAK,CAAA,EAAG;AACvC,IAAA,OAAA,CAAQ,eAAA,CAAgB,OAAO,MAAS,CAAA;AAAA,EAC1C;AAEA,EAAA,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAa,OAAO,GAAA,KAAwB;AAC1D,IAAA,IAAI,CAAC,aAAA,CAAc,GAAG,CAAA,EAAG;AACvB,MAAA,GAAA,CAAI,GAAA,GAAM,EAAE,MAAA,EAAQ,eAAA,EAAgB;AACpC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,EAAA,GAAK,WAAW,GAAG,CAAA;AACzB,IAAA,IAAI,CAAC,EAAA,IAAM,qBAAA,CAAsB,EAAE,CAAA,EAAG;AACpC,MAAA,GAAA,CAAI,GAAA,GAAM,EAAE,MAAA,EAAQ,SAAA,EAAU;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,OAAA,CAAQ,EAAE,CAAA;AACtC,IAAA,GAAA,CAAI,GAAA,GAAM,MAAA,CAAO,EAAA,GACb,EAAE,QAAQ,UAAA,EAAY,KAAA,EAAO,MAAA,CAAO,KAAA,KACpC,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,OAAO,KAAA,EAAM;AAAA,EAC9C,CAAC,CAAA;AACH,CAAA;AAEO,IAAM,UAAA,GAAa,GAAG,MAAA,EAAQ;AAAA,EACnC,OAAA,EAAS,iBAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAC;AAEM,SAAS,OAAO,GAAA,EAAgC;AACrD,EAAA,OAAO,GAAA,CAAI,GAAA,IAAO,EAAE,MAAA,EAAQ,eAAA,EAAgB;AAC9C;AAEA,SAAS,cAAc,OAAA,EAAoD;AACzE,EAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAO,OAAA,CAAQ,MAAA;AACnC,EAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,IAAA,MAAM,IAAI,MAAM,sEAAsE,CAAA;AAAA,EACxF;AACA,EAAA,OAAO,IAAI,iBAAiB,EAAE,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAG,OAAA,CAAQ,aAAA,EAAe,CAAA;AAClF","file":"index.js","sourcesContent":["import { IpGeoTraceClient, isPrivateOrReservedIp, type GeoLookup } from '@ipgeotrace/client';\nimport type { FastifyPluginAsync, FastifyRequest } from 'fastify';\nimport fp from 'fastify-plugin';\nimport type { IpGeoTracePluginOptions } from './types.js';\n\nconst plugin: FastifyPluginAsync<IpGeoTracePluginOptions> = async (fastify, options) => {\n const client = resolveClient(options);\n const shouldResolve = options.shouldResolve ?? (() => true);\n const ipSelector = options.ipSelector ?? ((req: FastifyRequest) => req.ip);\n\n if (!fastify.hasRequestDecorator('geo')) {\n fastify.decorateRequest('geo', undefined);\n }\n\n fastify.addHook('onRequest', async (req: FastifyRequest) => {\n if (!shouldResolve(req)) {\n req.geo = { status: 'not_attempted' };\n return;\n }\n\n const ip = ipSelector(req);\n if (!ip || isPrivateOrReservedIp(ip)) {\n req.geo = { status: 'skipped' };\n return;\n }\n\n const result = await client.resolve(ip);\n req.geo = result.ok\n ? { status: 'resolved', value: result.value }\n : { status: 'failed', error: result.error };\n });\n};\n\nexport const ipgeotrace = fp(plugin, {\n fastify: '>=4.26.0 <6.0.0',\n name: '@ipgeotrace/fastify',\n});\n\nexport function getGeo(req: FastifyRequest): GeoLookup {\n return req.geo ?? { status: 'not_attempted' };\n}\n\nfunction resolveClient(options: IpGeoTracePluginOptions): IpGeoTraceClient {\n if (options.client) return options.client;\n if (!options.apiKey) {\n throw new Error('IPGeoTrace: pass either a client or an apiKey to the fastify plugin.');\n }\n return new IpGeoTraceClient({ apiKey: options.apiKey, ...options.clientOptions });\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ipgeotrace/fastify",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fastify plugin for IPGeoTrace. Resolves the caller's location once per request and exposes it on request.geo.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ipgeotrace",
|
|
7
|
+
"geolocation",
|
|
8
|
+
"geoip",
|
|
9
|
+
"fastify",
|
|
10
|
+
"plugin",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"homepage": "https://ipgeotrace.com",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.cjs",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.17"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"fastify-plugin": "^4.5.1 || ^5.0.1",
|
|
35
|
+
"@ipgeotrace/client": "0.1.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"fastify": "^4.26.0 || ^5.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"fastify": "^5.0.0",
|
|
42
|
+
"tsup": "^8.3.5",
|
|
43
|
+
"typescript": "^5.6.3"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup",
|
|
47
|
+
"dev": "tsup --watch",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"clean": "rm -rf dist"
|
|
50
|
+
}
|
|
51
|
+
}
|