Add Plausible analytics on REST API
parent
b0e30cceb4
commit
0f69388e1a
|
@ -33,6 +33,7 @@
|
|||
"@publicodes/api": "^1.0.0-beta.52",
|
||||
"@sentry/node": "^7.1.1",
|
||||
"@sentry/tracing": "^7.1.1",
|
||||
"got": "^12.4.1",
|
||||
"ioredis": "^5.2.3",
|
||||
"koa": "^2.13.4",
|
||||
"koa-body": "^5.0.0",
|
||||
|
|
|
@ -6,6 +6,7 @@ import rules from 'modele-social'
|
|||
import Engine from 'publicodes'
|
||||
import { catchErrors } from './errors.js'
|
||||
import openapi from './openapi.json' assert { type: 'json' }
|
||||
import { plausibleMiddleware } from './plausible.js'
|
||||
import { rateLimiterMiddleware } from './rate-limiter.js'
|
||||
import { docRoutes } from './route/doc.js'
|
||||
import { openapiRoutes } from './route/openapi.js'
|
||||
|
@ -39,11 +40,9 @@ app.use(cors())
|
|||
|
||||
router.use('/api/v1', docRoutes(), openapiRoutes(openapi))
|
||||
|
||||
router.use(rateLimiterMiddleware)
|
||||
|
||||
const apiRoutes = publicodesAPI(new Engine(rules))
|
||||
|
||||
router.use('/api/v1', apiRoutes)
|
||||
router.use('/api/v1', plausibleMiddleware, rateLimiterMiddleware, apiRoutes)
|
||||
|
||||
app.use(router.routes())
|
||||
app.use(router.allowedMethods())
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
import got, { RequestError } from 'got'
|
||||
import { BaseContext, Next } from 'koa'
|
||||
|
||||
interface PlausibleEvent {
|
||||
eventName: string
|
||||
props?: Record<string, string | number | boolean>
|
||||
}
|
||||
|
||||
export const plausibleEvent = (
|
||||
ctx: BaseContext,
|
||||
{ eventName, props }: PlausibleEvent
|
||||
) => {
|
||||
const userAgent = ctx.headers['user-agent'] ?? ''
|
||||
const xForwardedFor =
|
||||
(Array.isArray(ctx.headers['x-forwarded-for'])
|
||||
? ctx.headers['x-forwarded-for'][0]
|
||||
: ctx.headers['x-forwarded-for']) ?? ''
|
||||
const referer = ctx.headers.referer ?? ''
|
||||
const url = ctx.href
|
||||
|
||||
return got('https://plausible.io/api/event', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'user-agent': userAgent,
|
||||
'x-forwarded-for': xForwardedFor,
|
||||
},
|
||||
json: {
|
||||
domain: 'mon-entreprise.urssaf.fr/api',
|
||||
name: eventName,
|
||||
referer,
|
||||
url,
|
||||
props,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const plausibleMiddleware = async (ctx: BaseContext, next: Next) => {
|
||||
const xxx = Date.now().toString()
|
||||
console.time('requestA-' + xxx)
|
||||
void plausibleEvent(ctx, { eventName: 'pageview' })
|
||||
.catch((err) => {
|
||||
const error = err as RequestError
|
||||
console.error(error.code, error.message)
|
||||
})
|
||||
.then(() => {
|
||||
console.timeEnd('requestA-' + xxx)
|
||||
})
|
||||
console.timeLog('requestA-' + xxx)
|
||||
|
||||
const result = (await next()) as unknown
|
||||
|
||||
console.time('requestB-' + xxx)
|
||||
void plausibleEvent(ctx, {
|
||||
eventName: 'status',
|
||||
props: {
|
||||
status: ctx.status,
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
const error = err as RequestError
|
||||
console.error(error.code, error.message)
|
||||
})
|
||||
.then(() => {
|
||||
console.timeEnd('requestB-' + xxx)
|
||||
})
|
||||
console.timeLog('requestB-' + xxx)
|
||||
|
||||
return result
|
||||
}
|
|
@ -44,7 +44,7 @@ export const rateLimiterMiddleware = async (ctx: BaseContext, next: Next) => {
|
|||
return
|
||||
}
|
||||
|
||||
await next()
|
||||
return (await next()) as unknown
|
||||
}
|
||||
|
||||
const isRateLimiterRes = (val: unknown): val is RateLimiterRes => {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import Router from '@koa/router'
|
||||
import koaStatic from 'koa-static'
|
||||
import { absolutePath } from 'swagger-ui-dist'
|
||||
import { plausibleMiddleware } from '../plausible.js'
|
||||
|
||||
export const docRoutes = () => {
|
||||
const router = new Router()
|
||||
|
||||
router.all(
|
||||
'/doc/(.*)',
|
||||
plausibleMiddleware,
|
||||
async (ctx, next) => {
|
||||
const rewriteURL =
|
||||
(typeof ctx.url === 'string' && ctx.url.replace(/.*\/doc\//, '/')) ||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Router from '@koa/router'
|
||||
import { Context } from 'koa'
|
||||
import { openapi as publicodesOpenapi } from '@publicodes/api'
|
||||
import { Context } from 'koa'
|
||||
import { plausibleMiddleware } from '../plausible.js'
|
||||
import { mergeDeep } from '../utils.js'
|
||||
|
||||
/**
|
||||
|
@ -13,7 +14,7 @@ export const openapiRoutes = (customOpenapi: Record<string, unknown>) => {
|
|||
|
||||
const mergedOpenapi = mergeDeep(publicodesOpenapi, customOpenapi)
|
||||
|
||||
router.get('/openapi.json', (ctx: Context) => {
|
||||
router.get('/openapi.json', plausibleMiddleware, (ctx: Context) => {
|
||||
ctx.type = 'application/json'
|
||||
ctx.body = mergedOpenapi
|
||||
})
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
"resolveJsonModule": true,
|
||||
|
||||
/* Advanced Options */
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
// temporary disable lib check waiting a fix for https://github.com/sindresorhus/got/issues/2051
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
|
|
120
yarn.lock
120
yarn.lock
|
@ -6392,6 +6392,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/is@npm:^5.2.0":
|
||||
version: 5.3.0
|
||||
resolution: "@sindresorhus/is@npm:5.3.0"
|
||||
checksum: b31cebabcdece3d5322de2a4dbc8c0f004e04147a00f2606787bcaf5655ad4b1954f6727fc6914c524009b2b9a2cc01c42835b55f651ce69fd2a0083b60bb852
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/slugify@npm:^1.1.0":
|
||||
version: 1.1.2
|
||||
resolution: "@sindresorhus/slugify@npm:1.1.2"
|
||||
|
@ -7926,6 +7933,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@szmarczak/http-timer@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "@szmarczak/http-timer@npm:5.0.1"
|
||||
dependencies:
|
||||
defer-to-connect: ^2.0.1
|
||||
checksum: fc9cb993e808806692e4a3337c90ece0ec00c89f4b67e3652a356b89730da98bc824273a6d67ca84d5f33cd85f317dcd5ce39d8cc0a2f060145a608a7cb8ce92
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/dom@npm:^8.3.0":
|
||||
version: 8.12.0
|
||||
resolution: "@testing-library/dom@npm:8.12.0"
|
||||
|
@ -8026,7 +8042,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/cacheable-request@npm:^6.0.1":
|
||||
"@types/cacheable-request@npm:^6.0.1, @types/cacheable-request@npm:^6.0.2":
|
||||
version: 6.0.2
|
||||
resolution: "@types/cacheable-request@npm:6.0.2"
|
||||
dependencies:
|
||||
|
@ -10007,6 +10023,7 @@ __metadata:
|
|||
"@types/node": ^17.0.35
|
||||
"@types/swagger-ui-dist": ^3.30.1
|
||||
chai-http: ^4.3.0
|
||||
got: ^12.4.1
|
||||
ioredis: ^5.2.3
|
||||
koa: ^2.13.4
|
||||
koa-body: ^5.0.0
|
||||
|
@ -11448,6 +11465,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cacheable-lookup@npm:^6.0.4":
|
||||
version: 6.1.0
|
||||
resolution: "cacheable-lookup@npm:6.1.0"
|
||||
checksum: 4e37afe897219b1035335b0765106a2c970ffa930497b43cac5000b860f3b17f48d004187279fae97e2e4cbf6a3693709b6d64af65279c7d6c8453321d36d118
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cacheable-request@npm:^2.1.1":
|
||||
version: 2.1.4
|
||||
resolution: "cacheable-request@npm:2.1.4"
|
||||
|
@ -11478,7 +11502,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cacheable-request@npm:^7.0.1":
|
||||
"cacheable-request@npm:^7.0.1, cacheable-request@npm:^7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "cacheable-request@npm:7.0.2"
|
||||
dependencies:
|
||||
|
@ -13281,6 +13305,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-response@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "decompress-response@npm:6.0.0"
|
||||
dependencies:
|
||||
mimic-response: ^3.1.0
|
||||
checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-tar@npm:^4.0.0, decompress-tar@npm:^4.1.0, decompress-tar@npm:^4.1.1":
|
||||
version: 4.1.1
|
||||
resolution: "decompress-tar@npm:4.1.1"
|
||||
|
@ -13438,7 +13471,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"defer-to-connect@npm:^2.0.0":
|
||||
"defer-to-connect@npm:^2.0.0, defer-to-connect@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "defer-to-connect@npm:2.0.1"
|
||||
checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b
|
||||
|
@ -16138,6 +16171,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data-encoder@npm:^2.1.0":
|
||||
version: 2.1.2
|
||||
resolution: "form-data-encoder@npm:2.1.2"
|
||||
checksum: 5c6401e3ebd2ba2adfa151c9fbd1df5adae8b1dd7bca5b18ab25ad1f9b83e20ddffb6b9ff77f5006b93d7ec2032e22828c9543c0bd4b2bc5b05335c31a3ba5b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data@npm:^2.3.1, form-data@npm:^2.5.0":
|
||||
version: 2.5.1
|
||||
resolution: "form-data@npm:2.5.1"
|
||||
|
@ -16915,6 +16955,26 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"got@npm:^12.4.1":
|
||||
version: 12.4.1
|
||||
resolution: "got@npm:12.4.1"
|
||||
dependencies:
|
||||
"@sindresorhus/is": ^5.2.0
|
||||
"@szmarczak/http-timer": ^5.0.1
|
||||
"@types/cacheable-request": ^6.0.2
|
||||
cacheable-lookup: ^6.0.4
|
||||
cacheable-request: ^7.0.2
|
||||
decompress-response: ^6.0.0
|
||||
form-data-encoder: ^2.1.0
|
||||
get-stream: ^6.0.1
|
||||
http2-wrapper: ^2.1.10
|
||||
lowercase-keys: ^3.0.0
|
||||
p-cancelable: ^3.0.0
|
||||
responselike: ^3.0.0
|
||||
checksum: 56a150ea144c951868d0fb3d288bbcbc2c0d3f8f9c200c6fd60ffdc921f6aeb26d140f57fb973ab89e1aeb03a92c4b6422743e5a74d3cb081715901e249f2640
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"got@npm:^8.3.1":
|
||||
version: 8.3.2
|
||||
resolution: "got@npm:8.3.2"
|
||||
|
@ -17588,6 +17648,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"http2-wrapper@npm:^2.1.10":
|
||||
version: 2.1.11
|
||||
resolution: "http2-wrapper@npm:2.1.11"
|
||||
dependencies:
|
||||
quick-lru: ^5.1.1
|
||||
resolve-alpn: ^1.2.0
|
||||
checksum: 5da05aa2c77226ac9cc82c616383f59c8f31b79897b02ecbe44b09714be1fca1f21bb184e672a669ca2830eefea4edac5f07e71c00cb5a8c5afec8e5a20cfaf7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-browserify@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "https-browserify@npm:1.0.0"
|
||||
|
@ -20208,6 +20278,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lowercase-keys@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "lowercase-keys@npm:3.0.0"
|
||||
checksum: 67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^5.1.1":
|
||||
version: 5.1.1
|
||||
resolution: "lru-cache@npm:5.1.1"
|
||||
|
@ -20764,6 +20841,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mimic-response@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "mimic-response@npm:3.1.0"
|
||||
checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"min-document@npm:^2.19.0":
|
||||
version: 2.19.0
|
||||
resolution: "min-document@npm:2.19.0"
|
||||
|
@ -22161,6 +22245,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-cancelable@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "p-cancelable@npm:3.0.0"
|
||||
checksum: 2b5ae34218f9c2cf7a7c18e5d9a726ef9b165ef07e6c959f6738371509e747334b5f78f3bcdeb03d8a12dcb978faf641fd87eb21486ed7d36fb823b8ddef3219
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-event@npm:^2.1.0":
|
||||
version: 2.3.1
|
||||
resolution: "p-event@npm:2.3.1"
|
||||
|
@ -23495,6 +23586,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"quick-lru@npm:^5.1.1":
|
||||
version: 5.1.1
|
||||
resolution: "quick-lru@npm:5.1.1"
|
||||
checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"quick-temp@npm:^0.1.8":
|
||||
version: 0.1.8
|
||||
resolution: "quick-temp@npm:0.1.8"
|
||||
|
@ -24549,6 +24647,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve-alpn@npm:^1.2.0":
|
||||
version: 1.2.1
|
||||
resolution: "resolve-alpn@npm:1.2.1"
|
||||
checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve-from@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "resolve-from@npm:4.0.0"
|
||||
|
@ -24691,6 +24796,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"responselike@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "responselike@npm:3.0.0"
|
||||
dependencies:
|
||||
lowercase-keys: ^3.0.0
|
||||
checksum: e0cc9be30df4f415d6d83cdede3c5c887cd4a73e7cc1708bcaab1d50a28d15acb68460ac5b02bcc55a42f3d493729c8856427dcf6e57e6e128ad05cba4cfb95e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"restore-cursor@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "restore-cursor@npm:2.0.0"
|
||||
|
|
Loading…
Reference in New Issue