@minimoth/sdk-node 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,49 +17,50 @@ Requires Node.js 18+.
17
17
  ```ts
18
18
  import { MiniMoth } from '@minimoth/sdk-node'
19
19
 
20
- const client = new MiniMoth({
20
+ const mm = new MiniMoth({
21
21
  apiKey: 'mm_live_...', // from app.minimoth.dev
22
22
  })
23
23
 
24
24
  // Send OTP
25
- const { otpId } = await client.otp.send({ phone: '919876543210' })
25
+ const { otpId } = await mm.otp.send({ phone: '919876543210' })
26
26
 
27
27
  // Verify OTP
28
- const result = await client.otp.verify({ phone: '919876543210', otp: '123456' })
28
+ const result = await mm.otp.verify({ phone: '919876543210', otp: '123456' })
29
29
  if (result.valid) {
30
30
  // Store tokens — SDK auto-stores in memory by default
31
31
  console.log(result.accessToken, result.refreshToken, result.sessionId)
32
+ // result.identityId is set once identity lookups are enabled for the project — see Identity below
32
33
  }
33
34
 
34
35
  // Validate on every request
35
- const session = await client.session.validate(req.headers['x-access-token'])
36
- // session.projectId, session.sessionId, session.expiresAt
36
+ const session = await mm.session.validate(req.headers['x-access-token'])
37
+ // session.projectId, session.sessionId, session.expiresAt, session.identityId (if enabled)
37
38
  // If session.newTokens is set, send new tokens back to client
38
39
  //
39
40
  // Session no longer carries a phone number — access tokens don't embed it, by
40
41
  // design (JWT payloads are unencrypted and travel client-side). Store your own
41
- // session_id -> phone mapping when you call client.otp.verify() (you already
42
+ // session_id -> phone mapping when you call mm.otp.verify() (you already
42
43
  // have the phone number then), and look it up from session.sessionId whenever
43
44
  // you need it.
44
45
 
45
46
  // Safe variant — never throws
46
- const safe = await client.session.safeValidate(token)
47
+ const safe = await mm.session.safeValidate(token)
47
48
  if (!safe.valid) {
48
49
  res.status(401).json({ error: safe.code })
49
50
  return
50
51
  }
51
52
 
52
53
  // Refresh — SDK handles this automatically on validate(); call manually only if needed proactively
53
- const tokens = await client.session.refresh(refreshToken)
54
+ const tokens = await mm.session.refresh(refreshToken)
54
55
 
55
56
  // Logout (auto-refreshes if access token is expired)
56
- await client.session.logout({ accessToken, refreshToken })
57
+ await mm.session.logout({ accessToken, refreshToken })
57
58
  ```
58
59
 
59
60
  ## Configuration
60
61
 
61
62
  ```ts
62
- const client = new MiniMoth({
63
+ const mm = new MiniMoth({
63
64
  apiKey: 'mm_live_...', // required
64
65
 
65
66
  // Logging
@@ -73,7 +74,7 @@ const client = new MiniMoth({
73
74
  }
74
75
  })
75
76
 
76
- client.setLogLevel('warn') // update at runtime (only affects built-in console logger)
77
+ mm.setLogLevel('warn') // update at runtime (only affects built-in console logger)
77
78
  ```
78
79
 
79
80
  ## validateMode
@@ -90,7 +91,7 @@ client.setLogLevel('warn') // update at runtime (only affects built-in cons
90
91
  By default, the SDK uses an in-memory Map. In production with multiple server replicas, provide a shared store (e.g. Redis):
91
92
 
92
93
  ```ts
93
- const client = new MiniMoth({
94
+ const mm = new MiniMoth({
94
95
  apiKey: 'mm_live_...',
95
96
  session: {
96
97
  store: {
@@ -114,7 +115,7 @@ const client = new MiniMoth({
114
115
  import { MiniMothError } from '@minimoth/sdk-node'
115
116
 
116
117
  try {
117
- await client.session.validate(token)
118
+ await mm.session.validate(token)
118
119
  } catch (err) {
119
120
  if (err instanceof MiniMothError) {
120
121
  // err.code: 'INVALID_ACCESS_TOKEN' | 'SESSION_EXPIRED' | 'NETWORK_ERROR' | ...
@@ -127,7 +128,7 @@ try {
127
128
  Use `safeValidate` / `otp.verify` to avoid try/catch:
128
129
 
129
130
  ```ts
130
- const result = await client.session.safeValidate(token)
131
+ const result = await mm.session.safeValidate(token)
131
132
  if (!result.valid) return res.status(401).json({ error: result.code })
132
133
  const { session } = result
133
134
  ```
@@ -195,6 +196,34 @@ Revoke all tokens for a session.
195
196
  - Returns: Promise<void>
196
197
  - Throws: `MiniMothError` if the token can't be decoded, the pre-logout refresh fails, or the logout call itself fails. Local session store cleanup errors are caught and logged internally — they don't affect the promise.
197
198
 
199
+ ### IdentityClient
200
+
201
+ MiniMoth recognizes the same person across multiple logins over time via a per-project identity — `result.identityId` from `otp.verify()` and `session.identityId` from `session.validate()` are the id to use here. Identity lookup and deletion are opt-in per project (enable them in Project Settings at app.minimoth.dev) and only apply to live sessions — sandbox (`mm_test_`) keys always get `IDENTITY_NOT_FOUND`.
202
+
203
+ #### `get(identityId)`
204
+
205
+ Look up an identity by id.
206
+
207
+ - `identityId` (string, required): Identity id from `otp.verify()`/`session.validate()`
208
+ - Returns: `Promise<Identity>` where `Identity` is `{ id: string; createdAt: Date; factors: { type: string; value: string }[] }`
209
+ - Throws: `MiniMothError` with code `IDENTITY_NOT_FOUND` (no match, or lookup is disabled for a sandbox key) or `IDENTITY_LOOKUP_DISABLED` (not enabled for this project)
210
+
211
+ #### `getByPhone(phone)`
212
+
213
+ Look up an identity by phone number.
214
+
215
+ - `phone` (string, required): Indian phone number (e.g. `919876543210`)
216
+ - Returns: `Promise<Identity>`
217
+ - Throws: `MiniMothError` with code `IDENTITY_NOT_FOUND` or `IDENTITY_LOOKUP_DISABLED`, same as `get()`
218
+
219
+ #### `delete(identityId)`
220
+
221
+ Hard-delete an identity and revoke every active session tied to it.
222
+
223
+ - `identityId` (string, required): Identity id to delete
224
+ - Returns: `Promise<{ deleted: true }>`
225
+ - Throws: `MiniMothError` with code `IDENTITY_NOT_FOUND` or `IDENTITY_DELETE_DISABLED` (not enabled for this project)
226
+
198
227
  ## Error Codes
199
228
 
200
229
  Common `MiniMothError.code` values:
@@ -207,6 +236,9 @@ Common `MiniMothError.code` values:
207
236
  - `SESSION_EXPIRED`: Session has expired or was revoked — user must re-verify
208
237
  - `INVALID_PHONE`: Phone number format is invalid
209
238
  - `INSUFFICIENT_BALANCE`: Account has insufficient credits/balance
239
+ - `IDENTITY_NOT_FOUND`: No identity matches this id/phone, or the caller is a sandbox key
240
+ - `IDENTITY_LOOKUP_DISABLED`: Identity lookup is not enabled for this project
241
+ - `IDENTITY_DELETE_DISABLED`: Identity deletion is not enabled for this project
210
242
  - `NETWORK_ERROR`: Network request failed
211
243
  - `UNKNOWN_ERROR`: Unexpected server error
212
244
 
@@ -217,15 +249,15 @@ The SDK is fully typed. All client methods include inline JSDoc and return prope
217
249
  ```ts
218
250
  import { MiniMoth, MiniMothError } from '@minimoth/sdk-node'
219
251
 
220
- const client = new MiniMoth({ apiKey: 'mm_live_...' })
252
+ const mm = new MiniMoth({ apiKey: 'mm_live_...' })
221
253
 
222
254
  // All methods are fully typed
223
- const result = await client.otp.verify({
255
+ const result = await mm.otp.verify({
224
256
  phone: '919876543210',
225
257
  otp: '123456',
226
258
  })
227
259
 
228
- const session: Session = await client.session.validate(token)
260
+ const session: Session = await mm.session.validate(token)
229
261
  ```
230
262
 
231
263
  ## License
package/dist/index.cjs CHANGED
@@ -69,7 +69,10 @@ var BACKEND_CODE_MAP = {
69
69
  OTP_RATE_LIMITED: "OTP_RATE_LIMITED",
70
70
  VERIFY_RATE_LIMITED: "VERIFY_RATE_LIMITED",
71
71
  INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
72
- INVALID_PHONE: "INVALID_PHONE"
72
+ INVALID_PHONE: "INVALID_PHONE",
73
+ IDENTITY_NOT_FOUND: "IDENTITY_NOT_FOUND",
74
+ IDENTITY_DELETE_DISABLED: "IDENTITY_DELETE_DISABLED",
75
+ IDENTITY_LOOKUP_DISABLED: "IDENTITY_LOOKUP_DISABLED"
73
76
  };
74
77
  async function handleResponse(response) {
75
78
  if (response.ok) return response.json();
@@ -109,6 +112,35 @@ async function apiGet(path, apiKey) {
109
112
  }
110
113
  return handleResponse(response);
111
114
  }
115
+ async function apiDelete(path, apiKey) {
116
+ let response;
117
+ try {
118
+ response = await fetch(`${BASE_URL}${path}`, {
119
+ method: "DELETE",
120
+ headers: {
121
+ "X-Api-Key": apiKey,
122
+ "User-Agent": USER_AGENT
123
+ }
124
+ });
125
+ } catch (err) {
126
+ throw new MiniMothError("NETWORK_ERROR", "Network request failed", 0, err);
127
+ }
128
+ return handleResponse(response);
129
+ }
130
+
131
+ // src/phone.ts
132
+ function normalizePhone(raw) {
133
+ if (!raw || typeof raw !== "string") {
134
+ throw new MiniMothError("INVALID_PHONE", "Phone number is required", 422);
135
+ }
136
+ if (/[\s-]/.test(raw)) {
137
+ throw new MiniMothError("INVALID_PHONE", "Phone number must not contain spaces or hyphens", 422);
138
+ }
139
+ let phone = raw;
140
+ if (phone.startsWith("+")) phone = phone.slice(1);
141
+ if (phone.length === 10) phone = "91" + phone;
142
+ return phone;
143
+ }
112
144
 
113
145
  // src/otp/OtpClient.ts
114
146
  var OtpClient = class {
@@ -161,7 +193,8 @@ var OtpClient = class {
161
193
  valid: true,
162
194
  accessToken: res.access_token,
163
195
  refreshToken: res.refresh_token,
164
- sessionId: payload.session_id
196
+ sessionId: payload.session_id,
197
+ ...payload.identity_id ? { identityId: payload.identity_id } : {}
165
198
  };
166
199
  } catch (err) {
167
200
  if (err instanceof MiniMothError) {
@@ -174,18 +207,6 @@ var OtpClient = class {
174
207
  }
175
208
  }
176
209
  };
177
- function normalizePhone(raw) {
178
- if (!raw || typeof raw !== "string") {
179
- throw new MiniMothError("INVALID_PHONE", "Phone number is required", 422);
180
- }
181
- if (/[\s-]/.test(raw)) {
182
- throw new MiniMothError("INVALID_PHONE", "Phone number must not contain spaces or hyphens", 422);
183
- }
184
- let phone = raw;
185
- if (phone.startsWith("+")) phone = phone.slice(1);
186
- if (phone.length === 10) phone = "91" + phone;
187
- return phone;
188
- }
189
210
  function validateOtp(otp) {
190
211
  if (!otp || typeof otp !== "string") {
191
212
  throw new MiniMothError("INVALID_OTP", "OTP is required", 422);
@@ -268,6 +289,7 @@ var SessionClient = class {
268
289
  sessionId: payload.session_id,
269
290
  expiresAt: new Date(payload.exp * 1e3)
270
291
  };
292
+ if (payload.identity_id) session.identityId = payload.identity_id;
271
293
  if (newTokens) session.newTokens = newTokens;
272
294
  this.logger.info("session.validated", { sessionId: payload.session_id.slice(0, 8) });
273
295
  return session;
@@ -336,6 +358,37 @@ var SessionClient = class {
336
358
  }
337
359
  };
338
360
 
361
+ // src/identity/IdentityClient.ts
362
+ var IdentityClient = class {
363
+ constructor(apiKey, logger) {
364
+ this.apiKey = apiKey;
365
+ this.logger = logger;
366
+ }
367
+ apiKey;
368
+ logger;
369
+ async get(identityId) {
370
+ const res = await apiGet(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey);
371
+ return toIdentity(res);
372
+ }
373
+ async getByPhone(phone) {
374
+ const normalized = normalizePhone(phone);
375
+ const res = await apiGet(`/v1/identity?phone=${encodeURIComponent(normalized)}`, this.apiKey);
376
+ return toIdentity(res);
377
+ }
378
+ async delete(identityId) {
379
+ await apiDelete(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey);
380
+ this.logger.info("identity.deleted", { identityId: identityId.slice(0, 8) });
381
+ return { deleted: true };
382
+ }
383
+ };
384
+ function toIdentity(res) {
385
+ return {
386
+ id: res.id,
387
+ createdAt: new Date(res.created_at),
388
+ factors: res.factors
389
+ };
390
+ }
391
+
339
392
  // src/session/JwksCache.ts
340
393
  var import_crypto = __toESM(require("crypto"), 1);
341
394
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -532,6 +585,7 @@ var ConsoleLogger = class {
532
585
  var MiniMoth = class {
533
586
  otp;
534
587
  session;
588
+ identity;
535
589
  consoleLogger;
536
590
  constructor(config) {
537
591
  this.consoleLogger = new ConsoleLogger(config.logLevel ?? "info");
@@ -550,6 +604,7 @@ var MiniMoth = class {
550
604
  store,
551
605
  logger
552
606
  );
607
+ this.identity = new IdentityClient(config.apiKey, logger);
553
608
  }
554
609
  // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.
555
610
  setLogLevel(level) {
@@ -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, 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 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"]}
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/phone.ts","../src/session/SessionClient.ts","../src/identity/IdentityClient.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, Identity, IdentityFactor } 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 { normalizePhone } from '../phone'\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; identityId?: 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 ...(payload.identity_id ? { identityId: payload.identity_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\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 | 'IDENTITY_NOT_FOUND'\n | 'IDENTITY_DELETE_DISABLED'\n | 'IDENTITY_LOOKUP_DISABLED'\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 IDENTITY_NOT_FOUND: 'IDENTITY_NOT_FOUND',\n IDENTITY_DELETE_DISABLED: 'IDENTITY_DELETE_DISABLED',\n IDENTITY_LOOKUP_DISABLED: 'IDENTITY_LOOKUP_DISABLED',\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\nexport async function apiDelete<T>(path: string, apiKey: string): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'DELETE',\n headers: {\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import { MiniMothError } from './MiniMothError'\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nexport function 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","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 projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (payload.identity_id) session.identityId = payload.identity_id\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 { apiGet, apiDelete } from '../http'\nimport { normalizePhone } from '../phone'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Identity, IdentityFactor } from '../types'\n\ntype IdentityResponse = {\n id: string\n created_at: string\n factors: IdentityFactor[]\n}\n\nexport class IdentityClient {\n constructor(\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async get(identityId: string): Promise<Identity> {\n const res = await apiGet<IdentityResponse>(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey)\n return toIdentity(res)\n }\n\n async getByPhone(phone: string): Promise<Identity> {\n const normalized = normalizePhone(phone)\n const res = await apiGet<IdentityResponse>(`/v1/identity?phone=${encodeURIComponent(normalized)}`, this.apiKey)\n return toIdentity(res)\n }\n\n async delete(identityId: string): Promise<{ deleted: true }> {\n await apiDelete<{ deleted: boolean }>(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey)\n this.logger.info('identity.deleted', { identityId: identityId.slice(0, 8) })\n return { deleted: true }\n }\n}\n\nfunction toIdentity(res: IdentityResponse): Identity {\n return {\n id: res.id,\n createdAt: new Date(res.created_at),\n factors: res.factors,\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 { IdentityClient } from './identity/IdentityClient'\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 readonly identity: IdentityClient\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 this.identity = new IdentityClient(config.apiKey, logger)\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKA,IAAM,mBAAmB,MACvB,OAAO,aAAa,cAChB,IAAI,IAAI,QAAQ,UAAU,EAAE,EAAE,OAC7B,SAAS,iBAAiB,SAAS,cAAc,QAAQ,YAAY,MAAM,WAC1E,SAAS,cAAc,MACvB,IAAI,IAAI,WAAW,SAAS,OAAO,EAAE;AAEtC,IAAM,gBAAgC,iCAAiB;;;ACZ9D,0BAAgB;;;ACeT,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAC9B;AAAA,EACA;AAAA,EAET,YAAY,MAAyB,SAAiB,YAAoB,OAAiB;AACzF,UAAM,SAAS,UAAU,SAAY,EAAE,MAAM,IAAI,MAAS;AAC1D,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,aAAa;AAElB,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;;;AC1BA,oBAA8B;AAE9B,IAAMA,eAAU,6BAAc,aAAe;AAE7C,IAAM,MAAMA,SAAQ,iBAAiB;AAErC,IAAM,WAAW;AACjB,IAAM,aAAa,qBAAqB,IAAI,OAAO;AAEnD,IAAM,mBAAsD;AAAA,EAC1D,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,0BAA0B;AAC5B;AAEA,eAAe,eAAkB,UAAgC;AAC/D,MAAI,SAAS,GAAI,QAAO,SAAS,KAAK;AAEtC,MAAI,OAA0C,CAAC;AAC/C,MAAI;AAAE,WAAO,MAAM,SAAS,KAAK;AAAA,EAAuC,QAAQ;AAAA,EAAC;AAEjF,QAAM,UAA6B,iBAAiB,KAAK,QAAQ,EAAE,KAAK;AACxE,QAAM,IAAI,cAAc,SAAS,KAAK,SAAS,iBAAiB,SAAS,MAAM;AACjF;AAEA,eAAsB,QACpB,MACA,QACA,MACY;AACZ,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI;AAAA,MAC3C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,aAAa;AAAA,QACb,cAAc;AAAA,MAChB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,IAAI,cAAc,iBAAiB,0BAA0B,GAAG,GAAG;AAAA,EAC3E;AACA,SAAO,eAAkB,QAAQ;AACnC;AAEA,eAAsB,OAAU,MAAc,QAA6B;AACzE,QAAM,UAAkC,EAAE,cAAc,WAAW;AACnE,MAAI,OAAQ,SAAQ,WAAW,IAAI;AACnC,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI,EAAE,QAAQ,CAAC;AAAA,EAC1D,SAAS,KAAK;AACZ,UAAM,IAAI,cAAc,iBAAiB,0BAA0B,GAAG,GAAG;AAAA,EAC3E;AACA,SAAO,eAAkB,QAAQ;AACnC;AAEA,eAAsB,UAAa,MAAc,QAA4B;AAC3E,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI;AAAA,MAC3C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,aAAa;AAAA,QACb,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,IAAI,cAAc,iBAAiB,0BAA0B,GAAG,GAAG;AAAA,EAC3E;AACA,SAAO,eAAkB,QAAQ;AACnC;;;AC9EO,SAAS,eAAe,KAAqB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,cAAc,iBAAiB,4BAA4B,GAAG;AAAA,EAC1E;AACA,MAAI,QAAQ,KAAK,GAAG,GAAG;AACrB,UAAM,IAAI,cAAc,iBAAiB,mDAAmD,GAAG;AAAA,EACjG;AACA,MAAI,QAAQ;AACZ,MAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAEhD,MAAI,MAAM,WAAW,GAAI,SAAQ,OAAO;AACxC,SAAO;AACT;;;AHGO,IAAM,YAAN,MAAgB;AAAA,EACrB,YACmB,QACA,OACA,QACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,MAAM,KAAK,QAAuD;AAChE,UAAM,QAAQ,eAAe,OAAO,KAAK;AACzC,UAAM,MAAM,MAAM,QAA6C,gBAAgB,KAAK,QAAQ,EAAE,MAAM,CAAC;AACrG,SAAK,OAAO,KAAK,YAAY,EAAE,OAAO,UAAU,KAAK,EAAE,CAAC;AACxD,WAAO,EAAE,OAAO,IAAI,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAM,OAAO,OAAmC;AAC9C,UAAM,MAAM,MAAM,OAKf,kBAAkB,mBAAmB,KAAK,CAAC,IAAI,KAAK,MAAM;AAC7D,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,MACX,SAAS,IAAI;AAAA,MACb,QAAQ,IAAI;AAAA,MACZ,aAAa,IAAI;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,QAA+D;AAC1E,UAAM,QAAQ,eAAe,OAAO,KAAK;AACzC,gBAAY,OAAO,GAAG;AAEtB,QAAI;AACF,YAAM,MAAM,MAAM;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL,EAAE,OAAO,MAAM,OAAO,IAAI;AAAA,MAC5B;AAEA,YAAM,UAAU,oBAAAC,QAAI,OAAO,IAAI,YAAY;AAC3C,UAAI,CAAC,SAAS,YAAY;AACxB,cAAM,IAAI,cAAc,wBAAwB,iDAAiD,CAAC;AAAA,MACpG;AAEA,UAAI;AACF,cAAM,KAAK,MAAM,UAAU,QAAQ,YAAY;AAAA,UAC7C,aAAa,IAAI;AAAA,UACjB,cAAc,IAAI;AAAA,QACpB,CAAC;AAAA,MACH,QAAQ;AACN,aAAK,OAAO,MAAM,8BAA8B,EAAE,WAAW,QAAQ,WAAW,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,MAC/F;AAEA,WAAK,OAAO,KAAK,gBAAgB,EAAE,WAAW,QAAQ,WAAW,MAAM,GAAG,CAAC,EAAE,CAAC;AAE9E,aAAO;AAAA,QACL,OAAO;AAAA,QACP,aAAa,IAAI;AAAA,QACjB,cAAc,IAAI;AAAA,QAClB,WAAW,QAAQ;AAAA,QACnB,GAAI,QAAQ,cAAc,EAAE,YAAY,QAAQ,YAAY,IAAI,CAAC;AAAA,MACnE;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,eAAe;AAChC,YACE,IAAI,SAAS,iBACb,IAAI,SAAS,mBACb,IAAI,SAAS,mBACb,IAAI,SAAS,uBACb;AACA,eAAK,OAAO,MAAM,qBAAqB,EAAE,MAAM,IAAI,KAAK,CAAC;AACzD,iBAAO,EAAE,OAAO,OAAO,MAAM,IAAI,KAAK;AAAA,QACxC;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,YAAY,KAAmB;AACtC,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,cAAc,eAAe,mBAAmB,GAAG;AAAA,EAC/D;AACF;AAEO,SAAS,UAAU,OAAuB;AAC/C,MAAI,MAAM,UAAU,EAAG,QAAO;AAC9B,SAAO,MAAM,MAAM,GAAG,CAAC,IAAI,IAAI,OAAO,KAAK,IAAI,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,MAAM,MAAM,EAAE;AACvF;;;AI5GA,IAAAC,uBAAgB;AAgBT,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACmB,QACA,WACA,iBACA,cACA,OACA,QACjB;AANiB;AACA;AACA;AACA;AACA;AACA;AAAA,EAChB;AAAA,EANgB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,MAAM,SAAS,aAAuC;AACpD,UAAM,UAAU,qBAAAC,QAAI,OAAO,aAAa,EAAE,UAAU,KAAK,CAAC;AAC1D,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,YAAM,IAAI,cAAc,wBAAwB,sBAAsB,GAAG;AAAA,IAC3E;AAEA,UAAM,MAAO,QAAQ,OAA6C,KAAK;AACvE,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,wBAAwB,+BAA+B,GAAG;AAE5F,UAAM,YAAY,MAAM,KAAK,UAAU,OAAO,GAAG;AAEjD,QAAI,eAAe;AACnB,QAAI;AAEJ,QAAI;AACF,2BAAAA,QAAI,OAAO,aAAa,WAAW,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC;AAAA,IAC9D,SAAS,KAAK;AACZ,UAAI,eAAe,qBAAAA,QAAI,mBAAmB;AACxC,cAAM,iBAAiB,QAAQ;AAC/B,cAAM,YAAY,gBAAgB;AAClC,YAAI,CAAC,UAAW,OAAM,IAAI,cAAc,wBAAwB,oBAAoB,GAAG;AAEvF,oBAAY,MAAM,KAAK,aAAa,SAAS,WAAW,YAAY;AAClE,gBAAM,eAAe,MAAM,KAAK,MAAM,gBAAgB,SAAS;AAC/D,cAAI,CAAC,cAAc;AACjB,kBAAM,IAAI,cAAc,wBAAwB,uDAAuD,GAAG;AAAA,UAC5G;AAEA,eAAK,OAAO,KAAK,wBAAwB,EAAE,WAAW,UAAU,MAAM,GAAG,CAAC,EAAE,CAAC;AAC7E,gBAAM,MAAM,MAAM;AAAA,YAChB;AAAA,YACA,KAAK;AAAA,YACL,EAAE,eAAe,aAAa;AAAA,UAChC;AAEA,cAAI;AACF,kBAAM,KAAK,MAAM,UAAU,WAAW;AAAA,cACpC,aAAa,IAAI;AAAA,cACjB,cAAc,IAAI;AAAA,YACpB,CAAC;AAAA,UACH,SAASC,MAAK;AACZ,iBAAK,OAAO,MAAM,kCAAkC,EAAE,WAAW,UAAU,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,UAC1F;AAEA,iBAAO,EAAE,aAAa,IAAI,cAAc,cAAc,IAAI,cAAc;AAAA,QAC1E,CAAC;AAED,uBAAe,UAAU;AAGzB,cAAM,aAAa,qBAAAD,QAAI,OAAO,cAAc,EAAE,UAAU,KAAK,CAAC;AAC9D,cAAM,SAAU,YAAY,SAAgD,KAAK;AACjF,cAAM,SAAS,SAAS,MAAM,KAAK,UAAU,OAAO,MAAM,IAAI;AAC9D,6BAAAA,QAAI,OAAO,cAAc,QAAQ,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC;AAAA,MAC5D,OAAO;AACL,cAAM,IAAI,cAAc,wBAAwB,8BAA8B,GAAG;AAAA,MACnF;AAAA,IACF;AAEA,UAAM,UAAU,qBAAAA,QAAI,OAAO,YAAY;AACvC,UAAM,UAAU,MAAM,KAAK,gBAAgB,MAAM,QAAQ,KAAK,YAAY;AAC1E,QAAI,CAAC,QAAS,OAAM,IAAI,cAAc,mBAAmB,4BAA4B,GAAG;AAExF,UAAM,UAAmB;AAAA,MACvB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,IAAI,KAAK,QAAQ,MAAM,GAAI;AAAA,IACxC;AACA,QAAI,QAAQ,YAAa,SAAQ,aAAa,QAAQ;AACtD,QAAI,UAAW,SAAQ,YAAY;AAEnC,SAAK,OAAO,KAAK,qBAAqB,EAAE,WAAW,QAAQ,WAAW,MAAM,GAAG,CAAC,EAAE,CAAC;AACnF,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,aAAkD;AACnE,QAAI;AACF,YAAM,UAAU,MAAM,KAAK,SAAS,WAAW;AAC/C,aAAO,EAAE,OAAO,MAAM,QAAQ;AAAA,IAChC,SAAS,KAAK;AACZ,UAAI,eAAe,cAAe,QAAO,EAAE,OAAO,OAAO,MAAM,IAAI,KAAK;AACxE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,cAAuC;AACnD,UAAM,MAAM,MAAM;AAAA,MAChB;AAAA,MACA,KAAK;AAAA,MACL,EAAE,eAAe,aAAa;AAAA,IAChC;AAGA,UAAM,UAAU,qBAAAA,QAAI,OAAO,IAAI,YAAY;AAC3C,QAAI,SAAS,YAAY;AACvB,UAAI;AACF,cAAM,KAAK,MAAM,UAAU,QAAQ,YAAY;AAAA,UAC7C,aAAa,IAAI;AAAA,UACjB,cAAc,IAAI;AAAA,QACpB,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,aAAK,OAAO,MAAM,kCAAkC,EAAE,WAAW,QAAQ,WAAW,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,MACnG;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,mBAAmB;AACpC,WAAO,EAAE,aAAa,IAAI,cAAc,cAAc,IAAI,cAAc;AAAA,EAC1E;AAAA,EAEA,MAAM,OAAO,QAAsE;AACjF,UAAM,UAAU,qBAAAA,QAAI,OAAO,OAAO,WAAW;AAC7C,UAAM,YAAY,SAAS,cAAc;AAEzC,QAAI,CAAC,UAAW,OAAM,IAAI,cAAc,wBAAwB,uBAAuB,GAAG;AAE1F,QAAI,qBAAqB,OAAO;AAGhC,QAAI,WAAW,QAAQ,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,GAAG;AAC1D,YAAM,YAAY,MAAM,KAAK,aAAa,SAAS,WAAW,YAAY;AACxE,cAAM,MAAM,MAAM;AAAA,UAChB;AAAA,UACA,KAAK;AAAA,UACL,EAAE,eAAe,OAAO,aAAa;AAAA,QACvC;AACA,eAAO,EAAE,aAAa,IAAI,cAAc,cAAc,IAAI,cAAc;AAAA,MAC1E,CAAC;AACD,2BAAqB,UAAU;AAC/B,UAAI;AACF,cAAM,KAAK,MAAM,UAAU,WAAW,SAAS;AAAA,MACjD,SAAS,KAAK;AACZ,aAAK,OAAO,MAAM,kCAAkC,EAAE,WAAW,UAAU,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,MAC1F;AAAA,IACF;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,KAAK;AAAA,MACL,EAAE,cAAc,mBAAmB;AAAA,IACrC;AAEA,QAAI;AACF,YAAM,KAAK,MAAM,cAAc,SAAS;AAAA,IAC1C,SAAS,KAAK;AACZ,WAAK,OAAO,MAAM,sCAAsC,EAAE,WAAW,UAAU,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,IAC9F;AACA,SAAK,OAAO,KAAK,sBAAsB,EAAE,WAAW,UAAU,MAAM,GAAG,CAAC,EAAE,CAAC;AAAA,EAC7E;AACF;;;ACnKO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YACmB,QACA,QACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,MAAM,IAAI,YAAuC;AAC/C,UAAM,MAAM,MAAM,OAAyB,gBAAgB,mBAAmB,UAAU,CAAC,IAAI,KAAK,MAAM;AACxG,WAAO,WAAW,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,WAAW,OAAkC;AACjD,UAAM,aAAa,eAAe,KAAK;AACvC,UAAM,MAAM,MAAM,OAAyB,sBAAsB,mBAAmB,UAAU,CAAC,IAAI,KAAK,MAAM;AAC9G,WAAO,WAAW,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,OAAO,YAAgD;AAC3D,UAAM,UAAgC,gBAAgB,mBAAmB,UAAU,CAAC,IAAI,KAAK,MAAM;AACnG,SAAK,OAAO,KAAK,oBAAoB,EAAE,YAAY,WAAW,MAAM,GAAG,CAAC,EAAE,CAAC;AAC3E,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACF;AAEA,SAAS,WAAW,KAAiC;AACnD,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,IAClC,SAAS,IAAI;AAAA,EACf;AACF;;;ACzCA,oBAAmB;AAKnB,IAAM,eAAe,KAAK,KAAK;AAIxB,IAAM,YAAN,MAAgB;AAAA,EAKrB,YAA6B,QAAwB;AAAxB;AAAA,EAAyB;AAAA,EAAzB;AAAA,EAJrB,SAAS,oBAAI,IAA8B;AAAA,EAC3C,YAAY;AAAA,EACZ,WAAiC;AAAA,EAIzC,MAAM,OAAO,KAAwC;AACnD,QAAI,KAAK,OAAO,SAAS,KAAK,KAAK,IAAI,IAAI,KAAK,YAAY,cAAc;AACxE,YAAM,KAAK,MAAM;AAAA,IACnB;AAEA,QAAI,MAAM,KAAK,OAAO,IAAI,GAAG;AAC7B,QAAI,CAAC,KAAK;AACR,WAAK,OAAO,MAAM,oBAAoB,EAAE,IAAI,CAAC;AAC7C,YAAM,KAAK,MAAM;AACjB,YAAM,KAAK,OAAO,IAAI,GAAG;AAAA,IAC3B;AAEA,QAAI,CAAC,IAAK,OAAM,IAAI,cAAc,wBAAwB,gCAAgC,GAAG,IAAI,GAAG;AACpG,WAAO;AAAA,EACT;AAAA,EAEQ,QAAuB;AAC7B,QAAI,KAAK,SAAU,QAAO,KAAK;AAC/B,SAAK,WAAW,KAAK,QAAQ,EAAE,QAAQ,MAAM;AAAE,WAAK,WAAW;AAAA,IAAK,CAAC;AACrE,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,UAAyB;AACrC,SAAK,OAAO,MAAM,YAAY;AAC9B,UAAM,OAAO,MAAM,OAA6B,wBAAwB;AACxE,UAAM,SAAS,oBAAI,IAA8B;AACjD,eAAW,OAAO,KAAK,MAAM;AAC3B,UAAI,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM,OAAO;AACtC,cAAM,MAAM,cAAAE,QAAO,gBAAgB,EAAE,KAAK,KAAqC,QAAQ,MAAM,CAAC;AAC9F,eAAO,IAAI,IAAI,KAAK,GAAG,GAAG;AAAA,MAC5B;AAAA,IACF;AACA,SAAK,SAAS;AACd,SAAK,YAAY,KAAK,IAAI;AAC1B,SAAK,OAAO,MAAM,gBAAgB,EAAE,UAAU,OAAO,KAAK,CAAC;AAAA,EAC7D;AACF;;;AChDA,IAAM,cAAqD;AAAA,EACzD,YAAY;AAAA,EACZ,YAAY;AACd;AAEA,IAAM,kBAAkB,IAAI,KAAK;AACjC,IAAM,oBAAoB,IAAI,KAAK;AAI5B,IAAM,kBAAN,MAAsB;AAAA,EAI3B,YACmB,MACA,QACA,QACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EANF,QAAQ,oBAAI,IAAmB;AAAA,EACxC,gBAAgB;AAAA,EAQxB,MAAM,MAAM,KAAa,aAAuC;AAC9D,QAAI,KAAK,SAAS,UAAW,QAAO;AAEpC,QAAI,KAAK,SAAS,SAAU,MAAK,aAAa;AAE9C,UAAM,MAAM,YAAY,KAAK,IAAI,KAAK;AACtC,QAAI,MAAM,GAAG;AACX,YAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,UAAI,SAAS,KAAK,IAAI,IAAI,MAAM,YAAY,KAAK;AAC/C,aAAK,OAAO,MAAM,wBAAwB,EAAE,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;AAClE,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,KAAK;AAAA,QACL,EAAE,cAAc,YAAY;AAAA,MAC9B;AAEA,UAAI,OAAO,SAAS,MAAM,GAAG;AAC3B,aAAK,MAAM,IAAI,KAAK,EAAE,WAAW,KAAK,IAAI,EAAE,CAAC;AAAA,MAC/C;AAEA,aAAO,OAAO;AAAA,IAChB,SAAS,KAAK;AACZ,UAAI,KAAK,SAAS,SAAU,OAAM;AAGlC,WAAK,OAAO,KAAK,gCAAgC;AAAA,QAC/C,KAAK,IAAI,MAAM,GAAG,CAAC;AAAA,QACnB,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,MAC9C,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,eAAqB;AAC3B,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,MAAM,KAAK,gBAAgB,kBAAmB;AAClD,SAAK,gBAAgB;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,OAAO;AACrC,UAAI,MAAM,MAAM,YAAY,iBAAiB;AAC3C,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;ACpEO,IAAM,sBAAN,MAA0B;AAAA,EAG/B,YAA6B,QAAwB;AAAxB;AAAA,EAAyB;AAAA,EAAzB;AAAA,EAFZ,WAAW,oBAAI,IAA8B;AAAA,EAI9D,SAAY,WAAmB,IAAkC;AAC/D,UAAM,WAAW,KAAK,SAAS,IAAI,SAAS;AAC5C,QAAI,UAAU;AACZ,WAAK,OAAO,MAAM,qBAAqB,EAAE,KAAK,UAAU,CAAC;AACzD,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,GAAG,EAAE,QAAQ,MAAM;AACjC,WAAK,SAAS,OAAO,SAAS;AAAA,IAChC,CAAC;AAED,SAAK,SAAS,IAAI,WAAW,OAAO;AACpC,WAAO;AAAA,EACT;AACF;;;AClBO,IAAM,sBAAN,MAA0D;AAAA,EAI/D,YAA6B,QAAwB;AAAxB;AAAA,EAAyB;AAAA,EAAzB;AAAA,EAHZ,MAAM,oBAAI,IAAmB;AAAA,EACtC,mBAAmB;AAAA,EAInB,YAAkB;AACxB,QAAI,QAAQ,IAAI,UAAU,MAAM,gBAAgB,CAAC,KAAK,kBAAkB;AACtE,WAAK,mBAAmB;AACxB,WAAK,OAAO,KAAK,yFAAoF;AAAA,IACvG;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,WAA2C;AAC/D,SAAK,UAAU;AACf,WAAO,KAAK,IAAI,IAAI,SAAS,GAAG,gBAAgB;AAAA,EAClD;AAAA,EAEA,MAAM,UAAU,WAAmB,QAAsE;AACvG,SAAK,UAAU;AACf,SAAK,IAAI,IAAI,WAAW,MAAM;AAAA,EAChC;AAAA,EAEA,MAAM,cAAc,WAAkC;AACpD,SAAK,IAAI,OAAO,SAAS;AAAA,EAC3B;AACF;;;AC3BA,IAAM,cAAwC;AAAA,EAC5C,OAAO;AAAA,EAAG,MAAM;AAAA,EAAG,MAAM;AAAA,EAAG,OAAO;AAAA,EAAG,QAAQ;AAChD;AAEO,IAAM,gBAAN,MAA8C;AAAA,EAC3C;AAAA,EAER,YAAY,QAAkB,QAAQ;AACpC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,SAAS,OAAuB;AAC9B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,UAAU,OAA0B;AAC1C,WAAO,YAAY,KAAK,KAAK,YAAY,KAAK,KAAK;AAAA,EACrD;AAAA,EAEQ,OAAO,KAAa,MAAwC;AAClE,QAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,EAAE,WAAW,EAAG,QAAO,cAAc,GAAG;AACrE,WAAO,cAAc,GAAG,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,KAAa,MAAsC;AACvD,QAAI,KAAK,UAAU,OAAO,EAAG,SAAQ,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,EACnE;AAAA,EAEA,KAAK,KAAa,MAAsC;AACtD,QAAI,KAAK,UAAU,MAAM,EAAG,SAAQ,KAAK,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,EACjE;AAAA,EAEA,KAAK,KAAa,MAAsC;AACtD,QAAI,KAAK,UAAU,MAAM,EAAG,SAAQ,KAAK,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,EACjE;AAAA,EAEA,MAAM,KAAa,MAAsC;AACvD,QAAI,KAAK,UAAU,OAAO,EAAG,SAAQ,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,EACnE;AACF;;;AC/BO,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA,EAEjB,YAAY,QAAwB;AAClC,SAAK,gBAAgB,IAAI,cAAc,OAAO,YAAY,MAAM;AAChE,UAAM,SAAS,OAAO,UAAU,KAAK;AAErC,UAAM,QAAQ,OAAO,SAAS,SAAS,IAAI,oBAAoB,MAAM;AACrE,UAAM,eAAe,OAAO,SAAS,gBAAgB;AAErD,UAAM,YAAY,IAAI,UAAU,MAAM;AACtC,UAAM,kBAAkB,IAAI,gBAAgB,cAAc,OAAO,QAAQ,MAAM;AAC/E,UAAM,eAAe,IAAI,oBAAoB,MAAM;AAEnD,SAAK,MAAM,IAAI,UAAU,OAAO,QAAQ,OAAO,MAAM;AACrD,SAAK,UAAU,IAAI;AAAA,MACjB,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,SAAK,WAAW,IAAI,eAAe,OAAO,QAAQ,MAAM;AAAA,EAC1D;AAAA;AAAA,EAGA,YAAY,OAAuB;AACjC,SAAK,cAAc,SAAS,KAAK;AAAA,EACnC;AACF;","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 = 'INVALID_ACCESS_TOKEN' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'OTP_NOT_FOUND' | 'OTP_RATE_LIMITED' | 'VERIFY_RATE_LIMITED' | 'INSUFFICIENT_BALANCE' | 'NETWORK_ERROR' | 'INVALID_PHONE' | 'UNKNOWN_ERROR';
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' | 'IDENTITY_NOT_FOUND' | 'IDENTITY_DELETE_DISABLED' | 'IDENTITY_LOOKUP_DISABLED' | 'UNKNOWN_ERROR';
4
4
  declare class MiniMothError extends Error {
5
5
  readonly code: MiniMothErrorCode;
6
6
  readonly statusCode: number;
@@ -28,6 +28,7 @@ type VerifyResult = {
28
28
  accessToken: string;
29
29
  refreshToken: string;
30
30
  sessionId: string;
31
+ identityId?: string;
31
32
  } | {
32
33
  valid: false;
33
34
  code: MiniMothErrorCode;
@@ -80,6 +81,7 @@ type Session = {
80
81
  projectId: string;
81
82
  sessionId: string;
82
83
  expiresAt: Date;
84
+ identityId?: string;
83
85
  newTokens?: {
84
86
  accessToken: string;
85
87
  refreshToken: string;
@@ -92,6 +94,16 @@ type AccessTokenPayload = {
92
94
  jti: string;
93
95
  iat: number;
94
96
  exp: number;
97
+ identity_id?: string;
98
+ };
99
+ type IdentityFactor = {
100
+ type: string;
101
+ value: string;
102
+ };
103
+ type Identity = {
104
+ id: string;
105
+ createdAt: Date;
106
+ factors: IdentityFactor[];
95
107
  };
96
108
 
97
109
  declare class RevocationCache {
@@ -140,13 +152,25 @@ declare class SessionClient {
140
152
  }): Promise<void>;
141
153
  }
142
154
 
155
+ declare class IdentityClient {
156
+ private readonly apiKey;
157
+ private readonly logger;
158
+ constructor(apiKey: string, logger: MiniMothLogger);
159
+ get(identityId: string): Promise<Identity>;
160
+ getByPhone(phone: string): Promise<Identity>;
161
+ delete(identityId: string): Promise<{
162
+ deleted: true;
163
+ }>;
164
+ }
165
+
143
166
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
144
167
  declare class MiniMoth {
145
168
  readonly otp: OtpClient;
146
169
  readonly session: SessionClient;
170
+ readonly identity: IdentityClient;
147
171
  private readonly consoleLogger;
148
172
  constructor(config: MiniMothConfig);
149
173
  setLogLevel(level: LogLevel): void;
150
174
  }
151
175
 
152
- export { type AccessTokenPayload, MiniMoth, type MiniMothConfig, MiniMothError, type MiniMothErrorCode, type MiniMothLogger, type MiniMothSessionStore, type Session, type ValidateMode };
176
+ export { type AccessTokenPayload, type Identity, type IdentityFactor, MiniMoth, type MiniMothConfig, MiniMothError, type MiniMothErrorCode, type MiniMothLogger, type MiniMothSessionStore, type Session, type ValidateMode };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import crypto from 'crypto';
2
2
 
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';
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' | 'IDENTITY_NOT_FOUND' | 'IDENTITY_DELETE_DISABLED' | 'IDENTITY_LOOKUP_DISABLED' | 'UNKNOWN_ERROR';
4
4
  declare class MiniMothError extends Error {
5
5
  readonly code: MiniMothErrorCode;
6
6
  readonly statusCode: number;
@@ -28,6 +28,7 @@ type VerifyResult = {
28
28
  accessToken: string;
29
29
  refreshToken: string;
30
30
  sessionId: string;
31
+ identityId?: string;
31
32
  } | {
32
33
  valid: false;
33
34
  code: MiniMothErrorCode;
@@ -80,6 +81,7 @@ type Session = {
80
81
  projectId: string;
81
82
  sessionId: string;
82
83
  expiresAt: Date;
84
+ identityId?: string;
83
85
  newTokens?: {
84
86
  accessToken: string;
85
87
  refreshToken: string;
@@ -92,6 +94,16 @@ type AccessTokenPayload = {
92
94
  jti: string;
93
95
  iat: number;
94
96
  exp: number;
97
+ identity_id?: string;
98
+ };
99
+ type IdentityFactor = {
100
+ type: string;
101
+ value: string;
102
+ };
103
+ type Identity = {
104
+ id: string;
105
+ createdAt: Date;
106
+ factors: IdentityFactor[];
95
107
  };
96
108
 
97
109
  declare class RevocationCache {
@@ -140,13 +152,25 @@ declare class SessionClient {
140
152
  }): Promise<void>;
141
153
  }
142
154
 
155
+ declare class IdentityClient {
156
+ private readonly apiKey;
157
+ private readonly logger;
158
+ constructor(apiKey: string, logger: MiniMothLogger);
159
+ get(identityId: string): Promise<Identity>;
160
+ getByPhone(phone: string): Promise<Identity>;
161
+ delete(identityId: string): Promise<{
162
+ deleted: true;
163
+ }>;
164
+ }
165
+
143
166
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
144
167
  declare class MiniMoth {
145
168
  readonly otp: OtpClient;
146
169
  readonly session: SessionClient;
170
+ readonly identity: IdentityClient;
147
171
  private readonly consoleLogger;
148
172
  constructor(config: MiniMothConfig);
149
173
  setLogLevel(level: LogLevel): void;
150
174
  }
151
175
 
152
- export { type AccessTokenPayload, MiniMoth, type MiniMothConfig, MiniMothError, type MiniMothErrorCode, type MiniMothLogger, type MiniMothSessionStore, type Session, type ValidateMode };
176
+ export { type AccessTokenPayload, type Identity, type IdentityFactor, MiniMoth, type MiniMothConfig, MiniMothError, type MiniMothErrorCode, type MiniMothLogger, type MiniMothSessionStore, type Session, type ValidateMode };
package/dist/index.js CHANGED
@@ -28,7 +28,10 @@ var BACKEND_CODE_MAP = {
28
28
  OTP_RATE_LIMITED: "OTP_RATE_LIMITED",
29
29
  VERIFY_RATE_LIMITED: "VERIFY_RATE_LIMITED",
30
30
  INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
31
- INVALID_PHONE: "INVALID_PHONE"
31
+ INVALID_PHONE: "INVALID_PHONE",
32
+ IDENTITY_NOT_FOUND: "IDENTITY_NOT_FOUND",
33
+ IDENTITY_DELETE_DISABLED: "IDENTITY_DELETE_DISABLED",
34
+ IDENTITY_LOOKUP_DISABLED: "IDENTITY_LOOKUP_DISABLED"
32
35
  };
33
36
  async function handleResponse(response) {
34
37
  if (response.ok) return response.json();
@@ -68,6 +71,35 @@ async function apiGet(path, apiKey) {
68
71
  }
69
72
  return handleResponse(response);
70
73
  }
74
+ async function apiDelete(path, apiKey) {
75
+ let response;
76
+ try {
77
+ response = await fetch(`${BASE_URL}${path}`, {
78
+ method: "DELETE",
79
+ headers: {
80
+ "X-Api-Key": apiKey,
81
+ "User-Agent": USER_AGENT
82
+ }
83
+ });
84
+ } catch (err) {
85
+ throw new MiniMothError("NETWORK_ERROR", "Network request failed", 0, err);
86
+ }
87
+ return handleResponse(response);
88
+ }
89
+
90
+ // src/phone.ts
91
+ function normalizePhone(raw) {
92
+ if (!raw || typeof raw !== "string") {
93
+ throw new MiniMothError("INVALID_PHONE", "Phone number is required", 422);
94
+ }
95
+ if (/[\s-]/.test(raw)) {
96
+ throw new MiniMothError("INVALID_PHONE", "Phone number must not contain spaces or hyphens", 422);
97
+ }
98
+ let phone = raw;
99
+ if (phone.startsWith("+")) phone = phone.slice(1);
100
+ if (phone.length === 10) phone = "91" + phone;
101
+ return phone;
102
+ }
71
103
 
72
104
  // src/otp/OtpClient.ts
73
105
  var OtpClient = class {
@@ -120,7 +152,8 @@ var OtpClient = class {
120
152
  valid: true,
121
153
  accessToken: res.access_token,
122
154
  refreshToken: res.refresh_token,
123
- sessionId: payload.session_id
155
+ sessionId: payload.session_id,
156
+ ...payload.identity_id ? { identityId: payload.identity_id } : {}
124
157
  };
125
158
  } catch (err) {
126
159
  if (err instanceof MiniMothError) {
@@ -133,18 +166,6 @@ var OtpClient = class {
133
166
  }
134
167
  }
135
168
  };
136
- function normalizePhone(raw) {
137
- if (!raw || typeof raw !== "string") {
138
- throw new MiniMothError("INVALID_PHONE", "Phone number is required", 422);
139
- }
140
- if (/[\s-]/.test(raw)) {
141
- throw new MiniMothError("INVALID_PHONE", "Phone number must not contain spaces or hyphens", 422);
142
- }
143
- let phone = raw;
144
- if (phone.startsWith("+")) phone = phone.slice(1);
145
- if (phone.length === 10) phone = "91" + phone;
146
- return phone;
147
- }
148
169
  function validateOtp(otp) {
149
170
  if (!otp || typeof otp !== "string") {
150
171
  throw new MiniMothError("INVALID_OTP", "OTP is required", 422);
@@ -227,6 +248,7 @@ var SessionClient = class {
227
248
  sessionId: payload.session_id,
228
249
  expiresAt: new Date(payload.exp * 1e3)
229
250
  };
251
+ if (payload.identity_id) session.identityId = payload.identity_id;
230
252
  if (newTokens) session.newTokens = newTokens;
231
253
  this.logger.info("session.validated", { sessionId: payload.session_id.slice(0, 8) });
232
254
  return session;
@@ -295,6 +317,37 @@ var SessionClient = class {
295
317
  }
296
318
  };
297
319
 
320
+ // src/identity/IdentityClient.ts
321
+ var IdentityClient = class {
322
+ constructor(apiKey, logger) {
323
+ this.apiKey = apiKey;
324
+ this.logger = logger;
325
+ }
326
+ apiKey;
327
+ logger;
328
+ async get(identityId) {
329
+ const res = await apiGet(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey);
330
+ return toIdentity(res);
331
+ }
332
+ async getByPhone(phone) {
333
+ const normalized = normalizePhone(phone);
334
+ const res = await apiGet(`/v1/identity?phone=${encodeURIComponent(normalized)}`, this.apiKey);
335
+ return toIdentity(res);
336
+ }
337
+ async delete(identityId) {
338
+ await apiDelete(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey);
339
+ this.logger.info("identity.deleted", { identityId: identityId.slice(0, 8) });
340
+ return { deleted: true };
341
+ }
342
+ };
343
+ function toIdentity(res) {
344
+ return {
345
+ id: res.id,
346
+ createdAt: new Date(res.created_at),
347
+ factors: res.factors
348
+ };
349
+ }
350
+
298
351
  // src/session/JwksCache.ts
299
352
  import crypto from "crypto";
300
353
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -491,6 +544,7 @@ var ConsoleLogger = class {
491
544
  var MiniMoth = class {
492
545
  otp;
493
546
  session;
547
+ identity;
494
548
  consoleLogger;
495
549
  constructor(config) {
496
550
  this.consoleLogger = new ConsoleLogger(config.logLevel ?? "info");
@@ -509,6 +563,7 @@ var MiniMoth = class {
509
563
  store,
510
564
  logger
511
565
  );
566
+ this.identity = new IdentityClient(config.apiKey, logger);
512
567
  }
513
568
  // Only affects the built-in ConsoleLogger. Has no effect if a custom logger was provided.
514
569
  setLogLevel(level) {
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, 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 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"]}
1
+ {"version":3,"sources":["../src/otp/OtpClient.ts","../src/MiniMothError.ts","../src/http.ts","../src/phone.ts","../src/session/SessionClient.ts","../src/identity/IdentityClient.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 { normalizePhone } from '../phone'\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; identityId?: 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 ...(payload.identity_id ? { identityId: payload.identity_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\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 | 'IDENTITY_NOT_FOUND'\n | 'IDENTITY_DELETE_DISABLED'\n | 'IDENTITY_LOOKUP_DISABLED'\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 IDENTITY_NOT_FOUND: 'IDENTITY_NOT_FOUND',\n IDENTITY_DELETE_DISABLED: 'IDENTITY_DELETE_DISABLED',\n IDENTITY_LOOKUP_DISABLED: 'IDENTITY_LOOKUP_DISABLED',\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\nexport async function apiDelete<T>(path: string, apiKey: string): Promise<T> {\n let response: Response\n try {\n response = await fetch(`${BASE_URL}${path}`, {\n method: 'DELETE',\n headers: {\n 'X-Api-Key': apiKey,\n 'User-Agent': USER_AGENT,\n },\n })\n } catch (err) {\n throw new MiniMothError('NETWORK_ERROR', 'Network request failed', 0, err)\n }\n return handleResponse<T>(response)\n}\n","import { MiniMothError } from './MiniMothError'\n\n// Normalizes to 12-digit canonical Indian format (91XXXXXXXXXX).\n// Rejects if spaces or hyphens are present.\nexport function 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","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 projectId: payload.project_id,\n sessionId: payload.session_id,\n expiresAt: new Date(payload.exp * 1000),\n }\n if (payload.identity_id) session.identityId = payload.identity_id\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 { apiGet, apiDelete } from '../http'\nimport { normalizePhone } from '../phone'\nimport type { MiniMothLogger } from '../logger/MiniMothLogger'\nimport type { Identity, IdentityFactor } from '../types'\n\ntype IdentityResponse = {\n id: string\n created_at: string\n factors: IdentityFactor[]\n}\n\nexport class IdentityClient {\n constructor(\n private readonly apiKey: string,\n private readonly logger: MiniMothLogger\n ) {}\n\n async get(identityId: string): Promise<Identity> {\n const res = await apiGet<IdentityResponse>(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey)\n return toIdentity(res)\n }\n\n async getByPhone(phone: string): Promise<Identity> {\n const normalized = normalizePhone(phone)\n const res = await apiGet<IdentityResponse>(`/v1/identity?phone=${encodeURIComponent(normalized)}`, this.apiKey)\n return toIdentity(res)\n }\n\n async delete(identityId: string): Promise<{ deleted: true }> {\n await apiDelete<{ deleted: boolean }>(`/v1/identity/${encodeURIComponent(identityId)}`, this.apiKey)\n this.logger.info('identity.deleted', { identityId: identityId.slice(0, 8) })\n return { deleted: true }\n }\n}\n\nfunction toIdentity(res: IdentityResponse): Identity {\n return {\n id: res.id,\n createdAt: new Date(res.created_at),\n factors: res.factors,\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 { IdentityClient } from './identity/IdentityClient'\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 readonly identity: IdentityClient\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 this.identity = new IdentityClient(config.apiKey, logger)\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.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Official MiniMoth Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",