@minimoth/sdk-node 0.1.2 → 0.1.4
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/dist/index.cjs +30 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +30 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -62,13 +62,12 @@ var pkg = require2("../package.json");
|
|
|
62
62
|
var BASE_URL = "https://api.minimoth.dev";
|
|
63
63
|
var USER_AGENT = `minimoth-sdk-node/${pkg.version}`;
|
|
64
64
|
var BACKEND_CODE_MAP = {
|
|
65
|
-
INVALID_ACCESS_TOKEN: "
|
|
66
|
-
|
|
67
|
-
TOKEN_REVOKED: "TOKEN_REVOKED",
|
|
65
|
+
INVALID_ACCESS_TOKEN: "INVALID_ACCESS_TOKEN",
|
|
66
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
68
67
|
INVALID_OTP: "INVALID_OTP",
|
|
69
|
-
OTP_NOT_FOUND: "
|
|
70
|
-
OTP_RATE_LIMITED: "
|
|
71
|
-
VERIFY_RATE_LIMITED: "
|
|
68
|
+
OTP_NOT_FOUND: "OTP_NOT_FOUND",
|
|
69
|
+
OTP_RATE_LIMITED: "OTP_RATE_LIMITED",
|
|
70
|
+
VERIFY_RATE_LIMITED: "VERIFY_RATE_LIMITED",
|
|
72
71
|
INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
|
|
73
72
|
INVALID_PHONE: "INVALID_PHONE"
|
|
74
73
|
};
|
|
@@ -99,12 +98,12 @@ async function apiPost(path, apiKey, body) {
|
|
|
99
98
|
}
|
|
100
99
|
return handleResponse(response);
|
|
101
100
|
}
|
|
102
|
-
async function apiGet(path) {
|
|
101
|
+
async function apiGet(path, apiKey) {
|
|
102
|
+
const headers = { "User-Agent": USER_AGENT };
|
|
103
|
+
if (apiKey) headers["X-Api-Key"] = apiKey;
|
|
103
104
|
let response;
|
|
104
105
|
try {
|
|
105
|
-
response = await fetch(`${BASE_URL}${path}`, {
|
|
106
|
-
headers: { "User-Agent": USER_AGENT }
|
|
107
|
-
});
|
|
106
|
+
response = await fetch(`${BASE_URL}${path}`, { headers });
|
|
108
107
|
} catch (err) {
|
|
109
108
|
throw new MiniMothError("NETWORK_ERROR", "Network request failed", 0, err);
|
|
110
109
|
}
|
|
@@ -123,8 +122,18 @@ var OtpClient = class {
|
|
|
123
122
|
logger;
|
|
124
123
|
async send(params) {
|
|
125
124
|
const phone = normalizePhone(params.phone);
|
|
126
|
-
await apiPost("/v1/otp/send", this.apiKey, { phone });
|
|
125
|
+
const res = await apiPost("/v1/otp/send", this.apiKey, { phone });
|
|
127
126
|
this.logger.info("otp.sent", { phone: maskPhone(phone) });
|
|
127
|
+
return { otpId: res.otp_id };
|
|
128
|
+
}
|
|
129
|
+
async status(otpId) {
|
|
130
|
+
const res = await apiGet(`/v1/otp/status/${encodeURIComponent(otpId)}`, this.apiKey);
|
|
131
|
+
return {
|
|
132
|
+
otpId: res.otp_id,
|
|
133
|
+
channel: res.channel,
|
|
134
|
+
status: res.status,
|
|
135
|
+
deliveredAt: res.delivered_at
|
|
136
|
+
};
|
|
128
137
|
}
|
|
129
138
|
async verify(params) {
|
|
130
139
|
const phone = normalizePhone(params.phone);
|
|
@@ -137,7 +146,7 @@ var OtpClient = class {
|
|
|
137
146
|
);
|
|
138
147
|
const payload = import_jsonwebtoken.default.decode(res.access_token);
|
|
139
148
|
if (!payload?.session_id) {
|
|
140
|
-
throw new MiniMothError("
|
|
149
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Could not decode session_id from access token", 0);
|
|
141
150
|
}
|
|
142
151
|
try {
|
|
143
152
|
await this.store.setTokens(payload.session_id, {
|
|
@@ -156,7 +165,7 @@ var OtpClient = class {
|
|
|
156
165
|
};
|
|
157
166
|
} catch (err) {
|
|
158
167
|
if (err instanceof MiniMothError) {
|
|
159
|
-
if (err.code === "INVALID_OTP" || err.code === "
|
|
168
|
+
if (err.code === "INVALID_OTP" || err.code === "OTP_NOT_FOUND" || err.code === "INVALID_PHONE" || err.code === "VERIFY_RATE_LIMITED") {
|
|
160
169
|
this.logger.debug("otp.verify.failed", { code: err.code });
|
|
161
170
|
return { valid: false, code: err.code };
|
|
162
171
|
}
|
|
@@ -207,10 +216,10 @@ var SessionClient = class {
|
|
|
207
216
|
async validate(accessToken) {
|
|
208
217
|
const decoded = import_jsonwebtoken2.default.decode(accessToken, { complete: true });
|
|
209
218
|
if (!decoded || typeof decoded === "string") {
|
|
210
|
-
throw new MiniMothError("
|
|
219
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is malformed", 401);
|
|
211
220
|
}
|
|
212
221
|
const kid = decoded.header["kid"];
|
|
213
|
-
if (!kid) throw new MiniMothError("
|
|
222
|
+
if (!kid) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is missing kid header", 401);
|
|
214
223
|
const publicKey = await this.jwksCache.getKey(kid);
|
|
215
224
|
let currentToken = accessToken;
|
|
216
225
|
let newTokens;
|
|
@@ -220,11 +229,11 @@ var SessionClient = class {
|
|
|
220
229
|
if (err instanceof import_jsonwebtoken2.default.TokenExpiredError) {
|
|
221
230
|
const expiredPayload = decoded.payload;
|
|
222
231
|
const sessionId = expiredPayload?.session_id;
|
|
223
|
-
if (!sessionId) throw new MiniMothError("
|
|
232
|
+
if (!sessionId) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is invalid", 401);
|
|
224
233
|
newTokens = await this.deduplicator.getOrRun(sessionId, async () => {
|
|
225
234
|
const refreshToken = await this.store.getRefreshToken(sessionId);
|
|
226
235
|
if (!refreshToken) {
|
|
227
|
-
throw new MiniMothError("
|
|
236
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Access token expired and no refresh token available", 401);
|
|
228
237
|
}
|
|
229
238
|
this.logger.info("session.auto_refresh", { sessionId: sessionId.slice(0, 8) });
|
|
230
239
|
const res = await apiPost(
|
|
@@ -248,12 +257,12 @@ var SessionClient = class {
|
|
|
248
257
|
const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey;
|
|
249
258
|
import_jsonwebtoken2.default.verify(currentToken, newKey, { algorithms: ["RS256"] });
|
|
250
259
|
} else {
|
|
251
|
-
throw new MiniMothError("
|
|
260
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token signature is invalid", 401);
|
|
252
261
|
}
|
|
253
262
|
}
|
|
254
263
|
const payload = import_jsonwebtoken2.default.decode(currentToken);
|
|
255
264
|
const isValid = await this.revocationCache.check(payload.jti, currentToken);
|
|
256
|
-
if (!isValid) throw new MiniMothError("
|
|
265
|
+
if (!isValid) throw new MiniMothError("SESSION_EXPIRED", "Session has been revoked", 401);
|
|
257
266
|
const session = {
|
|
258
267
|
phone: payload.sub,
|
|
259
268
|
projectId: payload.project_id,
|
|
@@ -296,7 +305,7 @@ var SessionClient = class {
|
|
|
296
305
|
async logout(params) {
|
|
297
306
|
const payload = import_jsonwebtoken2.default.decode(params.accessToken);
|
|
298
307
|
const sessionId = payload?.session_id ?? null;
|
|
299
|
-
if (!sessionId) throw new MiniMothError("
|
|
308
|
+
if (!sessionId) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Cannot decode token", 401);
|
|
300
309
|
let currentAccessToken = params.accessToken;
|
|
301
310
|
if (payload && payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
302
311
|
const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {
|
|
@@ -349,7 +358,7 @@ var JwksCache = class {
|
|
|
349
358
|
await this.fetch();
|
|
350
359
|
key = this.keyMap.get(kid);
|
|
351
360
|
}
|
|
352
|
-
if (!key) throw new MiniMothError("
|
|
361
|
+
if (!key) throw new MiniMothError("INVALID_ACCESS_TOKEN", `No public key found for kid: ${kid}`, 401);
|
|
353
362
|
return key;
|
|
354
363
|
}
|
|
355
364
|
fetch() {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/otp/OtpClient.ts","../src/MiniMothError.ts","../src/http.ts","../src/session/SessionClient.ts","../src/session/JwksCache.ts","../src/session/RevocationCache.ts","../src/session/RefreshDeduplicator.ts","../src/store/DefaultSessionStore.ts","../src/logger/ConsoleLogger.ts","../src/MiniMoth.ts"],"sourcesContent":["export { MiniMoth } from './MiniMoth'\nexport { MiniMothError } from './MiniMothError'\nexport type { MiniMothErrorCode } from './MiniMothError'\nexport type { Session, ValidateMode, MiniMothConfig, AccessTokenPayload } from './types'\nexport type { MiniMothSessionStore } from './store/MiniMothSessionStore'\nexport type { MiniMothLogger } from './logger/MiniMothLogger'\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { AccessTokenPayload } from '../types'\n\ntype VerifyResult =\n | { valid: true; accessToken: string; refreshToken: string; sessionId: string }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class OtpClient {\n constructor(\n private readonly apiKey: string,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async send(params: { phone: string }): Promise<void> {\n const phone = normalizePhone(params.phone)\n await apiPost<{ message: string }>('/v1/otp/send', this.apiKey, { phone })\n this.logger.info('otp.sent', { phone: maskPhone(phone) })\n }\n\n async verify(params: { phone: string; otp: string }): Promise<VerifyResult> {\n const phone = normalizePhone(params.phone)\n validateOtp(params.otp)\n\n try {\n const res = await apiPost<{ access_token: string; refresh_token: string; expires_at: string }>(\n '/v1/otp/verify',\n this.apiKey,\n { phone, code: params.otp }\n )\n\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (!payload?.session_id) {\n throw new MiniMothError('INVALID_TOKEN', 'Could not decode session_id from access token', 0)\n }\n\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch {\n this.logger.error('otp.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n\n this.logger.info('otp.verified', { sessionId: payload.session_id.slice(0, 8) })\n\n return {\n valid: true,\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n sessionId: payload.session_id,\n }\n } catch (err) {\n if (err instanceof MiniMothError) {\n if (err.code === 'INVALID_OTP' || err.code === 'OTP_EXPIRED' || err.code === 'INVALID_PHONE') {\n this.logger.debug('otp.verify.failed', { code: err.code })\n return { valid: false, code: err.code }\n }\n }\n throw err\n }\n }\n}\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nfunction normalizePhone(raw: string): string {\n if (!raw || typeof raw !== 'string') {\n throw new MiniMothError('INVALID_PHONE', 'Phone number is required', 422)\n }\n if (/[\\s-]/.test(raw)) {\n throw new MiniMothError('INVALID_PHONE', 'Phone number must not contain spaces or hyphens', 422)\n }\n let phone = raw\n if (phone.startsWith('+')) phone = phone.slice(1)\n // 10-digit subscriber number — prepend country code\n if (phone.length === 10) phone = '91' + phone\n return phone\n}\n\nfunction validateOtp(otp: string): void {\n if (!otp || typeof otp !== 'string') {\n throw new MiniMothError('INVALID_OTP', 'OTP is required', 422)\n }\n}\n\nexport function maskPhone(phone: string): string {\n if (phone.length <= 4) return '****'\n return phone.slice(0, 4) + '*'.repeat(Math.max(phone.length - 6, 1)) + phone.slice(-2)\n}\n","export type MiniMothErrorCode =\n | 'TOKEN_EXPIRED'\n | 'TOKEN_REVOKED'\n | 'INVALID_TOKEN'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'RATE_LIMITED'\n | 'INSUFFICIENT_BALANCE'\n | 'NETWORK_ERROR'\n | 'INVALID_PHONE'\n | 'UNKNOWN_ERROR'\n\nexport class MiniMothError extends Error {\n readonly code: MiniMothErrorCode\n readonly statusCode: number\n\n constructor(code: MiniMothErrorCode, message: string, statusCode: number, cause?: unknown) {\n super(message, cause !== undefined ? { cause } : undefined)\n this.name = 'MiniMothError'\n this.code = code\n this.statusCode = statusCode\n // Restore prototype chain for instanceof checks across module boundaries\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { MiniMothError, type MiniMothErrorCode } from './MiniMothError'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\nconst pkg = require('../package.json') as { version: string }\n\nconst BASE_URL = 'https://api.minimoth.dev'\nconst USER_AGENT = `minimoth-sdk-node/${pkg.version}`\n\nconst BACKEND_CODE_MAP: Record<string, MiniMothErrorCode> = {\n INVALID_ACCESS_TOKEN: 'INVALID_TOKEN',\n TOKEN_EXPIRED: 'TOKEN_EXPIRED',\n TOKEN_REVOKED: 'TOKEN_REVOKED',\n INVALID_OTP: 'INVALID_OTP',\n OTP_NOT_FOUND: 'OTP_EXPIRED',\n OTP_RATE_LIMITED: 'RATE_LIMITED',\n VERIFY_RATE_LIMITED: 'RATE_LIMITED',\n INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',\n INVALID_PHONE: 'INVALID_PHONE',\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) return response.json() as Promise<T>\n\n let body: { code?: string; error?: string } = {}\n try { body = await response.json() as { code?: string; error?: string } } catch {}\n\n const sdkCode: MiniMothErrorCode = BACKEND_CODE_MAP[body.code ?? ''] ?? 'UNKNOWN_ERROR'\n throw new MiniMothError(sdkCode, body.error ?? 'Unknown error', response.status)\n}\n\nexport async function apiPost<T>(\n path: string,\n apiKey: string,\n body: Record<string, unknown>\n): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n\nexport async function apiGet<T>(path: string): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n headers: { 'User-Agent': USER_AGENT },\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { JwksCache } from './JwksCache'\nimport type { RevocationCache } from './RevocationCache'\nimport type { RefreshDeduplicator } from './RefreshDeduplicator'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Session, AccessTokenPayload } from '../types'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\ntype SafeValidateResult =\n | { valid: true; session: Session }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class SessionClient {\n constructor(\n private readonly apiKey: string,\n private readonly jwksCache: JwksCache,\n private readonly revocationCache: RevocationCache,\n private readonly deduplicator: RefreshDeduplicator,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async validate(accessToken: string): Promise<Session> {\n const decoded = jwt.decode(accessToken, { complete: true })\n if (!decoded || typeof decoded === 'string') {\n throw new MiniMothError('INVALID_TOKEN', 'Token is malformed', 401)\n }\n\n const kid = (decoded.header as unknown as Record<string, string>)['kid']\n if (!kid) throw new MiniMothError('INVALID_TOKEN', 'Token is missing kid header', 401)\n\n const publicKey = await this.jwksCache.getKey(kid)\n\n let currentToken = accessToken\n let newTokens: Tokens | undefined\n\n try {\n jwt.verify(accessToken, publicKey, { algorithms: ['RS256'] })\n } catch (err) {\n if (err instanceof jwt.TokenExpiredError) {\n const expiredPayload = decoded.payload as AccessTokenPayload\n const sessionId = expiredPayload?.session_id\n if (!sessionId) throw new MiniMothError('INVALID_TOKEN', 'Token is invalid', 401)\n\n newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const refreshToken = await this.store.getRefreshToken(sessionId)\n if (!refreshToken) {\n throw new MiniMothError('TOKEN_EXPIRED', 'Access token expired and no refresh token available', 401)\n }\n\n this.logger.info('session.auto_refresh', { sessionId: sessionId.slice(0, 8) })\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n try {\n await this.store.setTokens(sessionId, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n\n currentToken = newTokens.accessToken\n\n // Verify the new token\n const newDecoded = jwt.decode(currentToken, { complete: true })\n const newKid = (newDecoded?.header as Record<string, string> | undefined)?.['kid']\n const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey\n jwt.verify(currentToken, newKey, { algorithms: ['RS256'] })\n } else {\n throw new MiniMothError('INVALID_TOKEN', 'Token signature is invalid', 401)\n }\n }\n\n const payload = jwt.decode(currentToken) as AccessTokenPayload\n const isValid = await this.revocationCache.check(payload.jti, currentToken)\n if (!isValid) throw new MiniMothError('TOKEN_REVOKED', 'Session has been revoked', 401)\n\n const session: Session = {\n phone: payload.sub,\n projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (newTokens) session.newTokens = newTokens\n\n this.logger.info('session.validated', { sessionId: payload.session_id.slice(0, 8) })\n return session\n }\n\n async safeValidate(accessToken: string): Promise<SafeValidateResult> {\n try {\n const session = await this.validate(accessToken)\n return { valid: true, session }\n } catch (err) {\n if (err instanceof MiniMothError) return { valid: false, code: err.code }\n throw err\n }\n }\n\n async refresh(refreshToken: string): Promise<Tokens> {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n // Update store if session_id is decodable from new token\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (payload?.session_id) {\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n }\n\n this.logger.info('session.refreshed')\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n }\n\n async logout(params: { accessToken: string; refreshToken: string }): Promise<void> {\n const payload = jwt.decode(params.accessToken) as AccessTokenPayload | null\n const sessionId = payload?.session_id ?? null\n\n if (!sessionId) throw new MiniMothError('INVALID_TOKEN', 'Cannot decode token', 401)\n\n let currentAccessToken = params.accessToken\n\n // If token is expired, refresh before logout — deduplicated to prevent concurrent refresh races\n if (payload && payload.exp < Math.floor(Date.now() / 1000)) {\n const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: params.refreshToken }\n )\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n currentAccessToken = newTokens.accessToken\n try {\n await this.store.setTokens(sessionId, newTokens)\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n }\n\n await apiPost<{ message: string }>(\n '/v1/session/logout',\n this.apiKey,\n { access_token: currentAccessToken }\n )\n\n try {\n await this.store.deleteSession(sessionId)\n } catch (err) {\n this.logger.error('session.store.deleteSession.failed', { sessionId: sessionId.slice(0, 8) })\n }\n this.logger.info('session.logged_out', { sessionId: sessionId.slice(0, 8) })\n }\n}\n","import crypto from 'crypto'\nimport { apiGet } from '../http'\nimport { MiniMothError } from '../MiniMothError'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\nconst CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\ntype JwkEntry = Record<string, string>\n\nexport class JwksCache {\n private keyMap = new Map<string, crypto.KeyObject>()\n private fetchedAt = 0\n private fetching: Promise<void> | null = null\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n async getKey(kid: string): Promise<crypto.KeyObject> {\n if (this.keyMap.size === 0 || Date.now() - this.fetchedAt > CACHE_TTL_MS) {\n await this.fetch()\n }\n\n let key = this.keyMap.get(kid)\n if (!key) {\n this.logger.debug('jwks.unknown_kid', { kid })\n await this.fetch()\n key = this.keyMap.get(kid)\n }\n\n if (!key) throw new MiniMothError('INVALID_TOKEN', `No public key found for kid: ${kid}`, 401)\n return key\n }\n\n private fetch(): Promise<void> {\n if (this.fetching) return this.fetching\n this.fetching = this.doFetch().finally(() => { this.fetching = null })\n return this.fetching\n }\n\n private async doFetch(): Promise<void> {\n this.logger.debug('jwks.fetch')\n const data = await apiGet<{ keys: JwkEntry[] }>('/.well-known/jwks.json')\n const newMap = new Map<string, crypto.KeyObject>()\n for (const jwk of data.keys) {\n if (jwk['kid'] && jwk['kty'] === 'RSA') {\n const key = crypto.createPublicKey({ key: jwk as unknown as crypto.JsonWebKey, format: 'jwk' })\n newMap.set(jwk['kid'], key)\n }\n }\n this.keyMap = newMap\n this.fetchedAt = Date.now()\n this.logger.debug('jwks.updated', { keyCount: newMap.size })\n }\n}\n","import { apiPost } from '../http'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { ValidateMode } from '../types'\n\nconst MODE_TTL_MS: Partial<Record<ValidateMode, number>> = {\n recheck_1m: 60_000,\n recheck_3m: 180_000,\n}\n\nconst EVICTION_TTL_MS = 5 * 60 * 1000 // JWT max lifetime\nconst CLEANUP_WINDOW_MS = 5 * 60 * 1000\n\ntype Entry = { checkedAt: number }\n\nexport class RevocationCache {\n private readonly cache = new Map<string, Entry>()\n private lastCleanedAt = 0\n\n constructor(\n private readonly mode: ValidateMode,\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async check(jti: string, accessToken: string): Promise<boolean> {\n if (this.mode === 'instant') return true\n\n if (this.mode !== 'strict') this.maybeCleanup()\n\n const ttl = MODE_TTL_MS[this.mode] ?? 0\n if (ttl > 0) {\n const entry = this.cache.get(jti)\n if (entry && Date.now() - entry.checkedAt < ttl) {\n this.logger.debug('revocation.cache.hit', { jti: jti.slice(0, 8) })\n return true\n }\n }\n\n try {\n const result = await apiPost<{ valid: boolean }>(\n '/v1/session/validate',\n this.apiKey,\n { access_token: accessToken }\n )\n\n if (result.valid && ttl > 0) {\n this.cache.set(jti, { checkedAt: Date.now() })\n }\n\n return result.valid\n } catch (err) {\n if (this.mode === 'strict') throw err\n\n // recheck_*m: fail open\n this.logger.warn('revocation.check.failed_open', {\n jti: jti.slice(0, 8),\n error: err instanceof Error ? err.message : 'unknown',\n })\n return true\n }\n }\n\n private maybeCleanup(): void {\n const now = Date.now()\n if (now - this.lastCleanedAt < CLEANUP_WINDOW_MS) return\n this.lastCleanedAt = now // set before iteration to prevent concurrent double-clean\n for (const [jti, entry] of this.cache) {\n if (now - entry.checkedAt > EVICTION_TTL_MS) {\n this.cache.delete(jti)\n }\n }\n }\n}\n","import { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\nexport class RefreshDeduplicator {\n private readonly inflight = new Map<string, Promise<unknown>>()\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n getOrRun<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(sessionId)\n if (existing) {\n this.logger.debug('refresh dedup hit', { key: sessionId })\n return existing as Promise<T>\n }\n\n const promise = fn().finally(() => {\n this.inflight.delete(sessionId)\n })\n\n this.inflight.set(sessionId, promise)\n return promise\n }\n}\n","import type { MiniMothSessionStore } from './MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Entry = { accessToken: string; refreshToken: string }\n\nexport class DefaultSessionStore implements MiniMothSessionStore {\n private readonly map = new Map<string, Entry>()\n private warnedProduction = false\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n private maybeWarn(): void {\n if (process.env['NODE_ENV'] === 'production' && !this.warnedProduction) {\n this.warnedProduction = true\n this.logger.warn('using default in-memory session store — not suitable for multi-replica deployments')\n }\n }\n\n async getRefreshToken(sessionId: string): Promise<string | null> {\n this.maybeWarn()\n return this.map.get(sessionId)?.refreshToken ?? null\n }\n\n async setTokens(sessionId: string, tokens: { accessToken: string; refreshToken: string }): Promise<void> {\n this.maybeWarn()\n this.map.set(sessionId, tokens)\n }\n\n async deleteSession(sessionId: string): Promise<void> {\n this.map.delete(sessionId)\n }\n}\n","import type { MiniMothLogger } from './MiniMothLogger'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0, info: 1, warn: 2, error: 3, silent: 4,\n}\n\nexport class ConsoleLogger implements MiniMothLogger {\n private level: LogLevel\n\n constructor(level: LogLevel = 'info') {\n this.level = level\n }\n\n setLevel(level: LogLevel): void {\n this.level = level\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level]\n }\n\n private format(msg: string, meta?: Record<string, unknown>): string {\n if (!meta || Object.keys(meta).length === 0) return `[minimoth] ${msg}`\n return `[minimoth] ${msg} ${JSON.stringify(meta)}`\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('debug')) console.debug(this.format(msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('info')) console.info(this.format(msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('warn')) console.warn(this.format(msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('error')) console.error(this.format(msg, meta))\n }\n}\n","import { OtpClient } from './otp/OtpClient'\nimport { SessionClient } from './session/SessionClient'\nimport { JwksCache } from './session/JwksCache'\nimport { RevocationCache } from './session/RevocationCache'\nimport { RefreshDeduplicator } from './session/RefreshDeduplicator'\nimport { DefaultSessionStore } from './store/DefaultSessionStore'\nimport { ConsoleLogger } from './logger/ConsoleLogger'\nimport type { MiniMothConfig } from './types'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nexport class MiniMoth {\n readonly otp: OtpClient\n readonly session: SessionClient\n private readonly consoleLogger: ConsoleLogger\n\n constructor(config: MiniMothConfig) {\n this.consoleLogger = new ConsoleLogger(config.logLevel ?? 'info')\n const logger = config.logger ?? this.consoleLogger\n\n const store = config.session?.store ?? new DefaultSessionStore(logger)\n const validateMode = config.session?.validateMode ?? 'instant'\n\n const jwksCache = new JwksCache(logger)\n const revocationCache = new RevocationCache(validateMode, config.apiKey, logger)\n const deduplicator = new RefreshDeduplicator(logger)\n\n this.otp = new OtpClient(config.apiKey, store, logger)\n this.session = new SessionClient(\n config.apiKey,\n jwksCache,\n revocationCache,\n deduplicator,\n store,\n logger\n )\n }\n\n // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.\n setLogLevel(level: LogLevel): void {\n this.consoleLogger.setLevel(level)\n }\n}\n"],"mappings":"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","names":["require","jwt","import_jsonwebtoken","jwt","err","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/otp/OtpClient.ts","../src/MiniMothError.ts","../src/http.ts","../src/session/SessionClient.ts","../src/session/JwksCache.ts","../src/session/RevocationCache.ts","../src/session/RefreshDeduplicator.ts","../src/store/DefaultSessionStore.ts","../src/logger/ConsoleLogger.ts","../src/MiniMoth.ts"],"sourcesContent":["export { MiniMoth } from './MiniMoth'\nexport { MiniMothError } from './MiniMothError'\nexport type { MiniMothErrorCode } from './MiniMothError'\nexport type { Session, ValidateMode, MiniMothConfig, AccessTokenPayload } from './types'\nexport type { MiniMothSessionStore } from './store/MiniMothSessionStore'\nexport type { MiniMothLogger } from './logger/MiniMothLogger'\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import jwt from 'jsonwebtoken'\nimport { apiPost, apiGet } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { AccessTokenPayload } from '../types'\n\ntype VerifyResult =\n | { valid: true; accessToken: string; refreshToken: string; sessionId: string }\n | { valid: false; code: MiniMothErrorCode }\n\ntype OtpStatus = {\n otpId: string\n channel: string | null\n status: 'queued' | 'delivered' | 'failed'\n deliveredAt: string | null\n}\n\nexport class OtpClient {\n constructor(\n private readonly apiKey: string,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async send(params: { phone: string }): Promise<{ otpId: string }> {\n const phone = normalizePhone(params.phone)\n const res = await apiPost<{ message: string; otp_id: string }>('/v1/otp/send', this.apiKey, { phone })\n this.logger.info('otp.sent', { phone: maskPhone(phone) })\n return { otpId: res.otp_id }\n }\n\n async status(otpId: string): Promise<OtpStatus> {\n const res = await apiGet<{\n otp_id: string\n channel: string | null\n status: 'queued' | 'delivered' | 'failed'\n delivered_at: string | null\n }>(`/v1/otp/status/${encodeURIComponent(otpId)}`, this.apiKey)\n return {\n otpId: res.otp_id,\n channel: res.channel,\n status: res.status,\n deliveredAt: res.delivered_at,\n }\n }\n\n async verify(params: { phone: string; otp: string }): Promise<VerifyResult> {\n const phone = normalizePhone(params.phone)\n validateOtp(params.otp)\n\n try {\n const res = await apiPost<{ access_token: string; refresh_token: string; expires_at: string }>(\n '/v1/otp/verify',\n this.apiKey,\n { phone, code: params.otp }\n )\n\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (!payload?.session_id) {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Could not decode session_id from access token', 0)\n }\n\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch {\n this.logger.error('otp.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n\n this.logger.info('otp.verified', { sessionId: payload.session_id.slice(0, 8) })\n\n return {\n valid: true,\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n sessionId: payload.session_id,\n }\n } catch (err) {\n if (err instanceof MiniMothError) {\n if (\n err.code === 'INVALID_OTP' ||\n err.code === 'OTP_NOT_FOUND' ||\n err.code === 'INVALID_PHONE' ||\n err.code === 'VERIFY_RATE_LIMITED'\n ) {\n this.logger.debug('otp.verify.failed', { code: err.code })\n return { valid: false, code: err.code }\n }\n }\n throw err\n }\n }\n}\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nfunction normalizePhone(raw: string): string {\n if (!raw || typeof raw !== 'string') {\n throw new MiniMothError('INVALID_PHONE', 'Phone number is required', 422)\n }\n if (/[\\s-]/.test(raw)) {\n throw new MiniMothError('INVALID_PHONE', 'Phone number must not contain spaces or hyphens', 422)\n }\n let phone = raw\n if (phone.startsWith('+')) phone = phone.slice(1)\n // 10-digit subscriber number — prepend country code\n if (phone.length === 10) phone = '91' + phone\n return phone\n}\n\nfunction validateOtp(otp: string): void {\n if (!otp || typeof otp !== 'string') {\n throw new MiniMothError('INVALID_OTP', 'OTP is required', 422)\n }\n}\n\nexport function maskPhone(phone: string): string {\n if (phone.length <= 4) return '****'\n return phone.slice(0, 4) + '*'.repeat(Math.max(phone.length - 6, 1)) + phone.slice(-2)\n}\n","export type MiniMothErrorCode =\n | 'INVALID_ACCESS_TOKEN'\n | 'SESSION_EXPIRED'\n | 'INVALID_OTP'\n | 'OTP_NOT_FOUND'\n | 'OTP_RATE_LIMITED'\n | 'VERIFY_RATE_LIMITED'\n | 'INSUFFICIENT_BALANCE'\n | 'NETWORK_ERROR'\n | 'INVALID_PHONE'\n | 'UNKNOWN_ERROR'\n\nexport class MiniMothError extends Error {\n readonly code: MiniMothErrorCode\n readonly statusCode: number\n\n constructor(code: MiniMothErrorCode, message: string, statusCode: number, cause?: unknown) {\n super(message, cause !== undefined ? { cause } : undefined)\n this.name = 'MiniMothError'\n this.code = code\n this.statusCode = statusCode\n // Restore prototype chain for instanceof checks across module boundaries\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { MiniMothError, type MiniMothErrorCode } from './MiniMothError'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\nconst pkg = require('../package.json') as { version: string }\n\nconst BASE_URL = 'https://api.minimoth.dev'\nconst USER_AGENT = `minimoth-sdk-node/${pkg.version}`\n\nconst BACKEND_CODE_MAP: Record<string, MiniMothErrorCode> = {\n INVALID_ACCESS_TOKEN: 'INVALID_ACCESS_TOKEN',\n SESSION_EXPIRED: 'SESSION_EXPIRED',\n INVALID_OTP: 'INVALID_OTP',\n OTP_NOT_FOUND: 'OTP_NOT_FOUND',\n OTP_RATE_LIMITED: 'OTP_RATE_LIMITED',\n VERIFY_RATE_LIMITED: 'VERIFY_RATE_LIMITED',\n INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',\n INVALID_PHONE: 'INVALID_PHONE',\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) return response.json() as Promise<T>\n\n let body: { code?: string; error?: string } = {}\n try { body = await response.json() as { code?: string; error?: string } } catch {}\n\n const sdkCode: MiniMothErrorCode = BACKEND_CODE_MAP[body.code ?? ''] ?? 'UNKNOWN_ERROR'\n throw new MiniMothError(sdkCode, body.error ?? 'Unknown error', response.status)\n}\n\nexport async function apiPost<T>(\n path: string,\n apiKey: string,\n body: Record<string, unknown>\n): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n\nexport async function apiGet<T>(path: string, apiKey?: string): Promise<T> {\n const headers: Record<string, string> = { 'User-Agent': USER_AGENT }\n if (apiKey) headers['X-Api-Key'] = apiKey\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, { headers })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { JwksCache } from './JwksCache'\nimport type { RevocationCache } from './RevocationCache'\nimport type { RefreshDeduplicator } from './RefreshDeduplicator'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Session, AccessTokenPayload } from '../types'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\ntype SafeValidateResult =\n | { valid: true; session: Session }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class SessionClient {\n constructor(\n private readonly apiKey: string,\n private readonly jwksCache: JwksCache,\n private readonly revocationCache: RevocationCache,\n private readonly deduplicator: RefreshDeduplicator,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async validate(accessToken: string): Promise<Session> {\n const decoded = jwt.decode(accessToken, { complete: true })\n if (!decoded || typeof decoded === 'string') {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is malformed', 401)\n }\n\n const kid = (decoded.header as unknown as Record<string, string>)['kid']\n if (!kid) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is missing kid header', 401)\n\n const publicKey = await this.jwksCache.getKey(kid)\n\n let currentToken = accessToken\n let newTokens: Tokens | undefined\n\n try {\n jwt.verify(accessToken, publicKey, { algorithms: ['RS256'] })\n } catch (err) {\n if (err instanceof jwt.TokenExpiredError) {\n const expiredPayload = decoded.payload as AccessTokenPayload\n const sessionId = expiredPayload?.session_id\n if (!sessionId) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is invalid', 401)\n\n newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const refreshToken = await this.store.getRefreshToken(sessionId)\n if (!refreshToken) {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Access token expired and no refresh token available', 401)\n }\n\n this.logger.info('session.auto_refresh', { sessionId: sessionId.slice(0, 8) })\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n try {\n await this.store.setTokens(sessionId, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n\n currentToken = newTokens.accessToken\n\n // Verify the new token\n const newDecoded = jwt.decode(currentToken, { complete: true })\n const newKid = (newDecoded?.header as Record<string, string> | undefined)?.['kid']\n const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey\n jwt.verify(currentToken, newKey, { algorithms: ['RS256'] })\n } else {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token signature is invalid', 401)\n }\n }\n\n const payload = jwt.decode(currentToken) as AccessTokenPayload\n const isValid = await this.revocationCache.check(payload.jti, currentToken)\n if (!isValid) throw new MiniMothError('SESSION_EXPIRED', 'Session has been revoked', 401)\n\n const session: Session = {\n phone: payload.sub,\n projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (newTokens) session.newTokens = newTokens\n\n this.logger.info('session.validated', { sessionId: payload.session_id.slice(0, 8) })\n return session\n }\n\n async safeValidate(accessToken: string): Promise<SafeValidateResult> {\n try {\n const session = await this.validate(accessToken)\n return { valid: true, session }\n } catch (err) {\n if (err instanceof MiniMothError) return { valid: false, code: err.code }\n throw err\n }\n }\n\n async refresh(refreshToken: string): Promise<Tokens> {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n // Update store if session_id is decodable from new token\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (payload?.session_id) {\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n }\n\n this.logger.info('session.refreshed')\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n }\n\n async logout(params: { accessToken: string; refreshToken: string }): Promise<void> {\n const payload = jwt.decode(params.accessToken) as AccessTokenPayload | null\n const sessionId = payload?.session_id ?? null\n\n if (!sessionId) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Cannot decode token', 401)\n\n let currentAccessToken = params.accessToken\n\n // If token is expired, refresh before logout — deduplicated to prevent concurrent refresh races\n if (payload && payload.exp < Math.floor(Date.now() / 1000)) {\n const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: params.refreshToken }\n )\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n currentAccessToken = newTokens.accessToken\n try {\n await this.store.setTokens(sessionId, newTokens)\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n }\n\n await apiPost<{ message: string }>(\n '/v1/session/logout',\n this.apiKey,\n { access_token: currentAccessToken }\n )\n\n try {\n await this.store.deleteSession(sessionId)\n } catch (err) {\n this.logger.error('session.store.deleteSession.failed', { sessionId: sessionId.slice(0, 8) })\n }\n this.logger.info('session.logged_out', { sessionId: sessionId.slice(0, 8) })\n }\n}\n","import crypto from 'crypto'\nimport { apiGet } from '../http'\nimport { MiniMothError } from '../MiniMothError'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\nconst CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\ntype JwkEntry = Record<string, string>\n\nexport class JwksCache {\n private keyMap = new Map<string, crypto.KeyObject>()\n private fetchedAt = 0\n private fetching: Promise<void> | null = null\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n async getKey(kid: string): Promise<crypto.KeyObject> {\n if (this.keyMap.size === 0 || Date.now() - this.fetchedAt > CACHE_TTL_MS) {\n await this.fetch()\n }\n\n let key = this.keyMap.get(kid)\n if (!key) {\n this.logger.debug('jwks.unknown_kid', { kid })\n await this.fetch()\n key = this.keyMap.get(kid)\n }\n\n if (!key) throw new MiniMothError('INVALID_ACCESS_TOKEN', `No public key found for kid: ${kid}`, 401)\n return key\n }\n\n private fetch(): Promise<void> {\n if (this.fetching) return this.fetching\n this.fetching = this.doFetch().finally(() => { this.fetching = null })\n return this.fetching\n }\n\n private async doFetch(): Promise<void> {\n this.logger.debug('jwks.fetch')\n const data = await apiGet<{ keys: JwkEntry[] }>('/.well-known/jwks.json')\n const newMap = new Map<string, crypto.KeyObject>()\n for (const jwk of data.keys) {\n if (jwk['kid'] && jwk['kty'] === 'RSA') {\n const key = crypto.createPublicKey({ key: jwk as unknown as crypto.JsonWebKey, format: 'jwk' })\n newMap.set(jwk['kid'], key)\n }\n }\n this.keyMap = newMap\n this.fetchedAt = Date.now()\n this.logger.debug('jwks.updated', { keyCount: newMap.size })\n }\n}\n","import { apiPost } from '../http'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { ValidateMode } from '../types'\n\nconst MODE_TTL_MS: Partial<Record<ValidateMode, number>> = {\n recheck_1m: 60_000,\n recheck_3m: 180_000,\n}\n\nconst EVICTION_TTL_MS = 5 * 60 * 1000 // JWT max lifetime\nconst CLEANUP_WINDOW_MS = 5 * 60 * 1000\n\ntype Entry = { checkedAt: number }\n\nexport class RevocationCache {\n private readonly cache = new Map<string, Entry>()\n private lastCleanedAt = 0\n\n constructor(\n private readonly mode: ValidateMode,\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async check(jti: string, accessToken: string): Promise<boolean> {\n if (this.mode === 'instant') return true\n\n if (this.mode !== 'strict') this.maybeCleanup()\n\n const ttl = MODE_TTL_MS[this.mode] ?? 0\n if (ttl > 0) {\n const entry = this.cache.get(jti)\n if (entry && Date.now() - entry.checkedAt < ttl) {\n this.logger.debug('revocation.cache.hit', { jti: jti.slice(0, 8) })\n return true\n }\n }\n\n try {\n const result = await apiPost<{ valid: boolean }>(\n '/v1/session/validate',\n this.apiKey,\n { access_token: accessToken }\n )\n\n if (result.valid && ttl > 0) {\n this.cache.set(jti, { checkedAt: Date.now() })\n }\n\n return result.valid\n } catch (err) {\n if (this.mode === 'strict') throw err\n\n // recheck_*m: fail open\n this.logger.warn('revocation.check.failed_open', {\n jti: jti.slice(0, 8),\n error: err instanceof Error ? err.message : 'unknown',\n })\n return true\n }\n }\n\n private maybeCleanup(): void {\n const now = Date.now()\n if (now - this.lastCleanedAt < CLEANUP_WINDOW_MS) return\n this.lastCleanedAt = now // set before iteration to prevent concurrent double-clean\n for (const [jti, entry] of this.cache) {\n if (now - entry.checkedAt > EVICTION_TTL_MS) {\n this.cache.delete(jti)\n }\n }\n }\n}\n","import { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\nexport class RefreshDeduplicator {\n private readonly inflight = new Map<string, Promise<unknown>>()\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n getOrRun<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(sessionId)\n if (existing) {\n this.logger.debug('refresh dedup hit', { key: sessionId })\n return existing as Promise<T>\n }\n\n const promise = fn().finally(() => {\n this.inflight.delete(sessionId)\n })\n\n this.inflight.set(sessionId, promise)\n return promise\n }\n}\n","import type { MiniMothSessionStore } from './MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Entry = { accessToken: string; refreshToken: string }\n\nexport class DefaultSessionStore implements MiniMothSessionStore {\n private readonly map = new Map<string, Entry>()\n private warnedProduction = false\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n private maybeWarn(): void {\n if (process.env['NODE_ENV'] === 'production' && !this.warnedProduction) {\n this.warnedProduction = true\n this.logger.warn('using default in-memory session store — not suitable for multi-replica deployments')\n }\n }\n\n async getRefreshToken(sessionId: string): Promise<string | null> {\n this.maybeWarn()\n return this.map.get(sessionId)?.refreshToken ?? null\n }\n\n async setTokens(sessionId: string, tokens: { accessToken: string; refreshToken: string }): Promise<void> {\n this.maybeWarn()\n this.map.set(sessionId, tokens)\n }\n\n async deleteSession(sessionId: string): Promise<void> {\n this.map.delete(sessionId)\n }\n}\n","import type { MiniMothLogger } from './MiniMothLogger'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0, info: 1, warn: 2, error: 3, silent: 4,\n}\n\nexport class ConsoleLogger implements MiniMothLogger {\n private level: LogLevel\n\n constructor(level: LogLevel = 'info') {\n this.level = level\n }\n\n setLevel(level: LogLevel): void {\n this.level = level\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level]\n }\n\n private format(msg: string, meta?: Record<string, unknown>): string {\n if (!meta || Object.keys(meta).length === 0) return `[minimoth] ${msg}`\n return `[minimoth] ${msg} ${JSON.stringify(meta)}`\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('debug')) console.debug(this.format(msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('info')) console.info(this.format(msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('warn')) console.warn(this.format(msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('error')) console.error(this.format(msg, meta))\n }\n}\n","import { OtpClient } from './otp/OtpClient'\nimport { SessionClient } from './session/SessionClient'\nimport { JwksCache } from './session/JwksCache'\nimport { RevocationCache } from './session/RevocationCache'\nimport { RefreshDeduplicator } from './session/RefreshDeduplicator'\nimport { DefaultSessionStore } from './store/DefaultSessionStore'\nimport { ConsoleLogger } from './logger/ConsoleLogger'\nimport type { MiniMothConfig } from './types'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nexport class MiniMoth {\n readonly otp: OtpClient\n readonly session: SessionClient\n private readonly consoleLogger: ConsoleLogger\n\n constructor(config: MiniMothConfig) {\n this.consoleLogger = new ConsoleLogger(config.logLevel ?? 'info')\n const logger = config.logger ?? this.consoleLogger\n\n const store = config.session?.store ?? new DefaultSessionStore(logger)\n const validateMode = config.session?.validateMode ?? 'instant'\n\n const jwksCache = new JwksCache(logger)\n const revocationCache = new RevocationCache(validateMode, config.apiKey, logger)\n const deduplicator = new RefreshDeduplicator(logger)\n\n this.otp = new OtpClient(config.apiKey, store, logger)\n this.session = new SessionClient(\n config.apiKey,\n jwksCache,\n revocationCache,\n deduplicator,\n store,\n logger\n )\n }\n\n // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.\n setLogLevel(level: LogLevel): void {\n this.consoleLogger.setLevel(level)\n }\n}\n"],"mappings":"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","names":["require","jwt","import_jsonwebtoken","jwt","err","crypto"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
|
|
3
|
-
type MiniMothErrorCode = '
|
|
3
|
+
type MiniMothErrorCode = 'INVALID_ACCESS_TOKEN' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'OTP_NOT_FOUND' | 'OTP_RATE_LIMITED' | 'VERIFY_RATE_LIMITED' | 'INSUFFICIENT_BALANCE' | 'NETWORK_ERROR' | 'INVALID_PHONE' | 'UNKNOWN_ERROR';
|
|
4
4
|
declare class MiniMothError extends Error {
|
|
5
5
|
readonly code: MiniMothErrorCode;
|
|
6
6
|
readonly statusCode: number;
|
|
@@ -32,6 +32,12 @@ type VerifyResult = {
|
|
|
32
32
|
valid: false;
|
|
33
33
|
code: MiniMothErrorCode;
|
|
34
34
|
};
|
|
35
|
+
type OtpStatus = {
|
|
36
|
+
otpId: string;
|
|
37
|
+
channel: string | null;
|
|
38
|
+
status: 'queued' | 'delivered' | 'failed';
|
|
39
|
+
deliveredAt: string | null;
|
|
40
|
+
};
|
|
35
41
|
declare class OtpClient {
|
|
36
42
|
private readonly apiKey;
|
|
37
43
|
private readonly store;
|
|
@@ -39,7 +45,10 @@ declare class OtpClient {
|
|
|
39
45
|
constructor(apiKey: string, store: MiniMothSessionStore, logger: MiniMothLogger);
|
|
40
46
|
send(params: {
|
|
41
47
|
phone: string;
|
|
42
|
-
}): Promise<
|
|
48
|
+
}): Promise<{
|
|
49
|
+
otpId: string;
|
|
50
|
+
}>;
|
|
51
|
+
status(otpId: string): Promise<OtpStatus>;
|
|
43
52
|
verify(params: {
|
|
44
53
|
phone: string;
|
|
45
54
|
otp: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
|
|
3
|
-
type MiniMothErrorCode = '
|
|
3
|
+
type MiniMothErrorCode = 'INVALID_ACCESS_TOKEN' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'OTP_NOT_FOUND' | 'OTP_RATE_LIMITED' | 'VERIFY_RATE_LIMITED' | 'INSUFFICIENT_BALANCE' | 'NETWORK_ERROR' | 'INVALID_PHONE' | 'UNKNOWN_ERROR';
|
|
4
4
|
declare class MiniMothError extends Error {
|
|
5
5
|
readonly code: MiniMothErrorCode;
|
|
6
6
|
readonly statusCode: number;
|
|
@@ -32,6 +32,12 @@ type VerifyResult = {
|
|
|
32
32
|
valid: false;
|
|
33
33
|
code: MiniMothErrorCode;
|
|
34
34
|
};
|
|
35
|
+
type OtpStatus = {
|
|
36
|
+
otpId: string;
|
|
37
|
+
channel: string | null;
|
|
38
|
+
status: 'queued' | 'delivered' | 'failed';
|
|
39
|
+
deliveredAt: string | null;
|
|
40
|
+
};
|
|
35
41
|
declare class OtpClient {
|
|
36
42
|
private readonly apiKey;
|
|
37
43
|
private readonly store;
|
|
@@ -39,7 +45,10 @@ declare class OtpClient {
|
|
|
39
45
|
constructor(apiKey: string, store: MiniMothSessionStore, logger: MiniMothLogger);
|
|
40
46
|
send(params: {
|
|
41
47
|
phone: string;
|
|
42
|
-
}): Promise<
|
|
48
|
+
}): Promise<{
|
|
49
|
+
otpId: string;
|
|
50
|
+
}>;
|
|
51
|
+
status(otpId: string): Promise<OtpStatus>;
|
|
43
52
|
verify(params: {
|
|
44
53
|
phone: string;
|
|
45
54
|
otp: string;
|
package/dist/index.js
CHANGED
|
@@ -21,13 +21,12 @@ var pkg = require2("../package.json");
|
|
|
21
21
|
var BASE_URL = "https://api.minimoth.dev";
|
|
22
22
|
var USER_AGENT = `minimoth-sdk-node/${pkg.version}`;
|
|
23
23
|
var BACKEND_CODE_MAP = {
|
|
24
|
-
INVALID_ACCESS_TOKEN: "
|
|
25
|
-
|
|
26
|
-
TOKEN_REVOKED: "TOKEN_REVOKED",
|
|
24
|
+
INVALID_ACCESS_TOKEN: "INVALID_ACCESS_TOKEN",
|
|
25
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
27
26
|
INVALID_OTP: "INVALID_OTP",
|
|
28
|
-
OTP_NOT_FOUND: "
|
|
29
|
-
OTP_RATE_LIMITED: "
|
|
30
|
-
VERIFY_RATE_LIMITED: "
|
|
27
|
+
OTP_NOT_FOUND: "OTP_NOT_FOUND",
|
|
28
|
+
OTP_RATE_LIMITED: "OTP_RATE_LIMITED",
|
|
29
|
+
VERIFY_RATE_LIMITED: "VERIFY_RATE_LIMITED",
|
|
31
30
|
INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
|
|
32
31
|
INVALID_PHONE: "INVALID_PHONE"
|
|
33
32
|
};
|
|
@@ -58,12 +57,12 @@ async function apiPost(path, apiKey, body) {
|
|
|
58
57
|
}
|
|
59
58
|
return handleResponse(response);
|
|
60
59
|
}
|
|
61
|
-
async function apiGet(path) {
|
|
60
|
+
async function apiGet(path, apiKey) {
|
|
61
|
+
const headers = { "User-Agent": USER_AGENT };
|
|
62
|
+
if (apiKey) headers["X-Api-Key"] = apiKey;
|
|
62
63
|
let response;
|
|
63
64
|
try {
|
|
64
|
-
response = await fetch(`${BASE_URL}${path}`, {
|
|
65
|
-
headers: { "User-Agent": USER_AGENT }
|
|
66
|
-
});
|
|
65
|
+
response = await fetch(`${BASE_URL}${path}`, { headers });
|
|
67
66
|
} catch (err) {
|
|
68
67
|
throw new MiniMothError("NETWORK_ERROR", "Network request failed", 0, err);
|
|
69
68
|
}
|
|
@@ -82,8 +81,18 @@ var OtpClient = class {
|
|
|
82
81
|
logger;
|
|
83
82
|
async send(params) {
|
|
84
83
|
const phone = normalizePhone(params.phone);
|
|
85
|
-
await apiPost("/v1/otp/send", this.apiKey, { phone });
|
|
84
|
+
const res = await apiPost("/v1/otp/send", this.apiKey, { phone });
|
|
86
85
|
this.logger.info("otp.sent", { phone: maskPhone(phone) });
|
|
86
|
+
return { otpId: res.otp_id };
|
|
87
|
+
}
|
|
88
|
+
async status(otpId) {
|
|
89
|
+
const res = await apiGet(`/v1/otp/status/${encodeURIComponent(otpId)}`, this.apiKey);
|
|
90
|
+
return {
|
|
91
|
+
otpId: res.otp_id,
|
|
92
|
+
channel: res.channel,
|
|
93
|
+
status: res.status,
|
|
94
|
+
deliveredAt: res.delivered_at
|
|
95
|
+
};
|
|
87
96
|
}
|
|
88
97
|
async verify(params) {
|
|
89
98
|
const phone = normalizePhone(params.phone);
|
|
@@ -96,7 +105,7 @@ var OtpClient = class {
|
|
|
96
105
|
);
|
|
97
106
|
const payload = jwt.decode(res.access_token);
|
|
98
107
|
if (!payload?.session_id) {
|
|
99
|
-
throw new MiniMothError("
|
|
108
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Could not decode session_id from access token", 0);
|
|
100
109
|
}
|
|
101
110
|
try {
|
|
102
111
|
await this.store.setTokens(payload.session_id, {
|
|
@@ -115,7 +124,7 @@ var OtpClient = class {
|
|
|
115
124
|
};
|
|
116
125
|
} catch (err) {
|
|
117
126
|
if (err instanceof MiniMothError) {
|
|
118
|
-
if (err.code === "INVALID_OTP" || err.code === "
|
|
127
|
+
if (err.code === "INVALID_OTP" || err.code === "OTP_NOT_FOUND" || err.code === "INVALID_PHONE" || err.code === "VERIFY_RATE_LIMITED") {
|
|
119
128
|
this.logger.debug("otp.verify.failed", { code: err.code });
|
|
120
129
|
return { valid: false, code: err.code };
|
|
121
130
|
}
|
|
@@ -166,10 +175,10 @@ var SessionClient = class {
|
|
|
166
175
|
async validate(accessToken) {
|
|
167
176
|
const decoded = jwt2.decode(accessToken, { complete: true });
|
|
168
177
|
if (!decoded || typeof decoded === "string") {
|
|
169
|
-
throw new MiniMothError("
|
|
178
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is malformed", 401);
|
|
170
179
|
}
|
|
171
180
|
const kid = decoded.header["kid"];
|
|
172
|
-
if (!kid) throw new MiniMothError("
|
|
181
|
+
if (!kid) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is missing kid header", 401);
|
|
173
182
|
const publicKey = await this.jwksCache.getKey(kid);
|
|
174
183
|
let currentToken = accessToken;
|
|
175
184
|
let newTokens;
|
|
@@ -179,11 +188,11 @@ var SessionClient = class {
|
|
|
179
188
|
if (err instanceof jwt2.TokenExpiredError) {
|
|
180
189
|
const expiredPayload = decoded.payload;
|
|
181
190
|
const sessionId = expiredPayload?.session_id;
|
|
182
|
-
if (!sessionId) throw new MiniMothError("
|
|
191
|
+
if (!sessionId) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token is invalid", 401);
|
|
183
192
|
newTokens = await this.deduplicator.getOrRun(sessionId, async () => {
|
|
184
193
|
const refreshToken = await this.store.getRefreshToken(sessionId);
|
|
185
194
|
if (!refreshToken) {
|
|
186
|
-
throw new MiniMothError("
|
|
195
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Access token expired and no refresh token available", 401);
|
|
187
196
|
}
|
|
188
197
|
this.logger.info("session.auto_refresh", { sessionId: sessionId.slice(0, 8) });
|
|
189
198
|
const res = await apiPost(
|
|
@@ -207,12 +216,12 @@ var SessionClient = class {
|
|
|
207
216
|
const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey;
|
|
208
217
|
jwt2.verify(currentToken, newKey, { algorithms: ["RS256"] });
|
|
209
218
|
} else {
|
|
210
|
-
throw new MiniMothError("
|
|
219
|
+
throw new MiniMothError("INVALID_ACCESS_TOKEN", "Token signature is invalid", 401);
|
|
211
220
|
}
|
|
212
221
|
}
|
|
213
222
|
const payload = jwt2.decode(currentToken);
|
|
214
223
|
const isValid = await this.revocationCache.check(payload.jti, currentToken);
|
|
215
|
-
if (!isValid) throw new MiniMothError("
|
|
224
|
+
if (!isValid) throw new MiniMothError("SESSION_EXPIRED", "Session has been revoked", 401);
|
|
216
225
|
const session = {
|
|
217
226
|
phone: payload.sub,
|
|
218
227
|
projectId: payload.project_id,
|
|
@@ -255,7 +264,7 @@ var SessionClient = class {
|
|
|
255
264
|
async logout(params) {
|
|
256
265
|
const payload = jwt2.decode(params.accessToken);
|
|
257
266
|
const sessionId = payload?.session_id ?? null;
|
|
258
|
-
if (!sessionId) throw new MiniMothError("
|
|
267
|
+
if (!sessionId) throw new MiniMothError("INVALID_ACCESS_TOKEN", "Cannot decode token", 401);
|
|
259
268
|
let currentAccessToken = params.accessToken;
|
|
260
269
|
if (payload && payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
261
270
|
const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {
|
|
@@ -308,7 +317,7 @@ var JwksCache = class {
|
|
|
308
317
|
await this.fetch();
|
|
309
318
|
key = this.keyMap.get(kid);
|
|
310
319
|
}
|
|
311
|
-
if (!key) throw new MiniMothError("
|
|
320
|
+
if (!key) throw new MiniMothError("INVALID_ACCESS_TOKEN", `No public key found for kid: ${kid}`, 401);
|
|
312
321
|
return key;
|
|
313
322
|
}
|
|
314
323
|
fetch() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/otp/OtpClient.ts","../src/MiniMothError.ts","../src/http.ts","../src/session/SessionClient.ts","../src/session/JwksCache.ts","../src/session/RevocationCache.ts","../src/session/RefreshDeduplicator.ts","../src/store/DefaultSessionStore.ts","../src/logger/ConsoleLogger.ts","../src/MiniMoth.ts"],"sourcesContent":["import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { AccessTokenPayload } from '../types'\n\ntype VerifyResult =\n | { valid: true; accessToken: string; refreshToken: string; sessionId: string }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class OtpClient {\n constructor(\n private readonly apiKey: string,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async send(params: { phone: string }): Promise<void> {\n const phone = normalizePhone(params.phone)\n await apiPost<{ message: string }>('/v1/otp/send', this.apiKey, { phone })\n this.logger.info('otp.sent', { phone: maskPhone(phone) })\n }\n\n async verify(params: { phone: string; otp: string }): Promise<VerifyResult> {\n const phone = normalizePhone(params.phone)\n validateOtp(params.otp)\n\n try {\n const res = await apiPost<{ access_token: string; refresh_token: string; expires_at: string }>(\n '/v1/otp/verify',\n this.apiKey,\n { phone, code: params.otp }\n )\n\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (!payload?.session_id) {\n throw new MiniMothError('INVALID_TOKEN', 'Could not decode session_id from access token', 0)\n }\n\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch {\n this.logger.error('otp.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n\n this.logger.info('otp.verified', { sessionId: payload.session_id.slice(0, 8) })\n\n return {\n valid: true,\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n sessionId: payload.session_id,\n }\n } catch (err) {\n if (err instanceof MiniMothError) {\n if (err.code === 'INVALID_OTP' || err.code === 'OTP_EXPIRED' || err.code === 'INVALID_PHONE') {\n this.logger.debug('otp.verify.failed', { code: err.code })\n return { valid: false, code: err.code }\n }\n }\n throw err\n }\n }\n}\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nfunction normalizePhone(raw: string): string {\n if (!raw || typeof raw !== 'string') {\n throw new MiniMothError('INVALID_PHONE', 'Phone number is required', 422)\n }\n if (/[\\s-]/.test(raw)) {\n throw new MiniMothError('INVALID_PHONE', 'Phone number must not contain spaces or hyphens', 422)\n }\n let phone = raw\n if (phone.startsWith('+')) phone = phone.slice(1)\n // 10-digit subscriber number — prepend country code\n if (phone.length === 10) phone = '91' + phone\n return phone\n}\n\nfunction validateOtp(otp: string): void {\n if (!otp || typeof otp !== 'string') {\n throw new MiniMothError('INVALID_OTP', 'OTP is required', 422)\n }\n}\n\nexport function maskPhone(phone: string): string {\n if (phone.length <= 4) return '****'\n return phone.slice(0, 4) + '*'.repeat(Math.max(phone.length - 6, 1)) + phone.slice(-2)\n}\n","export type MiniMothErrorCode =\n | 'TOKEN_EXPIRED'\n | 'TOKEN_REVOKED'\n | 'INVALID_TOKEN'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'RATE_LIMITED'\n | 'INSUFFICIENT_BALANCE'\n | 'NETWORK_ERROR'\n | 'INVALID_PHONE'\n | 'UNKNOWN_ERROR'\n\nexport class MiniMothError extends Error {\n readonly code: MiniMothErrorCode\n readonly statusCode: number\n\n constructor(code: MiniMothErrorCode, message: string, statusCode: number, cause?: unknown) {\n super(message, cause !== undefined ? { cause } : undefined)\n this.name = 'MiniMothError'\n this.code = code\n this.statusCode = statusCode\n // Restore prototype chain for instanceof checks across module boundaries\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { MiniMothError, type MiniMothErrorCode } from './MiniMothError'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\nconst pkg = require('../package.json') as { version: string }\n\nconst BASE_URL = 'https://api.minimoth.dev'\nconst USER_AGENT = `minimoth-sdk-node/${pkg.version}`\n\nconst BACKEND_CODE_MAP: Record<string, MiniMothErrorCode> = {\n INVALID_ACCESS_TOKEN: 'INVALID_TOKEN',\n TOKEN_EXPIRED: 'TOKEN_EXPIRED',\n TOKEN_REVOKED: 'TOKEN_REVOKED',\n INVALID_OTP: 'INVALID_OTP',\n OTP_NOT_FOUND: 'OTP_EXPIRED',\n OTP_RATE_LIMITED: 'RATE_LIMITED',\n VERIFY_RATE_LIMITED: 'RATE_LIMITED',\n INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',\n INVALID_PHONE: 'INVALID_PHONE',\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) return response.json() as Promise<T>\n\n let body: { code?: string; error?: string } = {}\n try { body = await response.json() as { code?: string; error?: string } } catch {}\n\n const sdkCode: MiniMothErrorCode = BACKEND_CODE_MAP[body.code ?? ''] ?? 'UNKNOWN_ERROR'\n throw new MiniMothError(sdkCode, body.error ?? 'Unknown error', response.status)\n}\n\nexport async function apiPost<T>(\n path: string,\n apiKey: string,\n body: Record<string, unknown>\n): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n\nexport async function apiGet<T>(path: string): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n headers: { 'User-Agent': USER_AGENT },\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { JwksCache } from './JwksCache'\nimport type { RevocationCache } from './RevocationCache'\nimport type { RefreshDeduplicator } from './RefreshDeduplicator'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Session, AccessTokenPayload } from '../types'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\ntype SafeValidateResult =\n | { valid: true; session: Session }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class SessionClient {\n constructor(\n private readonly apiKey: string,\n private readonly jwksCache: JwksCache,\n private readonly revocationCache: RevocationCache,\n private readonly deduplicator: RefreshDeduplicator,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async validate(accessToken: string): Promise<Session> {\n const decoded = jwt.decode(accessToken, { complete: true })\n if (!decoded || typeof decoded === 'string') {\n throw new MiniMothError('INVALID_TOKEN', 'Token is malformed', 401)\n }\n\n const kid = (decoded.header as unknown as Record<string, string>)['kid']\n if (!kid) throw new MiniMothError('INVALID_TOKEN', 'Token is missing kid header', 401)\n\n const publicKey = await this.jwksCache.getKey(kid)\n\n let currentToken = accessToken\n let newTokens: Tokens | undefined\n\n try {\n jwt.verify(accessToken, publicKey, { algorithms: ['RS256'] })\n } catch (err) {\n if (err instanceof jwt.TokenExpiredError) {\n const expiredPayload = decoded.payload as AccessTokenPayload\n const sessionId = expiredPayload?.session_id\n if (!sessionId) throw new MiniMothError('INVALID_TOKEN', 'Token is invalid', 401)\n\n newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const refreshToken = await this.store.getRefreshToken(sessionId)\n if (!refreshToken) {\n throw new MiniMothError('TOKEN_EXPIRED', 'Access token expired and no refresh token available', 401)\n }\n\n this.logger.info('session.auto_refresh', { sessionId: sessionId.slice(0, 8) })\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n try {\n await this.store.setTokens(sessionId, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n\n currentToken = newTokens.accessToken\n\n // Verify the new token\n const newDecoded = jwt.decode(currentToken, { complete: true })\n const newKid = (newDecoded?.header as Record<string, string> | undefined)?.['kid']\n const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey\n jwt.verify(currentToken, newKey, { algorithms: ['RS256'] })\n } else {\n throw new MiniMothError('INVALID_TOKEN', 'Token signature is invalid', 401)\n }\n }\n\n const payload = jwt.decode(currentToken) as AccessTokenPayload\n const isValid = await this.revocationCache.check(payload.jti, currentToken)\n if (!isValid) throw new MiniMothError('TOKEN_REVOKED', 'Session has been revoked', 401)\n\n const session: Session = {\n phone: payload.sub,\n projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (newTokens) session.newTokens = newTokens\n\n this.logger.info('session.validated', { sessionId: payload.session_id.slice(0, 8) })\n return session\n }\n\n async safeValidate(accessToken: string): Promise<SafeValidateResult> {\n try {\n const session = await this.validate(accessToken)\n return { valid: true, session }\n } catch (err) {\n if (err instanceof MiniMothError) return { valid: false, code: err.code }\n throw err\n }\n }\n\n async refresh(refreshToken: string): Promise<Tokens> {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n // Update store if session_id is decodable from new token\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (payload?.session_id) {\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n }\n\n this.logger.info('session.refreshed')\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n }\n\n async logout(params: { accessToken: string; refreshToken: string }): Promise<void> {\n const payload = jwt.decode(params.accessToken) as AccessTokenPayload | null\n const sessionId = payload?.session_id ?? null\n\n if (!sessionId) throw new MiniMothError('INVALID_TOKEN', 'Cannot decode token', 401)\n\n let currentAccessToken = params.accessToken\n\n // If token is expired, refresh before logout — deduplicated to prevent concurrent refresh races\n if (payload && payload.exp < Math.floor(Date.now() / 1000)) {\n const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: params.refreshToken }\n )\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n currentAccessToken = newTokens.accessToken\n try {\n await this.store.setTokens(sessionId, newTokens)\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n }\n\n await apiPost<{ message: string }>(\n '/v1/session/logout',\n this.apiKey,\n { access_token: currentAccessToken }\n )\n\n try {\n await this.store.deleteSession(sessionId)\n } catch (err) {\n this.logger.error('session.store.deleteSession.failed', { sessionId: sessionId.slice(0, 8) })\n }\n this.logger.info('session.logged_out', { sessionId: sessionId.slice(0, 8) })\n }\n}\n","import crypto from 'crypto'\nimport { apiGet } from '../http'\nimport { MiniMothError } from '../MiniMothError'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\nconst CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\ntype JwkEntry = Record<string, string>\n\nexport class JwksCache {\n private keyMap = new Map<string, crypto.KeyObject>()\n private fetchedAt = 0\n private fetching: Promise<void> | null = null\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n async getKey(kid: string): Promise<crypto.KeyObject> {\n if (this.keyMap.size === 0 || Date.now() - this.fetchedAt > CACHE_TTL_MS) {\n await this.fetch()\n }\n\n let key = this.keyMap.get(kid)\n if (!key) {\n this.logger.debug('jwks.unknown_kid', { kid })\n await this.fetch()\n key = this.keyMap.get(kid)\n }\n\n if (!key) throw new MiniMothError('INVALID_TOKEN', `No public key found for kid: ${kid}`, 401)\n return key\n }\n\n private fetch(): Promise<void> {\n if (this.fetching) return this.fetching\n this.fetching = this.doFetch().finally(() => { this.fetching = null })\n return this.fetching\n }\n\n private async doFetch(): Promise<void> {\n this.logger.debug('jwks.fetch')\n const data = await apiGet<{ keys: JwkEntry[] }>('/.well-known/jwks.json')\n const newMap = new Map<string, crypto.KeyObject>()\n for (const jwk of data.keys) {\n if (jwk['kid'] && jwk['kty'] === 'RSA') {\n const key = crypto.createPublicKey({ key: jwk as unknown as crypto.JsonWebKey, format: 'jwk' })\n newMap.set(jwk['kid'], key)\n }\n }\n this.keyMap = newMap\n this.fetchedAt = Date.now()\n this.logger.debug('jwks.updated', { keyCount: newMap.size })\n }\n}\n","import { apiPost } from '../http'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { ValidateMode } from '../types'\n\nconst MODE_TTL_MS: Partial<Record<ValidateMode, number>> = {\n recheck_1m: 60_000,\n recheck_3m: 180_000,\n}\n\nconst EVICTION_TTL_MS = 5 * 60 * 1000 // JWT max lifetime\nconst CLEANUP_WINDOW_MS = 5 * 60 * 1000\n\ntype Entry = { checkedAt: number }\n\nexport class RevocationCache {\n private readonly cache = new Map<string, Entry>()\n private lastCleanedAt = 0\n\n constructor(\n private readonly mode: ValidateMode,\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async check(jti: string, accessToken: string): Promise<boolean> {\n if (this.mode === 'instant') return true\n\n if (this.mode !== 'strict') this.maybeCleanup()\n\n const ttl = MODE_TTL_MS[this.mode] ?? 0\n if (ttl > 0) {\n const entry = this.cache.get(jti)\n if (entry && Date.now() - entry.checkedAt < ttl) {\n this.logger.debug('revocation.cache.hit', { jti: jti.slice(0, 8) })\n return true\n }\n }\n\n try {\n const result = await apiPost<{ valid: boolean }>(\n '/v1/session/validate',\n this.apiKey,\n { access_token: accessToken }\n )\n\n if (result.valid && ttl > 0) {\n this.cache.set(jti, { checkedAt: Date.now() })\n }\n\n return result.valid\n } catch (err) {\n if (this.mode === 'strict') throw err\n\n // recheck_*m: fail open\n this.logger.warn('revocation.check.failed_open', {\n jti: jti.slice(0, 8),\n error: err instanceof Error ? err.message : 'unknown',\n })\n return true\n }\n }\n\n private maybeCleanup(): void {\n const now = Date.now()\n if (now - this.lastCleanedAt < CLEANUP_WINDOW_MS) return\n this.lastCleanedAt = now // set before iteration to prevent concurrent double-clean\n for (const [jti, entry] of this.cache) {\n if (now - entry.checkedAt > EVICTION_TTL_MS) {\n this.cache.delete(jti)\n }\n }\n }\n}\n","import { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\nexport class RefreshDeduplicator {\n private readonly inflight = new Map<string, Promise<unknown>>()\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n getOrRun<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(sessionId)\n if (existing) {\n this.logger.debug('refresh dedup hit', { key: sessionId })\n return existing as Promise<T>\n }\n\n const promise = fn().finally(() => {\n this.inflight.delete(sessionId)\n })\n\n this.inflight.set(sessionId, promise)\n return promise\n }\n}\n","import type { MiniMothSessionStore } from './MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Entry = { accessToken: string; refreshToken: string }\n\nexport class DefaultSessionStore implements MiniMothSessionStore {\n private readonly map = new Map<string, Entry>()\n private warnedProduction = false\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n private maybeWarn(): void {\n if (process.env['NODE_ENV'] === 'production' && !this.warnedProduction) {\n this.warnedProduction = true\n this.logger.warn('using default in-memory session store — not suitable for multi-replica deployments')\n }\n }\n\n async getRefreshToken(sessionId: string): Promise<string | null> {\n this.maybeWarn()\n return this.map.get(sessionId)?.refreshToken ?? null\n }\n\n async setTokens(sessionId: string, tokens: { accessToken: string; refreshToken: string }): Promise<void> {\n this.maybeWarn()\n this.map.set(sessionId, tokens)\n }\n\n async deleteSession(sessionId: string): Promise<void> {\n this.map.delete(sessionId)\n }\n}\n","import type { MiniMothLogger } from './MiniMothLogger'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0, info: 1, warn: 2, error: 3, silent: 4,\n}\n\nexport class ConsoleLogger implements MiniMothLogger {\n private level: LogLevel\n\n constructor(level: LogLevel = 'info') {\n this.level = level\n }\n\n setLevel(level: LogLevel): void {\n this.level = level\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level]\n }\n\n private format(msg: string, meta?: Record<string, unknown>): string {\n if (!meta || Object.keys(meta).length === 0) return `[minimoth] ${msg}`\n return `[minimoth] ${msg} ${JSON.stringify(meta)}`\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('debug')) console.debug(this.format(msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('info')) console.info(this.format(msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('warn')) console.warn(this.format(msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('error')) console.error(this.format(msg, meta))\n }\n}\n","import { OtpClient } from './otp/OtpClient'\nimport { SessionClient } from './session/SessionClient'\nimport { JwksCache } from './session/JwksCache'\nimport { RevocationCache } from './session/RevocationCache'\nimport { RefreshDeduplicator } from './session/RefreshDeduplicator'\nimport { DefaultSessionStore } from './store/DefaultSessionStore'\nimport { ConsoleLogger } from './logger/ConsoleLogger'\nimport type { MiniMothConfig } from './types'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nexport class MiniMoth {\n readonly otp: OtpClient\n readonly session: SessionClient\n private readonly consoleLogger: ConsoleLogger\n\n constructor(config: MiniMothConfig) {\n this.consoleLogger = new ConsoleLogger(config.logLevel ?? 'info')\n const logger = config.logger ?? this.consoleLogger\n\n const store = config.session?.store ?? new DefaultSessionStore(logger)\n const validateMode = config.session?.validateMode ?? 'instant'\n\n const jwksCache = new JwksCache(logger)\n const revocationCache = new RevocationCache(validateMode, config.apiKey, logger)\n const deduplicator = new RefreshDeduplicator(logger)\n\n this.otp = new OtpClient(config.apiKey, store, logger)\n this.session = new SessionClient(\n config.apiKey,\n jwksCache,\n revocationCache,\n deduplicator,\n store,\n logger\n )\n }\n\n // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.\n setLogLevel(level: LogLevel): void {\n this.consoleLogger.setLevel(level)\n }\n}\n"],"mappings":"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","names":["require","jwt","jwt","err"]}
|
|
1
|
+
{"version":3,"sources":["../src/otp/OtpClient.ts","../src/MiniMothError.ts","../src/http.ts","../src/session/SessionClient.ts","../src/session/JwksCache.ts","../src/session/RevocationCache.ts","../src/session/RefreshDeduplicator.ts","../src/store/DefaultSessionStore.ts","../src/logger/ConsoleLogger.ts","../src/MiniMoth.ts"],"sourcesContent":["import jwt from 'jsonwebtoken'\nimport { apiPost, apiGet } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { AccessTokenPayload } from '../types'\n\ntype VerifyResult =\n | { valid: true; accessToken: string; refreshToken: string; sessionId: string }\n | { valid: false; code: MiniMothErrorCode }\n\ntype OtpStatus = {\n otpId: string\n channel: string | null\n status: 'queued' | 'delivered' | 'failed'\n deliveredAt: string | null\n}\n\nexport class OtpClient {\n constructor(\n private readonly apiKey: string,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async send(params: { phone: string }): Promise<{ otpId: string }> {\n const phone = normalizePhone(params.phone)\n const res = await apiPost<{ message: string; otp_id: string }>('/v1/otp/send', this.apiKey, { phone })\n this.logger.info('otp.sent', { phone: maskPhone(phone) })\n return { otpId: res.otp_id }\n }\n\n async status(otpId: string): Promise<OtpStatus> {\n const res = await apiGet<{\n otp_id: string\n channel: string | null\n status: 'queued' | 'delivered' | 'failed'\n delivered_at: string | null\n }>(`/v1/otp/status/${encodeURIComponent(otpId)}`, this.apiKey)\n return {\n otpId: res.otp_id,\n channel: res.channel,\n status: res.status,\n deliveredAt: res.delivered_at,\n }\n }\n\n async verify(params: { phone: string; otp: string }): Promise<VerifyResult> {\n const phone = normalizePhone(params.phone)\n validateOtp(params.otp)\n\n try {\n const res = await apiPost<{ access_token: string; refresh_token: string; expires_at: string }>(\n '/v1/otp/verify',\n this.apiKey,\n { phone, code: params.otp }\n )\n\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (!payload?.session_id) {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Could not decode session_id from access token', 0)\n }\n\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch {\n this.logger.error('otp.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n\n this.logger.info('otp.verified', { sessionId: payload.session_id.slice(0, 8) })\n\n return {\n valid: true,\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n sessionId: payload.session_id,\n }\n } catch (err) {\n if (err instanceof MiniMothError) {\n if (\n err.code === 'INVALID_OTP' ||\n err.code === 'OTP_NOT_FOUND' ||\n err.code === 'INVALID_PHONE' ||\n err.code === 'VERIFY_RATE_LIMITED'\n ) {\n this.logger.debug('otp.verify.failed', { code: err.code })\n return { valid: false, code: err.code }\n }\n }\n throw err\n }\n }\n}\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nfunction normalizePhone(raw: string): string {\n if (!raw || typeof raw !== 'string') {\n throw new MiniMothError('INVALID_PHONE', 'Phone number is required', 422)\n }\n if (/[\\s-]/.test(raw)) {\n throw new MiniMothError('INVALID_PHONE', 'Phone number must not contain spaces or hyphens', 422)\n }\n let phone = raw\n if (phone.startsWith('+')) phone = phone.slice(1)\n // 10-digit subscriber number — prepend country code\n if (phone.length === 10) phone = '91' + phone\n return phone\n}\n\nfunction validateOtp(otp: string): void {\n if (!otp || typeof otp !== 'string') {\n throw new MiniMothError('INVALID_OTP', 'OTP is required', 422)\n }\n}\n\nexport function maskPhone(phone: string): string {\n if (phone.length <= 4) return '****'\n return phone.slice(0, 4) + '*'.repeat(Math.max(phone.length - 6, 1)) + phone.slice(-2)\n}\n","export type MiniMothErrorCode =\n | 'INVALID_ACCESS_TOKEN'\n | 'SESSION_EXPIRED'\n | 'INVALID_OTP'\n | 'OTP_NOT_FOUND'\n | 'OTP_RATE_LIMITED'\n | 'VERIFY_RATE_LIMITED'\n | 'INSUFFICIENT_BALANCE'\n | 'NETWORK_ERROR'\n | 'INVALID_PHONE'\n | 'UNKNOWN_ERROR'\n\nexport class MiniMothError extends Error {\n readonly code: MiniMothErrorCode\n readonly statusCode: number\n\n constructor(code: MiniMothErrorCode, message: string, statusCode: number, cause?: unknown) {\n super(message, cause !== undefined ? { cause } : undefined)\n this.name = 'MiniMothError'\n this.code = code\n this.statusCode = statusCode\n // Restore prototype chain for instanceof checks across module boundaries\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { MiniMothError, type MiniMothErrorCode } from './MiniMothError'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\nconst pkg = require('../package.json') as { version: string }\n\nconst BASE_URL = 'https://api.minimoth.dev'\nconst USER_AGENT = `minimoth-sdk-node/${pkg.version}`\n\nconst BACKEND_CODE_MAP: Record<string, MiniMothErrorCode> = {\n INVALID_ACCESS_TOKEN: 'INVALID_ACCESS_TOKEN',\n SESSION_EXPIRED: 'SESSION_EXPIRED',\n INVALID_OTP: 'INVALID_OTP',\n OTP_NOT_FOUND: 'OTP_NOT_FOUND',\n OTP_RATE_LIMITED: 'OTP_RATE_LIMITED',\n VERIFY_RATE_LIMITED: 'VERIFY_RATE_LIMITED',\n INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',\n INVALID_PHONE: 'INVALID_PHONE',\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) return response.json() as Promise<T>\n\n let body: { code?: string; error?: string } = {}\n try { body = await response.json() as { code?: string; error?: string } } catch {}\n\n const sdkCode: MiniMothErrorCode = BACKEND_CODE_MAP[body.code ?? ''] ?? 'UNKNOWN_ERROR'\n throw new MiniMothError(sdkCode, body.error ?? 'Unknown error', response.status)\n}\n\nexport async function apiPost<T>(\n path: string,\n apiKey: string,\n body: Record<string, unknown>\n): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n\nexport async function apiGet<T>(path: string, apiKey?: string): Promise<T> {\n const headers: Record<string, string> = { 'User-Agent': USER_AGENT }\n if (apiKey) headers['X-Api-Key'] = apiKey\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, { headers })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import jwt from 'jsonwebtoken'\nimport { apiPost } from '../http'\nimport { MiniMothError, type MiniMothErrorCode } from '../MiniMothError'\nimport type { JwksCache } from './JwksCache'\nimport type { RevocationCache } from './RevocationCache'\nimport type { RefreshDeduplicator } from './RefreshDeduplicator'\nimport type { MiniMothSessionStore } from '../store/MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Session, AccessTokenPayload } from '../types'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\ntype SafeValidateResult =\n | { valid: true; session: Session }\n | { valid: false; code: MiniMothErrorCode }\n\nexport class SessionClient {\n constructor(\n private readonly apiKey: string,\n private readonly jwksCache: JwksCache,\n private readonly revocationCache: RevocationCache,\n private readonly deduplicator: RefreshDeduplicator,\n private readonly store: MiniMothSessionStore,\n private readonly logger: MiniMothLogger\n ) {}\n\n async validate(accessToken: string): Promise<Session> {\n const decoded = jwt.decode(accessToken, { complete: true })\n if (!decoded || typeof decoded === 'string') {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is malformed', 401)\n }\n\n const kid = (decoded.header as unknown as Record<string, string>)['kid']\n if (!kid) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is missing kid header', 401)\n\n const publicKey = await this.jwksCache.getKey(kid)\n\n let currentToken = accessToken\n let newTokens: Tokens | undefined\n\n try {\n jwt.verify(accessToken, publicKey, { algorithms: ['RS256'] })\n } catch (err) {\n if (err instanceof jwt.TokenExpiredError) {\n const expiredPayload = decoded.payload as AccessTokenPayload\n const sessionId = expiredPayload?.session_id\n if (!sessionId) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token is invalid', 401)\n\n newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const refreshToken = await this.store.getRefreshToken(sessionId)\n if (!refreshToken) {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Access token expired and no refresh token available', 401)\n }\n\n this.logger.info('session.auto_refresh', { sessionId: sessionId.slice(0, 8) })\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n try {\n await this.store.setTokens(sessionId, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n\n currentToken = newTokens.accessToken\n\n // Verify the new token\n const newDecoded = jwt.decode(currentToken, { complete: true })\n const newKid = (newDecoded?.header as Record<string, string> | undefined)?.['kid']\n const newKey = newKid ? await this.jwksCache.getKey(newKid) : publicKey\n jwt.verify(currentToken, newKey, { algorithms: ['RS256'] })\n } else {\n throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Token signature is invalid', 401)\n }\n }\n\n const payload = jwt.decode(currentToken) as AccessTokenPayload\n const isValid = await this.revocationCache.check(payload.jti, currentToken)\n if (!isValid) throw new MiniMothError('SESSION_EXPIRED', 'Session has been revoked', 401)\n\n const session: Session = {\n phone: payload.sub,\n projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (newTokens) session.newTokens = newTokens\n\n this.logger.info('session.validated', { sessionId: payload.session_id.slice(0, 8) })\n return session\n }\n\n async safeValidate(accessToken: string): Promise<SafeValidateResult> {\n try {\n const session = await this.validate(accessToken)\n return { valid: true, session }\n } catch (err) {\n if (err instanceof MiniMothError) return { valid: false, code: err.code }\n throw err\n }\n }\n\n async refresh(refreshToken: string): Promise<Tokens> {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: refreshToken }\n )\n\n // Update store if session_id is decodable from new token\n const payload = jwt.decode(res.access_token) as AccessTokenPayload | null\n if (payload?.session_id) {\n try {\n await this.store.setTokens(payload.session_id, {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n })\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: payload.session_id.slice(0, 8) })\n }\n }\n\n this.logger.info('session.refreshed')\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n }\n\n async logout(params: { accessToken: string; refreshToken: string }): Promise<void> {\n const payload = jwt.decode(params.accessToken) as AccessTokenPayload | null\n const sessionId = payload?.session_id ?? null\n\n if (!sessionId) throw new MiniMothError('INVALID_ACCESS_TOKEN', 'Cannot decode token', 401)\n\n let currentAccessToken = params.accessToken\n\n // If token is expired, refresh before logout — deduplicated to prevent concurrent refresh races\n if (payload && payload.exp < Math.floor(Date.now() / 1000)) {\n const newTokens = await this.deduplicator.getOrRun(sessionId, async () => {\n const res = await apiPost<{ access_token: string; refresh_token: string }>(\n '/v1/session/refresh',\n this.apiKey,\n { refresh_token: params.refreshToken }\n )\n return { accessToken: res.access_token, refreshToken: res.refresh_token }\n })\n currentAccessToken = newTokens.accessToken\n try {\n await this.store.setTokens(sessionId, newTokens)\n } catch (err) {\n this.logger.error('session.store.setTokens.failed', { sessionId: sessionId.slice(0, 8) })\n }\n }\n\n await apiPost<{ message: string }>(\n '/v1/session/logout',\n this.apiKey,\n { access_token: currentAccessToken }\n )\n\n try {\n await this.store.deleteSession(sessionId)\n } catch (err) {\n this.logger.error('session.store.deleteSession.failed', { sessionId: sessionId.slice(0, 8) })\n }\n this.logger.info('session.logged_out', { sessionId: sessionId.slice(0, 8) })\n }\n}\n","import crypto from 'crypto'\nimport { apiGet } from '../http'\nimport { MiniMothError } from '../MiniMothError'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\nconst CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\ntype JwkEntry = Record<string, string>\n\nexport class JwksCache {\n private keyMap = new Map<string, crypto.KeyObject>()\n private fetchedAt = 0\n private fetching: Promise<void> | null = null\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n async getKey(kid: string): Promise<crypto.KeyObject> {\n if (this.keyMap.size === 0 || Date.now() - this.fetchedAt > CACHE_TTL_MS) {\n await this.fetch()\n }\n\n let key = this.keyMap.get(kid)\n if (!key) {\n this.logger.debug('jwks.unknown_kid', { kid })\n await this.fetch()\n key = this.keyMap.get(kid)\n }\n\n if (!key) throw new MiniMothError('INVALID_ACCESS_TOKEN', `No public key found for kid: ${kid}`, 401)\n return key\n }\n\n private fetch(): Promise<void> {\n if (this.fetching) return this.fetching\n this.fetching = this.doFetch().finally(() => { this.fetching = null })\n return this.fetching\n }\n\n private async doFetch(): Promise<void> {\n this.logger.debug('jwks.fetch')\n const data = await apiGet<{ keys: JwkEntry[] }>('/.well-known/jwks.json')\n const newMap = new Map<string, crypto.KeyObject>()\n for (const jwk of data.keys) {\n if (jwk['kid'] && jwk['kty'] === 'RSA') {\n const key = crypto.createPublicKey({ key: jwk as unknown as crypto.JsonWebKey, format: 'jwk' })\n newMap.set(jwk['kid'], key)\n }\n }\n this.keyMap = newMap\n this.fetchedAt = Date.now()\n this.logger.debug('jwks.updated', { keyCount: newMap.size })\n }\n}\n","import { apiPost } from '../http'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { ValidateMode } from '../types'\n\nconst MODE_TTL_MS: Partial<Record<ValidateMode, number>> = {\n recheck_1m: 60_000,\n recheck_3m: 180_000,\n}\n\nconst EVICTION_TTL_MS = 5 * 60 * 1000 // JWT max lifetime\nconst CLEANUP_WINDOW_MS = 5 * 60 * 1000\n\ntype Entry = { checkedAt: number }\n\nexport class RevocationCache {\n private readonly cache = new Map<string, Entry>()\n private lastCleanedAt = 0\n\n constructor(\n private readonly mode: ValidateMode,\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async check(jti: string, accessToken: string): Promise<boolean> {\n if (this.mode === 'instant') return true\n\n if (this.mode !== 'strict') this.maybeCleanup()\n\n const ttl = MODE_TTL_MS[this.mode] ?? 0\n if (ttl > 0) {\n const entry = this.cache.get(jti)\n if (entry && Date.now() - entry.checkedAt < ttl) {\n this.logger.debug('revocation.cache.hit', { jti: jti.slice(0, 8) })\n return true\n }\n }\n\n try {\n const result = await apiPost<{ valid: boolean }>(\n '/v1/session/validate',\n this.apiKey,\n { access_token: accessToken }\n )\n\n if (result.valid && ttl > 0) {\n this.cache.set(jti, { checkedAt: Date.now() })\n }\n\n return result.valid\n } catch (err) {\n if (this.mode === 'strict') throw err\n\n // recheck_*m: fail open\n this.logger.warn('revocation.check.failed_open', {\n jti: jti.slice(0, 8),\n error: err instanceof Error ? err.message : 'unknown',\n })\n return true\n }\n }\n\n private maybeCleanup(): void {\n const now = Date.now()\n if (now - this.lastCleanedAt < CLEANUP_WINDOW_MS) return\n this.lastCleanedAt = now // set before iteration to prevent concurrent double-clean\n for (const [jti, entry] of this.cache) {\n if (now - entry.checkedAt > EVICTION_TTL_MS) {\n this.cache.delete(jti)\n }\n }\n }\n}\n","import { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Tokens = { accessToken: string; refreshToken: string }\n\nexport class RefreshDeduplicator {\n private readonly inflight = new Map<string, Promise<unknown>>()\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n getOrRun<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(sessionId)\n if (existing) {\n this.logger.debug('refresh dedup hit', { key: sessionId })\n return existing as Promise<T>\n }\n\n const promise = fn().finally(() => {\n this.inflight.delete(sessionId)\n })\n\n this.inflight.set(sessionId, promise)\n return promise\n }\n}\n","import type { MiniMothSessionStore } from './MiniMothSessionStore'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\n\ntype Entry = { accessToken: string; refreshToken: string }\n\nexport class DefaultSessionStore implements MiniMothSessionStore {\n private readonly map = new Map<string, Entry>()\n private warnedProduction = false\n\n constructor(private readonly logger: MiniMothLogger) {}\n\n private maybeWarn(): void {\n if (process.env['NODE_ENV'] === 'production' && !this.warnedProduction) {\n this.warnedProduction = true\n this.logger.warn('using default in-memory session store — not suitable for multi-replica deployments')\n }\n }\n\n async getRefreshToken(sessionId: string): Promise<string | null> {\n this.maybeWarn()\n return this.map.get(sessionId)?.refreshToken ?? null\n }\n\n async setTokens(sessionId: string, tokens: { accessToken: string; refreshToken: string }): Promise<void> {\n this.maybeWarn()\n this.map.set(sessionId, tokens)\n }\n\n async deleteSession(sessionId: string): Promise<void> {\n this.map.delete(sessionId)\n }\n}\n","import type { MiniMothLogger } from './MiniMothLogger'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0, info: 1, warn: 2, error: 3, silent: 4,\n}\n\nexport class ConsoleLogger implements MiniMothLogger {\n private level: LogLevel\n\n constructor(level: LogLevel = 'info') {\n this.level = level\n }\n\n setLevel(level: LogLevel): void {\n this.level = level\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level]\n }\n\n private format(msg: string, meta?: Record<string, unknown>): string {\n if (!meta || Object.keys(meta).length === 0) return `[minimoth] ${msg}`\n return `[minimoth] ${msg} ${JSON.stringify(meta)}`\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('debug')) console.debug(this.format(msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('info')) console.info(this.format(msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('warn')) console.warn(this.format(msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (this.shouldLog('error')) console.error(this.format(msg, meta))\n }\n}\n","import { OtpClient } from './otp/OtpClient'\nimport { SessionClient } from './session/SessionClient'\nimport { JwksCache } from './session/JwksCache'\nimport { RevocationCache } from './session/RevocationCache'\nimport { RefreshDeduplicator } from './session/RefreshDeduplicator'\nimport { DefaultSessionStore } from './store/DefaultSessionStore'\nimport { ConsoleLogger } from './logger/ConsoleLogger'\nimport type { MiniMothConfig } from './types'\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nexport class MiniMoth {\n readonly otp: OtpClient\n readonly session: SessionClient\n private readonly consoleLogger: ConsoleLogger\n\n constructor(config: MiniMothConfig) {\n this.consoleLogger = new ConsoleLogger(config.logLevel ?? 'info')\n const logger = config.logger ?? this.consoleLogger\n\n const store = config.session?.store ?? new DefaultSessionStore(logger)\n const validateMode = config.session?.validateMode ?? 'instant'\n\n const jwksCache = new JwksCache(logger)\n const revocationCache = new RevocationCache(validateMode, config.apiKey, logger)\n const deduplicator = new RefreshDeduplicator(logger)\n\n this.otp = new OtpClient(config.apiKey, store, logger)\n this.session = new SessionClient(\n config.apiKey,\n jwksCache,\n revocationCache,\n deduplicator,\n store,\n logger\n )\n }\n\n // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.\n setLogLevel(level: LogLevel): void {\n this.consoleLogger.setLevel(level)\n }\n}\n"],"mappings":"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","names":["require","jwt","jwt","err"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minimoth/sdk-node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Official MiniMoth Node.js SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"license": "MIT",
|
|
20
|
+
"homepage": "https://minimoth.dev",
|
|
20
21
|
"bugs": {
|
|
21
22
|
"email": "dev@minimoth.dev"
|
|
22
23
|
},
|