fix: sync handle refresh token + up modjo
All checks were successful
/ deploy (push) Successful in 13s
/ build (map[dockerfile:./services/app/Dockerfile name:app]) (push) Successful in 53s
/ build (map[dockerfile:./services/files/Dockerfile name:files]) (push) Successful in 1m57s
/ build (map[dockerfile:./services/watchers/Dockerfile name:watchers]) (push) Successful in 2m5s
/ build (map[dockerfile:./services/web/Dockerfile name:web]) (push) Successful in 2m6s
/ build (map[dockerfile:./services/api/Dockerfile name:api]) (push) Successful in 2m10s
/ build (map[dockerfile:./services/hasura/Dockerfile name:hasura]) (push) Successful in 1m10s
/ build (map[dockerfile:./services/tasks/Dockerfile name:tasks]) (push) Successful in 2m3s

This commit is contained in:
devthejo 2025-06-30 12:34:00 +02:00
parent c036839233
commit 3bfa3d78d5
13 changed files with 444 additions and 274 deletions

View file

@ -1,5 +1,4 @@
const { jwtVerify } = require("jose")
const jwtDecode = require("jwt-decode")
const getHasuraClaimsFromJWT = require("@modjo/hasura/utils/jwt/get-hasura-claims-from-jwt")
const { ctx } = require("@modjo/core")
const { reqCtx } = require("@modjo/express/ctx")
@ -27,7 +26,7 @@ module.exports = function () {
}
return async function auth(jwt, scopes) {
const hasMetaExpUser = scopes.includes("meta.exp-user")
const hasMetaAuthToken = scopes.includes("meta.auth-token")
let jwtVerified = false
try {
@ -42,11 +41,11 @@ module.exports = function () {
} catch (err) {
const logger = ctx.require("logger")
// Allow expired JWT only if meta.exp-user scope is present
if (hasMetaExpUser && err.code === "ERR_JWT_EXPIRED") {
// Allow expired JWT only if meta.auth-token scope is present
if (hasMetaAuthToken && err.code === "ERR_JWT_EXPIRED") {
logger.debug(
{ error: err },
"Allowing expired JWT for meta.exp-user scope"
"Allowing expired JWT for meta.auth-token scope"
)
// Continue processing with expired JWT
} else {
@ -55,22 +54,23 @@ module.exports = function () {
}
}
const claims = getHasuraClaimsFromJWT(jwt, claimsNamespace)
const session = sessionVarsFromClaims(claims)
// For meta.auth-token scope, check for X-Auth-Token header
if (hasMetaAuthToken) {
const req = reqCtx.get("req")
const authTokenHeader = req?.headers?.["x-auth-token"]
// Add exp claim to session if meta.exp-user scope is present
if (hasMetaExpUser) {
try {
const payload = jwtDecode(jwt)
if (payload && payload.exp) {
session.exp = payload.exp
}
} catch (err) {
const logger = ctx.require("logger")
logger.error({ error: err }, "Failed to decode JWT for exp claim")
if (authTokenHeader) {
// Create a session that indicates auth token processing is needed
const session = { isAuthTokenRequest: true, authToken: authTokenHeader }
reqCtx.set("session", session)
return true
}
}
// Regular user JWT processing
const claims = getHasuraClaimsFromJWT(jwt, claimsNamespace)
const session = sessionVarsFromClaims(claims)
if (!isScopeAllowed(session, scopes)) {
return false
}

View file

@ -5,9 +5,9 @@
"eslint": "^8.10.0"
},
"dependencies": {
"@modjo/core": "*",
"@modjo/hasura": "*",
"@modjo/microservice-oapi": "*",
"@modjo/core": "^1.10.0",
"@modjo/hasura": "^1.10.0",
"@modjo/microservice-oapi": "^1.10.0",
"@what3words/api": "^5.4.0",
"fast-levenshtein": "^3.0.0",
"fnv-plus": "^1.3.1",

View file

@ -2,7 +2,7 @@
"name": "redis-queue-dedup",
"packageManager": "yarn@4.1.0",
"dependencies": {
"@modjo/core": "^1.6.0",
"@modjo/core": "^1.10.0",
"murmurhash": "^2.0.1"
}
}

View file

@ -27,7 +27,8 @@
"lint": "eslint .",
"test": "jest tests",
"clear:local": "git clean -xdf",
"postinstall": "[ -d '.husky' ] && husky install || true && bin/direnv allow"
"postinstall": "[ -d '.husky' ] && husky install || true && bin/direnv allow",
"up:modjo": "yarn up '@modjo/*'"
},
"lint-staged": {
"*.{js,jsx}": "eslint"

View file

@ -14,15 +14,15 @@
},
"dependencies": {
"@as/postgres-types": "workspace:^",
"@modjo/amqp": "*",
"@modjo/core": "*",
"@modjo/express": "*",
"@modjo/hasura": "*",
"@modjo/ioredis": "*",
"@modjo/microservice-oapi": "*",
"@modjo/oa-graphql": "*",
"@modjo/postgres": "*",
"@modjo/sentry": "*",
"@modjo/amqp": "^1.10.0",
"@modjo/core": "^1.10.0",
"@modjo/express": "^1.10.0",
"@modjo/hasura": "^1.10.0",
"@modjo/ioredis": "^1.10.0",
"@modjo/microservice-oapi": "^1.10.0",
"@modjo/oa-graphql": "^1.10.0",
"@modjo/postgres": "^1.10.0",
"@modjo/sentry": "^1.10.0",
"@vercel/ncc": "^0.33.3",
"argon2": "^0.31.0",
"async": "^3.2.5",

View file

@ -1,151 +1,25 @@
const httpError = require("http-errors")
const jwtDecode = require("jwt-decode")
const { nanoid } = require("nanoid")
const { ctx } = require("@modjo/core")
module.exports = async function ({ services: { sortRolesByLevel, signJwt } }) {
const config = ctx.require("config.project")
const sql = ctx.require("postgres")
const { claimsNamespace, jwtExpirationInHours } = config
module.exports = async function ({ services: { authTokenHandler } }) {
async function doAuthLoginToken(req) {
const { authTokenJwt, phoneModel = null, deviceUuid = null } = req.body
const { authToken } = jwtDecode(authTokenJwt)
let userId
let deviceId
let roles
// Validate the auth token JWT and extract the auth token
const authToken = authTokenHandler.validateAuthToken(authTokenJwt)
try {
const [row] = await sql`
SELECT
"user_id" as "userId",
"device_id" as "deviceId"
FROM
"auth_token"
WHERE
"auth_token" = ${authToken}
`
userId = row.userId
deviceId = row.deviceId
} catch (e) {
throw httpError(410)
}
if (!userId) {
await sql.begin(async (sql) => {
await sql`set constraints all deferred`
;[{ id: userId }] = await sql`
INSERT INTO "user" DEFAULT
VALUES
RETURNING
id
`
;[{ id: deviceId }] = await sql`
INSERT INTO "device" ("user_id", "phone_model", "uuid")
VALUES (${userId}, ${phoneModel}, ${deviceUuid})
RETURNING
id
`
await sql`
UPDATE
"auth_token"
SET
"user_id" = ${userId},
"device_id" = ${deviceId}
WHERE
"auth_token" = ${authToken}
`
// Get or create user session (userId, deviceId, roles)
const { userId, deviceId, roles } =
await authTokenHandler.getOrCreateUserSession(
authToken,
phoneModel,
deviceUuid
)
const role = "user"
await sql`
INSERT INTO "user_role" ("user_id", "role")
VALUES (${userId}, ${role})
`
roles = [role]
const authSignKey = nanoid()
await sql`
INSERT INTO "auth_sign_key" ("user_id", "key")
VALUES (${userId}, ${authSignKey})
`
})
} else {
if (!deviceId && deviceUuid) {
// First check if a device with this UUID already exists for this user
const existingDevice = await sql`
SELECT
id
FROM
"device"
WHERE
"user_id" = ${userId}
AND "uuid" = ${deviceUuid}
LIMIT 1
`
if (existingDevice.length > 0) {
deviceId = existingDevice[0].id
}
}
if (!deviceId) {
// Only create new device if UUID doesn't exist
;[{ id: deviceId }] = await sql`
INSERT INTO "device" ("user_id", "phone_model", "uuid")
VALUES (${userId}, ${phoneModel}, ${deviceUuid})
RETURNING
id
`
}
// Update the auth_token to reference this device
await sql`
UPDATE
"auth_token"
SET
"device_id" = ${deviceId}
WHERE
"auth_token" = ${authToken}
`
roles = (
await sql`
SELECT
"role"
FROM
"user_role"
WHERE
"user_id" = ${userId}
`.values()
).map(([role]) => role)
}
if (roles.length === 0) {
roles.push("user")
}
const [defaultRole] = sortRolesByLevel(roles)
const hasuraClaim = {}
hasuraClaim["x-hasura-default-role"] = defaultRole
hasuraClaim["x-hasura-allowed-roles"] = roles
hasuraClaim["x-hasura-user-id"] = userId.toString()
hasuraClaim["x-hasura-device-id"] = deviceId.toString()
const exp = Math.round(
new Date(Date.now() + jwtExpirationInHours * 3600000) / 1000
// Generate user JWT
const userBearerJwt = await authTokenHandler.generateUserJwt(
userId,
deviceId,
roles
)
// DEV
// const exp = Math.round(new Date(Date.now() + 5000) / 1000)
const jwtData = {
[claimsNamespace]: hasuraClaim,
exp,
}
const userBearerJwt = await signJwt(jwtData)
return { userBearerJwt }
}

View file

@ -5,7 +5,7 @@ const { reqCtx } = require("@modjo/express/ctx")
const tasks = require("~/tasks")
module.exports = function () {
module.exports = function ({ services: { authTokenHandler } }) {
const { addTask } = ctx.require("amqp")
const redis = ctx.require("redisHotGeodata")
@ -23,39 +23,69 @@ module.exports = function () {
longitude,
},
} = location
// console.log("addOneGeolocSync", req.body)
const session = reqCtx.get("session")
let userId
let deviceId
let userBearerJwt = null
const { deviceId } = session
// Check if this is an auth token request (set by auth.js)
if (session && session.isAuthTokenRequest) {
// This is an auth token request, process it
try {
logger.debug("Processing auth token for geoloc sync")
// Check JWT expiration sequence to prevent replay attacks
if (session.exp) {
const deviceExpKey = `device:${deviceId}:last_exp`
const storedLastExp = await redis.get(deviceExpKey)
const { authToken } = session
const {
userId: newUserId,
deviceId: newDeviceId,
roles,
} = await authTokenHandler.getOrCreateUserSession(
authToken,
req.body.phoneModel,
req.body.deviceUuid
)
if (storedLastExp && session.exp < parseInt(storedLastExp, 10)) {
throw httpError(401, "not the latest jwt")
userId = newUserId
deviceId = newDeviceId
// Generate new user JWT for token refresh
userBearerJwt = await authTokenHandler.generateUserJwt(
userId,
deviceId,
roles
)
logger.debug({
action: "geoloc-sync-auth-token",
userId,
deviceId,
tokenRefreshed: true,
})
} catch (error) {
logger.error("Failed to process auth token", { error: error.message })
throw httpError(401, "Invalid auth token")
}
// Store the new expiration date
await redis.set(deviceExpKey, session.exp)
} else if (session && session.userId && session.deviceId) {
// Regular user JWT session
userId = session.userId
deviceId = session.deviceId
logger.debug({ action: "geoloc-sync-user-jwt", userId, deviceId })
} else {
// Invalid session
logger.error("Invalid session", { session })
throw httpError(401, "Invalid session")
}
const { userId } = session
logger.debug({ action: "geoloc-sync", userId, deviceId })
if (!userId || !deviceId) {
throw httpError(401, "Missing user or device information")
}
const coordinates = [longitude, latitude]
await async.parallel([
async () => {
// const transaction = redis.multi()
// transaction.geoadd("device", longitude, latitude, deviceId)
// transaction.publish("deviceSet", deviceId)
// await transaction.exec()
await redis.geoadd("device", longitude, latitude, deviceId)
await addTask(tasks.GEOCODE_MOVE, { deviceId, userId, coordinates })
},
async () =>
@ -70,7 +100,14 @@ module.exports = function () {
}),
])
return { ok: true }
const response = { ok: true }
// Include userBearerJwt in response if token refresh occurred
if (userBearerJwt) {
response.userBearerJwt = userBearerJwt
}
return response
}
return [addOneGeolocSync]

View file

@ -1,6 +1,13 @@
# description:
x-security:
- auth: ["user", "meta.exp-user"]
- auth: ["user", "meta.auth-token"]
parameters:
- name: X-Auth-Token
in: header
required: false
schema:
type: string
description: Auth token for token refresh when user JWT is expired
requestBody:
required: true
content:
@ -101,3 +108,7 @@ responses:
properties:
ok:
type: boolean
userBearerJwt:
type: string
description: New user JWT token when auth token refresh occurred
nullable: true

View file

@ -0,0 +1,169 @@
const httpError = require("http-errors")
const jwtDecode = require("jwt-decode")
const { nanoid } = require("nanoid")
const { ctx } = require("@modjo/core")
module.exports = ({ services: { sortRolesByLevel, signJwt } }) => {
const config = ctx.require("config.project")
const sql = ctx.require("postgres")
const { claimsNamespace, jwtExpirationInHours } = config
async function validateAuthToken(authTokenJwt) {
try {
const { authToken } = jwtDecode(authTokenJwt)
return authToken
} catch (e) {
throw httpError(400, "Invalid auth token JWT")
}
}
async function getOrCreateUserSession(
authToken,
phoneModel = null,
deviceUuid = null
) {
let userId
let deviceId
let roles
try {
const [row] = await sql`
SELECT
"user_id" as "userId",
"device_id" as "deviceId"
FROM
"auth_token"
WHERE
"auth_token" = ${authToken}
`
userId = row.userId
deviceId = row.deviceId
} catch (e) {
throw httpError(410, "Auth token not found")
}
if (!userId) {
await sql.begin(async (sql) => {
await sql`set constraints all deferred`
;[{ id: userId }] = await sql`
INSERT INTO "user" DEFAULT
VALUES
RETURNING
id
`
;[{ id: deviceId }] = await sql`
INSERT INTO "device" ("user_id", "phone_model", "uuid")
VALUES (${userId}, ${phoneModel}, ${deviceUuid})
RETURNING
id
`
await sql`
UPDATE
"auth_token"
SET
"user_id" = ${userId},
"device_id" = ${deviceId}
WHERE
"auth_token" = ${authToken}
`
const role = "user"
await sql`
INSERT INTO "user_role" ("user_id", "role")
VALUES (${userId}, ${role})
`
roles = [role]
const authSignKey = nanoid()
await sql`
INSERT INTO "auth_sign_key" ("user_id", "key")
VALUES (${userId}, ${authSignKey})
`
})
} else {
if (!deviceId && deviceUuid) {
// First check if a device with this UUID already exists for this user
const existingDevice = await sql`
SELECT
id
FROM
"device"
WHERE
"user_id" = ${userId}
AND "uuid" = ${deviceUuid}
LIMIT 1
`
if (existingDevice.length > 0) {
deviceId = existingDevice[0].id
}
}
if (!deviceId) {
// Only create new device if UUID doesn't exist
;[{ id: deviceId }] = await sql`
INSERT INTO "device" ("user_id", "phone_model", "uuid")
VALUES (${userId}, ${phoneModel}, ${deviceUuid})
RETURNING
id
`
}
// Update the auth_token to reference this device
await sql`
UPDATE
"auth_token"
SET
"device_id" = ${deviceId}
WHERE
"auth_token" = ${authToken}
`
roles = (
await sql`
SELECT
"role"
FROM
"user_role"
WHERE
"user_id" = ${userId}
`.values()
).map(([role]) => role)
}
if (roles.length === 0) {
roles.push("user")
}
return { userId, deviceId, roles }
}
async function generateUserJwt(userId, deviceId, roles) {
const [defaultRole] = sortRolesByLevel(roles)
const hasuraClaim = {}
hasuraClaim["x-hasura-default-role"] = defaultRole
hasuraClaim["x-hasura-allowed-roles"] = roles
hasuraClaim["x-hasura-user-id"] = userId.toString()
hasuraClaim["x-hasura-device-id"] = deviceId.toString()
const exp = Math.round(
new Date(Date.now() + jwtExpirationInHours * 3600000) / 1000
)
const jwtData = {
[claimsNamespace]: hasuraClaim,
exp,
}
return signJwt(jwtData)
}
return {
validateAuthToken,
getOrCreateUserSession,
generateUserJwt,
}
}

View file

@ -11,13 +11,13 @@
},
"dependencies": {
"@as/postgres-types": "workspace:^",
"@modjo/amqp": "*",
"@modjo/core": "*",
"@modjo/express": "*",
"@modjo/microservice-oapi": "*",
"@modjo/minio": "*",
"@modjo/postgres": "*",
"@modjo/sentry": "^1.6.2",
"@modjo/amqp": "^1.10.0",
"@modjo/core": "^1.10.0",
"@modjo/express": "^1.10.0",
"@modjo/microservice-oapi": "^1.10.0",
"@modjo/minio": "^1.10.0",
"@modjo/postgres": "^1.10.0",
"@modjo/sentry": "^1.10.0",
"@vercel/ncc": "^0.33.3",
"common": "workspace:^",
"lodash.tointeger": "^4.0.4",

View file

@ -10,11 +10,11 @@
},
"dependencies": {
"@as/postgres-types": "workspace:^",
"@modjo/core": "*",
"@modjo/ioredis": "^1.6.0",
"@modjo/microservice-worker": "*",
"@modjo/postgres": "*",
"@modjo/sentry": "^1.6.2",
"@modjo/core": "^1.10.0",
"@modjo/ioredis": "^1.10.0",
"@modjo/microservice-worker": "^1.10.0",
"@modjo/postgres": "^1.10.0",
"@modjo/sentry": "^1.10.0",
"@vercel/ncc": "^0.30.0",
"@what3words/api": "^4.0.4",
"async": "^3.2.5",

View file

@ -12,11 +12,11 @@
"dependencies": {
"@apollo/client": "^3.5.8",
"@as/postgres-types": "workspace:^",
"@modjo/core": "*",
"@modjo/ioredis": "*",
"@modjo/microservice-watcher": "*",
"@modjo/postgres": "*",
"@modjo/sentry": "^1.6.2",
"@modjo/core": "^1.10.0",
"@modjo/ioredis": "^1.10.0",
"@modjo/microservice-watcher": "^1.10.0",
"@modjo/postgres": "^1.10.0",
"@modjo/sentry": "^1.10.0",
"@vercel/ncc": "^0.30.0",
"async": "^3.2.5",
"common": "workspace:^",

204
yarn.lock
View file

@ -314,15 +314,15 @@ __metadata:
resolution: "@as/api@workspace:services/api"
dependencies:
"@as/postgres-types": "workspace:^"
"@modjo/amqp": "npm:*"
"@modjo/core": "npm:*"
"@modjo/express": "npm:*"
"@modjo/hasura": "npm:*"
"@modjo/ioredis": "npm:*"
"@modjo/microservice-oapi": "npm:*"
"@modjo/oa-graphql": "npm:*"
"@modjo/postgres": "npm:*"
"@modjo/sentry": "npm:*"
"@modjo/amqp": "npm:^1.10.0"
"@modjo/core": "npm:^1.10.0"
"@modjo/express": "npm:^1.10.0"
"@modjo/hasura": "npm:^1.10.0"
"@modjo/ioredis": "npm:^1.10.0"
"@modjo/microservice-oapi": "npm:^1.10.0"
"@modjo/oa-graphql": "npm:^1.10.0"
"@modjo/postgres": "npm:^1.10.0"
"@modjo/sentry": "npm:^1.10.0"
"@vercel/ncc": "npm:^0.33.3"
argon2: "npm:^0.31.0"
async: "npm:^3.2.5"
@ -351,13 +351,13 @@ __metadata:
resolution: "@as/files@workspace:services/files"
dependencies:
"@as/postgres-types": "workspace:^"
"@modjo/amqp": "npm:*"
"@modjo/core": "npm:*"
"@modjo/express": "npm:*"
"@modjo/microservice-oapi": "npm:*"
"@modjo/minio": "npm:*"
"@modjo/postgres": "npm:*"
"@modjo/sentry": "npm:^1.6.2"
"@modjo/amqp": "npm:^1.10.0"
"@modjo/core": "npm:^1.10.0"
"@modjo/express": "npm:^1.10.0"
"@modjo/microservice-oapi": "npm:^1.10.0"
"@modjo/minio": "npm:^1.10.0"
"@modjo/postgres": "npm:^1.10.0"
"@modjo/sentry": "npm:^1.10.0"
"@vercel/ncc": "npm:^0.33.3"
common: "workspace:^"
link-module-alias: "npm:^1.2.0"
@ -380,11 +380,11 @@ __metadata:
resolution: "@as/tasks@workspace:services/tasks"
dependencies:
"@as/postgres-types": "workspace:^"
"@modjo/core": "npm:*"
"@modjo/ioredis": "npm:^1.6.0"
"@modjo/microservice-worker": "npm:*"
"@modjo/postgres": "npm:*"
"@modjo/sentry": "npm:^1.6.2"
"@modjo/core": "npm:^1.10.0"
"@modjo/ioredis": "npm:^1.10.0"
"@modjo/microservice-worker": "npm:^1.10.0"
"@modjo/postgres": "npm:^1.10.0"
"@modjo/sentry": "npm:^1.10.0"
"@vercel/ncc": "npm:^0.30.0"
"@what3words/api": "npm:^4.0.4"
async: "npm:^3.2.5"
@ -428,11 +428,11 @@ __metadata:
dependencies:
"@apollo/client": "npm:^3.5.8"
"@as/postgres-types": "workspace:^"
"@modjo/core": "npm:*"
"@modjo/ioredis": "npm:*"
"@modjo/microservice-watcher": "npm:*"
"@modjo/postgres": "npm:*"
"@modjo/sentry": "npm:^1.6.2"
"@modjo/core": "npm:^1.10.0"
"@modjo/ioredis": "npm:^1.10.0"
"@modjo/microservice-watcher": "npm:^1.10.0"
"@modjo/postgres": "npm:^1.10.0"
"@modjo/sentry": "npm:^1.10.0"
"@vercel/ncc": "npm:^0.30.0"
async: "npm:^3.2.5"
common: "workspace:^"
@ -3153,6 +3153,20 @@ __metadata:
languageName: node
linkType: hard
"@modjo/amqp@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/amqp@npm:1.10.0"
dependencies:
"@modjo/config": "npm:*"
"@modjo/logger": "npm:*"
amqplib: "npm:^0.10.5"
nctx: "npm:^2.2.0"
wait-on: "npm:^6.0.1"
ya-retry: "npm:^1.2.0"
checksum: 10/37c15566a1d46ed900452330886e04f9861f24fb24f6aa49f2e8f74bf4994e9cde787a892b47849e458b390d3d20d88f54558c35124d21de338f6a9286b13400
languageName: node
linkType: hard
"@modjo/apollo-client@npm:*":
version: 1.9.6
resolution: "@modjo/apollo-client@npm:1.9.6"
@ -3179,7 +3193,7 @@ __metadata:
languageName: node
linkType: hard
"@modjo/core@npm:*, @modjo/core@npm:^1.6.0":
"@modjo/core@npm:*":
version: 1.9.6
resolution: "@modjo/core@npm:1.9.6"
dependencies:
@ -3205,6 +3219,32 @@ __metadata:
languageName: node
linkType: hard
"@modjo/core@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/core@npm:1.10.0"
dependencies:
"@foundernetes/dbug": "npm:^1.0.0"
commander: "npm:^9.1.0"
fs-extra: "npm:^11.1.1"
js-yaml: "npm:^4.1.0"
link-module-alias: "npm:^1.2.0"
lodash: "npm:^4.17.21"
lodash.camelcase: "npm:^4.3.0"
lodash.capitalize: "npm:^4.2.1"
lodash.defaultsdeep: "npm:^4.6.1"
lodash.get: "npm:^4.4.2"
lodash.kebabcase: "npm:^4.1.1"
lodash.merge: "npm:^4.6.2"
lodash.mergewith: "npm:^4.6.2"
lodash.omit: "npm:^4.5.0"
lodash.set: "npm:^4.3.2"
nctx: "npm:^2.2.0"
pretty-ms: "npm:^7.0.1"
yup: "npm:^0.32.11"
checksum: 10/d29008c0bf8b5a932c46414469b1fc26fb979e263109b1e484b777ed4d7a41fff8a26b9dd071d92e9e94244a9b094f82d8ebc9680734458878418322d1d52197
languageName: node
linkType: hard
"@modjo/express@npm:*":
version: 1.9.6
resolution: "@modjo/express@npm:1.9.6"
@ -3225,6 +3265,26 @@ __metadata:
languageName: node
linkType: hard
"@modjo/express@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/express@npm:1.10.0"
dependencies:
"@modjo/config": "npm:*"
"@modjo/http-logger": "npm:*"
"@modjo/http-server": "npm:*"
"@modjo/logger": "npm:*"
"@types/express": "npm:^5.0.0"
"@types/ws": "npm:^8.5.12"
cookie-parser: "npm:^1.4.6"
cors: "npm:^2.8.5"
express: "npm:^5.0.1"
nctx: "npm:^2.2.0"
websocket-express: "npm:^3.1.2"
ws: "npm:^8.18.0"
checksum: 10/026621b82f27d9f489748f8b9114f27b605c81ce299c5fe6e1895c0318ae29fbcf29817ed89d094ed58fcd274b2abda414cf3fbaad7e932d0b4e0ede0a35fde2
languageName: node
linkType: hard
"@modjo/graphql-pubsub@npm:*":
version: 1.9.6
resolution: "@modjo/graphql-pubsub@npm:1.9.6"
@ -3237,9 +3297,9 @@ __metadata:
languageName: node
linkType: hard
"@modjo/hasura@npm:*":
version: 1.9.6
resolution: "@modjo/hasura@npm:1.9.6"
"@modjo/hasura@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/hasura@npm:1.10.0"
dependencies:
"@modjo/config": "npm:*"
axios: "npm:^1.4.0"
@ -3251,7 +3311,7 @@ __metadata:
nctx: "npm:^2.2.0"
postgres: "npm:^3.4.4"
wait-on: "npm:^6.0.1"
checksum: 10/3adcf528d13888a7e3f81f54e1475c71b4eb39df82dffcdff354443a7091b1a59fc191714821af2cb4cf9582d07306227c0bc1204b258abcf55fb244c2574390
checksum: 10/744bd911203f48c6e2046168998677550bf32dd959bd57455eff4cbdaed5c0ce02732413c9c9848718a496bd7f4f9819aa7296515edaf8a648cd06e76cb7da88
languageName: node
linkType: hard
@ -3278,15 +3338,15 @@ __metadata:
languageName: node
linkType: hard
"@modjo/ioredis@npm:*, @modjo/ioredis@npm:^1.6.0":
version: 1.9.6
resolution: "@modjo/ioredis@npm:1.9.6"
"@modjo/ioredis@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/ioredis@npm:1.10.0"
dependencies:
"@modjo/config": "npm:*"
ioredis: "npm:^5.3.2"
nctx: "npm:^2.2.0"
wait-on: "npm:^6.0.1"
checksum: 10/1b66d88c7f1a84693519965196c48764a42e62db6d4dd145e46ee757053fcedb0f93d919cca98a02662579199a0765c6bf0ab1f8597f72779ca3df26f2386fac
checksum: 10/324a3b2cbb5f43b80fc8445b907517c1cd077b72495051efdc733571641efaddac5d59d9829718882c3159172d65af0b8797fa5b15035ec8cdaadc131ed6beb7
languageName: node
linkType: hard
@ -3332,21 +3392,39 @@ __metadata:
languageName: node
linkType: hard
"@modjo/microservice-watcher@npm:*":
version: 1.9.6
resolution: "@modjo/microservice-watcher@npm:1.9.6"
"@modjo/microservice-oapi@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/microservice-oapi@npm:1.10.0"
dependencies:
"@modjo/core": "npm:*"
"@modjo/express": "npm:*"
"@modjo/http-logger": "npm:*"
"@modjo/http-server": "npm:*"
"@modjo/lightship": "npm:*"
"@modjo/logger": "npm:*"
"@modjo/microservice-oapi": "npm:*"
"@modjo/oa": "npm:*"
"@modjo/shutdown-handlers": "npm:*"
nctx: "npm:^2.2.0"
checksum: 10/e6e4671d6718b98b7c4bacf4cfccc33bc6b812f418742ecfdd2b9a3870e4c2c81cd20d4fb813af7d62721dc0327747237b66e1e9824b1d3d6973df9d250a4929
languageName: node
linkType: hard
"@modjo/microservice-watcher@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/microservice-watcher@npm:1.10.0"
dependencies:
"@modjo/amqp": "npm:*"
"@modjo/apollo-client": "npm:*"
"@modjo/core": "npm:*"
nctx: "npm:^2.2.0"
checksum: 10/43a8c8d6cf323df9c57e6bbe400d700fd6a4d6d5c379d842454b05189e77a14461675864b3b72949e8d7b7fbebd3312f0f7c7aeba1ab1066216b236a5af9c970
checksum: 10/543927812b86e2a52ac963441e4c14e3ab3a7b8e7d69de9f78086fd500adb6c5c2b86ac0a7bff182c477166be8fb7c1952935f9d5b3d1f5935899603a53c8a4f
languageName: node
linkType: hard
"@modjo/microservice-worker@npm:*":
version: 1.9.6
resolution: "@modjo/microservice-worker@npm:1.9.6"
"@modjo/microservice-worker@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/microservice-worker@npm:1.10.0"
dependencies:
"@modjo/amqp": "npm:*"
"@modjo/config": "npm:*"
@ -3356,25 +3434,25 @@ __metadata:
lodash.kebabcase: "npm:^4.1.1"
nctx: "npm:^2.2.0"
pretty-ms: "npm:^7.0.1"
checksum: 10/69ef8240d0db165dd11bb154811809ac82a31cf679bd4c7d76faa3b0129e4342cb4d57652892022c74cbdde2ae222145c1582fecddcf21fcc05d4ffdc2bf8559
checksum: 10/74a2e2aa676742745109705dbde62b617bdae0bffa1bb4085b151c24dfcc9d5e1f75269835a1939478b7e64c19d96ca808d282a8ec385f058fab88f779f0dae2
languageName: node
linkType: hard
"@modjo/minio@npm:*":
version: 1.9.6
resolution: "@modjo/minio@npm:1.9.6"
"@modjo/minio@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/minio@npm:1.10.0"
dependencies:
"@modjo/config": "npm:*"
minio: "npm:^7.0.26"
nctx: "npm:^2.2.0"
wait-on: "npm:^6.0.1"
checksum: 10/71ab47c7b14681aaf92d44a370cfedceff4015afc5563931e9c7c2999141711ac8812c141adcd090a06236666327766ca7907a42a1174b8693003b4d86dbbba0
checksum: 10/cb250571b01eb902ec93e42c17122527278a6fdfcc7f2f2fc0b75e1ea6aa8adbddb7dd8032379387a22ac336061b50b402255e50750dcdff0c8ab85cdcab92f3
languageName: node
linkType: hard
"@modjo/oa-graphql@npm:*":
version: 1.9.6
resolution: "@modjo/oa-graphql@npm:1.9.6"
"@modjo/oa-graphql@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/oa-graphql@npm:1.10.0"
dependencies:
"@apollo/server": "npm:^4.7.5"
"@apollo/server-plugin-landing-page-graphql-playground": "npm:^4.0.1"
@ -3398,7 +3476,7 @@ __metadata:
nctx: "npm:^2.2.0"
openapi-to-graphql: "npm:^3.0.5"
subscriptions-transport-ws: "npm:^0.11.0"
checksum: 10/861db20404f67daf0a18fc18ac3086ad900f9fb0f8a378f6253bcb1f9002b8f2cc2b0e6c9c9d605d86451d64c9673510b544e3b0f84be0584c7c5cccf26c8a32
checksum: 10/bba8eb52ac5a0bbe81061071190efd99d4348dd005f13c0b8ee7b52e9e17d58dd0a17fd1f9ae1d849bbc2c4d544f75da8423de35b2cb4cad0f67949808cde180
languageName: node
linkType: hard
@ -3430,9 +3508,9 @@ __metadata:
languageName: node
linkType: hard
"@modjo/postgres@npm:*":
version: 1.9.6
resolution: "@modjo/postgres@npm:1.9.6"
"@modjo/postgres@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/postgres@npm:1.10.0"
dependencies:
"@opentelemetry/api": "npm:^1.9.0"
"@opentelemetry/core": "npm:^1.25.1"
@ -3440,18 +3518,18 @@ __metadata:
lodash.defaultsdeep: "npm:^4.6.1"
nctx: "npm:^2.2.0"
postgres: "npm:^3.4.4"
checksum: 10/bda561de7d9a0cd193eb1d7b0313b6a5eb5272b7fcab8c85315cfb4207feecec40a6cc0eaa89e94ab81facfc58266942a066bb90b3e2d9860c5b57ce1ea26339
checksum: 10/b9711ff444f0f978d78c6a1d2cc4dac7e9816cbee2ee7395d2ac8e7b794606e22155e69a6debea99c592f58a63110f2207cd9dfdd199cc06d9bfa6814a9ed4cd
languageName: node
linkType: hard
"@modjo/sentry@npm:*, @modjo/sentry@npm:^1.6.2":
version: 1.9.6
resolution: "@modjo/sentry@npm:1.9.6"
"@modjo/sentry@npm:^1.10.0":
version: 1.10.0
resolution: "@modjo/sentry@npm:1.10.0"
dependencies:
"@sentry/node": "npm:^8.15.0"
"@sentry/profiling-node": "npm:^8.15.0"
nctx: "npm:^2.2.0"
checksum: 10/643113547d38022e75b12e4404f13fd02ddff83f19fa74c5a580ee9ff523297bcfb2abe3d75cf7973d2ced3d15c4da55e4f0fff1830bdd71d62ff941b9adf422
checksum: 10/050e5d724fcc49542f839705c96765fdee1e185ba9f1d0c5bbb276fab5b755c4c6b2fe4a8c3e9519d44948149eca8506545e3713c76dcb14ac4aeefc87f65656
languageName: node
linkType: hard
@ -7992,9 +8070,9 @@ __metadata:
version: 0.0.0-use.local
resolution: "common@workspace:libs/common"
dependencies:
"@modjo/core": "npm:*"
"@modjo/hasura": "npm:*"
"@modjo/microservice-oapi": "npm:*"
"@modjo/core": "npm:^1.10.0"
"@modjo/hasura": "npm:^1.10.0"
"@modjo/microservice-oapi": "npm:^1.10.0"
"@what3words/api": "npm:^5.4.0"
eslint: "npm:^8.10.0"
fast-levenshtein: "npm:^3.0.0"
@ -19490,7 +19568,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "redis-queue-dedup@workspace:libs/redis-queue-dedup"
dependencies:
"@modjo/core": "npm:^1.6.0"
"@modjo/core": "npm:^1.10.0"
murmurhash: "npm:^2.0.1"
languageName: unknown
linkType: soft