pinqloq 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/buffering/callback.ts","../src/logging/types.ts","../src/buffering/buffer.ts","../src/buffering/dispatcher.ts","../src/express/middleware.ts","../src/redaction/plan.ts","../src/internal/throttledWarn.ts","../src/redaction/redaction.ts","../src/express/pathMatch.ts","../src/express/captureResponseBody.ts","../src/options.ts","../src/http/ingestClient.ts","../src/logging/logger.ts","../src/client.ts"],"sourcesContent":["import type { PinqloqLogEntry, PinqloqLogError, PinqloqOnFailed, PinqloqOnSent } from \"../logging/types.js\";\n\nexport function raiseSent(onSent: PinqloqOnSent | undefined, entry: PinqloqLogEntry): void {\n if (!onSent) return;\n\n try {\n onSent(entry);\n } catch (error) {\n console.warn(\"Pinqloq: the onSent callback threw an exception; swallowed.\", error);\n }\n}\n\nexport function raiseFailed(\n onFailed: PinqloqOnFailed | undefined,\n entry: PinqloqLogEntry,\n error: PinqloqLogError\n): void {\n if (!onFailed) return;\n\n try {\n onFailed(entry, error);\n } catch (callbackError) {\n console.warn(\"Pinqloq: the onFailed callback threw an exception; swallowed.\", callbackError);\n }\n}\n","\nexport enum PinqloqLogLevel {\n Debug = 1,\n Information = 2,\n Warning = 3,\n Error = 4,\n Fatal = 5\n}\n\nexport enum PinqloqLogSourceType {\n Device = 1,\n Backend = 2\n}\n\nexport enum PinqloqLogFailureReason {\n \n Unauthorized = \"Unauthorized\",\n \n Forbidden = \"Forbidden\",\n \n MissingCollection = \"MissingCollection\",\n \n QueueFull = \"QueueFull\",\n \n HttpError = \"HttpError\",\n \n Timeout = \"Timeout\",\n \n Network = \"Network\",\n \n Unknown = \"Unknown\"\n}\n\nexport interface PinqloqLogError {\n reason: PinqloqLogFailureReason;\n statusCode?: number;\n message: string;\n cause?: unknown;\n}\n\nexport interface PinqloqLogEntry {\n logLevel?: PinqloqLogLevel;\n \n event: string;\n \n date?: Date;\n \n appVersionName?: string;\n \n deviceIdentifier?: string;\n logSourceType?: PinqloqLogSourceType;\n \n collectionName?: string;\n \n correlationId?: string;\n path?: string;\n metadata?: Record<string, string>;\n detail?: Record<string, string>;\n}\n\nexport type PinqloqOnSent = (entry: PinqloqLogEntry) => void;\nexport type PinqloqOnFailed = (entry: PinqloqLogEntry, error: PinqloqLogError) => void;\n\nexport interface PinqloqLogger {\n\n enqueue(entry: PinqloqLogEntry, onSent?: PinqloqOnSent, onFailed?: PinqloqOnFailed): boolean;\n\n enqueueMany(\n entries: readonly PinqloqLogEntry[],\n onSent?: PinqloqOnSent,\n onFailed?: PinqloqOnFailed\n ): number;\n}\n","import { raiseFailed } from \"./callback.js\";\nimport { PinqloqLogFailureReason } from \"../logging/types.js\";\nimport type { PinqloqLogEntry, PinqloqOnFailed, PinqloqOnSent } from \"../logging/types.js\";\n\nexport interface QueuedLog {\n entry: PinqloqLogEntry;\n onSent?: PinqloqOnSent;\n onFailed?: PinqloqOnFailed;\n}\n\nexport class PinqloqLogBuffer {\n private readonly queue: QueuedLog[] = [];\n private droppedCount = 0;\n private completed = false;\n\n constructor(private readonly capacity: number) {}\n\n get size(): number {\n return this.queue.length;\n }\n\n enqueue(entry: PinqloqLogEntry, onSent?: PinqloqOnSent, onFailed?: PinqloqOnFailed): boolean {\n if (this.completed) throw new Error(\"Pinqloq: the log queue is closed.\");\n if (!entry) return false;\n\n entry.date ??= new Date();\n\n if (this.queue.length >= this.capacity) {\n this.droppedCount++;\n if (this.droppedCount === 1 || this.droppedCount % 1000 === 0) {\n console.warn(`Pinqloq: log queue is full; ${this.droppedCount} logs dropped so far.`);\n }\n\n raiseFailed(onFailed, entry, {\n reason: PinqloqLogFailureReason.QueueFull,\n message: \"Log queue is full; the log was dropped. Increase queueCapacity or lower flushIntervalMs.\"\n });\n\n return false;\n }\n\n this.queue.push({ entry, onSent, onFailed });\n return true;\n }\n\n enqueueMany(entries: readonly PinqloqLogEntry[], onSent?: PinqloqOnSent, onFailed?: PinqloqOnFailed): number {\n if (!entries) return 0;\n\n let queuedCount = 0;\n for (const entry of entries) {\n if (this.enqueue(entry, onSent, onFailed)) queuedCount++;\n }\n\n return queuedCount;\n }\n\n complete(): void {\n this.completed = true;\n }\n\n drain(max: number): QueuedLog[] {\n return this.queue.splice(0, max);\n }\n}\n","import type { PinqloqLogBuffer } from \"./buffer.js\";\nimport type { PinqloqIngestApiClient } from \"../http/ingestClient.js\";\nimport type { ResolvedPinqloqOptions } from \"../options.js\";\n\nexport class PinqloqLogDispatcher {\n private timer?: ReturnType<typeof setTimeout>;\n private pendingSend?: Promise<void>;\n private stopping = false;\n\n constructor(\n private readonly buffer: PinqloqLogBuffer,\n private readonly apiClient: PinqloqIngestApiClient,\n private readonly options: ResolvedPinqloqOptions\n ) {}\n\n start(): void {\n this.notifyEnqueued();\n }\n\n notifyEnqueued(): void {\n if (this.stopping || this.pendingSend || this.buffer.size === 0) return;\n if (this.buffer.size >= this.options.batchSize) {\n void this.flush();\n return;\n }\n if (this.timer) return;\n this.timer = setTimeout(() => void this.flush(), this.options.flushIntervalMs);\n this.timer.unref?.();\n }\n\n flush(): Promise<void> {\n if (this.pendingSend) return this.pendingSend;\n this.clearTimer();\n if (this.buffer.size === 0) return Promise.resolve();\n this.pendingSend = this.sendBatches().finally(() => {\n this.pendingSend = undefined;\n this.notifyEnqueued();\n });\n return this.pendingSend;\n }\n\n private async sendBatches(): Promise<void> {\n do {\n const batch = this.buffer.drain(this.options.batchSize);\n try {\n await this.apiClient.sendBatch(batch);\n } catch (error) {\n console.warn(`Pinqloq: batch of ${batch.length} logs could not be sent; dropped.`, error);\n }\n } while (this.buffer.size > 0 && (this.stopping || this.buffer.size >= this.options.batchSize));\n }\n\n private clearTimer(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = undefined;\n }\n\n async shutdown(): Promise<void> {\n this.stopping = true;\n this.buffer.complete();\n this.clearTimer();\n await this.flush();\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { NextFunction, Request, RequestHandler, Response } from \"express\";\nimport type { PinqloqLogger } from \"../logging/types.js\";\nimport { PinqloqLogLevel, PinqloqLogSourceType } from \"../logging/types.js\";\nimport type { ResolvedPinqloqOptions } from \"../options.js\";\nimport { applyBodyRedaction, PinqloqRedactionPlan, serializeHeaders } from \"../redaction/redaction.js\";\nimport { matchesAnyPathPrefix } from \"./pathMatch.js\";\nimport { captureResponseBody } from \"./captureResponseBody.js\";\nimport type { PinqloqRequestLoggingOptions } from \"./options.js\";\nimport { warnThrottled } from \"../internal/throttledWarn.js\";\n\nconst MAX_BODY_CHARACTERS = 32 * 1024;\nconst MAX_BODY_BYTES = 4 * MAX_BODY_CHARACTERS;\n\nconst SELECTOR_WARNING_THROTTLE_MS = 60_000;\n\nexport const DEVICE_IDENTIFIER_HEADER_NAME = \"device-identifier\";\n\nexport const CORRELATION_ID_HEADER_NAME = \"correlation-id\";\n\nconst DEVICE_IDENTIFIER_REQUIRED_MESSAGE =\n \"Pinqloq: the required deviceIdentifier could not be resolved. Send the 'device-identifier' request header, \" +\n \"or configure resolveDeviceIdentifier, or set PinqloqOptions.deviceIdentifier.\";\n\nconst SERVER_ERROR_STATUS_THRESHOLD = 500;\nconst CLIENT_ERROR_STATUS_THRESHOLD = 400;\n\nfunction resolveLogLevel(statusCode: number): PinqloqLogLevel {\n if (statusCode >= SERVER_ERROR_STATUS_THRESHOLD) return PinqloqLogLevel.Error;\n if (statusCode >= CLIENT_ERROR_STATUS_THRESHOLD) return PinqloqLogLevel.Warning;\n return PinqloqLogLevel.Information;\n}\n\nfunction truncate(value: string): string {\n return value.length <= MAX_BODY_CHARACTERS ? value : value.slice(0, MAX_BODY_CHARACTERS);\n}\n\nfunction resolveSelector(\n selector: ((req: Request) => string | undefined) | undefined,\n req: Request,\n throttleKey: string\n): string {\n if (!selector) return \"\";\n\n try {\n return selector(req) ?? \"\";\n } catch (error) {\n warnThrottled(throttleKey, SELECTOR_WARNING_THROTTLE_MS, `Pinqloq: ${throttleKey} threw an exception; ignored.`, error);\n return \"\";\n }\n}\n\nfunction resolveDeviceIdentifier(\n req: Request,\n requestOptions: PinqloqRequestLoggingOptions,\n globalOptions: ResolvedPinqloqOptions\n): string {\n const overridden = resolveSelector(requestOptions.resolveDeviceIdentifier, req, \"resolveDeviceIdentifier\");\n if (overridden.trim()) return overridden;\n\n const header = req.headers[DEVICE_IDENTIFIER_HEADER_NAME];\n const headerValue = Array.isArray(header) ? header[0] : header;\n if (headerValue?.trim()) return headerValue;\n\n return globalOptions.deviceIdentifier ?? \"\";\n}\n\nfunction resolveCorrelationId(req: Request): string {\n const header = req.headers[CORRELATION_ID_HEADER_NAME];\n const headerValue = Array.isArray(header) ? header[0] : header;\n return headerValue?.trim() ? headerValue : randomUUID();\n}\n\nfunction applyEnrichers(\n target: Record<string, string>,\n enrichers: Record<string, (req: Request, res: Response) => string | undefined> | undefined,\n req: Request,\n res: Response\n): void {\n if (!enrichers) return;\n\n for (const [key, selector] of Object.entries(enrichers)) {\n let value: string | undefined;\n try {\n value = selector(req, res);\n } catch (error) {\n warnThrottled(`enricher:${key}`, SELECTOR_WARNING_THROTTLE_MS, `Pinqloq: the '${key}' enricher threw an exception; ignored.`, error);\n continue;\n }\n\n if (value) target[key] = value;\n }\n}\n\nexport function createPinqloqRequestLogging(\n logger: PinqloqLogger,\n globalOptions: ResolvedPinqloqOptions,\n requestOptions: PinqloqRequestLoggingOptions = {}\n): RequestHandler {\n return function pinqloqRequestLoggingMiddleware(req: Request, res: Response, next: NextFunction): void {\n if (matchesAnyPathPrefix(req.path, requestOptions.excludePaths)) {\n next();\n return;\n }\n\n const deviceIdentifier = resolveDeviceIdentifier(req, requestOptions, globalOptions);\n if (!deviceIdentifier.trim()) {\n res.status(400).send(DEVICE_IDENTIFIER_REQUIRED_MESSAGE);\n return;\n }\n\n const startedAt = process.hrtime.bigint();\n\n const redactPlan = requestOptions.redactPaths?.length && matchesAnyPathPrefix(req.path, requestOptions.redactPaths)\n ? PinqloqRedactionPlan.ALL\n : new PinqloqRedactionPlan(false, requestOptions.redactFields ?? []);\n\n const requestHeaders = truncate(serializeHeaders(req.headers as Record<string, string | string[] | undefined>, redactPlan));\n const inputJson = truncate(\n applyBodyRedaction(req.body !== undefined ? JSON.stringify(req.body) : \"\", redactPlan)\n );\n\n const correlationId = resolveCorrelationId(req);\n const appVersionName = resolveSelector(requestOptions.resolveAppVersionName, req, \"resolveAppVersionName\");\n\n const capture = captureResponseBody(res, MAX_BODY_BYTES);\n\n res.once(\"finish\", () => {\n capture.restore();\n\n const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000;\n const statusCode = res.statusCode;\n const method = req.method;\n const path = req.path;\n\n const outputJson = truncate(applyBodyRedaction(capture.getBody(), redactPlan));\n const responseHeaders = truncate(serializeHeaders(res.getHeaders(), redactPlan));\n\n const metadata: Record<string, string> = {};\n metadata.event = `${method} ${path}`.trim();\n applyEnrichers(metadata, requestOptions.metadata, req, res);\n const resolvedEventName = metadata.event;\n delete metadata.event;\n\n metadata.method = method;\n metadata.statusCode = String(statusCode);\n metadata.durationMs = String(Math.round(elapsedMs));\n\n metadata.RequestMethod = method;\n metadata.ResponseCode = String(statusCode);\n\n const detail: Record<string, string> = {};\n applyEnrichers(detail, requestOptions.detail, req, res);\n detail.InputJson = inputJson;\n detail.OutputJson = outputJson;\n detail.RequestHeaders = requestHeaders;\n detail.ResponseHeaders = responseHeaders;\n\n const logLevel = resolveLogLevel(statusCode);\n const resolvedAppVersionName = appVersionName || undefined;\n\n logger.enqueue({\n logLevel,\n event: resolvedEventName,\n deviceIdentifier,\n appVersionName: resolvedAppVersionName,\n logSourceType: PinqloqLogSourceType.Backend,\n correlationId,\n path,\n metadata,\n detail\n });\n });\n\n next();\n };\n}\n","\n\nconst ALWAYS_REDACTED_NAMES = new Set(\n [\n \n \"authorization\",\n \"proxy-authorization\",\n \"cookie\",\n \"set-cookie\",\n \"x-api-key\",\n \"x-secret-key\",\n \"x-auth-token\",\n \"x-access-token\",\n \"x-csrf-token\",\n \"x-xsrf-token\",\n\n \"secret_key\",\n\n \"password\",\n \"newpassword\",\n \"oldpassword\",\n \"currentpassword\",\n \"passwordconfirmation\",\n \"confirmpassword\",\n \"secret\",\n \"secretkey\",\n \"clientsecret\",\n \"apikey\",\n \"accesstoken\",\n \"refreshtoken\",\n \"idtoken\",\n \"token\",\n \"otp\",\n \"otpcode\",\n \"verificationcode\",\n \"pin\",\n \"privatekey\",\n\n \"cardnumber\",\n \"cvv\",\n \"cvc\",\n \"securitycode\",\n \"iban\",\n \"ssn\"\n ].map((name) => name.toLowerCase())\n);\n\nfunction isLetterOrDigit(char: string | undefined): boolean {\n return char !== undefined && /[A-Za-z0-9]/.test(char);\n}\n\nfunction isUpper(char: string | undefined): boolean {\n return char !== undefined && char !== char.toLowerCase() && char === char.toUpperCase();\n}\n\nfunction isBoundedName(body: string, index: number, length: number): boolean {\n const endIndex = index + length;\n\n const isStartBounded =\n index === 0 || !isLetterOrDigit(body[index - 1]) || (isUpper(body[index]) && !isUpper(body[index - 1]));\n\n const isEndBounded = endIndex === body.length || !isLetterOrDigit(body[endIndex]) || isUpper(body[endIndex]);\n\n return isStartBounded && isEndBounded;\n}\n\nfunction containsWholeName(body: string, names: Iterable<string>): boolean {\n const lowerBody = body.toLowerCase();\n\n for (const name of names) {\n if (name.length === 0) continue;\n\n let searchFrom = 0;\n while (searchFrom <= lowerBody.length - name.length) {\n const index = lowerBody.indexOf(name, searchFrom);\n if (index < 0) break;\n\n if (isBoundedName(body, index, name.length)) return true;\n searchFrom = index + 1;\n }\n }\n\n return false;\n}\n\nexport class PinqloqRedactionPlan {\n static readonly NONE = new PinqloqRedactionPlan(false, []);\n static readonly ALL = new PinqloqRedactionPlan(true, []);\n\n private readonly declaredNames: Set<string>;\n\n constructor(\n public readonly redactAll: boolean,\n declaredNames: Iterable<string>\n ) {\n this.declaredNames = new Set([...declaredNames].map((name) => name.toLowerCase()));\n }\n\n get hasDeclaredRedactions(): boolean {\n return this.redactAll || this.declaredNames.size > 0;\n }\n\n shouldRedact(propertyOrHeaderName: string): boolean {\n const lower = propertyOrHeaderName.toLowerCase();\n return this.redactAll || ALWAYS_REDACTED_NAMES.has(lower) || this.declaredNames.has(lower);\n }\n\n containsDeclaredName(body: string): boolean {\n return containsWholeName(body, this.declaredNames);\n }\n\n static containsAlwaysRedactedName(body: string): boolean {\n return containsWholeName(body, ALWAYS_REDACTED_NAMES);\n }\n}\n","const nextAllowedAt = new Map<string, number>();\n\nexport function warnThrottled(key: string, intervalMs: number, message: string, ...args: unknown[]): void {\n const now = Date.now();\n const next = nextAllowedAt.get(key) ?? 0;\n if (now < next) return;\n\n nextAllowedAt.set(key, now + intervalMs);\n console.warn(message, ...args);\n}\n","import { PinqloqRedactionPlan } from \"./plan.js\";\nimport { warnThrottled } from \"../internal/throttledWarn.js\";\n\nconst REDACTED_VALUE = \"*****REDACTED*****\";\n\nconst MALFORMED_BODY_WARNING_THROTTLE_MS = 60_000;\n\nconst UNPARSEABLE_SENSITIVE_BODY_VALUE =\n \"*****REDACTED: body carries a credential field and is not parseable JSON \" +\n \"(non-JSON content type, or longer than the capture limit)*****\";\n\nfunction redactProperties(value: unknown, plan: PinqloqRedactionPlan): unknown {\n if (Array.isArray(value)) return value.map((item) => redactProperties(item, plan));\n\n if (value !== null && typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n result[key] = plan.shouldRedact(key) ? REDACTED_VALUE : redactProperties(item, plan);\n }\n return result;\n }\n\n return value;\n}\n\nfunction redactFully(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(redactFully);\n\n if (value !== null && typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) result[key] = redactFully(item);\n return result;\n }\n\n return REDACTED_VALUE;\n}\n\nfunction redactJsonProperties(body: string, plan: PinqloqRedactionPlan, isSensitive: boolean): string {\n if (!body.trim()) return body;\n\n try {\n return JSON.stringify(redactProperties(JSON.parse(body), plan));\n } catch (error) {\n warnThrottled(\n \"redactJsonProperties\",\n MALFORMED_BODY_WARNING_THROTTLE_MS,\n \"Pinqloq: a captured body could not be parsed as JSON; falling back to whole-body handling.\",\n error\n );\n return isSensitive ? UNPARSEABLE_SENSITIVE_BODY_VALUE : body;\n }\n}\n\nfunction redactJsonFully(body: string): string {\n if (!body.trim()) return body;\n\n try {\n return JSON.stringify(redactFully(JSON.parse(body)));\n } catch (error) {\n warnThrottled(\n \"redactJsonFully\",\n MALFORMED_BODY_WARNING_THROTTLE_MS,\n \"Pinqloq: a captured body under a redactAll plan could not be parsed as JSON; masking it wholesale.\",\n error\n );\n return REDACTED_VALUE;\n }\n}\n\nexport function applyBodyRedaction(body: string, plan: PinqloqRedactionPlan): string {\n if (plan.redactAll) return redactJsonFully(body);\n\n const mentionsCredential = PinqloqRedactionPlan.containsAlwaysRedactedName(body) || plan.containsDeclaredName(body);\n\n if (!plan.hasDeclaredRedactions && !mentionsCredential) return body;\n\n return redactJsonProperties(body, plan, mentionsCredential);\n}\n\nexport function serializeHeaders(\n headers: Record<string, string | string[] | number | undefined>,\n plan: PinqloqRedactionPlan\n): string {\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue;\n\n const stringValue = Array.isArray(value) ? value.join(\", \") : String(value);\n result[key] = plan.shouldRedact(key) ? REDACTED_VALUE : stringValue;\n }\n\n return JSON.stringify(result);\n}\n\nexport { PinqloqRedactionPlan } from \"./plan.js\";\n","\n\nexport function matchesAnyPathPrefix(path: string, prefixes: readonly string[] | undefined): boolean {\n if (!prefixes || prefixes.length === 0) return false;\n\n const lowerPath = path.toLowerCase();\n return prefixes.some((prefix) => matchesSegmentPrefix(lowerPath, prefix.toLowerCase()));\n}\n\nfunction matchesSegmentPrefix(lowerPath: string, prefix: string): boolean {\n const normalized = prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n const trimmed = normalized.length > 1 && normalized.endsWith(\"/\") ? normalized.slice(0, -1) : normalized;\n\n if (!lowerPath.startsWith(trimmed)) return false;\n\n return lowerPath.length === trimmed.length || lowerPath[trimmed.length] === \"/\";\n}\n","import type { Response } from \"express\";\n\nexport function captureResponseBody(res: Response, maxBytes: number): { getBody: () => string; restore: () => void } {\n const originalWrite = res.write.bind(res);\n const originalEnd = res.end.bind(res);\n\n const chunks: Buffer[] = [];\n let capturedBytes = 0;\n\n function capture(chunk: unknown): void {\n if (chunk === undefined || chunk === null || capturedBytes >= maxBytes) return;\n\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n const remaining = maxBytes - capturedBytes;\n const slice = buffer.length > remaining ? buffer.subarray(0, remaining) : buffer;\n\n chunks.push(slice);\n capturedBytes += slice.length;\n }\n\n (res.write as any) = function (this: Response, chunk: unknown, ...args: unknown[]) {\n capture(chunk);\n \n return (originalWrite as any)(chunk, ...args);\n };\n\n (res.end as any) = function (this: Response, chunk?: unknown, ...args: unknown[]) {\n if (chunk !== undefined && typeof chunk !== \"function\") capture(chunk);\n \n return (originalEnd as any)(chunk, ...args);\n };\n\n return {\n getBody: () => Buffer.concat(chunks).toString(\"utf8\"),\n restore: () => {\n res.write = originalWrite;\n res.end = originalEnd;\n }\n };\n}\n","\nexport interface PinqloqOptions {\n \n secretKey: string;\n\n apiLogsCollectionName?: string;\n\n bulkPath?: string;\n\n batchSize?: number;\n\n flushIntervalMs?: number;\n\n queueCapacity?: number;\n\n httpTimeoutMs?: number;\n\n appVersionName?: string;\n\n deviceIdentifier?: string;\n}\n\nexport interface ResolvedPinqloqOptions extends Required<Omit<PinqloqOptions, \"apiLogsCollectionName\" | \"appVersionName\" | \"deviceIdentifier\">> {\n apiLogsCollectionName?: string;\n appVersionName?: string;\n deviceIdentifier?: string;\n}\n\nexport const INGEST_BASE_ADDRESS = \"https://pinqloq-external-api.pinqponq.io\";\n\nconst DEFAULTS = {\n bulkPath: \"api/client-logs/bulk\",\n batchSize: 200,\n flushIntervalMs: 2_000,\n queueCapacity: 10_000,\n httpTimeoutMs: 10_000\n} as const;\n\nexport function resolveOptions(options: PinqloqOptions): ResolvedPinqloqOptions {\n if (!options.secretKey) {\n throw new Error(\"Pinqloq: secretKey is required.\");\n }\n\n return {\n secretKey: options.secretKey,\n apiLogsCollectionName: options.apiLogsCollectionName,\n bulkPath: options.bulkPath ?? DEFAULTS.bulkPath,\n batchSize: Math.max(1, options.batchSize ?? DEFAULTS.batchSize),\n flushIntervalMs: Math.max(1, options.flushIntervalMs ?? DEFAULTS.flushIntervalMs),\n queueCapacity: Math.max(1, options.queueCapacity ?? DEFAULTS.queueCapacity),\n httpTimeoutMs: Math.max(1, options.httpTimeoutMs ?? DEFAULTS.httpTimeoutMs),\n appVersionName: options.appVersionName,\n deviceIdentifier: options.deviceIdentifier\n };\n}\n","import { raiseFailed, raiseSent } from \"../buffering/callback.js\";\nimport type { QueuedLog } from \"../buffering/buffer.js\";\nimport { INGEST_BASE_ADDRESS, type ResolvedPinqloqOptions } from \"../options.js\";\nimport { PinqloqLogFailureReason, PinqloqLogSourceType } from \"../logging/types.js\";\nimport type { PinqloqLogEntry, PinqloqLogError } from \"../logging/types.js\";\n\nconst SECRET_KEY_HEADER = \"X-Secret-Key\";\n\nconst HTTP_WARNING_THROTTLE_MS = 60_000;\n\nconst MAX_ERROR_BODY_CHARACTERS = 512;\n\ninterface WireLogItem {\n logLevel: number;\n event: string;\n date?: string;\n appVersionName?: string;\n deviceIdentifier: string;\n logSourceType: string;\n correlationId?: string;\n path?: string;\n metadata?: Record<string, string>;\n detail?: Record<string, string>;\n}\n\nexport class PinqloqIngestApiClient {\n private nextHttpWarningAt = 0;\n\n constructor(private readonly options: ResolvedPinqloqOptions) {}\n\n async sendBatch(items: readonly QueuedLog[]): Promise<void> {\n if (items.length === 0) return;\n\n const groups = new Map<string, QueuedLog[]>();\n for (const item of items) {\n const collectionName = this.resolveCollectionName(item.entry) ?? \"\";\n const group = groups.get(collectionName);\n if (group) group.push(item);\n else groups.set(collectionName, [item]);\n }\n\n for (const [collectionName, groupItems] of groups) {\n await this.sendGroup(collectionName || undefined, groupItems);\n }\n }\n\n private async sendGroup(collectionName: string | undefined, groupItems: QueuedLog[]): Promise<void> {\n const url = `${INGEST_BASE_ADDRESS}/${this.options.bulkPath.replace(/^\\/+/, \"\")}`;\n const payload = {\n collectionName,\n logs: groupItems.map((item) => this.toWireItem(item.entry))\n };\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.options.httpTimeoutMs);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n [SECRET_KEY_HEADER]: this.options.secretKey\n },\n body: JSON.stringify(payload),\n signal: controller.signal\n });\n\n if (response.ok) {\n for (const item of groupItems) raiseSent(item.onSent, item.entry);\n return;\n }\n\n const errorBody = await this.readErrorBody(response);\n const error = this.buildHttpError(response.status, collectionName, errorBody);\n for (const item of groupItems) raiseFailed(item.onFailed, item.entry, error);\n } catch (exception) {\n const aborted = controller.signal.aborted;\n const error = this.buildExceptionError(exception, aborted);\n console.warn(\n `Pinqloq: group of ${groupItems.length} logs could not be sent (${this.formatCollectionName(collectionName)}).`,\n exception\n );\n for (const item of groupItems) raiseFailed(item.onFailed, item.entry, error);\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private buildHttpError(statusCode: number, collectionName: string | undefined, errorBody: string): PinqloqLogError {\n const reason =\n statusCode === 401\n ? PinqloqLogFailureReason.Unauthorized\n : statusCode === 403\n ? PinqloqLogFailureReason.Forbidden\n : PinqloqLogFailureReason.HttpError;\n\n let message: string;\n if (reason === PinqloqLogFailureReason.Unauthorized) {\n message = \"Unauthorized (HTTP 401): the secret key is invalid or missing.\";\n } else if (reason === PinqloqLogFailureReason.Forbidden) {\n message = `Forbidden (HTTP 403): the secret key is not authorized for the '${this.formatCollectionName(collectionName)}' collection.`;\n } else if (statusCode === 400) {\n message =\n `The server rejected the request (HTTP 400, '${this.formatCollectionName(collectionName)}'): ` +\n \"check the collectionName (required for keys allowed on multiple collections) or event fields.\";\n } else {\n message = `The server returned an error (HTTP ${statusCode}).`;\n }\n\n if (errorBody) message += ` Server response: ${errorBody}`;\n\n if (this.shouldLogHttpFailure()) {\n console.error(\n `Pinqloq: batch send rejected (HTTP ${statusCode}, collection '${this.formatCollectionName(collectionName)}'); logs in this group were dropped. ${message}`\n );\n }\n\n return { reason, statusCode, message };\n }\n\n private buildExceptionError(exception: unknown, aborted: boolean): PinqloqLogError {\n const isTimeout = aborted || (exception instanceof DOMException && exception.name === \"AbortError\");\n return isTimeout\n ? { reason: PinqloqLogFailureReason.Timeout, message: \"The request timed out.\", cause: exception }\n : {\n reason: PinqloqLogFailureReason.Network,\n message: `Network error: ${exception instanceof Error ? exception.message : String(exception)}`,\n cause: exception\n };\n }\n\n private async readErrorBody(response: Response): Promise<string> {\n try {\n const body = (await response.text()).trim();\n return body.length <= MAX_ERROR_BODY_CHARACTERS ? body : body.slice(0, MAX_ERROR_BODY_CHARACTERS);\n } catch (error) {\n console.warn(\"Pinqloq: could not read the error response body; continuing without it.\", error);\n return \"\";\n }\n }\n\n private resolveCollectionName(entry: PinqloqLogEntry): string | undefined {\n return entry.collectionName?.trim() || this.options.apiLogsCollectionName;\n }\n\n private shouldLogHttpFailure(): boolean {\n const now = Date.now();\n if (now < this.nextHttpWarningAt) return false;\n\n this.nextHttpWarningAt = now + HTTP_WARNING_THROTTLE_MS;\n return true;\n }\n\n private formatCollectionName(collectionName: string | undefined): string {\n return collectionName?.trim() ? collectionName : \"(not resolved server-side)\";\n }\n\n private toWireItem(entry: PinqloqLogEntry): WireLogItem {\n return {\n logLevel: entry.logLevel ?? 2,\n event: entry.event,\n date: entry.date?.toISOString(),\n appVersionName: entry.appVersionName?.trim() ? entry.appVersionName : this.options.appVersionName,\n deviceIdentifier: entry.deviceIdentifier?.trim() ? entry.deviceIdentifier : (this.options.deviceIdentifier ?? \"\"),\n logSourceType: PinqloqLogSourceType[entry.logSourceType ?? PinqloqLogSourceType.Backend],\n correlationId: entry.correlationId,\n path: entry.path,\n metadata: entry.metadata,\n detail: entry.detail\n };\n }\n}\n","import type { PinqloqLogBuffer } from \"../buffering/buffer.js\";\nimport type { PinqloqLogDispatcher } from \"../buffering/dispatcher.js\";\nimport type { ResolvedPinqloqOptions } from \"../options.js\";\nimport type { PinqloqLogEntry, PinqloqLogger, PinqloqOnFailed, PinqloqOnSent } from \"./types.js\";\n\nconst DEVICE_IDENTIFIER_REQUIRED_MESSAGE =\n \"Pinqloq: deviceIdentifier is required. Set it on the entry, or configure the global PinqloqOptions.deviceIdentifier fallback.\";\n\nexport class DefaultPinqloqLogger implements PinqloqLogger {\n constructor(\n private readonly buffer: PinqloqLogBuffer,\n private readonly dispatcher: PinqloqLogDispatcher,\n private readonly options: ResolvedPinqloqOptions\n ) {}\n\n enqueue(entry: PinqloqLogEntry, onSent?: PinqloqOnSent, onFailed?: PinqloqOnFailed): boolean {\n this.ensureDeviceIdentifier(entry);\n const written = this.buffer.enqueue(entry, onSent, onFailed);\n this.dispatcher.notifyEnqueued();\n return written;\n }\n\n enqueueMany(entries: readonly PinqloqLogEntry[], onSent?: PinqloqOnSent, onFailed?: PinqloqOnFailed): number {\n for (const entry of entries) this.ensureDeviceIdentifier(entry);\n const written = this.buffer.enqueueMany(entries, onSent, onFailed);\n this.dispatcher.notifyEnqueued();\n return written;\n }\n\n private ensureDeviceIdentifier(entry: PinqloqLogEntry): void {\n if (!entry.deviceIdentifier?.trim() && !this.options.deviceIdentifier?.trim()) {\n throw new Error(DEVICE_IDENTIFIER_REQUIRED_MESSAGE);\n }\n }\n}\n","import type { RequestHandler } from \"express\";\nimport { PinqloqLogBuffer } from \"./buffering/buffer.js\";\nimport { PinqloqLogDispatcher } from \"./buffering/dispatcher.js\";\nimport { createPinqloqRequestLogging } from \"./express/middleware.js\";\nimport type { PinqloqRequestLoggingOptions } from \"./express/options.js\";\nimport { PinqloqIngestApiClient } from \"./http/ingestClient.js\";\nimport { DefaultPinqloqLogger } from \"./logging/logger.js\";\nimport type { PinqloqLogger } from \"./logging/types.js\";\nimport { resolveOptions } from \"./options.js\";\nimport type { PinqloqOptions } from \"./options.js\";\n\nexport interface PinqloqClient {\n \n logger: PinqloqLogger;\n\n requestLogging(options?: PinqloqRequestLoggingOptions): RequestHandler;\n\n shutdown(): Promise<void>;\n}\n\nexport function createPinqloq(options: PinqloqOptions): PinqloqClient {\n const resolved = resolveOptions(options);\n const buffer = new PinqloqLogBuffer(resolved.queueCapacity);\n const apiClient = new PinqloqIngestApiClient(resolved);\n const dispatcher = new PinqloqLogDispatcher(buffer, apiClient, resolved);\n const logger = new DefaultPinqloqLogger(buffer, dispatcher, resolved);\n\n dispatcher.start();\n\n return {\n logger,\n requestLogging: (requestOptions?: PinqloqRequestLoggingOptions) =>\n createPinqloqRequestLogging(logger, resolved, requestOptions),\n shutdown: () => dispatcher.shutdown()\n };\n}\n"],"mappings":"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","names":["PinqloqLogLevel","PinqloqLogSourceType","PinqloqLogFailureReason","DEVICE_IDENTIFIER_REQUIRED_MESSAGE"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "pinqloq",
3
+ "version": "1.1.0",
4
+ "description": "Structured logging and log shipping SDK for Express — captures HTTP request/response logs and manual application events, and ships them to the Pinqloq log management platform.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "CHANGELOG.md"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "test": "vitest run",
28
+ "typecheck": "tsc --noEmit"
29
+ },
30
+ "peerDependencies": {
31
+ "express": "^4.18.0 || ^5.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/express": "^4.17.21",
35
+ "@types/node": "^20.14.0",
36
+ "@types/supertest": "^6.0.2",
37
+ "express": "^4.19.2",
38
+ "supertest": "^7.0.0",
39
+ "tsup": "^8.3.0",
40
+ "typescript": "^5.6.0",
41
+ "vitest": "^2.1.0"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/pinqponq/pinqloq-nodejs-sdk.git"
46
+ },
47
+ "homepage": "https://pinqloq.pinqponq.io/documentation.html",
48
+ "keywords": [
49
+ "logging",
50
+ "express",
51
+ "middleware",
52
+ "observability",
53
+ "pinqloq"
54
+ ]
55
+ }