@mappa-ai/mappa-node 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -20
- package/dist/index.d.mts +44 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["jitter"],"sources":["../src/errors.ts","../src/resources/credits.ts","../src/resources/entities.ts","../src/resources/feedback.ts","../src/resources/files.ts","../src/resources/health.ts","../src/utils/index.ts","../src/resources/jobs.ts","../src/resources/reports.ts","../src/resources/transport.ts","../src/resources/webhooks.ts","../src/Mappa.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["/**\n * Symbol for custom Node.js inspect formatting.\n * Ensures errors display nicely in console.log, REPL, and debuggers.\n */\nconst customInspect = Symbol.for(\"nodejs.util.inspect.custom\");\n\n/**\n * Formats error details for display.\n */\nfunction formatDetails(details: unknown, indent = \" \"): string {\n\tif (details === undefined || details === null) return \"\";\n\ttry {\n\t\tconst json = JSON.stringify(details, null, 2);\n\t\t// Indent each line for nested display\n\t\treturn json.split(\"\\n\").join(`\\n${indent}`);\n\t} catch {\n\t\treturn String(details);\n\t}\n}\n\n/**\n * Base error type for all SDK-raised errors.\n *\n * When available, {@link MappaError.requestId} can be used to correlate a failure\n * with server logs/support.\n */\nexport class MappaError extends Error {\n\toverride name = \"MappaError\";\n\trequestId?: string;\n\tcode?: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts?: { requestId?: string; code?: string; cause?: unknown },\n\t) {\n\t\tsuper(message);\n\t\tthis.requestId = opts?.requestId;\n\t\tthis.code = opts?.code;\n\t\tthis.cause = opts?.cause;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\t[customInspect](): string {\n\t\treturn this.toString();\n\t}\n}\n\n/**\n * Error returned when the API responds with a non-2xx status.\n */\nexport class ApiError extends MappaError {\n\toverride name = \"ApiError\";\n\tstatus: number;\n\tdetails?: unknown;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts: {\n\t\t\tstatus: number;\n\t\t\trequestId?: string;\n\t\t\tcode?: string;\n\t\t\tdetails?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message, { requestId: opts.requestId, code: opts.code });\n\t\tthis.status = opts.status;\n\t\tthis.details = opts.details;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\tif (this.details !== undefined && this.details !== null) {\n\t\t\tlines.push(` Details: ${formatDetails(this.details)}`);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error returned for HTTP 429 responses.\n *\n * If provided by the server, {@link RateLimitError.retryAfterMs} indicates when\n * it is safe to retry.\n */\nexport class RateLimitError extends ApiError {\n\toverride name = \"RateLimitError\";\n\tretryAfterMs?: number;\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tif (this.retryAfterMs !== undefined) {\n\t\t\tlines.push(` Retry After: ${this.retryAfterMs}ms`);\n\t\t}\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error returned for authentication/authorization failures (typically 401/403).\n */\nexport class AuthError extends ApiError {\n\toverride name = \"AuthError\";\n}\n\n/**\n * Error returned when the server rejects a request as invalid (typically 422).\n */\nexport class ValidationError extends ApiError {\n\toverride name = \"ValidationError\";\n}\n\n/**\n * Error returned when the account lacks sufficient credits (HTTP 402).\n *\n * Use {@link InsufficientCreditsError.required} and {@link InsufficientCreditsError.available}\n * to inform users how many credits are needed.\n *\n * @example\n * ```typescript\n * try {\n * await mappa.reports.createJob({ ... });\n * } catch (err) {\n * if (err instanceof InsufficientCreditsError) {\n * console.log(`Need ${err.required} credits, have ${err.available}`);\n * }\n * }\n * ```\n */\nexport class InsufficientCreditsError extends ApiError {\n\toverride name = \"InsufficientCreditsError\";\n\t/** Credits required for the operation */\n\trequired: number;\n\t/** Credits currently available */\n\tavailable: number;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts: {\n\t\t\tstatus: number;\n\t\t\trequestId?: string;\n\t\t\tcode?: string;\n\t\t\tdetails?: { required?: number; available?: number };\n\t\t},\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.required = opts.details?.required ?? 0;\n\t\tthis.available = opts.details?.available ?? 0;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tlines.push(` Required: ${this.required} credits`);\n\t\tlines.push(` Available: ${this.available} credits`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error thrown by polling helpers when a job reaches the \"failed\" terminal state.\n */\nexport class JobFailedError extends MappaError {\n\toverride name = \"JobFailedError\";\n\tjobId: string;\n\n\tconstructor(\n\t\tjobId: string,\n\t\tmessage: string,\n\t\topts?: { requestId?: string; code?: string; cause?: unknown },\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.jobId = jobId;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Job ID: ${this.jobId}`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error thrown by polling helpers when a job reaches the \"canceled\" terminal state.\n */\nexport class JobCanceledError extends MappaError {\n\toverride name = \"JobCanceledError\";\n\tjobId: string;\n\n\tconstructor(\n\t\tjobId: string,\n\t\tmessage: string,\n\t\topts?: { requestId?: string; cause?: unknown },\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.jobId = jobId;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Job ID: ${this.jobId}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type { CreditBalance, CreditTransaction, CreditUsage } from \"$/types\";\n\nexport type ListTransactionsOptions = {\n\t/** Max transactions per page (1-100, default 50) */\n\tlimit?: number;\n\t/** Offset for pagination (default 0) */\n\toffset?: number;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListTransactionsResponse = {\n\ttransactions: CreditTransaction[];\n\tpagination: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\ttotal: number;\n\t};\n};\n\n/**\n * Credits API resource.\n *\n * Provides methods to manage and query credit balances, transaction history,\n * and job-specific credit usage.\n */\nexport class CreditsResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Get the current credit balance for your team.\n\t *\n\t * @example\n\t * const balance = await mappa.credits.getBalance();\n\t * console.log(`Available: ${balance.available} credits`);\n\t */\n\tasync getBalance(opts?: {\n\t\trequestId?: string;\n\t\tsignal?: AbortSignal;\n\t}): Promise<CreditBalance> {\n\t\tconst res = await this.transport.request<CreditBalance>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/credits/balance\",\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List credit transactions with offset pagination.\n\t *\n\t * @example\n\t * const { transactions, pagination } = await mappa.credits.listTransactions({ limit: 25 });\n\t * console.log(`Showing ${transactions.length} of ${pagination.total}`);\n\t */\n\tasync listTransactions(\n\t\topts?: ListTransactionsOptions,\n\t): Promise<ListTransactionsResponse> {\n\t\tconst query: Record<string, string> = {};\n\t\tif (opts?.limit !== undefined) query.limit = String(opts.limit);\n\t\tif (opts?.offset !== undefined) query.offset = String(opts.offset);\n\n\t\tconst res = await this.transport.request<ListTransactionsResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/credits/transactions\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Iterate over all transactions, automatically handling pagination.\n\t *\n\t * @example\n\t * for await (const tx of mappa.credits.listAllTransactions()) {\n\t * console.log(`${tx.type}: ${tx.amount}`);\n\t * }\n\t */\n\tasync *listAllTransactions(\n\t\topts?: Omit<ListTransactionsOptions, \"offset\">,\n\t): AsyncIterable<CreditTransaction> {\n\t\tlet offset = 0;\n\t\tconst limit = opts?.limit ?? 50;\n\n\t\twhile (true) {\n\t\t\tconst page = await this.listTransactions({ ...opts, limit, offset });\n\t\t\tfor (const tx of page.transactions) {\n\t\t\t\tyield tx;\n\t\t\t}\n\n\t\t\toffset += page.transactions.length;\n\t\t\tif (offset >= page.pagination.total) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get credit usage details for a completed job.\n\t *\n\t * @example\n\t * const usage = await mappa.credits.getJobUsage(\"job_xyz\");\n\t * console.log(`Net credits used: ${usage.creditsNetUsed}`);\n\t */\n\tasync getJobUsage(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<CreditUsage> {\n\t\tif (!jobId) throw new MappaError(\"jobId is required\");\n\n\t\tconst res = await this.transport.request<CreditUsage>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/credits/usage/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Check if the team has enough available credits for an operation.\n\t *\n\t * @example\n\t * if (await mappa.credits.hasEnough(100)) {\n\t * await mappa.reports.createJob(...);\n\t * }\n\t */\n\tasync hasEnough(\n\t\tcredits: number,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<boolean> {\n\t\tconst balance = await this.getBalance(opts);\n\t\treturn balance.available >= credits;\n\t}\n\n\t/**\n\t * Get the number of available credits (balance - reserved).\n\t *\n\t * @example\n\t * const available = await mappa.credits.getAvailable();\n\t * console.log(`You can spend ${available} credits`);\n\t */\n\tasync getAvailable(opts?: {\n\t\trequestId?: string;\n\t\tsignal?: AbortSignal;\n\t}): Promise<number> {\n\t\tconst balance = await this.getBalance(opts);\n\t\treturn balance.available;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tEntity,\n\tEntityTagsResult,\n\tListEntitiesOptions,\n\tListEntitiesResponse,\n} from \"$/types\";\n\n/**\n * Tag validation regex: 1-64 chars, alphanumeric with underscores and hyphens.\n */\nconst TAG_REGEX = /^[a-zA-Z0-9_-]{1,64}$/;\n\n/**\n * Maximum number of tags per request.\n */\nconst MAX_TAGS_PER_REQUEST = 10;\n\n/**\n * Validates a single tag.\n * @throws {MappaError} if validation fails\n */\nfunction validateTag(tag: string): void {\n\tif (typeof tag !== \"string\") {\n\t\tthrow new MappaError(\"Tags must be strings\");\n\t}\n\tif (!TAG_REGEX.test(tag)) {\n\t\tthrow new MappaError(\n\t\t\t`Invalid tag \"${tag}\": must be 1-64 characters, alphanumeric with underscores and hyphens only`,\n\t\t);\n\t}\n}\n\n/**\n * Validates an array of tags.\n * @throws {MappaError} if validation fails\n */\nfunction validateTags(tags: string[]): void {\n\tif (!Array.isArray(tags)) {\n\t\tthrow new MappaError(\"tags must be an array\");\n\t}\n\tif (tags.length > MAX_TAGS_PER_REQUEST) {\n\t\tthrow new MappaError(\n\t\t\t`Too many tags: maximum ${MAX_TAGS_PER_REQUEST} per request`,\n\t\t);\n\t}\n\tfor (const tag of tags) {\n\t\tvalidateTag(tag);\n\t}\n}\n\n/**\n * Entities API resource.\n *\n * Responsibilities:\n * - List entities with optional tag filtering (`GET /v1/entities`)\n * - Get single entity details (`GET /v1/entities/:entityId`)\n * - Add tags to entities (`POST /v1/entities/:entityId/tags`)\n * - Remove tags from entities (`DELETE /v1/entities/:entityId/tags`)\n * - Replace all entity tags (`PUT /v1/entities/:entityId/tags`)\n *\n * Entities represent analyzed speakers identified by voice fingerprints.\n * Tags allow you to label entities (e.g., \"interviewer\", \"sales-rep\") for easier\n * filtering and identification across multiple reports.\n */\nexport class EntitiesResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Get a single entity by ID.\n\t *\n\t * Returns entity metadata including tags, creation time, and usage statistics.\n\t *\n\t * @param entityId - The entity ID to retrieve\n\t * @param opts - Optional request options (requestId, signal)\n\t * @returns Entity details with tags and metadata\n\t *\n\t * @example\n\t * ```typescript\n\t * const entity = await mappa.entities.get(\"entity_abc123\");\n\t * console.log(entity.tags); // [\"interviewer\", \"john\"]\n\t * ```\n\t */\n\tasync get(\n\t\tentityId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Entity> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\n\t\tconst res = await this.transport.request<Entity>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List entities with optional tag filtering.\n\t *\n\t * Supports cursor-based pagination. Use the returned `cursor` for fetching\n\t * subsequent pages, or use {@link listAll} for automatic pagination.\n\t *\n\t * When `tags` is provided, only entities with ALL specified tags are returned (AND logic).\n\t *\n\t * @param opts - List options: tags filter, cursor, limit\n\t * @returns Paginated list of entities\n\t *\n\t * @example\n\t * ```typescript\n\t * // List all entities\n\t * const page1 = await mappa.entities.list({ limit: 20 });\n\t *\n\t * // Filter by tags (must have both \"interviewer\" AND \"sales\")\n\t * const filtered = await mappa.entities.list({\n\t * tags: [\"interviewer\", \"sales\"],\n\t * limit: 50\n\t * });\n\t *\n\t * // Pagination\n\t * const page2 = await mappa.entities.list({\n\t * cursor: page1.cursor,\n\t * limit: 20\n\t * });\n\t * ```\n\t */\n\tasync list(\n\t\topts?: ListEntitiesOptions & { requestId?: string; signal?: AbortSignal },\n\t): Promise<ListEntitiesResponse> {\n\t\tconst query: Record<string, string> = {};\n\n\t\tif (opts?.tags) {\n\t\t\tvalidateTags(opts.tags);\n\t\t\t// Join tags with comma for API query parameter\n\t\t\tquery.tags = opts.tags.join(\",\");\n\t\t}\n\n\t\tif (opts?.cursor) {\n\t\t\tquery.cursor = opts.cursor;\n\t\t}\n\n\t\tif (opts?.limit !== undefined) {\n\t\t\tquery.limit = String(opts.limit);\n\t\t}\n\n\t\tconst res = await this.transport.request<ListEntitiesResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/entities\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Async iterator that automatically paginates through all entities.\n\t *\n\t * Useful for processing large entity sets without manual pagination management.\n\t *\n\t * @param opts - List options: tags filter, limit per page\n\t * @yields Individual entities\n\t *\n\t * @example\n\t * ```typescript\n\t * // Process all entities with \"interviewer\" tag\n\t * for await (const entity of mappa.entities.listAll({ tags: [\"interviewer\"] })) {\n\t * console.log(`${entity.id}: ${entity.tags.join(\", \")}`);\n\t * }\n\t * ```\n\t */\n\tasync *listAll(\n\t\topts?: Omit<ListEntitiesOptions, \"cursor\"> & {\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): AsyncIterable<Entity> {\n\t\tlet cursor: string | undefined;\n\t\tlet hasMore = true;\n\n\t\twhile (hasMore) {\n\t\t\tconst page = await this.list({ ...opts, cursor });\n\t\t\tfor (const entity of page.entities) {\n\t\t\t\tyield entity;\n\t\t\t}\n\t\t\tcursor = page.cursor;\n\t\t\thasMore = page.hasMore;\n\t\t}\n\t}\n\n\t/**\n\t * Get all entities with a specific tag.\n\t *\n\t * Convenience wrapper around {@link list} for single-tag filtering.\n\t *\n\t * @param tag - The tag to filter by\n\t * @param opts - Optional pagination and request options\n\t * @returns Paginated list of entities with the specified tag\n\t *\n\t * @example\n\t * ```typescript\n\t * const interviewers = await mappa.entities.getByTag(\"interviewer\");\n\t * ```\n\t */\n\tasync getByTag(\n\t\ttag: string,\n\t\topts?: Omit<ListEntitiesOptions, \"tags\"> & {\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<ListEntitiesResponse> {\n\t\tvalidateTag(tag);\n\t\treturn this.list({ ...opts, tags: [tag] });\n\t}\n\n\t/**\n\t * Add tags to an entity.\n\t *\n\t * Idempotent: existing tags are preserved, duplicates are ignored.\n\t *\n\t * @param entityId - The entity ID to tag\n\t * @param tags - Array of tags to add (1-10 tags, each 1-64 chars)\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * await mappa.entities.addTags(\"entity_abc123\", [\"interviewer\", \"john\"]);\n\t * ```\n\t */\n\tasync addTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tif (tags.length === 0) {\n\t\t\tthrow new MappaError(\"At least one tag is required\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Remove tags from an entity.\n\t *\n\t * Idempotent: missing tags are silently ignored.\n\t *\n\t * @param entityId - The entity ID to update\n\t * @param tags - Array of tags to remove\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * await mappa.entities.removeTags(\"entity_abc123\", [\"interviewer\"]);\n\t * ```\n\t */\n\tasync removeTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tif (tags.length === 0) {\n\t\t\tthrow new MappaError(\"At least one tag is required\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"DELETE\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Replace all tags on an entity.\n\t *\n\t * Sets the complete tag list, removing any tags not in the provided array.\n\t * Pass an empty array to remove all tags.\n\t *\n\t * @param entityId - The entity ID to update\n\t * @param tags - New complete tag list (0-10 tags)\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * // Replace all tags\n\t * await mappa.entities.setTags(\"entity_abc123\", [\"sales-rep\", \"john\"]);\n\t *\n\t * // Remove all tags\n\t * await mappa.entities.setTags(\"entity_abc123\", []);\n\t * ```\n\t */\n\tasync setTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"PUT\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type { FeedbackReceipt } from \"$/types\";\n\nexport type FeedbackCreateRequest = {\n\treportId?: string;\n\tjobId?: string;\n\trating: \"thumbs_up\" | \"thumbs_down\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\";\n\ttags?: string[];\n\tcomment?: string;\n\tcorrections?: Array<{ path: string; expected?: unknown; observed?: unknown }>;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport class FeedbackResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Create feedback for a report or job. Provide exactly one of `reportId` or `jobId`.\n\t */\n\tasync create(req: FeedbackCreateRequest): Promise<FeedbackReceipt> {\n\t\tif (!!req.reportId === !!req.jobId)\n\t\t\tthrow new MappaError(\"Provide exactly one of reportId or jobId\");\n\n\t\tconst res = await this.transport.request<FeedbackReceipt>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/feedback\",\n\t\t\tbody: req,\n\t\t\tidempotencyKey: req.idempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tsignal: req.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tFileDeleteReceipt,\n\tMediaFile,\n\tMediaObject,\n\tRetentionLockResult,\n} from \"$/types\";\n\nexport type UploadRequest = {\n\tfile: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>;\n\t/**\n\t * Optional override.\n\t * If omitted, the SDK will try to infer it from `file.type` (Blob) and then from `filename`.\n\t */\n\tcontentType?: string;\n\tfilename?: string;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListFilesOptions = {\n\t/** Max files per page (1-100, default 20) */\n\tlimit?: number;\n\t/** Pagination cursor from previous response */\n\tcursor?: string;\n\t/** Include soft-deleted files (default false) */\n\tincludeDeleted?: boolean;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListFilesResponse = {\n\tfiles: MediaFile[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\n/**\n * Uses multipart/form-data for uploads.\n *\n * If you need resumable uploads, add a dedicated resumable protocol.\n */\nexport class FilesResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync upload(req: UploadRequest): Promise<MediaObject> {\n\t\tif (typeof FormData === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"FormData is not available in this runtime; cannot perform multipart upload\",\n\t\t\t);\n\t\t}\n\n\t\tconst derivedContentType = inferContentType(req.file, req.filename);\n\t\tconst contentType = req.contentType ?? derivedContentType;\n\t\tif (!contentType) {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"contentType is required when it cannot be inferred from file.type or filename\",\n\t\t\t);\n\t\t}\n\n\t\tconst filename = req.filename ?? inferFilename(req.file) ?? \"upload\";\n\t\tconst filePart = await toFormDataPart(req.file, contentType);\n\n\t\tconst form = new FormData();\n\t\t// Server expects multipart fields:\n\t\t// - file: binary\n\t\t// - contentType: string (may be used for validation/normalization)\n\t\t// - filename: string (optional)\n\t\tform.append(\"file\", filePart, filename);\n\t\tform.append(\"contentType\", contentType);\n\t\tif (req.filename) form.append(\"filename\", req.filename);\n\n\t\tconst res = await this.transport.request<MediaObject>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/files\",\n\t\t\tbody: form,\n\t\t\tidempotencyKey: req.idempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tsignal: req.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Retrieve metadata for a single uploaded file.\n\t *\n\t * @example\n\t * const file = await mappa.files.get(\"media_abc123\");\n\t * console.log(file.processingStatus); // \"COMPLETED\"\n\t */\n\tasync get(\n\t\tmediaId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<MediaFile> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<MediaFile>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List uploaded files with cursor pagination.\n\t *\n\t * @example\n\t * const page1 = await mappa.files.list({ limit: 10 });\n\t * if (page1.hasMore) {\n\t * const page2 = await mappa.files.list({ limit: 10, cursor: page1.cursor });\n\t * }\n\t */\n\tasync list(opts?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst query: Record<string, string> = {};\n\t\tif (opts?.limit !== undefined) query.limit = String(opts.limit);\n\t\tif (opts?.cursor) query.cursor = opts.cursor;\n\t\tif (opts?.includeDeleted !== undefined)\n\t\t\tquery.includeDeleted = String(opts.includeDeleted);\n\n\t\tconst res = await this.transport.request<ListFilesResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/files\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Iterate over all files, automatically handling pagination.\n\t *\n\t * @example\n\t * for await (const file of mappa.files.listAll()) {\n\t * console.log(file.mediaId);\n\t * }\n\t *\n\t * // Or collect all\n\t * const allFiles = [];\n\t * for await (const file of mappa.files.listAll({ limit: 50 })) {\n\t * allFiles.push(file);\n\t * }\n\t */\n\tasync *listAll(\n\t\topts?: Omit<ListFilesOptions, \"cursor\">,\n\t): AsyncIterable<MediaFile> {\n\t\tlet cursor: string | undefined;\n\t\tlet hasMore = true;\n\n\t\twhile (hasMore) {\n\t\t\tconst page = await this.list({ ...opts, cursor });\n\t\t\tfor (const file of page.files) {\n\t\t\t\tyield file;\n\t\t\t}\n\t\t\tcursor = page.cursor;\n\t\t\thasMore = page.hasMore;\n\t\t}\n\t}\n\n\t/**\n\t * Lock or unlock a file's retention to prevent/allow automatic deletion.\n\t *\n\t * @example\n\t * // Prevent automatic deletion\n\t * await mappa.files.setRetentionLock(\"media_abc\", true);\n\t *\n\t * // Allow automatic deletion\n\t * await mappa.files.setRetentionLock(\"media_abc\", false);\n\t */\n\tasync setRetentionLock(\n\t\tmediaId: string,\n\t\tlocked: boolean,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<RetentionLockResult> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<RetentionLockResult>({\n\t\t\tmethod: \"PATCH\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}/retention`,\n\t\t\tbody: { lock: locked },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\tasync delete(\n\t\tmediaId: string,\n\t\topts?: {\n\t\t\tidempotencyKey?: string;\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<FileDeleteReceipt> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<FileDeleteReceipt>({\n\t\t\tmethod: \"DELETE\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}`,\n\t\t\tidempotencyKey: opts?.idempotencyKey,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n}\n\nfunction inferContentType(\n\tfile: UploadRequest[\"file\"],\n\tfilename?: string,\n): string | undefined {\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tif (file.type) return file.type;\n\t}\n\tif (filename) return contentTypeFromFilename(filename);\n\treturn undefined;\n}\n\nfunction inferFilename(file: UploadRequest[\"file\"]): string | undefined {\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tconst anyBlob = file as unknown as { name?: unknown };\n\t\tif (typeof anyBlob.name === \"string\" && anyBlob.name) return anyBlob.name;\n\t}\n\treturn undefined;\n}\n\nfunction contentTypeFromFilename(filename: string): string | undefined {\n\tconst i = filename.lastIndexOf(\".\");\n\tif (i < 0) return undefined;\n\tconst ext = filename.slice(i + 1).toLowerCase();\n\n\t// Small built-in map to avoid an extra dependency.\n\t// Add more as needed.\n\tswitch (ext) {\n\t\tcase \"mp4\":\n\t\t\treturn \"video/mp4\";\n\t\tcase \"mov\":\n\t\t\treturn \"video/quicktime\";\n\t\tcase \"webm\":\n\t\t\treturn \"video/webm\";\n\t\tcase \"mp3\":\n\t\t\treturn \"audio/mpeg\";\n\t\tcase \"wav\":\n\t\t\treturn \"audio/wav\";\n\t\tcase \"m4a\":\n\t\t\treturn \"audio/mp4\";\n\t\tcase \"png\":\n\t\t\treturn \"image/png\";\n\t\tcase \"jpg\":\n\t\tcase \"jpeg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \"gif\":\n\t\t\treturn \"image/gif\";\n\t\tcase \"webp\":\n\t\t\treturn \"image/webp\";\n\t\tcase \"pdf\":\n\t\t\treturn \"application/pdf\";\n\t\tcase \"json\":\n\t\t\treturn \"application/json\";\n\t\tcase \"txt\":\n\t\t\treturn \"text/plain\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nasync function toFormDataPart(\n\tfile: UploadRequest[\"file\"],\n\tcontentType: string,\n): Promise<Blob> {\n\t// Blob: ensure the part has the intended type.\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tif (file.type === contentType) return file;\n\t\t// TS in this repo is configured without DOM lib, so `Blob#slice` isn't typed.\n\t\t// Most runtimes support it; we call it via an `any` cast.\n\t\tconst slicer = file as unknown as {\n\t\t\tslice?: (start?: number, end?: number, contentType?: string) => Blob;\n\t\t};\n\t\tif (typeof slicer.slice === \"function\") {\n\t\t\treturn slicer.slice(\n\t\t\t\t0,\n\t\t\t\t(file as unknown as { size?: number }).size,\n\t\t\t\tcontentType,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\n\t// ArrayBuffer / Uint8Array\n\tif (file instanceof ArrayBuffer)\n\t\treturn new Blob([file], { type: contentType });\n\tif (file instanceof Uint8Array)\n\t\treturn new Blob([file], { type: contentType });\n\n\t// ReadableStream<Uint8Array>\n\tif (typeof ReadableStream !== \"undefined\" && file instanceof ReadableStream) {\n\t\t// Most runtimes (Node 18+/Bun/modern browsers) can convert stream -> Blob via Response.\n\t\tif (typeof Response === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"ReadableStream upload requires Response to convert stream to Blob\",\n\t\t\t);\n\t\t}\n\n\t\tconst blob = await new Response(file).blob();\n\t\treturn blob.slice(0, blob.size, contentType);\n\t}\n\n\tthrow new MappaError(\"Unsupported file type for upload()\");\n}\n","import type { Transport } from \"$/resources/transport\";\n\nexport class HealthResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync ping(): Promise<{ ok: true; time: string }> {\n\t\tconst res = await this.transport.request<{ ok: true; time: string }>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/health/ping\",\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n}\n","import { init } from \"@paralleldrive/cuid2\";\n\nconst createId = init({\n\tlength: 32,\n});\n\nexport function assertNever(x: never): never {\n\tthrow new Error(`Unexpected object: ${String(x)}`);\n}\n\nexport function isObject(x: unknown): x is Record<string, unknown> {\n\treturn typeof x === \"object\" && x !== null;\n}\n\nexport function getHeader(headers: Headers, name: string): string | undefined {\n\tconst v = headers.get(name);\n\treturn v === null ? undefined : v;\n}\n\nexport function jitter(ms: number): number {\n\t// +/- 20%\n\tconst r = 0.8 + Math.random() * 0.4;\n\treturn Math.floor(ms * r);\n}\n\nexport function backoffMs(\n\tattempt: number,\n\tbaseMs: number,\n\tmaxMs: number,\n): number {\n\t// exponential: base * 2^(attempt-1)\n\tconst ms = baseMs * 2 ** Math.max(0, attempt - 1);\n\treturn Math.min(ms, maxMs);\n}\n\nexport function nowMs(): number {\n\treturn Date.now();\n}\n\nexport function hasAbortSignal(signal?: AbortSignal): boolean {\n\treturn !!signal && typeof signal.aborted === \"boolean\";\n}\n\nexport function makeAbortError(): Error {\n\tconst e = new Error(\"The operation was aborted\");\n\te.name = \"AbortError\";\n\treturn e;\n}\n\nexport function randomId(prefix = \"req\"): string {\n\treturn `${prefix}_${createId()}`;\n}\n","import { JobCanceledError, JobFailedError, MappaError } from \"$/errors\";\nimport type { SSEEvent, Transport } from \"$/resources/transport\";\nimport type { Job, JobEvent, JobStage, WaitOptions } from \"$/types\";\nimport { makeAbortError } from \"../utils\";\n\n/**\n * SSE event data shape from the server's job stream endpoint.\n */\ntype JobStreamEventData = {\n\tstatus?: string;\n\tstage?: string;\n\tprogress?: number;\n\tjob: Job;\n\treportId?: string;\n\terror?: { code: string; message: string };\n\ttimestamp?: string; // for heartbeat\n};\n\nexport class JobsResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync get(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Job> {\n\t\tconst res = await this.transport.request<Job>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/jobs/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\tasync cancel(\n\t\tjobId: string,\n\t\topts?: {\n\t\t\tidempotencyKey?: string;\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<Job> {\n\t\tconst res = await this.transport.request<Job>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: `/v1/jobs/${encodeURIComponent(jobId)}/cancel`,\n\t\t\tidempotencyKey: opts?.idempotencyKey,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Wait for a job to reach a terminal state.\n\t *\n\t * Uses SSE streaming internally for efficient real-time updates.\n\t */\n\tasync wait(jobId: string, opts?: WaitOptions): Promise<Job> {\n\t\tconst timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n\t\tconst controller = new AbortController();\n\n\t\t// Set up timeout\n\t\tconst timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n\t\t// Combine signals if user provided one\n\t\tif (opts?.signal) {\n\t\t\tif (opts.signal.aborted) {\n\t\t\t\tclearTimeout(timeoutId);\n\t\t\t\tthrow makeAbortError();\n\t\t\t}\n\t\t\topts.signal.addEventListener(\"abort\", () => controller.abort(), {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tfor await (const event of this.stream(jobId, {\n\t\t\t\tsignal: controller.signal,\n\t\t\t\tonEvent: opts?.onEvent,\n\t\t\t})) {\n\t\t\t\tif (event.type === \"terminal\") {\n\t\t\t\t\tconst job = event.job;\n\n\t\t\t\t\tif (job.status === \"succeeded\") {\n\t\t\t\t\t\treturn job;\n\t\t\t\t\t}\n\t\t\t\t\tif (job.status === \"failed\") {\n\t\t\t\t\t\tthrow new JobFailedError(\n\t\t\t\t\t\t\tjobId,\n\t\t\t\t\t\t\tjob.error?.message ?? \"Job failed\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trequestId: job.requestId,\n\t\t\t\t\t\t\t\tcode: job.error?.code,\n\t\t\t\t\t\t\t\tcause: job.error,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (job.status === \"canceled\") {\n\t\t\t\t\t\tthrow new JobCanceledError(jobId, \"Job canceled\", {\n\t\t\t\t\t\t\trequestId: job.requestId,\n\t\t\t\t\t\t\tcause: job.error,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stream ended without terminal event (timeout or unexpected close)\n\t\t\tthrow new JobFailedError(\n\t\t\t\tjobId,\n\t\t\t\t`Timed out waiting for job ${jobId} after ${timeoutMs}ms`,\n\t\t\t\t{\n\t\t\t\t\tcause: { jobId, timeoutMs },\n\t\t\t\t},\n\t\t\t);\n\t\t} finally {\n\t\t\tclearTimeout(timeoutId);\n\t\t}\n\t}\n\n\t/**\n\t * Stream job events via SSE.\n\t *\n\t * Yields events as they arrive from the server. Use `AbortSignal` to cancel streaming.\n\t * Automatically handles reconnection with `Last-Event-ID` for up to 3 retries.\n\t */\n\tasync *stream(\n\t\tjobId: string,\n\t\topts?: { signal?: AbortSignal; onEvent?: (e: JobEvent) => void },\n\t): AsyncIterable<JobEvent> {\n\t\tconst maxRetries = 3;\n\t\tlet lastEventId: string | undefined;\n\t\tlet retries = 0;\n\n\t\twhile (retries < maxRetries) {\n\t\t\ttry {\n\t\t\t\tconst sseStream = this.transport.streamSSE<JobStreamEventData>(\n\t\t\t\t\t`/v1/jobs/${encodeURIComponent(jobId)}/stream`,\n\t\t\t\t\t{ signal: opts?.signal, lastEventId },\n\t\t\t\t);\n\n\t\t\t\tfor await (const sseEvent of sseStream) {\n\t\t\t\t\tlastEventId = sseEvent.id;\n\n\t\t\t\t\t// Handle error event (job not found, etc.)\n\t\t\t\t\tif (sseEvent.event === \"error\") {\n\t\t\t\t\t\tconst errorData = sseEvent.data;\n\t\t\t\t\t\tthrow new MappaError(\n\t\t\t\t\t\t\terrorData.error?.message ?? \"Unknown SSE error\",\n\t\t\t\t\t\t\t{ code: errorData.error?.code },\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip heartbeat events (internal keep-alive)\n\t\t\t\t\tif (sseEvent.event === \"heartbeat\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Map SSE event to JobEvent\n\t\t\t\t\tconst jobEvent = this.mapSSEToJobEvent(sseEvent);\n\t\t\t\t\tif (jobEvent) {\n\t\t\t\t\t\topts?.onEvent?.(jobEvent);\n\t\t\t\t\t\tyield jobEvent;\n\n\t\t\t\t\t\t// Exit on terminal event\n\t\t\t\t\t\tif (sseEvent.event === \"terminal\") {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reset retry counter on successful event\n\t\t\t\t\tretries = 0;\n\t\t\t\t}\n\n\t\t\t\t// Stream ended without terminal event (server timeout)\n\t\t\t\t// Reconnect with last event ID\n\t\t\t\tretries++;\n\t\t\t\tif (retries < maxRetries) {\n\t\t\t\t\tawait this.backoff(retries);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// If aborted, rethrow immediately\n\t\t\t\tif (opts?.signal?.aborted) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tretries++;\n\t\t\t\tif (retries >= maxRetries) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tawait this.backoff(retries);\n\t\t\t}\n\t\t}\n\n\t\tthrow new MappaError(\n\t\t\t`Failed to get status for job ${jobId} after ${maxRetries} retries`,\n\t\t);\n\t}\n\n\t/**\n\t * Map an SSE event to a JobEvent.\n\t */\n\tprivate mapSSEToJobEvent(\n\t\tsseEvent: SSEEvent<JobStreamEventData>,\n\t): JobEvent | null {\n\t\tconst data = sseEvent.data;\n\n\t\tswitch (sseEvent.event) {\n\t\t\tcase \"status\":\n\t\t\t\treturn { type: \"status\", job: data.job };\n\t\t\tcase \"stage\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"stage\",\n\t\t\t\t\tstage: data.stage as JobStage,\n\t\t\t\t\tprogress: data.progress,\n\t\t\t\t\tjob: data.job,\n\t\t\t\t};\n\t\t\tcase \"terminal\":\n\t\t\t\treturn { type: \"terminal\", job: data.job };\n\t\t\tdefault:\n\t\t\t\t// Unknown event type, treat as status update\n\t\t\t\treturn { type: \"status\", job: data.job };\n\t\t}\n\t}\n\n\t/**\n\t * Exponential backoff with jitter for reconnection.\n\t */\n\tprivate async backoff(attempt: number): Promise<void> {\n\t\tconst delay = Math.min(1000 * 2 ** attempt, 10000);\n\t\tconst jitter = delay * 0.5 * Math.random();\n\t\tawait new Promise((r) => setTimeout(r, delay + jitter));\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { UploadRequest } from \"$/resources/files\";\nimport type { JobsResource } from \"$/resources/jobs\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tJobEvent,\n\tMediaIdRef,\n\tMediaObject,\n\tReport,\n\tReportCreateJobRequest,\n\tReportJobReceipt,\n\tReportRunHandle,\n\tWaitOptions,\n} from \"$/types\";\nimport { randomId } from \"$/utils\";\n\n/**\n * Runtime validation for the internal `MediaIdRef` requirement.\n *\n * The public API server expects a `mediaId` when creating a report job.\n * Use helpers like `createJobFromFile` / `createJobFromUrl` to start from bytes or a URL.\n */\nfunction validateMedia(media: MediaIdRef): void {\n\tconst m = media as unknown;\n\tconst isObj = (v: unknown): v is Record<string, unknown> =>\n\t\tv !== null && typeof v === \"object\";\n\n\tif (!isObj(m)) throw new MappaError(\"media must be an object\");\n\n\t// Report job creation only supports already-uploaded media references.\n\t// Use `createJobFromFile` / `createJobFromUrl` to start from bytes or a remote URL.\n\tif ((m as { url?: unknown }).url !== undefined) {\n\t\tthrow new MappaError(\n\t\t\t\"media.url is not supported; pass { mediaId } or use createJobFromUrl()\",\n\t\t);\n\t}\n\n\tconst mediaId = (m as { mediaId?: unknown }).mediaId;\n\tif (typeof mediaId !== \"string\" || !mediaId) {\n\t\tthrow new MappaError(\"media.mediaId must be a non-empty string\");\n\t}\n}\n\n/**\n * Request shape for {@link ReportsResource.createJobFromFile}.\n *\n * This helper performs two API calls as one logical operation:\n * 1) Upload bytes via `files.upload()` (multipart)\n * 2) Create a report job via {@link ReportsResource.createJob} using the returned `{ mediaId }`\n *\n * Differences vs {@link ReportCreateJobRequest}:\n * - `media` is derived from the upload result and therefore omitted.\n * - `idempotencyKey` applies to the *whole* upload + create-job sequence.\n * - `requestId` is forwarded to both requests for end-to-end correlation.\n *\n * Abort behavior:\n * - `signal` (from {@link UploadRequest}) is applied to the upload request.\n * Job creation only runs after a successful upload.\n */\nexport type ReportCreateJobFromFileRequest = Omit<\n\tReportCreateJobRequest,\n\t\"media\" | \"idempotencyKey\" | \"requestId\"\n> &\n\tOmit<UploadRequest, \"filename\"> & {\n\t\t/**\n\t\t * Optional filename to attach to the upload.\n\t\t *\n\t\t * When omitted, the upload layer may infer it (e.g. from a `File` object).\n\t\t */\n\t\tfilename?: string;\n\t\t/**\n\t\t * Idempotency for the upload + job creation sequence.\n\t\t */\n\t\tidempotencyKey?: string;\n\t\t/**\n\t\t * Optional request correlation ID forwarded to both the upload and the job creation call.\n\t\t */\n\t\trequestId?: string;\n\t};\n\n/**\n * Request shape for {@link ReportsResource.createJobFromUrl}.\n *\n * This helper performs two API calls as one logical operation:\n * 1) Download bytes from a remote URL using `fetch()`\n * 2) Upload bytes via `files.upload()` and then create a report job via {@link ReportsResource.createJob}\n *\n * Differences vs {@link ReportCreateJobRequest}:\n * - `media` is derived from the upload result and therefore omitted.\n * - `idempotencyKey` applies to the *whole* download + upload + create-job sequence.\n * - `requestId` is forwarded to both upload and job creation calls.\n */\nexport type ReportCreateJobFromUrlRequest = Omit<\n\tReportCreateJobRequest,\n\t\"media\" | \"idempotencyKey\" | \"requestId\"\n> & {\n\turl: string;\n\tcontentType?: string;\n\tfilename?: string;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\n/**\n * Reports API resource.\n *\n * Responsibilities:\n * - Create report jobs (`POST /v1/reports/jobs`).\n * - Fetch reports by report ID (`GET /v1/reports/:reportId`).\n * - Fetch reports by job ID (`GET /v1/reports/by-job/:jobId`).\n *\n * Convenience helpers:\n * - {@link ReportsResource.createJobFromFile} orchestrates `files.upload()` + {@link ReportsResource.createJob}.\n * - {@link ReportsResource.createJobFromUrl} downloads a remote URL, uploads it, then calls {@link ReportsResource.createJob}.\n * - {@link ReportsResource.generate} / {@link ReportsResource.generateFromFile} are script-friendly wrappers that\n * create a job, wait for completion, and then fetch the final report.\n *\n * For production systems, prefer `createJob*()` plus webhooks or streaming job events rather than blocking waits.\n */\nexport class ReportsResource {\n\tconstructor(\n\t\tprivate readonly transport: Transport,\n\t\tprivate readonly jobs: JobsResource,\n\t\tprivate readonly files: {\n\t\t\tupload: (req: UploadRequest) => Promise<MediaObject>;\n\t\t},\n\t\tprivate readonly fetchImpl: typeof fetch,\n\t) {}\n\n\t/**\n\t * Create a new report job.\n\t *\n\t * Behavior:\n\t * - Validates {@link MediaIdRef} at runtime (must provide `{ mediaId }`).\n\t * - Defaults to `{ strategy: \"dominant\" }` when `target` is omitted.\n\t * - Applies an idempotency key: uses `req.idempotencyKey` when provided; otherwise generates a best-effort default.\n\t * - Forwards `req.requestId` to the transport for end-to-end correlation.\n\t *\n\t * The returned receipt includes a {@link ReportRunHandle} (`receipt.handle`) which can be used to:\n\t * - stream job events\n\t * - wait for completion and fetch the final report\n\t * - cancel the job, or fetch job/report metadata\n\t */\n\tasync createJob(req: ReportCreateJobRequest): Promise<ReportJobReceipt> {\n\t\tvalidateMedia(req.media);\n\n\t\tconst idempotencyKey =\n\t\t\treq.idempotencyKey ?? this.defaultIdempotencyKey(req);\n\n\t\tconst res = await this.transport.request<Omit<ReportJobReceipt, \"handle\">>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/reports/jobs\",\n\t\t\tbody: this.normalizeJobRequest(req),\n\t\t\tidempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tretryable: true,\n\t\t});\n\n\t\tconst receipt: ReportJobReceipt = {\n\t\t\t...res.data,\n\t\t\trequestId: res.requestId ?? res.data.requestId,\n\t\t};\n\n\t\treceipt.handle = this.makeHandle(receipt.jobId);\n\t\treturn receipt;\n\t}\n\n\t/**\n\t * Upload a file and create a report job in one call.\n\t *\n\t * Keeps `createJob()` strict about `media: { mediaId }` while offering a\n\t * convenient helper when you start from raw bytes.\n\t */\n\tasync createJobFromFile(\n\t\treq: ReportCreateJobFromFileRequest,\n\t): Promise<ReportJobReceipt> {\n\t\tconst {\n\t\t\tfile,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t\t...rest\n\t\t} = req;\n\n\t\tconst upload = await this.files.upload({\n\t\t\tfile,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t});\n\n\t\treturn this.createJob({\n\t\t\t...(rest as Omit<ReportCreateJobRequest, \"media\">),\n\t\t\tmedia: { mediaId: upload.mediaId },\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t});\n\t}\n\n\t/**\n\t * Download a file from a URL, upload it, and create a report job.\n\t *\n\t * Recommended when starting from a remote URL because report job creation\n\t * only accepts `media: { mediaId }`.\n\t *\n\t * Workflow:\n\t * 1) `fetch(url)`\n\t * 2) Validate the response (2xx) and derive `contentType`\n\t * 3) `files.upload({ file: Blob, ... })`\n\t * 4) `createJob({ media: { mediaId }, ... })`\n\t *\n\t * Verification / safety:\n\t * - Only allows `http:` and `https:` URLs.\n\t * - Requires a resolvable `contentType` (from `req.contentType` or response header).\n\t */\n\tasync createJobFromUrl(\n\t\treq: ReportCreateJobFromUrlRequest,\n\t): Promise<ReportJobReceipt> {\n\t\tconst {\n\t\t\turl,\n\t\t\tcontentType: contentTypeOverride,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t\t...rest\n\t\t} = req;\n\n\t\tlet parsed: URL;\n\t\ttry {\n\t\t\tparsed = new URL(url);\n\t\t} catch {\n\t\t\tthrow new MappaError(\"url must be a valid URL\");\n\t\t}\n\t\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n\t\t\tthrow new MappaError(\"url must use http: or https:\");\n\t\t}\n\n\t\tconst res = await this.fetchImpl(parsed.toString(), { signal });\n\t\tif (!res.ok) {\n\t\t\tthrow new MappaError(`Failed to download url (status ${res.status})`);\n\t\t}\n\n\t\tconst derivedContentType = res.headers.get(\"content-type\") ?? undefined;\n\t\tconst contentType = contentTypeOverride ?? derivedContentType;\n\t\tif (!contentType) {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"contentType is required when it cannot be inferred from the download response\",\n\t\t\t);\n\t\t}\n\n\t\tif (typeof Blob === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"Blob is not available in this runtime; cannot download and upload from url\",\n\t\t\t);\n\t\t}\n\n\t\tconst blob = await res.blob();\n\t\tconst upload = await this.files.upload({\n\t\t\tfile: blob,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t});\n\n\t\treturn this.createJob({\n\t\t\t...(rest as Omit<ReportCreateJobRequest, \"media\">),\n\t\t\tmedia: { mediaId: upload.mediaId },\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t});\n\t}\n\n\tasync get(\n\t\treportId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Report> {\n\t\tconst res = await this.transport.request<Report>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/reports/${encodeURIComponent(reportId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\tasync getByJob(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Report | null> {\n\t\tconst res = await this.transport.request<Report | null>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/reports/by-job/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Convenience wrapper: createJob + wait + get\n\t * Use for scripts; for production prefer createJob + webhooks/stream.\n\t */\n\tasync generate(\n\t\treq: ReportCreateJobRequest,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<Report> {\n\t\tconst receipt = await this.createJob(req);\n\t\tif (!receipt.handle) {\n\t\t\tthrow new MappaError(\"Job receipt is missing handle\");\n\t\t}\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\t/**\n\t * Convenience wrapper: createJobFromFile + wait + get.\n\t * Use for scripts; for production prefer createJobFromFile + webhooks/stream.\n\t */\n\tasync generateFromFile(\n\t\treq: ReportCreateJobFromFileRequest,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<Report> {\n\t\tconst receipt = await this.createJobFromFile(req);\n\t\tif (!receipt.handle) throw new MappaError(\"Job receipt is missing handle\");\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\t/**\n\t * Convenience wrapper: createJobFromUrl + wait + get.\n\t * Use for scripts; for production prefer createJobFromUrl + webhooks/stream.\n\t */\n\tasync generateFromUrl(\n\t\treq: ReportCreateJobFromUrlRequest,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<Report> {\n\t\tconst receipt = await this.createJobFromUrl(req);\n\t\tif (!receipt.handle) throw new MappaError(\"Job receipt is missing handle\");\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\tmakeHandle(jobId: string): ReportRunHandle {\n\t\tconst self = this;\n\t\treturn {\n\t\t\tjobId,\n\t\t\tstream: (opts?: {\n\t\t\t\tsignal?: AbortSignal;\n\t\t\t\tonEvent?: (e: JobEvent) => void;\n\t\t\t}) => self.jobs.stream(jobId, opts),\n\t\t\tasync wait(opts?: WaitOptions): Promise<Report> {\n\t\t\t\tconst terminal = await self.jobs.wait(jobId, opts);\n\t\t\t\tif (!terminal.reportId)\n\t\t\t\t\tthrow new MappaError(\n\t\t\t\t\t\t`Job ${jobId} succeeded but no reportId was returned`,\n\t\t\t\t\t);\n\t\t\t\treturn self.get(terminal.reportId);\n\t\t\t},\n\t\t\tcancel: () => self.jobs.cancel(jobId),\n\t\t\tjob: () => self.jobs.get(jobId),\n\t\t\treport: () => self.getByJob(jobId),\n\t\t};\n\t}\n\n\tprivate defaultIdempotencyKey(_req: ReportCreateJobRequest): string {\n\t\t// Deterministic keys can be added later; random avoids accidental duplicates on retries.\n\t\treturn randomId(\"idem\");\n\t}\n\n\tprivate normalizeJobRequest(\n\t\treq: ReportCreateJobRequest,\n\t): Record<string, unknown> {\n\t\tconst target = req.target;\n\n\t\t// Default to dominant strategy when target is not provided\n\t\tif (!target) {\n\t\t\treturn {\n\t\t\t\t...req,\n\t\t\t\ttarget: { strategy: \"dominant\" },\n\t\t\t};\n\t\t}\n\n\t\tconst baseTarget: Record<string, unknown> = {\n\t\t\tstrategy: target.strategy,\n\t\t};\n\n\t\tif (target.onMiss) {\n\t\t\tbaseTarget.on_miss = target.onMiss;\n\t\t}\n\n\t\t// Add tags and excludeTags to baseTarget (common to all strategies)\n\t\tif (target.tags && target.tags.length > 0) {\n\t\t\tbaseTarget.tags = target.tags;\n\t\t}\n\n\t\tif (target.excludeTags && target.excludeTags.length > 0) {\n\t\t\tbaseTarget.exclude_tags = target.excludeTags;\n\t\t}\n\n\t\tswitch (target.strategy) {\n\t\t\tcase \"dominant\": {\n\t\t\t\treturn { ...req, target: baseTarget };\n\t\t\t}\n\t\t\tcase \"timerange\": {\n\t\t\t\tconst timeRange = target.timeRange ?? {};\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\ttimerange: {\n\t\t\t\t\t\t\tstart_seconds: timeRange.startSeconds ?? null,\n\t\t\t\t\t\t\tend_seconds: timeRange.endSeconds ?? null,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"entity_id\": {\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\tentity_id: target.entityId,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"magic_hint\": {\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\thint: target.hint,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn req;\n\t\t\t}\n\t\t}\n\t}\n}\n","import {\n\tApiError,\n\tAuthError,\n\tInsufficientCreditsError,\n\tMappaError,\n\tRateLimitError,\n\tValidationError,\n} from \"$/errors\";\nimport {\n\tbackoffMs,\n\tgetHeader,\n\thasAbortSignal,\n\tjitter,\n\tmakeAbortError,\n\trandomId,\n} from \"$/utils\";\n\n/**\n * Options for SSE streaming.\n */\nexport type SSEStreamOptions = {\n\tsignal?: AbortSignal;\n\tlastEventId?: string;\n};\n\n/**\n * A parsed SSE event.\n */\nexport type SSEEvent<T = unknown> = {\n\tid?: string;\n\tevent: string;\n\tdata: T;\n};\n\nexport type Telemetry = {\n\tonRequest?: (ctx: {\n\t\tmethod: string;\n\t\turl: string;\n\t\trequestId?: string;\n\t}) => void;\n\tonResponse?: (ctx: {\n\t\tstatus: number;\n\t\turl: string;\n\t\trequestId?: string;\n\t\tdurationMs: number;\n\t}) => void;\n\tonError?: (ctx: { url: string; requestId?: string; error: unknown }) => void;\n};\n\nexport type TransportOptions = {\n\tapiKey: string;\n\tbaseUrl: string;\n\ttimeoutMs: number;\n\tmaxRetries: number;\n\tdefaultHeaders?: Record<string, string>;\n\tfetch?: typeof fetch;\n\ttelemetry?: Telemetry;\n\tuserAgent?: string;\n};\n\nexport type RequestOptions = {\n\tmethod: \"GET\" | \"POST\" | \"DELETE\" | \"PUT\" | \"PATCH\";\n\tpath: string;\n\tquery?: Record<string, string | number | boolean | undefined>;\n\theaders?: Record<string, string | undefined>;\n\tbody?: unknown;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n\t// treat as safe to retry (typically true for GET and for idempotent POSTs)\n\tretryable?: boolean;\n};\n\nexport type TransportResponse<T> = {\n\tdata: T;\n\tstatus: number;\n\trequestId?: string;\n\theaders: Headers;\n};\n\nfunction buildUrl(\n\tbaseUrl: string,\n\tpath: string,\n\tquery?: RequestOptions[\"query\"],\n): string {\n\tconst u = new URL(\n\t\tpath.replace(/^\\//, \"\"),\n\t\tbaseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`,\n\t);\n\tif (query) {\n\t\tfor (const [k, v] of Object.entries(query)) {\n\t\t\tif (v === undefined) continue;\n\t\t\tu.searchParams.set(k, String(v));\n\t\t}\n\t}\n\treturn u.toString();\n}\n\nasync function readBody(\n\tres: Response,\n): Promise<{ parsed: unknown; text: string }> {\n\tconst text = await res.text();\n\tif (!text) return { parsed: null, text: \"\" };\n\ttry {\n\t\treturn { parsed: JSON.parse(text), text };\n\t} catch {\n\t\treturn { parsed: text, text };\n\t}\n}\n\nfunction coerceApiError(res: Response, parsed: unknown): ApiError {\n\tconst requestId = res.headers.get(\"x-request-id\") ?? undefined;\n\n\t// Expecting an error envelope like:\n\t// { error: { code, message, details } } OR { code, message, details }\n\tlet code: string | undefined;\n\tlet message = `Request failed with status ${res.status}`;\n\tlet details: unknown = parsed;\n\n\tif (typeof parsed === \"string\") {\n\t\tmessage = parsed;\n\t} else if (parsed && typeof parsed === \"object\") {\n\t\tconst p = parsed as Record<string, unknown>;\n\t\tconst err = (p.error ?? p) as unknown;\n\t\tif (err && typeof err === \"object\") {\n\t\t\tconst e = err as Record<string, unknown>;\n\t\t\tif (typeof e.message === \"string\") message = e.message;\n\t\t\tif (typeof e.code === \"string\") code = e.code;\n\t\t\tif (\"details\" in e) details = e.details;\n\t\t}\n\t}\n\n\tif (res.status === 401 || res.status === 403)\n\t\treturn new AuthError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\tif (res.status === 422)\n\t\treturn new ValidationError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\n\tif (res.status === 402 && code === \"insufficient_credits\") {\n\t\treturn new InsufficientCreditsError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails: details as { required?: number; available?: number },\n\t\t});\n\t}\n\n\tif (res.status === 429) {\n\t\tconst e = new RateLimitError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\t\tconst ra = res.headers.get(\"retry-after\");\n\t\tif (ra) {\n\t\t\tconst sec = Number(ra);\n\t\t\tif (Number.isFinite(sec) && sec >= 0) e.retryAfterMs = sec * 1000;\n\t\t}\n\t\treturn e;\n\t}\n\n\treturn new ApiError(message, {\n\t\tstatus: res.status,\n\t\trequestId,\n\t\tcode,\n\t\tdetails,\n\t});\n}\n\nfunction shouldRetry(\n\topts: RequestOptions,\n\terr: unknown,\n): { retry: boolean; retryAfterMs?: number } {\n\tif (!opts.retryable) return { retry: false };\n\n\t// Retry on RateLimitError / 5xx / network failures\n\tif (err instanceof RateLimitError)\n\t\treturn { retry: true, retryAfterMs: err.retryAfterMs };\n\tif (err instanceof ApiError)\n\t\treturn { retry: err.status >= 500 && err.status <= 599 };\n\t// fetch throws TypeError on network failure in many runtimes\n\tif (err instanceof TypeError) return { retry: true };\n\treturn { retry: false };\n}\n\nexport class Transport {\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(private readonly opts: TransportOptions) {\n\t\tthis.fetchImpl = opts.fetch ?? fetch;\n\t}\n\n\t/**\n\t * Stream SSE events from a given path.\n\t *\n\t * Uses native `fetch` with streaming response body (not browser-only `EventSource`).\n\t * Parses SSE format manually from the `ReadableStream`.\n\t */\n\tasync *streamSSE<T>(\n\t\tpath: string,\n\t\topts?: SSEStreamOptions,\n\t): AsyncGenerator<SSEEvent<T>> {\n\t\tconst url = buildUrl(this.opts.baseUrl, path);\n\t\tconst requestId = randomId(\"req\");\n\n\t\tconst headers: Record<string, string> = {\n\t\t\tAccept: \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\"Mappa-Api-Key\": this.opts.apiKey,\n\t\t\t\"X-Request-Id\": requestId,\n\t\t\t...(this.opts.userAgent ? { \"User-Agent\": this.opts.userAgent } : {}),\n\t\t\t...(this.opts.defaultHeaders ?? {}),\n\t\t};\n\n\t\tif (opts?.lastEventId) {\n\t\t\theaders[\"Last-Event-ID\"] = opts.lastEventId;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tconst timeout = setTimeout(\n\t\t\t() => controller.abort(makeAbortError()),\n\t\t\tthis.opts.timeoutMs,\n\t\t);\n\n\t\t// Combine signals: if caller aborts, abort our controller\n\t\tif (hasAbortSignal(opts?.signal)) {\n\t\t\tconst signal = opts?.signal;\n\t\t\tif (signal?.aborted) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthrow makeAbortError();\n\t\t\t}\n\t\t\tsignal?.addEventListener(\n\t\t\t\t\"abort\",\n\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t}\n\n\t\tthis.opts.telemetry?.onRequest?.({ method: \"GET\", url, requestId });\n\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await this.fetchImpl(url, {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders,\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: err });\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!res.ok) {\n\t\t\tclearTimeout(timeout);\n\t\t\tconst { parsed } = await readBody(res);\n\t\t\tconst apiErr = coerceApiError(res, parsed);\n\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: apiErr });\n\t\t\tthrow apiErr;\n\t\t}\n\n\t\tif (!res.body) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthrow new MappaError(\"SSE response has no body\");\n\t\t}\n\n\t\ttry {\n\t\t\tyield* this.parseSSEStream<T>(res.body);\n\t\t} finally {\n\t\t\tclearTimeout(timeout);\n\t\t}\n\t}\n\n\t/**\n\t * Parse SSE events from a ReadableStream.\n\t *\n\t * SSE format:\n\t * ```\n\t * id: <id>\n\t * event: <type>\n\t * data: <json>\n\t *\n\t * ```\n\t * Each event is terminated by an empty line.\n\t */\n\tprivate async *parseSSEStream<T>(\n\t\tbody: ReadableStream<Uint8Array>,\n\t): AsyncGenerator<SSEEvent<T>> {\n\t\tconst decoder = new TextDecoder();\n\t\tconst reader = body.getReader();\n\t\tlet buffer = \"\";\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\n\t\t\t\t// Process complete events (separated by double newline)\n\t\t\t\tconst events = buffer.split(\"\\n\\n\");\n\t\t\t\t// Keep the last incomplete chunk in buffer\n\t\t\t\tbuffer = events.pop() ?? \"\";\n\n\t\t\t\tfor (const eventText of events) {\n\t\t\t\t\tif (!eventText.trim()) continue;\n\n\t\t\t\t\tconst event = this.parseSSEEvent<T>(eventText);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tyield event;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process any remaining data in buffer\n\t\t\tif (buffer.trim()) {\n\t\t\t\tconst event = this.parseSSEEvent<T>(buffer);\n\t\t\t\tif (event) {\n\t\t\t\t\tyield event;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t}\n\n\t/**\n\t * Parse a single SSE event from text.\n\t */\n\tprivate parseSSEEvent<T>(text: string): SSEEvent<T> | null {\n\t\tconst lines = text.split(\"\\n\");\n\t\tlet id: string | undefined;\n\t\tlet event = \"message\"; // default event type per SSE spec\n\t\tlet data = \"\";\n\n\t\tfor (const line of lines) {\n\t\t\tif (line.startsWith(\"id:\")) {\n\t\t\t\tid = line.slice(3).trim();\n\t\t\t} else if (line.startsWith(\"event:\")) {\n\t\t\t\tevent = line.slice(6).trim();\n\t\t\t} else if (line.startsWith(\"data:\")) {\n\t\t\t\t// Append to data (SSE allows multiple data lines)\n\t\t\t\tif (data) data += \"\\n\";\n\t\t\t\tdata += line.slice(5).trim();\n\t\t\t}\n\t\t\t// Ignore retry: and comments (lines starting with :)\n\t\t}\n\n\t\tif (!data) return null;\n\n\t\tlet parsedData: T;\n\t\ttry {\n\t\t\tparsedData = JSON.parse(data) as T;\n\t\t} catch {\n\t\t\t// If data is not valid JSON, return it as-is (cast to T)\n\t\t\tparsedData = data as unknown as T;\n\t\t}\n\n\t\treturn { id, event, data: parsedData };\n\t}\n\n\tasync request<T>(req: RequestOptions): Promise<TransportResponse<T>> {\n\t\tconst url = buildUrl(this.opts.baseUrl, req.path, req.query);\n\n\t\tconst requestId = req.requestId ?? randomId(\"req\");\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Mappa-Api-Key\": this.opts.apiKey,\n\t\t\t\"X-Request-Id\": requestId,\n\t\t\t...(this.opts.userAgent ? { \"User-Agent\": this.opts.userAgent } : {}),\n\t\t\t...(this.opts.defaultHeaders ?? {}),\n\t\t};\n\n\t\tif (req.idempotencyKey) headers[\"Idempotency-Key\"] = req.idempotencyKey;\n\t\tif (req.headers) {\n\t\t\tfor (const [k, v] of Object.entries(req.headers)) {\n\t\t\t\tif (v !== undefined) headers[k] = v;\n\t\t\t}\n\t\t}\n\n\t\tconst isFormData =\n\t\t\ttypeof FormData !== \"undefined\" && req.body instanceof FormData;\n\t\tconst hasBody = req.body !== undefined;\n\n\t\tif (hasBody && !isFormData) headers[\"Content-Type\"] = \"application/json\";\n\n\t\tconst body =\n\t\t\treq.body === undefined\n\t\t\t\t? undefined\n\t\t\t\t: isFormData\n\t\t\t\t\t? (req.body as FormData)\n\t\t\t\t\t: JSON.stringify(req.body);\n\n\t\tconst maxRetries = Math.max(0, this.opts.maxRetries);\n\t\tconst startedAt = Date.now();\n\n\t\tfor (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n\t\t\tconst controller = new AbortController();\n\t\t\tconst timeout = setTimeout(\n\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\tthis.opts.timeoutMs,\n\t\t\t);\n\n\t\t\t// Combine signals: if caller aborts, abort our controller\n\t\t\tif (hasAbortSignal(req.signal)) {\n\t\t\t\tconst signal = req.signal;\n\t\t\t\tif (!signal) {\n\t\t\t\t\t// Type guard safety: hasAbortSignal should imply this is defined.\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthrow new Error(\"Unexpected: abort signal missing\");\n\t\t\t\t}\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthrow makeAbortError();\n\t\t\t\t}\n\t\t\t\tsignal.addEventListener(\n\t\t\t\t\t\"abort\",\n\t\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\t\t{ once: true },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.opts.telemetry?.onRequest?.({ method: req.method, url, requestId });\n\n\t\t\ttry {\n\t\t\t\tconst res = await this.fetchImpl(url, {\n\t\t\t\t\tmethod: req.method,\n\t\t\t\t\theaders,\n\t\t\t\t\tbody,\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\n\t\t\t\tconst durationMs = Date.now() - startedAt;\n\t\t\t\tconst serverRequestId =\n\t\t\t\t\tgetHeader(res.headers, \"x-request-id\") ?? requestId;\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst { parsed } = await readBody(res);\n\t\t\t\t\tconst apiErr = coerceApiError(res, parsed);\n\n\t\t\t\t\tthis.opts.telemetry?.onError?.({\n\t\t\t\t\t\turl,\n\t\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\t\terror: apiErr,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst decision = shouldRetry(req, apiErr);\n\t\t\t\t\tif (\n\t\t\t\t\t\tattempt <= maxRetries + 1 &&\n\t\t\t\t\t\tdecision.retry &&\n\t\t\t\t\t\tattempt <= maxRetries\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst base =\n\t\t\t\t\t\t\tdecision.retryAfterMs ?? jitter(backoffMs(attempt, 500, 4000));\n\t\t\t\t\t\tawait new Promise((r) => setTimeout(r, base));\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow apiErr;\n\t\t\t\t}\n\n\t\t\t\tconst ct = res.headers.get(\"content-type\") ?? \"\";\n\t\t\t\tlet data: unknown;\n\t\t\t\tif (ct.includes(\"application/json\")) {\n\t\t\t\t\tdata = (await res.json()) as unknown;\n\t\t\t\t} else {\n\t\t\t\t\tdata = await res.text();\n\t\t\t\t}\n\n\t\t\t\tthis.opts.telemetry?.onResponse?.({\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t\turl,\n\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\tdurationMs,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tdata: data as T,\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\theaders: res.headers,\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: err });\n\n\t\t\t\tconst decision = shouldRetry(req, err);\n\t\t\t\tif (attempt <= maxRetries && decision.retry) {\n\t\t\t\t\tconst sleep =\n\t\t\t\t\t\tdecision.retryAfterMs ?? jitter(backoffMs(attempt, 500, 4000));\n\t\t\t\t\tawait new Promise((r) => setTimeout(r, sleep));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t}\n\n\t\t// unreachable\n\t\tthrow new Error(\"Unexpected transport exit\");\n\t}\n}\n","function isObject(v: unknown): v is Record<string, unknown> {\n\treturn v !== null && typeof v === \"object\";\n}\n\n/**\n * Async signature verification using WebCrypto (works in modern Node and browsers).\n * Signature scheme placeholder:\n * headers[\"mappa-signature\"] = \"t=1700000000,v1=<hex_hmac_sha256>\"\n * Signed payload: `${t}.${rawBody}`\n */\n\nexport class WebhooksResource {\n\tasync verifySignature(params: {\n\t\tpayload: string; // raw body\n\t\theaders: Record<string, string | string[] | undefined>;\n\t\tsecret: string;\n\t\ttoleranceSec?: number;\n\t}): Promise<{ ok: true }> {\n\t\tconst tolerance = params.toleranceSec ?? 300;\n\n\t\tconst sigHeader = headerValue(params.headers, \"mappa-signature\");\n\t\tif (!sigHeader) throw new Error(\"Missing mappa-signature header\");\n\n\t\tconst parts = parseSig(sigHeader);\n\t\tconst ts = Number(parts.t);\n\t\tif (!Number.isFinite(ts)) throw new Error(\"Invalid signature timestamp\");\n\n\t\tconst nowSec = Math.floor(Date.now() / 1000);\n\t\tif (Math.abs(nowSec - ts) > tolerance)\n\t\t\tthrow new Error(\"Signature timestamp outside tolerance\");\n\n\t\tconst signed = `${parts.t}.${params.payload}`;\n\t\tconst expected = await hmacHex(params.secret, signed);\n\n\t\tif (!timingSafeEqualHex(expected, parts.v1))\n\t\t\tthrow new Error(\"Invalid signature\");\n\n\t\treturn { ok: true };\n\t}\n\n\tparseEvent<T = unknown>(\n\t\tpayload: string,\n\t): { id: string; type: string; createdAt: string; data: T } {\n\t\tconst raw: unknown = JSON.parse(payload);\n\t\tif (!isObject(raw))\n\t\t\tthrow new Error(\"Invalid webhook payload: not an object\");\n\t\tconst obj = raw;\n\n\t\tconst id = obj.id;\n\t\tconst type = obj.type;\n\t\tconst createdAt = obj.createdAt;\n\n\t\tif (typeof id !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: id must be a string\");\n\t\tif (typeof type !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: type must be a string\");\n\t\tif (typeof createdAt !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: createdAt must be a string\");\n\n\t\treturn {\n\t\t\tid,\n\t\t\ttype,\n\t\t\tcreatedAt,\n\t\t\tdata: \"data\" in obj ? (obj.data as T) : (undefined as unknown as T),\n\t\t};\n\t}\n}\n\nfunction headerValue(\n\theaders: Record<string, string | string[] | undefined>,\n\tname: string,\n): string | undefined {\n\tconst key = Object.keys(headers).find(\n\t\t(k) => k.toLowerCase() === name.toLowerCase(),\n\t);\n\tconst v = key ? headers[key] : undefined;\n\tif (!v) return undefined;\n\treturn Array.isArray(v) ? v[0] : v;\n}\n\nfunction parseSig(h: string): { t: string; v1: string } {\n\tconst out: Record<string, string> = {};\n\tfor (const part of h.split(\",\")) {\n\t\tconst [k, v] = part.split(\"=\");\n\t\tif (k && v) out[k.trim()] = v.trim();\n\t}\n\tif (!out.t || !out.v1) throw new Error(\"Invalid signature format\");\n\treturn { t: out.t, v1: out.v1 };\n}\n\nasync function hmacHex(secret: string, message: string): Promise<string> {\n\tconst enc = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tenc.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst sig = await crypto.subtle.sign(\"HMAC\", key, enc.encode(message));\n\treturn bufToHex(sig);\n}\n\nfunction bufToHex(buf: ArrayBuffer): string {\n\tconst b = new Uint8Array(buf);\n\tlet s = \"\";\n\tfor (const x of b) s += x.toString(16).padStart(2, \"0\");\n\treturn s;\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n\tif (a.length !== b.length) return false;\n\tlet r = 0;\n\tfor (let i = 0; i < a.length; i++) r |= a.charCodeAt(i) ^ b.charCodeAt(i);\n\treturn r === 0;\n}\n","import { MappaError } from \"$/errors\";\nimport { CreditsResource } from \"$/resources/credits\";\nimport { EntitiesResource } from \"$/resources/entities\";\nimport { FeedbackResource } from \"$/resources/feedback\";\nimport { FilesResource } from \"$/resources/files\";\nimport { HealthResource } from \"$/resources/health\";\nimport { JobsResource } from \"$/resources/jobs\";\nimport { ReportsResource } from \"$/resources/reports\";\nimport { type Telemetry, Transport } from \"$/resources/transport\";\nimport { WebhooksResource } from \"$/resources/webhooks\";\n\n/**\n * Options for constructing a {@link Mappa} client.\n */\nexport type MappaClientOptions = {\n\t/**\n\t * API key used for authenticating requests.\n\t */\n\tapiKey: string;\n\n\t/**\n\t * Base URL for the Mappa API.\n\t *\n\t * @defaultValue \"https://api.mappa.ai\"\n\t */\n\tbaseUrl?: string;\n\n\t/**\n\t * Per-request timeout, in milliseconds.\n\t *\n\t * Note: this timeout applies to individual HTTP attempts (including retries).\n\t * Long-running workflows should use {@link JobsResource.wait} through\n\t * {@link ReportsResource.makeHandle} instead.\n\t *\n\t * @defaultValue 30000\n\t */\n\ttimeoutMs?: number;\n\n\t/**\n\t * Maximum number of retries performed by the transport for retryable requests.\n\t *\n\t * @defaultValue 2\n\t */\n\tmaxRetries?: number;\n\n\t/**\n\t * Headers that will be sent with every request.\n\t */\n\tdefaultHeaders?: Record<string, string>;\n\n\t/**\n\t * Custom fetch implementation (useful for polyfills, instrumentation, or tests).\n\t */\n\tfetch?: typeof fetch;\n\n\t/**\n\t * Overrides the User-Agent header.\n\t */\n\tuserAgent?: string;\n\n\t/**\n\t * Telemetry hooks called on request/response/error.\n\t */\n\ttelemetry?: Telemetry;\n};\n\n/**\n * Main SDK client.\n *\n * Exposes resource namespaces ({@link Mappa.files}, {@link Mappa.reports}, etc.)\n * and configures a shared HTTP transport.\n */\nexport class Mappa {\n\tpublic readonly files: FilesResource;\n\tpublic readonly jobs: JobsResource;\n\tpublic readonly reports: ReportsResource;\n\tpublic readonly feedback: FeedbackResource;\n\tpublic readonly credits: CreditsResource;\n\tpublic readonly entities: EntitiesResource;\n\tpublic readonly webhooks: WebhooksResource;\n\tpublic readonly health: HealthResource;\n\n\tprivate readonly transport: Transport;\n\tprivate readonly opts: Required<\n\t\tPick<MappaClientOptions, \"apiKey\" | \"baseUrl\" | \"timeoutMs\" | \"maxRetries\">\n\t> &\n\t\tOmit<MappaClientOptions, \"apiKey\" | \"baseUrl\" | \"timeoutMs\" | \"maxRetries\">;\n\n\tconstructor(options: MappaClientOptions) {\n\t\tif (!options.apiKey) {\n\t\t\tthrow new MappaError(\"apiKey is required\");\n\t\t}\n\n\t\tconst baseUrl = options.baseUrl ?? \"https://api.mappa.ai\";\n\t\tconst timeoutMs = options.timeoutMs ?? 30_000;\n\t\tconst maxRetries = options.maxRetries ?? 2;\n\n\t\tthis.opts = {\n\t\t\t...options,\n\t\t\tapiKey: options.apiKey,\n\t\t\tbaseUrl,\n\t\t\ttimeoutMs,\n\t\t\tmaxRetries,\n\t\t};\n\n\t\tthis.transport = new Transport({\n\t\t\tapiKey: options.apiKey,\n\t\t\tbaseUrl,\n\t\t\ttimeoutMs,\n\t\t\tmaxRetries,\n\t\t\tdefaultHeaders: options.defaultHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\ttelemetry: options.telemetry,\n\t\t\tuserAgent: options.userAgent,\n\t\t});\n\n\t\tthis.files = new FilesResource(this.transport);\n\t\tthis.jobs = new JobsResource(this.transport);\n\t\tthis.reports = new ReportsResource(\n\t\t\tthis.transport,\n\t\t\tthis.jobs,\n\t\t\tthis.files,\n\t\t\tthis.opts.fetch ?? fetch,\n\t\t);\n\t\tthis.feedback = new FeedbackResource(this.transport);\n\t\tthis.credits = new CreditsResource(this.transport);\n\t\tthis.entities = new EntitiesResource(this.transport);\n\t\tthis.webhooks = new WebhooksResource();\n\t\tthis.health = new HealthResource(this.transport);\n\t}\n\n\twithOptions(overrides: Partial<MappaClientOptions>): Mappa {\n\t\treturn new Mappa({\n\t\t\t...this.opts,\n\t\t\t...overrides,\n\t\t\tapiKey: overrides.apiKey ?? this.opts.apiKey,\n\t\t});\n\t}\n\n\tclose(): void {\n\t\t// No-op today; reserved for future transport cleanup (keep-alive, SSE, etc.).\n\t}\n}\n","/**\n * JSON-serializable value.\n *\n * Used throughout the SDK for message payloads, webhook data, and server-provided\n * metadata where the exact shape is not known at compile time.\n */\nexport type JsonValue =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| { [k: string]: JsonValue }\n\t| JsonValue[];\n\nexport type MediaRef =\n\t| { url: string; contentType?: string; filename?: string }\n\t| { mediaId: string };\n\n/**\n * A reference to an already-uploaded media object.\n */\nexport type MediaIdRef = { mediaId: string };\n\nexport type ReportTemplateId =\n\t| \"sales_playbook\"\n\t| \"general_report\"\n\t| \"hiring_report\"\n\t| \"profile_alignment\";\n\nexport type ReportTemplateParamsMap = {\n\tsales_playbook: Record<string, never>;\n\tgeneral_report: Record<string, never>;\n\thiring_report: {\n\t\troleTitle: string;\n\t\troleDescription: string;\n\t\tcompanyCulture: string;\n\t};\n\tprofile_alignment: {\n\t\tidealProfile: string;\n\t};\n};\n\nexport type ReportOutputType = \"markdown\" | \"json\" | \"pdf\" | \"url\";\n\ntype ReportOutputEntry<\n\tOutputType extends ReportOutputType,\n\tTemplate extends ReportTemplateId,\n> = ReportTemplateParamsMap[Template] extends Record<string, never>\n\t? {\n\t\t\ttype: OutputType;\n\t\t\ttemplate: Template;\n\t\t\ttemplateParams?: ReportTemplateParamsMap[Template];\n\t\t}\n\t: {\n\t\t\ttype: OutputType;\n\t\t\ttemplate: Template;\n\t\t\ttemplateParams: ReportTemplateParamsMap[Template];\n\t\t};\n\ntype ReportOutputForType<OutputType extends ReportOutputType> =\n\t| ReportOutputEntry<OutputType, \"sales_playbook\">\n\t| ReportOutputEntry<OutputType, \"general_report\">\n\t| ReportOutputEntry<OutputType, \"hiring_report\">\n\t| ReportOutputEntry<OutputType, \"profile_alignment\">;\n\nexport type ReportOutput =\n\t| ReportOutputForType<\"markdown\">\n\t| ReportOutputForType<\"json\">\n\t| ReportOutputForType<\"pdf\">\n\t| ReportOutputForType<\"url\">;\n\nexport type TargetStrategy =\n\t| \"dominant\"\n\t| \"timerange\"\n\t| \"entity_id\"\n\t| \"magic_hint\";\n\nexport type TargetOnMiss = \"fallback_dominant\" | \"error\";\n\nexport type TargetTimeRange = {\n\t/**\n\t * Start time in seconds.\n\t * When omitted, starts from the beginning.\n\t */\n\tstartSeconds?: number;\n\t/**\n\t * End time in seconds.\n\t * When omitted, goes until the end.\n\t */\n\tendSeconds?: number;\n};\n\ntype TargetBase = {\n\t/**\n\t * Behavior when the entity is not found.\n\t */\n\tonMiss?: TargetOnMiss;\n\t/**\n\t * Tags to apply to the selected entity after job completion.\n\t *\n\t * Tags must be 1-64 characters, alphanumeric with underscores and hyphens only.\n\t * Maximum 10 tags per request.\n\t *\n\t * @example [\"interviewer\", \"sales-rep\", \"round-1\"]\n\t */\n\ttags?: string[];\n\t/**\n\t * Exclude speakers whose entities have ANY of these tags from selection.\n\t *\n\t * Useful for filtering out known interviewers, hosts, etc.\n\t *\n\t * @example [\"interviewer\", \"host\"]\n\t */\n\texcludeTags?: string[];\n};\n\nexport type TargetDominant = TargetBase & {\n\tstrategy: \"dominant\";\n};\n\nexport type TargetTimeRangeStrategy = TargetBase & {\n\tstrategy: \"timerange\";\n\ttimeRange: TargetTimeRange;\n};\n\nexport type TargetEntityId = TargetBase & {\n\tstrategy: \"entity_id\";\n\tentityId: string;\n};\n\nexport type TargetMagicHint = TargetBase & {\n\tstrategy: \"magic_hint\";\n\thint: string;\n};\n\nexport type TargetSelector =\n\t| TargetDominant\n\t| TargetTimeRangeStrategy\n\t| TargetEntityId\n\t| TargetMagicHint;\n\nexport type TargetStrategyMap = {\n\tdominant: TargetDominant;\n\ttimerange: TargetTimeRangeStrategy;\n\tentity_id: TargetEntityId;\n\tmagic_hint: TargetMagicHint;\n};\n\nexport type TargetFor<Strategy extends TargetStrategy> =\n\tTargetStrategyMap[Strategy];\n\nexport type Usage = {\n\tcreditsUsed: number;\n\tcreditsDiscounted?: number;\n\tcreditsNetUsed: number;\n\tdurationMs?: number;\n\tmodelVersion?: string;\n};\n\nexport type JobStage =\n\t| \"uploaded\"\n\t| \"queued\"\n\t| \"transcoding\"\n\t| \"extracting\"\n\t| \"scoring\"\n\t| \"rendering\"\n\t| \"finalizing\";\n\nexport type JobStatus =\n\t| \"queued\"\n\t| \"running\"\n\t| \"succeeded\"\n\t| \"failed\"\n\t| \"canceled\";\n\nexport type JobCreditReservation = {\n\treservedCredits: number | null;\n\treservationStatus: \"active\" | \"released\" | \"applied\" | null;\n};\n\nexport type Job = {\n\tid: string;\n\ttype: \"report.generate\";\n\tstatus: JobStatus;\n\tstage?: JobStage;\n\tprogress?: number; // 0..1\n\tcreatedAt: string;\n\tupdatedAt: string;\n\treportId?: string;\n\tusage?: Usage;\n\tcredits?: JobCreditReservation;\n\treleasedCredits?: number | null;\n\terror?: {\n\t\tcode: string;\n\t\tmessage: string;\n\t\tdetails?: JsonValue;\n\t\tretryable?: boolean;\n\t};\n\trequestId?: string;\n};\n\nexport type JobEvent =\n\t| { type: \"status\"; job: Job }\n\t| { type: \"stage\"; stage: JobStage; progress?: number; job: Job }\n\t| { type: \"log\"; message: string; ts: string }\n\t| { type: \"terminal\"; job: Job };\n\nexport type Subject = {\n\tid?: string;\n\texternalRef?: string;\n\tmetadata?: Record<string, JsonValue>;\n};\n\nexport type WebhookConfig = {\n\turl: string;\n\theaders?: Record<string, string>;\n};\n\nexport type ReportCreateJobRequest = {\n\tsubject?: Subject;\n\t/**\n\t * Reference to already-uploaded media.\n\t *\n\t * Note: Report job creation requires a `mediaId`. To start from a remote URL or local bytes,\n\t * use helper methods like `reports.createJobFromUrl()` / `reports.createJobFromFile()`.\n\t */\n\tmedia: MediaIdRef;\n\toutput: ReportOutput;\n\t/**\n\t * Select the target entity for analysis.\n\t *\n\t * @defaultValue `{ strategy: \"dominant\" }` - analyzes the dominant speaker\n\t */\n\ttarget?: TargetSelector;\n\toptions?: {\n\t\tlanguage?: string;\n\t\ttimezone?: string;\n\t\tincludeMetrics?: boolean;\n\t\tincludeRawModelOutput?: boolean;\n\t};\n\t/**\n\t * Webhook to call when the job completes or fails.\n\t *\n\t * @example\n\t * webhook: {\n\t * url: \"https://example.com/webhooks/mappa\",\n\t * headers: { \"X-Custom-Header\": \"value\" }\n\t * }\n\t */\n\twebhook?: WebhookConfig;\n\tidempotencyKey?: string;\n\trequestId?: string;\n};\n\nexport type ReportBase = {\n\tid: string;\n\tcreatedAt: string;\n\tjobId?: string;\n\tsubject?: Subject;\n\tmedia: { url?: string; mediaId?: string };\n\tentity: {\n\t\tid: string;\n\t\ttags: string[];\n\t};\n\tusage?: Usage;\n\tmetrics?: Record<string, JsonValue>;\n\traw?: JsonValue;\n};\n\nexport type MarkdownReport = ReportBase & {\n\toutput: { type: \"markdown\"; template: ReportTemplateId };\n\tmarkdown: string;\n};\n\nexport type JsonReport = ReportBase & {\n\toutput: { type: \"json\"; template: ReportTemplateId };\n\tsections: Array<{\n\t\tsection_title: string;\n\t\tsection_content: JsonValue;\n\t}>;\n};\n\nexport type PdfReport = ReportBase & {\n\toutput: { type: \"pdf\"; template: ReportTemplateId };\n\tmarkdown: string;\n\tpdfUrl: string;\n};\n\nexport type UrlReport = ReportBase & {\n\toutput: { type: \"url\"; template: ReportTemplateId };\n\tmarkdown: string;\n\tsections: Array<{\n\t\tsection_title: string;\n\t\tsection_content: JsonValue;\n\t}>;\n\treportUrl: string;\n};\n\nexport type Report = MarkdownReport | JsonReport | PdfReport | UrlReport;\n\nexport type ReportJobReceipt = {\n\tjobId: string;\n\tstatus: \"queued\" | \"running\";\n\tstage?: JobStage;\n\testimatedWaitSec?: number;\n\trequestId?: string;\n\thandle?: ReportRunHandle;\n};\n\nexport type FeedbackReceipt = {\n\tid: string;\n\tcreatedAt: string;\n\ttarget: { reportId?: string; jobId?: string };\n\trating: \"thumbs_up\" | \"thumbs_down\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\";\n\ttags?: string[];\n\tcomment?: string;\n\tcredits: {\n\t\teligible: boolean;\n\t\treason?: string;\n\t\tdiscountApplied: number;\n\t\tnetUsed: number;\n\t};\n};\n\nexport type MediaObject = {\n\tmediaId: string;\n\tcreatedAt: string;\n\tcontentType: string;\n\tfilename?: string;\n\tsizeBytes?: number;\n};\n\nexport type MediaProcessingStatus =\n\t| \"PENDING\"\n\t| \"PROCESSING\"\n\t| \"COMPLETED\"\n\t| \"FAILED\";\n\nexport type MediaRetention = {\n\texpiresAt: string | null;\n\tdaysRemaining: number | null;\n\tlocked: boolean;\n};\n\nexport type MediaFile = {\n\tmediaId: string;\n\tcreatedAt: string;\n\tcontentType: string;\n\tfilename: string | null;\n\tsizeBytes: number | null;\n\tdurationSeconds: number | null;\n\tprocessingStatus: MediaProcessingStatus;\n\tlastUsedAt: string | null;\n\tretention: MediaRetention;\n};\n\nexport type FileDeleteReceipt = {\n\tmediaId: string;\n\tdeleted: true;\n};\n\nexport type RetentionLockResult = {\n\tmediaId: string;\n\tretentionLock: boolean;\n\tmessage: string;\n};\n\nexport type CursorPaginationParams = {\n\tlimit?: number;\n\tcursor?: string;\n};\n\nexport type OffsetPaginationParams = {\n\tlimit?: number;\n\toffset?: number;\n};\n\nexport type CursorPage<T> = {\n\tdata: T[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\nexport type OffsetPage<T> = {\n\tdata: T[];\n\tpagination: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\ttotal: number;\n\t};\n};\n\nexport type CreditBalance = {\n\tbalance: number;\n\treserved: number;\n\tavailable: number;\n};\n\nexport type CreditTransactionType =\n\t| \"PURCHASE\"\n\t| \"SUBSCRIPTION_GRANT\"\n\t| \"PROMO_GRANT\"\n\t| \"USAGE\"\n\t| \"REFUND\"\n\t| \"FEEDBACK_DISCOUNT\"\n\t| \"ADJUSTMENT\"\n\t| \"EXPIRATION\";\n\nexport type CreditTransaction = {\n\tid: string;\n\ttype: CreditTransactionType;\n\tamount: number;\n\tcreatedAt: string;\n\teffectiveAt: string;\n\texpiresAt: string | null;\n\tjobId: string | null;\n\tjob?: {\n\t\tid: string;\n\t\tstatus: string;\n\t\tcreatedAt: string;\n\t};\n};\n\nexport type CreditUsage = {\n\tjobId: string;\n\tcreditsUsed: number;\n\tcreditsDiscounted?: number;\n\tcreditsNetUsed: number;\n\tdurationMs?: number;\n\tmodelVersion?: string;\n};\n\n/**\n * Options for waiting on job completion.\n */\nexport type WaitOptions = {\n\t/**\n\t * Maximum time to wait before failing.\n\t *\n\t * @defaultValue 300000\n\t */\n\ttimeoutMs?: number;\n\n\t/**\n\t * Optional callback invoked on meaningful job state transitions.\n\t */\n\tonEvent?: (event: JobEvent) => void;\n\n\t/**\n\t * Abort signal used to cancel waiting.\n\t */\n\tsignal?: AbortSignal;\n};\n\n// Forward decl to avoid circular imports; implemented in reports resource.\nexport type ReportRunHandle = {\n\tjobId: string;\n\tstream(opts?: {\n\t\tsignal?: AbortSignal;\n\t\tonEvent?: (e: JobEvent) => void;\n\t}): AsyncIterable<JobEvent>;\n\twait(opts?: WaitOptions): Promise<Report>;\n\tcancel(): Promise<Job>;\n\tjob(): Promise<Job>;\n\treport(): Promise<Report | null>;\n};\n\n/**\n * Type guard for MarkdownReport.\n */\nexport function isMarkdownReport(report: Report): report is MarkdownReport {\n\treturn report.output.type === \"markdown\";\n}\n\n/**\n * Type guard for JsonReport.\n */\nexport function isJsonReport(report: Report): report is JsonReport {\n\treturn report.output.type === \"json\";\n}\n\n/**\n * Type guard for PdfReport.\n */\nexport function isPdfReport(report: Report): report is PdfReport {\n\treturn report.output.type === \"pdf\";\n}\n\n/**\n * Type guard for UrlReport.\n */\nexport function isUrlReport(report: Report): report is UrlReport {\n\treturn report.output.type === \"url\";\n}\n\nexport type Entity = {\n\tid: string;\n\ttags: string[];\n\tcreatedAt: string;\n\tmediaCount: number;\n\tlastSeenAt: string | null;\n};\n\nexport type EntityTagsResult = {\n\tentityId: string;\n\ttags: string[];\n};\n\nexport type ListEntitiesOptions = CursorPaginationParams & {\n\t/**\n\t * Filter entities by tags.\n\t * Entities must have ALL specified tags (AND logic).\n\t */\n\ttags?: string[];\n};\n\nexport type ListEntitiesResponse = {\n\tentities: Entity[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\n/**\n * Type guard to check if a report has entity information.\n * Always returns true since entity is always present in reports.\n */\nexport function hasEntity(report: Report): report is Report & {\n\tentity: { id: string; tags: string[] };\n} {\n\treturn report.entity !== undefined && report.entity !== null;\n}\n","/**\n * Mappa Node SDK\n *\n * This module is the public entrypoint for the package. It re-exports:\n * - {@link Mappa} (the main client)\n * - Error types from {@link \"$/errors\"}\n * - Public TypeScript types from {@link \"$/types\"}\n */\nexport * from \"$/errors\";\nexport { Mappa } from \"$/Mappa\";\nexport type * from \"$/types\";\nexport {\n\thasEntity,\n\tisJsonReport,\n\tisMarkdownReport,\n\tisPdfReport,\n\tisUrlReport,\n} from \"$/types\";\n\nimport { InsufficientCreditsError, MappaError } from \"$/errors\";\n\n/**\n * Type guard for catching SDK errors.\n */\nexport function isMappaError(err: unknown): err is MappaError {\n\treturn err instanceof MappaError;\n}\n\n/**\n * Type guard for insufficient credits errors.\n *\n * @example\n * ```typescript\n * try {\n * await mappa.reports.createJob({ ... });\n * } catch (err) {\n * if (isInsufficientCreditsError(err)) {\n * console.log(`Need ${err.required} credits, have ${err.available}`);\n * }\n * }\n * ```\n */\nexport function isInsufficientCreditsError(\n\terr: unknown,\n): err is InsufficientCreditsError {\n\treturn err instanceof InsufficientCreditsError;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["jitter"],"sources":["../src/errors.ts","../src/resources/credits.ts","../src/resources/entities.ts","../src/resources/feedback.ts","../src/resources/files.ts","../src/resources/health.ts","../src/utils/index.ts","../src/resources/jobs.ts","../src/resources/reports.ts","../src/resources/transport.ts","../src/resources/webhooks.ts","../src/Mappa.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["/**\n * Symbol for custom Node.js inspect formatting.\n * Ensures errors display nicely in console.log, REPL, and debuggers.\n */\nconst customInspect = Symbol.for(\"nodejs.util.inspect.custom\");\n\n/**\n * Formats error details for display.\n */\nfunction formatDetails(details: unknown, indent = \" \"): string {\n\tif (details === undefined || details === null) return \"\";\n\ttry {\n\t\tconst json = JSON.stringify(details, null, 2);\n\t\t// Indent each line for nested display\n\t\treturn json.split(\"\\n\").join(`\\n${indent}`);\n\t} catch {\n\t\treturn String(details);\n\t}\n}\n\n/**\n * Base error type for all SDK-raised errors.\n *\n * When available, {@link MappaError.requestId} can be used to correlate a failure\n * with server logs/support.\n */\nexport class MappaError extends Error {\n\toverride name = \"MappaError\";\n\trequestId?: string;\n\tcode?: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts?: { requestId?: string; code?: string; cause?: unknown },\n\t) {\n\t\tsuper(message);\n\t\tthis.requestId = opts?.requestId;\n\t\tthis.code = opts?.code;\n\t\tthis.cause = opts?.cause;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\t[customInspect](): string {\n\t\treturn this.toString();\n\t}\n}\n\n/**\n * Error returned when the API responds with a non-2xx status.\n */\nexport class ApiError extends MappaError {\n\toverride name = \"ApiError\";\n\tstatus: number;\n\tdetails?: unknown;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts: {\n\t\t\tstatus: number;\n\t\t\trequestId?: string;\n\t\t\tcode?: string;\n\t\t\tdetails?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message, { requestId: opts.requestId, code: opts.code });\n\t\tthis.status = opts.status;\n\t\tthis.details = opts.details;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\tif (this.details !== undefined && this.details !== null) {\n\t\t\tlines.push(` Details: ${formatDetails(this.details)}`);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error returned for HTTP 429 responses.\n *\n * If provided by the server, {@link RateLimitError.retryAfterMs} indicates when\n * it is safe to retry.\n */\nexport class RateLimitError extends ApiError {\n\toverride name = \"RateLimitError\";\n\tretryAfterMs?: number;\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tif (this.retryAfterMs !== undefined) {\n\t\t\tlines.push(` Retry After: ${this.retryAfterMs}ms`);\n\t\t}\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error returned for authentication/authorization failures (typically 401/403).\n */\nexport class AuthError extends ApiError {\n\toverride name = \"AuthError\";\n}\n\n/**\n * Error returned when the server rejects a request as invalid (typically 422).\n */\nexport class ValidationError extends ApiError {\n\toverride name = \"ValidationError\";\n}\n\n/**\n * Error returned when the account lacks sufficient credits (HTTP 402).\n *\n * Use {@link InsufficientCreditsError.required} and {@link InsufficientCreditsError.available}\n * to inform users how many credits are needed.\n *\n * @example\n * ```typescript\n * try {\n * await mappa.reports.createJob({ ... });\n * } catch (err) {\n * if (err instanceof InsufficientCreditsError) {\n * console.log(`Need ${err.required} credits, have ${err.available}`);\n * }\n * }\n * ```\n */\nexport class InsufficientCreditsError extends ApiError {\n\toverride name = \"InsufficientCreditsError\";\n\t/** Credits required for the operation */\n\trequired: number;\n\t/** Credits currently available */\n\tavailable: number;\n\n\tconstructor(\n\t\tmessage: string,\n\t\topts: {\n\t\t\tstatus: number;\n\t\t\trequestId?: string;\n\t\t\tcode?: string;\n\t\t\tdetails?: { required?: number; available?: number };\n\t\t},\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.required = opts.details?.required ?? 0;\n\t\tthis.available = opts.details?.available ?? 0;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Status: ${this.status}`);\n\t\tlines.push(` Required: ${this.required} credits`);\n\t\tlines.push(` Available: ${this.available} credits`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error thrown by polling helpers when a job reaches the \"failed\" terminal state.\n */\nexport class JobFailedError extends MappaError {\n\toverride name = \"JobFailedError\";\n\tjobId: string;\n\n\tconstructor(\n\t\tjobId: string,\n\t\tmessage: string,\n\t\topts?: { requestId?: string; code?: string; cause?: unknown },\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.jobId = jobId;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Job ID: ${this.jobId}`);\n\t\tif (this.code) lines.push(` Code: ${this.code}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/**\n * Error thrown by polling helpers when a job reaches the \"canceled\" terminal state.\n */\nexport class JobCanceledError extends MappaError {\n\toverride name = \"JobCanceledError\";\n\tjobId: string;\n\n\tconstructor(\n\t\tjobId: string,\n\t\tmessage: string,\n\t\topts?: { requestId?: string; cause?: unknown },\n\t) {\n\t\tsuper(message, opts);\n\t\tthis.jobId = jobId;\n\t}\n\n\toverride toString(): string {\n\t\tconst lines = [`${this.name}: ${this.message}`];\n\t\tlines.push(` Job ID: ${this.jobId}`);\n\t\tif (this.requestId) lines.push(` Request ID: ${this.requestId}`);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type { CreditBalance, CreditTransaction, CreditUsage } from \"$/types\";\n\nexport type ListTransactionsOptions = {\n\t/** Max transactions per page (1-100, default 50) */\n\tlimit?: number;\n\t/** Offset for pagination (default 0) */\n\toffset?: number;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListTransactionsResponse = {\n\ttransactions: CreditTransaction[];\n\tpagination: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\ttotal: number;\n\t};\n};\n\n/**\n * Credits API resource.\n *\n * Provides methods to manage and query credit balances, transaction history,\n * and job-specific credit usage.\n */\nexport class CreditsResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Get the current credit balance for your team.\n\t *\n\t * @example\n\t * const balance = await mappa.credits.getBalance();\n\t * console.log(`Available: ${balance.available} credits`);\n\t */\n\tasync getBalance(opts?: {\n\t\trequestId?: string;\n\t\tsignal?: AbortSignal;\n\t}): Promise<CreditBalance> {\n\t\tconst res = await this.transport.request<CreditBalance>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/credits/balance\",\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List credit transactions with offset pagination.\n\t *\n\t * @example\n\t * const { transactions, pagination } = await mappa.credits.listTransactions({ limit: 25 });\n\t * console.log(`Showing ${transactions.length} of ${pagination.total}`);\n\t */\n\tasync listTransactions(\n\t\topts?: ListTransactionsOptions,\n\t): Promise<ListTransactionsResponse> {\n\t\tconst query: Record<string, string> = {};\n\t\tif (opts?.limit !== undefined) query.limit = String(opts.limit);\n\t\tif (opts?.offset !== undefined) query.offset = String(opts.offset);\n\n\t\tconst res = await this.transport.request<ListTransactionsResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/credits/transactions\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Iterate over all transactions, automatically handling pagination.\n\t *\n\t * @example\n\t * for await (const tx of mappa.credits.listAllTransactions()) {\n\t * console.log(`${tx.type}: ${tx.amount}`);\n\t * }\n\t */\n\tasync *listAllTransactions(\n\t\topts?: Omit<ListTransactionsOptions, \"offset\">,\n\t): AsyncIterable<CreditTransaction> {\n\t\tlet offset = 0;\n\t\tconst limit = opts?.limit ?? 50;\n\n\t\twhile (true) {\n\t\t\tconst page = await this.listTransactions({ ...opts, limit, offset });\n\t\t\tfor (const tx of page.transactions) {\n\t\t\t\tyield tx;\n\t\t\t}\n\n\t\t\toffset += page.transactions.length;\n\t\t\tif (offset >= page.pagination.total) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get credit usage details for a completed job.\n\t *\n\t * @example\n\t * const usage = await mappa.credits.getJobUsage(\"job_xyz\");\n\t * console.log(`Net credits used: ${usage.creditsNetUsed}`);\n\t */\n\tasync getJobUsage(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<CreditUsage> {\n\t\tif (!jobId) throw new MappaError(\"jobId is required\");\n\n\t\tconst res = await this.transport.request<CreditUsage>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/credits/usage/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Check if the team has enough available credits for an operation.\n\t *\n\t * @example\n\t * if (await mappa.credits.hasEnough(100)) {\n\t * await mappa.reports.createJob(...);\n\t * }\n\t */\n\tasync hasEnough(\n\t\tcredits: number,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<boolean> {\n\t\tconst balance = await this.getBalance(opts);\n\t\treturn balance.available >= credits;\n\t}\n\n\t/**\n\t * Get the number of available credits (balance - reserved).\n\t *\n\t * @example\n\t * const available = await mappa.credits.getAvailable();\n\t * console.log(`You can spend ${available} credits`);\n\t */\n\tasync getAvailable(opts?: {\n\t\trequestId?: string;\n\t\tsignal?: AbortSignal;\n\t}): Promise<number> {\n\t\tconst balance = await this.getBalance(opts);\n\t\treturn balance.available;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tEntity,\n\tEntityTagsResult,\n\tListEntitiesOptions,\n\tListEntitiesResponse,\n} from \"$/types\";\n\n/**\n * Tag validation regex: 1-64 chars, alphanumeric with underscores and hyphens.\n */\nconst TAG_REGEX = /^[a-zA-Z0-9_-]{1,64}$/;\n\n/**\n * Maximum number of tags per request.\n */\nconst MAX_TAGS_PER_REQUEST = 10;\n\n/**\n * Validates a single tag.\n * @throws {MappaError} if validation fails\n */\nfunction validateTag(tag: string): void {\n\tif (typeof tag !== \"string\") {\n\t\tthrow new MappaError(\"Tags must be strings\");\n\t}\n\tif (!TAG_REGEX.test(tag)) {\n\t\tthrow new MappaError(\n\t\t\t`Invalid tag \"${tag}\": must be 1-64 characters, alphanumeric with underscores and hyphens only`,\n\t\t);\n\t}\n}\n\n/**\n * Validates an array of tags.\n * @throws {MappaError} if validation fails\n */\nfunction validateTags(tags: string[]): void {\n\tif (!Array.isArray(tags)) {\n\t\tthrow new MappaError(\"tags must be an array\");\n\t}\n\tif (tags.length > MAX_TAGS_PER_REQUEST) {\n\t\tthrow new MappaError(\n\t\t\t`Too many tags: maximum ${MAX_TAGS_PER_REQUEST} per request`,\n\t\t);\n\t}\n\tfor (const tag of tags) {\n\t\tvalidateTag(tag);\n\t}\n}\n\n/**\n * Entities API resource.\n *\n * Responsibilities:\n * - List entities with optional tag filtering (`GET /v1/entities`)\n * - Get single entity details (`GET /v1/entities/:entityId`)\n * - Add tags to entities (`POST /v1/entities/:entityId/tags`)\n * - Remove tags from entities (`DELETE /v1/entities/:entityId/tags`)\n * - Replace all entity tags (`PUT /v1/entities/:entityId/tags`)\n *\n * Entities represent analyzed speakers identified by voice fingerprints.\n * Tags allow you to label entities (e.g., \"interviewer\", \"sales-rep\") for easier\n * filtering and identification across multiple reports.\n */\nexport class EntitiesResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Get a single entity by ID.\n\t *\n\t * Returns entity metadata including tags, creation time, and usage statistics.\n\t *\n\t * @param entityId - The entity ID to retrieve\n\t * @param opts - Optional request options (requestId, signal)\n\t * @returns Entity details with tags and metadata\n\t *\n\t * @example\n\t * ```typescript\n\t * const entity = await mappa.entities.get(\"entity_abc123\");\n\t * console.log(entity.tags); // [\"interviewer\", \"john\"]\n\t * ```\n\t */\n\tasync get(\n\t\tentityId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Entity> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\n\t\tconst res = await this.transport.request<Entity>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List entities with optional tag filtering.\n\t *\n\t * Supports cursor-based pagination. Use the returned `cursor` for fetching\n\t * subsequent pages, or use {@link listAll} for automatic pagination.\n\t *\n\t * When `tags` is provided, only entities with ALL specified tags are returned (AND logic).\n\t *\n\t * @param opts - List options: tags filter, cursor, limit\n\t * @returns Paginated list of entities\n\t *\n\t * @example\n\t * ```typescript\n\t * // List all entities\n\t * const page1 = await mappa.entities.list({ limit: 20 });\n\t *\n\t * // Filter by tags (must have both \"interviewer\" AND \"sales\")\n\t * const filtered = await mappa.entities.list({\n\t * tags: [\"interviewer\", \"sales\"],\n\t * limit: 50\n\t * });\n\t *\n\t * // Pagination\n\t * const page2 = await mappa.entities.list({\n\t * cursor: page1.cursor,\n\t * limit: 20\n\t * });\n\t * ```\n\t */\n\tasync list(\n\t\topts?: ListEntitiesOptions & { requestId?: string; signal?: AbortSignal },\n\t): Promise<ListEntitiesResponse> {\n\t\tconst query: Record<string, string> = {};\n\n\t\tif (opts?.tags) {\n\t\t\tvalidateTags(opts.tags);\n\t\t\t// Join tags with comma for API query parameter\n\t\t\tquery.tags = opts.tags.join(\",\");\n\t\t}\n\n\t\tif (opts?.cursor) {\n\t\t\tquery.cursor = opts.cursor;\n\t\t}\n\n\t\tif (opts?.limit !== undefined) {\n\t\t\tquery.limit = String(opts.limit);\n\t\t}\n\n\t\tconst res = await this.transport.request<ListEntitiesResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/entities\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Async iterator that automatically paginates through all entities.\n\t *\n\t * Useful for processing large entity sets without manual pagination management.\n\t *\n\t * @param opts - List options: tags filter, limit per page\n\t * @yields Individual entities\n\t *\n\t * @example\n\t * ```typescript\n\t * // Process all entities with \"interviewer\" tag\n\t * for await (const entity of mappa.entities.listAll({ tags: [\"interviewer\"] })) {\n\t * console.log(`${entity.id}: ${entity.tags.join(\", \")}`);\n\t * }\n\t * ```\n\t */\n\tasync *listAll(\n\t\topts?: Omit<ListEntitiesOptions, \"cursor\"> & {\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): AsyncIterable<Entity> {\n\t\tlet cursor: string | undefined;\n\t\tlet hasMore = true;\n\n\t\twhile (hasMore) {\n\t\t\tconst page = await this.list({ ...opts, cursor });\n\t\t\tfor (const entity of page.entities) {\n\t\t\t\tyield entity;\n\t\t\t}\n\t\t\tcursor = page.cursor;\n\t\t\thasMore = page.hasMore;\n\t\t}\n\t}\n\n\t/**\n\t * Get all entities with a specific tag.\n\t *\n\t * Convenience wrapper around {@link list} for single-tag filtering.\n\t *\n\t * @param tag - The tag to filter by\n\t * @param opts - Optional pagination and request options\n\t * @returns Paginated list of entities with the specified tag\n\t *\n\t * @example\n\t * ```typescript\n\t * const interviewers = await mappa.entities.getByTag(\"interviewer\");\n\t * ```\n\t */\n\tasync getByTag(\n\t\ttag: string,\n\t\topts?: Omit<ListEntitiesOptions, \"tags\"> & {\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<ListEntitiesResponse> {\n\t\tvalidateTag(tag);\n\t\treturn this.list({ ...opts, tags: [tag] });\n\t}\n\n\t/**\n\t * Add tags to an entity.\n\t *\n\t * Idempotent: existing tags are preserved, duplicates are ignored.\n\t *\n\t * @param entityId - The entity ID to tag\n\t * @param tags - Array of tags to add (1-10 tags, each 1-64 chars)\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * await mappa.entities.addTags(\"entity_abc123\", [\"interviewer\", \"john\"]);\n\t * ```\n\t */\n\tasync addTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tif (tags.length === 0) {\n\t\t\tthrow new MappaError(\"At least one tag is required\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Remove tags from an entity.\n\t *\n\t * Idempotent: missing tags are silently ignored.\n\t *\n\t * @param entityId - The entity ID to update\n\t * @param tags - Array of tags to remove\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * await mappa.entities.removeTags(\"entity_abc123\", [\"interviewer\"]);\n\t * ```\n\t */\n\tasync removeTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tif (tags.length === 0) {\n\t\t\tthrow new MappaError(\"At least one tag is required\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"DELETE\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Replace all tags on an entity.\n\t *\n\t * Sets the complete tag list, removing any tags not in the provided array.\n\t * Pass an empty array to remove all tags.\n\t *\n\t * @param entityId - The entity ID to update\n\t * @param tags - New complete tag list (0-10 tags)\n\t * @param opts - Optional request options\n\t * @returns Updated tags for the entity\n\t *\n\t * @example\n\t * ```typescript\n\t * // Replace all tags\n\t * await mappa.entities.setTags(\"entity_abc123\", [\"sales-rep\", \"john\"]);\n\t *\n\t * // Remove all tags\n\t * await mappa.entities.setTags(\"entity_abc123\", []);\n\t * ```\n\t */\n\tasync setTags(\n\t\tentityId: string,\n\t\ttags: string[],\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<EntityTagsResult> {\n\t\tif (!entityId || typeof entityId !== \"string\") {\n\t\t\tthrow new MappaError(\"entityId must be a non-empty string\");\n\t\t}\n\t\tvalidateTags(tags);\n\n\t\tconst res = await this.transport.request<EntityTagsResult>({\n\t\t\tmethod: \"PUT\",\n\t\t\tpath: `/v1/entities/${encodeURIComponent(entityId)}/tags`,\n\t\t\tbody: { tags },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type { FeedbackReceipt } from \"$/types\";\n\nexport type FeedbackCreateRequest = {\n\treportId?: string;\n\tjobId?: string;\n\trating: \"thumbs_up\" | \"thumbs_down\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\";\n\ttags?: string[];\n\tcomment?: string;\n\tcorrections?: Array<{ path: string; expected?: unknown; observed?: unknown }>;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport class FeedbackResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\t/**\n\t * Create feedback for a report or job. Provide exactly one of `reportId` or `jobId`.\n\t */\n\tasync create(req: FeedbackCreateRequest): Promise<FeedbackReceipt> {\n\t\tif (!!req.reportId === !!req.jobId)\n\t\t\tthrow new MappaError(\"Provide exactly one of reportId or jobId\");\n\n\t\tconst res = await this.transport.request<FeedbackReceipt>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/feedback\",\n\t\t\tbody: req,\n\t\t\tidempotencyKey: req.idempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tsignal: req.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tFileDeleteReceipt,\n\tMediaFile,\n\tMediaObject,\n\tRetentionLockResult,\n} from \"$/types\";\n\nexport type UploadRequest = {\n\tfile: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>;\n\t/**\n\t * Optional override.\n\t * If omitted, the SDK will try to infer it from `file.type` (Blob) and then from `filename`.\n\t */\n\tcontentType?: string;\n\tfilename?: string;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListFilesOptions = {\n\t/** Max files per page (1-100, default 20) */\n\tlimit?: number;\n\t/** Pagination cursor from previous response */\n\tcursor?: string;\n\t/** Include soft-deleted files (default false) */\n\tincludeDeleted?: boolean;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\nexport type ListFilesResponse = {\n\tfiles: MediaFile[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\n/**\n * Uses multipart/form-data for uploads.\n *\n * If you need resumable uploads, add a dedicated resumable protocol.\n */\nexport class FilesResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync upload(req: UploadRequest): Promise<MediaObject> {\n\t\tif (typeof FormData === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"FormData is not available in this runtime; cannot perform multipart upload\",\n\t\t\t);\n\t\t}\n\n\t\tconst derivedContentType = inferContentType(req.file, req.filename);\n\t\tconst contentType = req.contentType ?? derivedContentType;\n\t\tif (!contentType) {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"contentType is required when it cannot be inferred from file.type or filename\",\n\t\t\t);\n\t\t}\n\n\t\tconst filename = req.filename ?? inferFilename(req.file) ?? \"upload\";\n\t\tconst filePart = await toFormDataPart(req.file, contentType);\n\n\t\tconst form = new FormData();\n\t\t// Server expects multipart fields:\n\t\t// - file: binary\n\t\t// - contentType: string (may be used for validation/normalization)\n\t\t// - filename: string (optional)\n\t\tform.append(\"file\", filePart, filename);\n\t\tform.append(\"contentType\", contentType);\n\t\tif (req.filename) form.append(\"filename\", req.filename);\n\n\t\tconst res = await this.transport.request<MediaObject>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/files\",\n\t\t\tbody: form,\n\t\t\tidempotencyKey: req.idempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tsignal: req.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Retrieve metadata for a single uploaded file.\n\t *\n\t * @example\n\t * const file = await mappa.files.get(\"media_abc123\");\n\t * console.log(file.processingStatus); // \"COMPLETED\"\n\t */\n\tasync get(\n\t\tmediaId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<MediaFile> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<MediaFile>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * List uploaded files with cursor pagination.\n\t *\n\t * @example\n\t * const page1 = await mappa.files.list({ limit: 10 });\n\t * if (page1.hasMore) {\n\t * const page2 = await mappa.files.list({ limit: 10, cursor: page1.cursor });\n\t * }\n\t */\n\tasync list(opts?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst query: Record<string, string> = {};\n\t\tif (opts?.limit !== undefined) query.limit = String(opts.limit);\n\t\tif (opts?.cursor) query.cursor = opts.cursor;\n\t\tif (opts?.includeDeleted !== undefined)\n\t\t\tquery.includeDeleted = String(opts.includeDeleted);\n\n\t\tconst res = await this.transport.request<ListFilesResponse>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/files\",\n\t\t\tquery,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Iterate over all files, automatically handling pagination.\n\t *\n\t * @example\n\t * for await (const file of mappa.files.listAll()) {\n\t * console.log(file.mediaId);\n\t * }\n\t *\n\t * // Or collect all\n\t * const allFiles = [];\n\t * for await (const file of mappa.files.listAll({ limit: 50 })) {\n\t * allFiles.push(file);\n\t * }\n\t */\n\tasync *listAll(\n\t\topts?: Omit<ListFilesOptions, \"cursor\">,\n\t): AsyncIterable<MediaFile> {\n\t\tlet cursor: string | undefined;\n\t\tlet hasMore = true;\n\n\t\twhile (hasMore) {\n\t\t\tconst page = await this.list({ ...opts, cursor });\n\t\t\tfor (const file of page.files) {\n\t\t\t\tyield file;\n\t\t\t}\n\t\t\tcursor = page.cursor;\n\t\t\thasMore = page.hasMore;\n\t\t}\n\t}\n\n\t/**\n\t * Lock or unlock a file's retention to prevent/allow automatic deletion.\n\t *\n\t * @example\n\t * // Prevent automatic deletion\n\t * await mappa.files.setRetentionLock(\"media_abc\", true);\n\t *\n\t * // Allow automatic deletion\n\t * await mappa.files.setRetentionLock(\"media_abc\", false);\n\t */\n\tasync setRetentionLock(\n\t\tmediaId: string,\n\t\tlocked: boolean,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<RetentionLockResult> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<RetentionLockResult>({\n\t\t\tmethod: \"PATCH\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}/retention`,\n\t\t\tbody: { lock: locked },\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n\n\tasync delete(\n\t\tmediaId: string,\n\t\topts?: {\n\t\t\tidempotencyKey?: string;\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<FileDeleteReceipt> {\n\t\tif (!mediaId) throw new MappaError(\"mediaId is required\");\n\n\t\tconst res = await this.transport.request<FileDeleteReceipt>({\n\t\t\tmethod: \"DELETE\",\n\t\t\tpath: `/v1/files/${encodeURIComponent(mediaId)}`,\n\t\t\tidempotencyKey: opts?.idempotencyKey,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\n\t\treturn res.data;\n\t}\n}\n\nfunction inferContentType(\n\tfile: UploadRequest[\"file\"],\n\tfilename?: string,\n): string | undefined {\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tif (file.type) return file.type;\n\t}\n\tif (filename) return contentTypeFromFilename(filename);\n\treturn undefined;\n}\n\nfunction inferFilename(file: UploadRequest[\"file\"]): string | undefined {\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tconst anyBlob = file as unknown as { name?: unknown };\n\t\tif (typeof anyBlob.name === \"string\" && anyBlob.name) return anyBlob.name;\n\t}\n\treturn undefined;\n}\n\nfunction contentTypeFromFilename(filename: string): string | undefined {\n\tconst i = filename.lastIndexOf(\".\");\n\tif (i < 0) return undefined;\n\tconst ext = filename.slice(i + 1).toLowerCase();\n\n\t// Small built-in map to avoid an extra dependency.\n\t// Add more as needed.\n\tswitch (ext) {\n\t\tcase \"mp4\":\n\t\t\treturn \"video/mp4\";\n\t\tcase \"mov\":\n\t\t\treturn \"video/quicktime\";\n\t\tcase \"webm\":\n\t\t\treturn \"video/webm\";\n\t\tcase \"mp3\":\n\t\t\treturn \"audio/mpeg\";\n\t\tcase \"wav\":\n\t\t\treturn \"audio/wav\";\n\t\tcase \"m4a\":\n\t\t\treturn \"audio/mp4\";\n\t\tcase \"png\":\n\t\t\treturn \"image/png\";\n\t\tcase \"jpg\":\n\t\tcase \"jpeg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \"gif\":\n\t\t\treturn \"image/gif\";\n\t\tcase \"webp\":\n\t\t\treturn \"image/webp\";\n\t\tcase \"pdf\":\n\t\t\treturn \"application/pdf\";\n\t\tcase \"json\":\n\t\t\treturn \"application/json\";\n\t\tcase \"txt\":\n\t\t\treturn \"text/plain\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nasync function toFormDataPart(\n\tfile: UploadRequest[\"file\"],\n\tcontentType: string,\n): Promise<Blob> {\n\t// Blob: ensure the part has the intended type.\n\tif (typeof Blob !== \"undefined\" && file instanceof Blob) {\n\t\tif (file.type === contentType) return file;\n\t\t// TS in this repo is configured without DOM lib, so `Blob#slice` isn't typed.\n\t\t// Most runtimes support it; we call it via an `any` cast.\n\t\tconst slicer = file as unknown as {\n\t\t\tslice?: (start?: number, end?: number, contentType?: string) => Blob;\n\t\t};\n\t\tif (typeof slicer.slice === \"function\") {\n\t\t\treturn slicer.slice(\n\t\t\t\t0,\n\t\t\t\t(file as unknown as { size?: number }).size,\n\t\t\t\tcontentType,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\n\t// ArrayBuffer / Uint8Array\n\tif (file instanceof ArrayBuffer)\n\t\treturn new Blob([file], { type: contentType });\n\tif (file instanceof Uint8Array)\n\t\treturn new Blob([file], { type: contentType });\n\n\t// ReadableStream<Uint8Array>\n\tif (typeof ReadableStream !== \"undefined\" && file instanceof ReadableStream) {\n\t\t// Most runtimes (Node 18+/Bun/modern browsers) can convert stream -> Blob via Response.\n\t\tif (typeof Response === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"ReadableStream upload requires Response to convert stream to Blob\",\n\t\t\t);\n\t\t}\n\n\t\tconst blob = await new Response(file).blob();\n\t\treturn blob.slice(0, blob.size, contentType);\n\t}\n\n\tthrow new MappaError(\"Unsupported file type for upload()\");\n}\n","import type { Transport } from \"$/resources/transport\";\n\nexport class HealthResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync ping(): Promise<{ ok: true; time: string }> {\n\t\tconst res = await this.transport.request<{ ok: true; time: string }>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: \"/v1/health/ping\",\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n}\n","import { init } from \"@paralleldrive/cuid2\";\n\nconst createId = init({\n\tlength: 32,\n});\n\nexport function assertNever(x: never): never {\n\tthrow new Error(`Unexpected object: ${String(x)}`);\n}\n\nexport function isObject(x: unknown): x is Record<string, unknown> {\n\treturn typeof x === \"object\" && x !== null;\n}\n\nexport function getHeader(headers: Headers, name: string): string | undefined {\n\tconst v = headers.get(name);\n\treturn v === null ? undefined : v;\n}\n\nexport function jitter(ms: number): number {\n\t// +/- 20%\n\tconst r = 0.8 + Math.random() * 0.4;\n\treturn Math.floor(ms * r);\n}\n\nexport function backoffMs(\n\tattempt: number,\n\tbaseMs: number,\n\tmaxMs: number,\n): number {\n\t// exponential: base * 2^(attempt-1)\n\tconst ms = baseMs * 2 ** Math.max(0, attempt - 1);\n\treturn Math.min(ms, maxMs);\n}\n\nexport function nowMs(): number {\n\treturn Date.now();\n}\n\nexport function hasAbortSignal(signal?: AbortSignal): boolean {\n\treturn !!signal && typeof signal.aborted === \"boolean\";\n}\n\nexport function makeAbortError(): Error {\n\tconst e = new Error(\"The operation was aborted\");\n\te.name = \"AbortError\";\n\treturn e;\n}\n\nexport function randomId(prefix = \"req\"): string {\n\treturn `${prefix}_${createId()}`;\n}\n","import { JobCanceledError, JobFailedError, MappaError } from \"$/errors\";\nimport type { SSEEvent, Transport } from \"$/resources/transport\";\nimport type { Job, JobEvent, JobStage, WaitOptions } from \"$/types\";\nimport { makeAbortError } from \"../utils\";\n\n/**\n * SSE event data shape from the server's job stream endpoint.\n */\ntype JobStreamEventData = {\n\tstatus?: string;\n\tstage?: string;\n\tprogress?: number;\n\tjob: Job;\n\treportId?: string;\n\terror?: { code: string; message: string };\n\ttimestamp?: string; // for heartbeat\n};\n\nexport class JobsResource {\n\tconstructor(private readonly transport: Transport) {}\n\n\tasync get(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Job> {\n\t\tconst res = await this.transport.request<Job>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/jobs/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\tasync cancel(\n\t\tjobId: string,\n\t\topts?: {\n\t\t\tidempotencyKey?: string;\n\t\t\trequestId?: string;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<Job> {\n\t\tconst res = await this.transport.request<Job>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: `/v1/jobs/${encodeURIComponent(jobId)}/cancel`,\n\t\t\tidempotencyKey: opts?.idempotencyKey,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Wait for a job to reach a terminal state.\n\t *\n\t * Uses SSE streaming internally for efficient real-time updates.\n\t */\n\tasync wait(jobId: string, opts?: WaitOptions): Promise<Job> {\n\t\tconst timeoutMs = opts?.timeoutMs ?? 5 * 60_000;\n\t\tconst controller = new AbortController();\n\n\t\t// Set up timeout\n\t\tconst timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n\t\t// Combine signals if user provided one\n\t\tif (opts?.signal) {\n\t\t\tif (opts.signal.aborted) {\n\t\t\t\tclearTimeout(timeoutId);\n\t\t\t\tthrow makeAbortError();\n\t\t\t}\n\t\t\topts.signal.addEventListener(\"abort\", () => controller.abort(), {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tfor await (const event of this.stream(jobId, {\n\t\t\t\tsignal: controller.signal,\n\t\t\t\tonEvent: opts?.onEvent,\n\t\t\t})) {\n\t\t\t\tif (event.type === \"terminal\") {\n\t\t\t\t\tconst job = event.job;\n\n\t\t\t\t\tif (job.status === \"succeeded\") {\n\t\t\t\t\t\treturn job;\n\t\t\t\t\t}\n\t\t\t\t\tif (job.status === \"failed\") {\n\t\t\t\t\t\tthrow new JobFailedError(\n\t\t\t\t\t\t\tjobId,\n\t\t\t\t\t\t\tjob.error?.message ?? \"Job failed\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trequestId: job.requestId,\n\t\t\t\t\t\t\t\tcode: job.error?.code,\n\t\t\t\t\t\t\t\tcause: job.error,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (job.status === \"canceled\") {\n\t\t\t\t\t\tthrow new JobCanceledError(jobId, \"Job canceled\", {\n\t\t\t\t\t\t\trequestId: job.requestId,\n\t\t\t\t\t\t\tcause: job.error,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stream ended without terminal event (timeout or unexpected close)\n\t\t\tthrow new JobFailedError(\n\t\t\t\tjobId,\n\t\t\t\t`Timed out waiting for job ${jobId} after ${timeoutMs}ms`,\n\t\t\t\t{\n\t\t\t\t\tcause: { jobId, timeoutMs },\n\t\t\t\t},\n\t\t\t);\n\t\t} finally {\n\t\t\tclearTimeout(timeoutId);\n\t\t}\n\t}\n\n\t/**\n\t * Stream job events via SSE.\n\t *\n\t * Yields events as they arrive from the server. Use `AbortSignal` to cancel streaming.\n\t * Automatically handles reconnection with `Last-Event-ID` for up to 3 retries.\n\t */\n\tasync *stream(\n\t\tjobId: string,\n\t\topts?: { signal?: AbortSignal; onEvent?: (e: JobEvent) => void },\n\t): AsyncIterable<JobEvent> {\n\t\tconst maxRetries = 3;\n\t\tlet lastEventId: string | undefined;\n\t\tlet retries = 0;\n\n\t\twhile (retries < maxRetries) {\n\t\t\ttry {\n\t\t\t\tconst sseStream = this.transport.streamSSE<JobStreamEventData>(\n\t\t\t\t\t`/v1/jobs/${encodeURIComponent(jobId)}/stream`,\n\t\t\t\t\t{ signal: opts?.signal, lastEventId },\n\t\t\t\t);\n\n\t\t\t\tfor await (const sseEvent of sseStream) {\n\t\t\t\t\tlastEventId = sseEvent.id;\n\n\t\t\t\t\t// Handle error event (job not found, etc.)\n\t\t\t\t\tif (sseEvent.event === \"error\") {\n\t\t\t\t\t\tconst errorData = sseEvent.data;\n\t\t\t\t\t\tthrow new MappaError(\n\t\t\t\t\t\t\terrorData.error?.message ?? \"Unknown SSE error\",\n\t\t\t\t\t\t\t{ code: errorData.error?.code },\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip heartbeat events (internal keep-alive)\n\t\t\t\t\tif (sseEvent.event === \"heartbeat\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Map SSE event to JobEvent\n\t\t\t\t\tconst jobEvent = this.mapSSEToJobEvent(sseEvent);\n\t\t\t\t\tif (jobEvent) {\n\t\t\t\t\t\topts?.onEvent?.(jobEvent);\n\t\t\t\t\t\tyield jobEvent;\n\n\t\t\t\t\t\t// Exit on terminal event\n\t\t\t\t\t\tif (sseEvent.event === \"terminal\") {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reset retry counter on successful event\n\t\t\t\t\tretries = 0;\n\t\t\t\t}\n\n\t\t\t\t// Stream ended without terminal event (server timeout)\n\t\t\t\t// Reconnect with last event ID\n\t\t\t\tretries++;\n\t\t\t\tif (retries < maxRetries) {\n\t\t\t\t\tawait this.backoff(retries);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// If aborted, rethrow immediately\n\t\t\t\tif (opts?.signal?.aborted) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tretries++;\n\t\t\t\tif (retries >= maxRetries) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tawait this.backoff(retries);\n\t\t\t}\n\t\t}\n\n\t\tthrow new MappaError(\n\t\t\t`Failed to get status for job ${jobId} after ${maxRetries} retries`,\n\t\t);\n\t}\n\n\t/**\n\t * Map an SSE event to a JobEvent.\n\t */\n\tprivate mapSSEToJobEvent(\n\t\tsseEvent: SSEEvent<JobStreamEventData>,\n\t): JobEvent | null {\n\t\tconst data = sseEvent.data;\n\n\t\tswitch (sseEvent.event) {\n\t\t\tcase \"status\":\n\t\t\t\treturn { type: \"status\", job: data.job };\n\t\t\tcase \"stage\":\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"stage\",\n\t\t\t\t\tstage: data.stage as JobStage,\n\t\t\t\t\tprogress: data.progress,\n\t\t\t\t\tjob: data.job,\n\t\t\t\t};\n\t\t\tcase \"terminal\":\n\t\t\t\treturn { type: \"terminal\", job: data.job };\n\t\t\tdefault:\n\t\t\t\t// Unknown event type, treat as status update\n\t\t\t\treturn { type: \"status\", job: data.job };\n\t\t}\n\t}\n\n\t/**\n\t * Exponential backoff with jitter for reconnection.\n\t */\n\tprivate async backoff(attempt: number): Promise<void> {\n\t\tconst delay = Math.min(1000 * 2 ** attempt, 10000);\n\t\tconst jitter = delay * 0.5 * Math.random();\n\t\tawait new Promise((r) => setTimeout(r, delay + jitter));\n\t}\n}\n","import { MappaError } from \"$/errors\";\nimport type { UploadRequest } from \"$/resources/files\";\nimport type { JobsResource } from \"$/resources/jobs\";\nimport type { Transport } from \"$/resources/transport\";\nimport type {\n\tJobEvent,\n\tMediaIdRef,\n\tMediaObject,\n\tReport,\n\tReportCreateJobRequest,\n\tReportForOutputType,\n\tReportJobReceipt,\n\tReportOutputType,\n\tReportRunHandle,\n\tWaitOptions,\n} from \"$/types\";\nimport { randomId } from \"$/utils\";\n\n/**\n * Runtime validation for the internal `MediaIdRef` requirement.\n *\n * The public API server expects a `mediaId` when creating a report job.\n * Use helpers like `createJobFromFile` / `createJobFromUrl` to start from bytes or a URL.\n */\nfunction validateMedia(media: MediaIdRef): void {\n\tconst m = media as unknown;\n\tconst isObj = (v: unknown): v is Record<string, unknown> =>\n\t\tv !== null && typeof v === \"object\";\n\n\tif (!isObj(m)) throw new MappaError(\"media must be an object\");\n\n\t// Report job creation only supports already-uploaded media references.\n\t// Use `createJobFromFile` / `createJobFromUrl` to start from bytes or a remote URL.\n\tif ((m as { url?: unknown }).url !== undefined) {\n\t\tthrow new MappaError(\n\t\t\t\"media.url is not supported; pass { mediaId } or use createJobFromUrl()\",\n\t\t);\n\t}\n\n\tconst mediaId = (m as { mediaId?: unknown }).mediaId;\n\tif (typeof mediaId !== \"string\" || !mediaId) {\n\t\tthrow new MappaError(\"media.mediaId must be a non-empty string\");\n\t}\n}\n\n/**\n * Request shape for {@link ReportsResource.createJobFromFile}.\n *\n * This helper performs two API calls as one logical operation:\n * 1) Upload bytes via `files.upload()` (multipart)\n * 2) Create a report job via {@link ReportsResource.createJob} using the returned `{ mediaId }`\n *\n * Differences vs {@link ReportCreateJobRequest}:\n * - `media` is derived from the upload result and therefore omitted.\n * - `idempotencyKey` applies to the *whole* upload + create-job sequence.\n * - `requestId` is forwarded to both requests for end-to-end correlation.\n *\n * Abort behavior:\n * - `signal` (from {@link UploadRequest}) is applied to the upload request.\n * Job creation only runs after a successful upload.\n */\nexport type ReportCreateJobFromFileRequest<\n\tT extends ReportOutputType = ReportOutputType,\n> = Omit<ReportCreateJobRequest<T>, \"media\" | \"idempotencyKey\" | \"requestId\"> &\n\tOmit<UploadRequest, \"filename\"> & {\n\t\t/**\n\t\t * Optional filename to attach to the upload.\n\t\t *\n\t\t * When omitted, the upload layer may infer it (e.g. from a `File` object).\n\t\t */\n\t\tfilename?: string;\n\t\t/**\n\t\t * Idempotency for the upload + job creation sequence.\n\t\t */\n\t\tidempotencyKey?: string;\n\t\t/**\n\t\t * Optional request correlation ID forwarded to both the upload and the job creation call.\n\t\t */\n\t\trequestId?: string;\n\t};\n\n/**\n * Request shape for {@link ReportsResource.createJobFromUrl}.\n *\n * This helper performs two API calls as one logical operation:\n * 1) Download bytes from a remote URL using `fetch()`\n * 2) Upload bytes via `files.upload()` and then create a report job via {@link ReportsResource.createJob}\n *\n * Differences vs {@link ReportCreateJobRequest}:\n * - `media` is derived from the upload result and therefore omitted.\n * - `idempotencyKey` applies to the *whole* download + upload + create-job sequence.\n * - `requestId` is forwarded to both upload and job creation calls.\n */\nexport type ReportCreateJobFromUrlRequest<\n\tT extends ReportOutputType = ReportOutputType,\n> = Omit<\n\tReportCreateJobRequest<T>,\n\t\"media\" | \"idempotencyKey\" | \"requestId\"\n> & {\n\turl: string;\n\tcontentType?: string;\n\tfilename?: string;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n};\n\n/**\n * Reports API resource.\n *\n * Responsibilities:\n * - Create report jobs (`POST /v1/reports/jobs`).\n * - Fetch reports by report ID (`GET /v1/reports/:reportId`).\n * - Fetch reports by job ID (`GET /v1/reports/by-job/:jobId`).\n *\n * Convenience helpers:\n * - {@link ReportsResource.createJobFromFile} orchestrates `files.upload()` + {@link ReportsResource.createJob}.\n * - {@link ReportsResource.createJobFromUrl} downloads a remote URL, uploads it, then calls {@link ReportsResource.createJob}.\n * - {@link ReportsResource.generate} / {@link ReportsResource.generateFromFile} are script-friendly wrappers that\n * create a job, wait for completion, and then fetch the final report.\n *\n * For production systems, prefer `createJob*()` plus webhooks or streaming job events rather than blocking waits.\n */\nexport class ReportsResource {\n\tconstructor(\n\t\tprivate readonly transport: Transport,\n\t\tprivate readonly jobs: JobsResource,\n\t\tprivate readonly files: {\n\t\t\tupload: (req: UploadRequest) => Promise<MediaObject>;\n\t\t},\n\t\tprivate readonly fetchImpl: typeof fetch,\n\t) {}\n\n\t/**\n\t * Create a new report job.\n\t *\n\t * Behavior:\n\t * - Validates {@link MediaIdRef} at runtime (must provide `{ mediaId }`).\n\t * - Defaults to `{ strategy: \"dominant\" }` when `target` is omitted.\n\t * - Applies an idempotency key: uses `req.idempotencyKey` when provided; otherwise generates a best-effort default.\n\t * - Forwards `req.requestId` to the transport for end-to-end correlation.\n\t *\n\t * The returned receipt includes a {@link ReportRunHandle} (`receipt.handle`) which can be used to:\n\t * - stream job events\n\t * - wait for completion and fetch the final report\n\t * - cancel the job, or fetch job/report metadata\n\t */\n\tasync createJob<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobRequest<T>,\n\t): Promise<ReportJobReceipt<T>> {\n\t\tvalidateMedia(req.media);\n\n\t\tconst idempotencyKey =\n\t\t\treq.idempotencyKey ?? this.defaultIdempotencyKey(req);\n\n\t\tconst res = await this.transport.request<\n\t\t\tOmit<ReportJobReceipt<T>, \"handle\">\n\t\t>({\n\t\t\tmethod: \"POST\",\n\t\t\tpath: \"/v1/reports/jobs\",\n\t\t\tbody: this.normalizeJobRequest(req),\n\t\t\tidempotencyKey,\n\t\t\trequestId: req.requestId,\n\t\t\tretryable: true,\n\t\t});\n\n\t\tconst receipt: ReportJobReceipt<T> = {\n\t\t\t...res.data,\n\t\t\trequestId: res.requestId ?? res.data.requestId,\n\t\t};\n\n\t\treceipt.handle = this.makeHandle<T>(receipt.jobId);\n\t\treturn receipt;\n\t}\n\n\t/**\n\t * Upload a file and create a report job in one call.\n\t *\n\t * Keeps `createJob()` strict about `media: { mediaId }` while offering a\n\t * convenient helper when you start from raw bytes.\n\t */\n\tasync createJobFromFile<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobFromFileRequest<T>,\n\t): Promise<ReportJobReceipt<T>> {\n\t\tconst {\n\t\t\tfile,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t\t...rest\n\t\t} = req;\n\n\t\tconst upload = await this.files.upload({\n\t\t\tfile,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t});\n\n\t\treturn this.createJob<T>({\n\t\t\t...(rest as Omit<ReportCreateJobRequest<T>, \"media\">),\n\t\t\tmedia: { mediaId: upload.mediaId },\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t});\n\t}\n\n\t/**\n\t * Download a file from a URL, upload it, and create a report job.\n\t *\n\t * Recommended when starting from a remote URL because report job creation\n\t * only accepts `media: { mediaId }`.\n\t *\n\t * Workflow:\n\t * 1) `fetch(url)`\n\t * 2) Validate the response (2xx) and derive `contentType`\n\t * 3) `files.upload({ file: Blob, ... })`\n\t * 4) `createJob({ media: { mediaId }, ... })`\n\t *\n\t * Verification / safety:\n\t * - Only allows `http:` and `https:` URLs.\n\t * - Requires a resolvable `contentType` (from `req.contentType` or response header).\n\t */\n\tasync createJobFromUrl<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobFromUrlRequest<T>,\n\t): Promise<ReportJobReceipt<T>> {\n\t\tconst {\n\t\t\turl,\n\t\t\tcontentType: contentTypeOverride,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t\t...rest\n\t\t} = req;\n\n\t\tlet parsed: URL;\n\t\ttry {\n\t\t\tparsed = new URL(url);\n\t\t} catch {\n\t\t\tthrow new MappaError(\"url must be a valid URL\");\n\t\t}\n\t\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n\t\t\tthrow new MappaError(\"url must use http: or https:\");\n\t\t}\n\n\t\tconst res = await this.fetchImpl(parsed.toString(), { signal });\n\t\tif (!res.ok) {\n\t\t\tthrow new MappaError(`Failed to download url (status ${res.status})`);\n\t\t}\n\n\t\tconst derivedContentType = res.headers.get(\"content-type\") ?? undefined;\n\t\tconst contentType = contentTypeOverride ?? derivedContentType;\n\t\tif (!contentType) {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"contentType is required when it cannot be inferred from the download response\",\n\t\t\t);\n\t\t}\n\n\t\tif (typeof Blob === \"undefined\") {\n\t\t\tthrow new MappaError(\n\t\t\t\t\"Blob is not available in this runtime; cannot download and upload from url\",\n\t\t\t);\n\t\t}\n\n\t\tconst blob = await res.blob();\n\t\tconst upload = await this.files.upload({\n\t\t\tfile: blob,\n\t\t\tcontentType,\n\t\t\tfilename,\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t\tsignal,\n\t\t});\n\n\t\treturn this.createJob<T>({\n\t\t\t...(rest as Omit<ReportCreateJobRequest<T>, \"media\">),\n\t\t\tmedia: { mediaId: upload.mediaId },\n\t\t\tidempotencyKey,\n\t\t\trequestId,\n\t\t});\n\t}\n\n\tasync get(\n\t\treportId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Report> {\n\t\tconst res = await this.transport.request<Report>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/reports/${encodeURIComponent(reportId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\tasync getByJob(\n\t\tjobId: string,\n\t\topts?: { requestId?: string; signal?: AbortSignal },\n\t): Promise<Report | null> {\n\t\tconst res = await this.transport.request<Report | null>({\n\t\t\tmethod: \"GET\",\n\t\t\tpath: `/v1/reports/by-job/${encodeURIComponent(jobId)}`,\n\t\t\trequestId: opts?.requestId,\n\t\t\tsignal: opts?.signal,\n\t\t\tretryable: true,\n\t\t});\n\t\treturn res.data;\n\t}\n\n\t/**\n\t * Convenience wrapper: createJob + wait + get\n\t * Use for scripts; for production prefer createJob + webhooks/stream.\n\t */\n\tasync generate<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobRequest<T>,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<ReportForOutputType<T>> {\n\t\tconst receipt = await this.createJob<T>(req);\n\t\tif (!receipt.handle) {\n\t\t\tthrow new MappaError(\"Job receipt is missing handle\");\n\t\t}\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\t/**\n\t * Convenience wrapper: createJobFromFile + wait + get.\n\t * Use for scripts; for production prefer createJobFromFile + webhooks/stream.\n\t */\n\tasync generateFromFile<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobFromFileRequest<T>,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<ReportForOutputType<T>> {\n\t\tconst receipt = await this.createJobFromFile<T>(req);\n\t\tif (!receipt.handle) throw new MappaError(\"Job receipt is missing handle\");\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\t/**\n\t * Convenience wrapper: createJobFromUrl + wait + get.\n\t * Use for scripts; for production prefer createJobFromUrl + webhooks/stream.\n\t */\n\tasync generateFromUrl<T extends ReportOutputType = ReportOutputType>(\n\t\treq: ReportCreateJobFromUrlRequest<T>,\n\t\topts?: { wait?: WaitOptions },\n\t): Promise<ReportForOutputType<T>> {\n\t\tconst receipt = await this.createJobFromUrl<T>(req);\n\t\tif (!receipt.handle) throw new MappaError(\"Job receipt is missing handle\");\n\t\treturn receipt.handle.wait(opts?.wait);\n\t}\n\n\tmakeHandle<T extends ReportOutputType = ReportOutputType>(\n\t\tjobId: string,\n\t): ReportRunHandle<T> {\n\t\tconst self = this;\n\t\treturn {\n\t\t\tjobId,\n\t\t\tstream: (opts?: {\n\t\t\t\tsignal?: AbortSignal;\n\t\t\t\tonEvent?: (e: JobEvent) => void;\n\t\t\t}) => self.jobs.stream(jobId, opts),\n\t\t\tasync wait(opts?: WaitOptions): Promise<ReportForOutputType<T>> {\n\t\t\t\tconst terminal = await self.jobs.wait(jobId, opts);\n\t\t\t\tif (!terminal.reportId)\n\t\t\t\t\tthrow new MappaError(\n\t\t\t\t\t\t`Job ${jobId} succeeded but no reportId was returned`,\n\t\t\t\t\t);\n\t\t\t\treturn self.get(terminal.reportId) as Promise<ReportForOutputType<T>>;\n\t\t\t},\n\t\t\tcancel: () => self.jobs.cancel(jobId),\n\t\t\tjob: () => self.jobs.get(jobId),\n\t\t\treport: () =>\n\t\t\t\tself.getByJob(jobId) as Promise<ReportForOutputType<T> | null>,\n\t\t};\n\t}\n\n\tprivate defaultIdempotencyKey(_req: ReportCreateJobRequest): string {\n\t\t// Deterministic keys can be added later; random avoids accidental duplicates on retries.\n\t\treturn randomId(\"idem\");\n\t}\n\n\tprivate normalizeJobRequest(\n\t\treq: ReportCreateJobRequest,\n\t): Record<string, unknown> {\n\t\tconst target = req.target;\n\n\t\t// Default to dominant strategy when target is not provided\n\t\tif (!target) {\n\t\t\treturn {\n\t\t\t\t...req,\n\t\t\t\ttarget: { strategy: \"dominant\" },\n\t\t\t};\n\t\t}\n\n\t\tconst baseTarget: Record<string, unknown> = {\n\t\t\tstrategy: target.strategy,\n\t\t};\n\n\t\tif (target.onMiss) {\n\t\t\tbaseTarget.on_miss = target.onMiss;\n\t\t}\n\n\t\t// Add tags and excludeTags to baseTarget (common to all strategies)\n\t\tif (target.tags && target.tags.length > 0) {\n\t\t\tbaseTarget.tags = target.tags;\n\t\t}\n\n\t\tif (target.excludeTags && target.excludeTags.length > 0) {\n\t\t\tbaseTarget.exclude_tags = target.excludeTags;\n\t\t}\n\n\t\tswitch (target.strategy) {\n\t\t\tcase \"dominant\": {\n\t\t\t\treturn { ...req, target: baseTarget };\n\t\t\t}\n\t\t\tcase \"timerange\": {\n\t\t\t\tconst timeRange = target.timeRange ?? {};\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\ttimerange: {\n\t\t\t\t\t\t\tstart_seconds: timeRange.startSeconds ?? null,\n\t\t\t\t\t\t\tend_seconds: timeRange.endSeconds ?? null,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"entity_id\": {\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\tentity_id: target.entityId,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"magic_hint\": {\n\t\t\t\treturn {\n\t\t\t\t\t...req,\n\t\t\t\t\ttarget: {\n\t\t\t\t\t\t...baseTarget,\n\t\t\t\t\t\thint: target.hint,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn req;\n\t\t\t}\n\t\t}\n\t}\n}\n","import {\n\tApiError,\n\tAuthError,\n\tInsufficientCreditsError,\n\tMappaError,\n\tRateLimitError,\n\tValidationError,\n} from \"$/errors\";\nimport {\n\tbackoffMs,\n\tgetHeader,\n\thasAbortSignal,\n\tjitter,\n\tmakeAbortError,\n\trandomId,\n} from \"$/utils\";\n\n/**\n * Options for SSE streaming.\n */\nexport type SSEStreamOptions = {\n\tsignal?: AbortSignal;\n\tlastEventId?: string;\n};\n\n/**\n * A parsed SSE event.\n */\nexport type SSEEvent<T = unknown> = {\n\tid?: string;\n\tevent: string;\n\tdata: T;\n};\n\nexport type Telemetry = {\n\tonRequest?: (ctx: {\n\t\tmethod: string;\n\t\turl: string;\n\t\trequestId?: string;\n\t}) => void;\n\tonResponse?: (ctx: {\n\t\tstatus: number;\n\t\turl: string;\n\t\trequestId?: string;\n\t\tdurationMs: number;\n\t}) => void;\n\tonError?: (ctx: { url: string; requestId?: string; error: unknown }) => void;\n};\n\nexport type TransportOptions = {\n\tapiKey: string;\n\tbaseUrl: string;\n\ttimeoutMs: number;\n\tmaxRetries: number;\n\tdefaultHeaders?: Record<string, string>;\n\tfetch?: typeof fetch;\n\ttelemetry?: Telemetry;\n\tuserAgent?: string;\n};\n\nexport type RequestOptions = {\n\tmethod: \"GET\" | \"POST\" | \"DELETE\" | \"PUT\" | \"PATCH\";\n\tpath: string;\n\tquery?: Record<string, string | number | boolean | undefined>;\n\theaders?: Record<string, string | undefined>;\n\tbody?: unknown;\n\tidempotencyKey?: string;\n\trequestId?: string;\n\tsignal?: AbortSignal;\n\t// treat as safe to retry (typically true for GET and for idempotent POSTs)\n\tretryable?: boolean;\n};\n\nexport type TransportResponse<T> = {\n\tdata: T;\n\tstatus: number;\n\trequestId?: string;\n\theaders: Headers;\n};\n\nfunction buildUrl(\n\tbaseUrl: string,\n\tpath: string,\n\tquery?: RequestOptions[\"query\"],\n): string {\n\tconst u = new URL(\n\t\tpath.replace(/^\\//, \"\"),\n\t\tbaseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`,\n\t);\n\tif (query) {\n\t\tfor (const [k, v] of Object.entries(query)) {\n\t\t\tif (v === undefined) continue;\n\t\t\tu.searchParams.set(k, String(v));\n\t\t}\n\t}\n\treturn u.toString();\n}\n\nasync function readBody(\n\tres: Response,\n): Promise<{ parsed: unknown; text: string }> {\n\tconst text = await res.text();\n\tif (!text) return { parsed: null, text: \"\" };\n\ttry {\n\t\treturn { parsed: JSON.parse(text), text };\n\t} catch {\n\t\treturn { parsed: text, text };\n\t}\n}\n\nfunction coerceApiError(res: Response, parsed: unknown): ApiError {\n\tconst requestId = res.headers.get(\"x-request-id\") ?? undefined;\n\n\t// Expecting an error envelope like:\n\t// { error: { code, message, details } } OR { code, message, details }\n\tlet code: string | undefined;\n\tlet message = `Request failed with status ${res.status}`;\n\tlet details: unknown = parsed;\n\n\tif (typeof parsed === \"string\") {\n\t\tmessage = parsed;\n\t} else if (parsed && typeof parsed === \"object\") {\n\t\tconst p = parsed as Record<string, unknown>;\n\t\tconst err = (p.error ?? p) as unknown;\n\t\tif (err && typeof err === \"object\") {\n\t\t\tconst e = err as Record<string, unknown>;\n\t\t\tif (typeof e.message === \"string\") message = e.message;\n\t\t\tif (typeof e.code === \"string\") code = e.code;\n\t\t\tif (\"details\" in e) details = e.details;\n\t\t}\n\t}\n\n\tif (res.status === 401 || res.status === 403)\n\t\treturn new AuthError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\tif (res.status === 422)\n\t\treturn new ValidationError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\n\tif (res.status === 402 && code === \"insufficient_credits\") {\n\t\treturn new InsufficientCreditsError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails: details as { required?: number; available?: number },\n\t\t});\n\t}\n\n\tif (res.status === 429) {\n\t\tconst e = new RateLimitError(message, {\n\t\t\tstatus: res.status,\n\t\t\trequestId,\n\t\t\tcode,\n\t\t\tdetails,\n\t\t});\n\t\tconst ra = res.headers.get(\"retry-after\");\n\t\tif (ra) {\n\t\t\tconst sec = Number(ra);\n\t\t\tif (Number.isFinite(sec) && sec >= 0) e.retryAfterMs = sec * 1000;\n\t\t}\n\t\treturn e;\n\t}\n\n\treturn new ApiError(message, {\n\t\tstatus: res.status,\n\t\trequestId,\n\t\tcode,\n\t\tdetails,\n\t});\n}\n\nfunction shouldRetry(\n\topts: RequestOptions,\n\terr: unknown,\n): { retry: boolean; retryAfterMs?: number } {\n\tif (!opts.retryable) return { retry: false };\n\n\t// Retry on RateLimitError / 5xx / network failures\n\tif (err instanceof RateLimitError)\n\t\treturn { retry: true, retryAfterMs: err.retryAfterMs };\n\tif (err instanceof ApiError)\n\t\treturn { retry: err.status >= 500 && err.status <= 599 };\n\t// fetch throws TypeError on network failure in many runtimes\n\tif (err instanceof TypeError) return { retry: true };\n\treturn { retry: false };\n}\n\nexport class Transport {\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(private readonly opts: TransportOptions) {\n\t\tthis.fetchImpl = opts.fetch ?? fetch;\n\t}\n\n\t/**\n\t * Stream SSE events from a given path.\n\t *\n\t * Uses native `fetch` with streaming response body (not browser-only `EventSource`).\n\t * Parses SSE format manually from the `ReadableStream`.\n\t */\n\tasync *streamSSE<T>(\n\t\tpath: string,\n\t\topts?: SSEStreamOptions,\n\t): AsyncGenerator<SSEEvent<T>> {\n\t\tconst url = buildUrl(this.opts.baseUrl, path);\n\t\tconst requestId = randomId(\"req\");\n\n\t\tconst headers: Record<string, string> = {\n\t\t\tAccept: \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\"Mappa-Api-Key\": this.opts.apiKey,\n\t\t\t\"X-Request-Id\": requestId,\n\t\t\t...(this.opts.userAgent ? { \"User-Agent\": this.opts.userAgent } : {}),\n\t\t\t...(this.opts.defaultHeaders ?? {}),\n\t\t};\n\n\t\tif (opts?.lastEventId) {\n\t\t\theaders[\"Last-Event-ID\"] = opts.lastEventId;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tconst timeout = setTimeout(\n\t\t\t() => controller.abort(makeAbortError()),\n\t\t\tthis.opts.timeoutMs,\n\t\t);\n\n\t\t// Combine signals: if caller aborts, abort our controller\n\t\tif (hasAbortSignal(opts?.signal)) {\n\t\t\tconst signal = opts?.signal;\n\t\t\tif (signal?.aborted) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthrow makeAbortError();\n\t\t\t}\n\t\t\tsignal?.addEventListener(\n\t\t\t\t\"abort\",\n\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t}\n\n\t\tthis.opts.telemetry?.onRequest?.({ method: \"GET\", url, requestId });\n\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await this.fetchImpl(url, {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders,\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: err });\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!res.ok) {\n\t\t\tclearTimeout(timeout);\n\t\t\tconst { parsed } = await readBody(res);\n\t\t\tconst apiErr = coerceApiError(res, parsed);\n\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: apiErr });\n\t\t\tthrow apiErr;\n\t\t}\n\n\t\tif (!res.body) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthrow new MappaError(\"SSE response has no body\");\n\t\t}\n\n\t\ttry {\n\t\t\tyield* this.parseSSEStream<T>(res.body);\n\t\t} finally {\n\t\t\tclearTimeout(timeout);\n\t\t}\n\t}\n\n\t/**\n\t * Parse SSE events from a ReadableStream.\n\t *\n\t * SSE format:\n\t * ```\n\t * id: <id>\n\t * event: <type>\n\t * data: <json>\n\t *\n\t * ```\n\t * Each event is terminated by an empty line.\n\t */\n\tprivate async *parseSSEStream<T>(\n\t\tbody: ReadableStream<Uint8Array>,\n\t): AsyncGenerator<SSEEvent<T>> {\n\t\tconst decoder = new TextDecoder();\n\t\tconst reader = body.getReader();\n\t\tlet buffer = \"\";\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\n\t\t\t\t// Process complete events (separated by double newline)\n\t\t\t\tconst events = buffer.split(\"\\n\\n\");\n\t\t\t\t// Keep the last incomplete chunk in buffer\n\t\t\t\tbuffer = events.pop() ?? \"\";\n\n\t\t\t\tfor (const eventText of events) {\n\t\t\t\t\tif (!eventText.trim()) continue;\n\n\t\t\t\t\tconst event = this.parseSSEEvent<T>(eventText);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tyield event;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process any remaining data in buffer\n\t\t\tif (buffer.trim()) {\n\t\t\t\tconst event = this.parseSSEEvent<T>(buffer);\n\t\t\t\tif (event) {\n\t\t\t\t\tyield event;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t}\n\n\t/**\n\t * Parse a single SSE event from text.\n\t */\n\tprivate parseSSEEvent<T>(text: string): SSEEvent<T> | null {\n\t\tconst lines = text.split(\"\\n\");\n\t\tlet id: string | undefined;\n\t\tlet event = \"message\"; // default event type per SSE spec\n\t\tlet data = \"\";\n\n\t\tfor (const line of lines) {\n\t\t\tif (line.startsWith(\"id:\")) {\n\t\t\t\tid = line.slice(3).trim();\n\t\t\t} else if (line.startsWith(\"event:\")) {\n\t\t\t\tevent = line.slice(6).trim();\n\t\t\t} else if (line.startsWith(\"data:\")) {\n\t\t\t\t// Append to data (SSE allows multiple data lines)\n\t\t\t\tif (data) data += \"\\n\";\n\t\t\t\tdata += line.slice(5).trim();\n\t\t\t}\n\t\t\t// Ignore retry: and comments (lines starting with :)\n\t\t}\n\n\t\tif (!data) return null;\n\n\t\tlet parsedData: T;\n\t\ttry {\n\t\t\tparsedData = JSON.parse(data) as T;\n\t\t} catch {\n\t\t\t// If data is not valid JSON, return it as-is (cast to T)\n\t\t\tparsedData = data as unknown as T;\n\t\t}\n\n\t\treturn { id, event, data: parsedData };\n\t}\n\n\tasync request<T>(req: RequestOptions): Promise<TransportResponse<T>> {\n\t\tconst url = buildUrl(this.opts.baseUrl, req.path, req.query);\n\n\t\tconst requestId = req.requestId ?? randomId(\"req\");\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Mappa-Api-Key\": this.opts.apiKey,\n\t\t\t\"X-Request-Id\": requestId,\n\t\t\t...(this.opts.userAgent ? { \"User-Agent\": this.opts.userAgent } : {}),\n\t\t\t...(this.opts.defaultHeaders ?? {}),\n\t\t};\n\n\t\tif (req.idempotencyKey) headers[\"Idempotency-Key\"] = req.idempotencyKey;\n\t\tif (req.headers) {\n\t\t\tfor (const [k, v] of Object.entries(req.headers)) {\n\t\t\t\tif (v !== undefined) headers[k] = v;\n\t\t\t}\n\t\t}\n\n\t\tconst isFormData =\n\t\t\ttypeof FormData !== \"undefined\" && req.body instanceof FormData;\n\t\tconst hasBody = req.body !== undefined;\n\n\t\tif (hasBody && !isFormData) headers[\"Content-Type\"] = \"application/json\";\n\n\t\tconst body =\n\t\t\treq.body === undefined\n\t\t\t\t? undefined\n\t\t\t\t: isFormData\n\t\t\t\t\t? (req.body as FormData)\n\t\t\t\t\t: JSON.stringify(req.body);\n\n\t\tconst maxRetries = Math.max(0, this.opts.maxRetries);\n\t\tconst startedAt = Date.now();\n\n\t\tfor (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n\t\t\tconst controller = new AbortController();\n\t\t\tconst timeout = setTimeout(\n\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\tthis.opts.timeoutMs,\n\t\t\t);\n\n\t\t\t// Combine signals: if caller aborts, abort our controller\n\t\t\tif (hasAbortSignal(req.signal)) {\n\t\t\t\tconst signal = req.signal;\n\t\t\t\tif (!signal) {\n\t\t\t\t\t// Type guard safety: hasAbortSignal should imply this is defined.\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthrow new Error(\"Unexpected: abort signal missing\");\n\t\t\t\t}\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthrow makeAbortError();\n\t\t\t\t}\n\t\t\t\tsignal.addEventListener(\n\t\t\t\t\t\"abort\",\n\t\t\t\t\t() => controller.abort(makeAbortError()),\n\t\t\t\t\t{ once: true },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.opts.telemetry?.onRequest?.({ method: req.method, url, requestId });\n\n\t\t\ttry {\n\t\t\t\tconst res = await this.fetchImpl(url, {\n\t\t\t\t\tmethod: req.method,\n\t\t\t\t\theaders,\n\t\t\t\t\tbody,\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\n\t\t\t\tconst durationMs = Date.now() - startedAt;\n\t\t\t\tconst serverRequestId =\n\t\t\t\t\tgetHeader(res.headers, \"x-request-id\") ?? requestId;\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst { parsed } = await readBody(res);\n\t\t\t\t\tconst apiErr = coerceApiError(res, parsed);\n\n\t\t\t\t\tthis.opts.telemetry?.onError?.({\n\t\t\t\t\t\turl,\n\t\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\t\terror: apiErr,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst decision = shouldRetry(req, apiErr);\n\t\t\t\t\tif (\n\t\t\t\t\t\tattempt <= maxRetries + 1 &&\n\t\t\t\t\t\tdecision.retry &&\n\t\t\t\t\t\tattempt <= maxRetries\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst base =\n\t\t\t\t\t\t\tdecision.retryAfterMs ?? jitter(backoffMs(attempt, 500, 4000));\n\t\t\t\t\t\tawait new Promise((r) => setTimeout(r, base));\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow apiErr;\n\t\t\t\t}\n\n\t\t\t\tconst ct = res.headers.get(\"content-type\") ?? \"\";\n\t\t\t\tlet data: unknown;\n\t\t\t\tif (ct.includes(\"application/json\")) {\n\t\t\t\t\tdata = (await res.json()) as unknown;\n\t\t\t\t} else {\n\t\t\t\t\tdata = await res.text();\n\t\t\t\t}\n\n\t\t\t\tthis.opts.telemetry?.onResponse?.({\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t\turl,\n\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\tdurationMs,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tdata: data as T,\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t\trequestId: serverRequestId,\n\t\t\t\t\theaders: res.headers,\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tthis.opts.telemetry?.onError?.({ url, requestId, error: err });\n\n\t\t\t\tconst decision = shouldRetry(req, err);\n\t\t\t\tif (attempt <= maxRetries && decision.retry) {\n\t\t\t\t\tconst sleep =\n\t\t\t\t\t\tdecision.retryAfterMs ?? jitter(backoffMs(attempt, 500, 4000));\n\t\t\t\t\tawait new Promise((r) => setTimeout(r, sleep));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t} finally {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t}\n\n\t\t// unreachable\n\t\tthrow new Error(\"Unexpected transport exit\");\n\t}\n}\n","function isObject(v: unknown): v is Record<string, unknown> {\n\treturn v !== null && typeof v === \"object\";\n}\n\n/**\n * Async signature verification using WebCrypto (works in modern Node and browsers).\n * Signature scheme placeholder:\n * headers[\"mappa-signature\"] = \"t=1700000000,v1=<hex_hmac_sha256>\"\n * Signed payload: `${t}.${rawBody}`\n */\n\nexport class WebhooksResource {\n\tasync verifySignature(params: {\n\t\tpayload: string; // raw body\n\t\theaders: Record<string, string | string[] | undefined>;\n\t\tsecret: string;\n\t\ttoleranceSec?: number;\n\t}): Promise<{ ok: true }> {\n\t\tconst tolerance = params.toleranceSec ?? 300;\n\n\t\tconst sigHeader = headerValue(params.headers, \"mappa-signature\");\n\t\tif (!sigHeader) throw new Error(\"Missing mappa-signature header\");\n\n\t\tconst parts = parseSig(sigHeader);\n\t\tconst ts = Number(parts.t);\n\t\tif (!Number.isFinite(ts)) throw new Error(\"Invalid signature timestamp\");\n\n\t\tconst nowSec = Math.floor(Date.now() / 1000);\n\t\tif (Math.abs(nowSec - ts) > tolerance)\n\t\t\tthrow new Error(\"Signature timestamp outside tolerance\");\n\n\t\tconst signed = `${parts.t}.${params.payload}`;\n\t\tconst expected = await hmacHex(params.secret, signed);\n\n\t\tif (!timingSafeEqualHex(expected, parts.v1))\n\t\t\tthrow new Error(\"Invalid signature\");\n\n\t\treturn { ok: true };\n\t}\n\n\tparseEvent<T = unknown>(\n\t\tpayload: string,\n\t): { id: string; type: string; createdAt: string; data: T } {\n\t\tconst raw: unknown = JSON.parse(payload);\n\t\tif (!isObject(raw))\n\t\t\tthrow new Error(\"Invalid webhook payload: not an object\");\n\t\tconst obj = raw;\n\n\t\tconst id = obj.id;\n\t\tconst type = obj.type;\n\t\tconst createdAt = obj.createdAt;\n\n\t\tif (typeof id !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: id must be a string\");\n\t\tif (typeof type !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: type must be a string\");\n\t\tif (typeof createdAt !== \"string\")\n\t\t\tthrow new Error(\"Invalid webhook payload: createdAt must be a string\");\n\n\t\treturn {\n\t\t\tid,\n\t\t\ttype,\n\t\t\tcreatedAt,\n\t\t\tdata: \"data\" in obj ? (obj.data as T) : (undefined as unknown as T),\n\t\t};\n\t}\n}\n\nfunction headerValue(\n\theaders: Record<string, string | string[] | undefined>,\n\tname: string,\n): string | undefined {\n\tconst key = Object.keys(headers).find(\n\t\t(k) => k.toLowerCase() === name.toLowerCase(),\n\t);\n\tconst v = key ? headers[key] : undefined;\n\tif (!v) return undefined;\n\treturn Array.isArray(v) ? v[0] : v;\n}\n\nfunction parseSig(h: string): { t: string; v1: string } {\n\tconst out: Record<string, string> = {};\n\tfor (const part of h.split(\",\")) {\n\t\tconst [k, v] = part.split(\"=\");\n\t\tif (k && v) out[k.trim()] = v.trim();\n\t}\n\tif (!out.t || !out.v1) throw new Error(\"Invalid signature format\");\n\treturn { t: out.t, v1: out.v1 };\n}\n\nasync function hmacHex(secret: string, message: string): Promise<string> {\n\tconst enc = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tenc.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst sig = await crypto.subtle.sign(\"HMAC\", key, enc.encode(message));\n\treturn bufToHex(sig);\n}\n\nfunction bufToHex(buf: ArrayBuffer): string {\n\tconst b = new Uint8Array(buf);\n\tlet s = \"\";\n\tfor (const x of b) s += x.toString(16).padStart(2, \"0\");\n\treturn s;\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n\tif (a.length !== b.length) return false;\n\tlet r = 0;\n\tfor (let i = 0; i < a.length; i++) r |= a.charCodeAt(i) ^ b.charCodeAt(i);\n\treturn r === 0;\n}\n","import { MappaError } from \"$/errors\";\nimport { CreditsResource } from \"$/resources/credits\";\nimport { EntitiesResource } from \"$/resources/entities\";\nimport { FeedbackResource } from \"$/resources/feedback\";\nimport { FilesResource } from \"$/resources/files\";\nimport { HealthResource } from \"$/resources/health\";\nimport { JobsResource } from \"$/resources/jobs\";\nimport { ReportsResource } from \"$/resources/reports\";\nimport { type Telemetry, Transport } from \"$/resources/transport\";\nimport { WebhooksResource } from \"$/resources/webhooks\";\n\n/**\n * Options for constructing a {@link Mappa} client.\n */\nexport type MappaClientOptions = {\n\t/**\n\t * API key used for authenticating requests.\n\t */\n\tapiKey: string;\n\n\t/**\n\t * Base URL for the Mappa API.\n\t *\n\t * @defaultValue \"https://api.mappa.ai\"\n\t */\n\tbaseUrl?: string;\n\n\t/**\n\t * Per-request timeout, in milliseconds.\n\t *\n\t * Note: this timeout applies to individual HTTP attempts (including retries).\n\t * Long-running workflows should use {@link JobsResource.wait} through\n\t * {@link ReportsResource.makeHandle} instead.\n\t *\n\t * @defaultValue 30000\n\t */\n\ttimeoutMs?: number;\n\n\t/**\n\t * Maximum number of retries performed by the transport for retryable requests.\n\t *\n\t * @defaultValue 2\n\t */\n\tmaxRetries?: number;\n\n\t/**\n\t * Headers that will be sent with every request.\n\t */\n\tdefaultHeaders?: Record<string, string>;\n\n\t/**\n\t * Custom fetch implementation (useful for polyfills, instrumentation, or tests).\n\t */\n\tfetch?: typeof fetch;\n\n\t/**\n\t * Overrides the User-Agent header.\n\t */\n\tuserAgent?: string;\n\n\t/**\n\t * Telemetry hooks called on request/response/error.\n\t */\n\ttelemetry?: Telemetry;\n};\n\n/**\n * Main SDK client.\n *\n * Exposes resource namespaces ({@link Mappa.files}, {@link Mappa.reports}, etc.)\n * and configures a shared HTTP transport.\n */\nexport class Mappa {\n\tpublic readonly files: FilesResource;\n\tpublic readonly jobs: JobsResource;\n\tpublic readonly reports: ReportsResource;\n\tpublic readonly feedback: FeedbackResource;\n\tpublic readonly credits: CreditsResource;\n\tpublic readonly entities: EntitiesResource;\n\tpublic readonly webhooks: WebhooksResource;\n\tpublic readonly health: HealthResource;\n\n\tprivate readonly transport: Transport;\n\tprivate readonly opts: Required<\n\t\tPick<MappaClientOptions, \"apiKey\" | \"baseUrl\" | \"timeoutMs\" | \"maxRetries\">\n\t> &\n\t\tOmit<MappaClientOptions, \"apiKey\" | \"baseUrl\" | \"timeoutMs\" | \"maxRetries\">;\n\n\tconstructor(options: MappaClientOptions) {\n\t\tif (!options.apiKey) {\n\t\t\tthrow new MappaError(\"apiKey is required\");\n\t\t}\n\n\t\tconst baseUrl = options.baseUrl ?? \"https://api.mappa.ai\";\n\t\tconst timeoutMs = options.timeoutMs ?? 30_000;\n\t\tconst maxRetries = options.maxRetries ?? 2;\n\n\t\tthis.opts = {\n\t\t\t...options,\n\t\t\tapiKey: options.apiKey,\n\t\t\tbaseUrl,\n\t\t\ttimeoutMs,\n\t\t\tmaxRetries,\n\t\t};\n\n\t\tthis.transport = new Transport({\n\t\t\tapiKey: options.apiKey,\n\t\t\tbaseUrl,\n\t\t\ttimeoutMs,\n\t\t\tmaxRetries,\n\t\t\tdefaultHeaders: options.defaultHeaders,\n\t\t\tfetch: options.fetch,\n\t\t\ttelemetry: options.telemetry,\n\t\t\tuserAgent: options.userAgent,\n\t\t});\n\n\t\tthis.files = new FilesResource(this.transport);\n\t\tthis.jobs = new JobsResource(this.transport);\n\t\tthis.reports = new ReportsResource(\n\t\t\tthis.transport,\n\t\t\tthis.jobs,\n\t\t\tthis.files,\n\t\t\tthis.opts.fetch ?? fetch,\n\t\t);\n\t\tthis.feedback = new FeedbackResource(this.transport);\n\t\tthis.credits = new CreditsResource(this.transport);\n\t\tthis.entities = new EntitiesResource(this.transport);\n\t\tthis.webhooks = new WebhooksResource();\n\t\tthis.health = new HealthResource(this.transport);\n\t}\n\n\twithOptions(overrides: Partial<MappaClientOptions>): Mappa {\n\t\treturn new Mappa({\n\t\t\t...this.opts,\n\t\t\t...overrides,\n\t\t\tapiKey: overrides.apiKey ?? this.opts.apiKey,\n\t\t});\n\t}\n\n\tclose(): void {\n\t\t// No-op today; reserved for future transport cleanup (keep-alive, SSE, etc.).\n\t}\n}\n","/**\n * JSON-serializable value.\n *\n * Used throughout the SDK for message payloads, webhook data, and server-provided\n * metadata where the exact shape is not known at compile time.\n */\nexport type JsonValue =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| { [k: string]: JsonValue }\n\t| JsonValue[];\n\nexport type MediaRef =\n\t| { url: string; contentType?: string; filename?: string }\n\t| { mediaId: string };\n\n/**\n * A reference to an already-uploaded media object.\n */\nexport type MediaIdRef = { mediaId: string };\n\nexport type ReportTemplateId =\n\t| \"sales_playbook\"\n\t| \"general_report\"\n\t| \"hiring_report\"\n\t| \"profile_alignment\";\n\nexport type ReportTemplateParamsMap = {\n\tsales_playbook: Record<string, never>;\n\tgeneral_report: Record<string, never>;\n\thiring_report: {\n\t\troleTitle: string;\n\t\troleDescription: string;\n\t\tcompanyCulture: string;\n\t};\n\tprofile_alignment: {\n\t\tidealProfile: string;\n\t};\n};\n\nexport type ReportOutputType = \"markdown\" | \"json\" | \"pdf\" | \"url\";\n\ntype ReportOutputEntry<\n\tOutputType extends ReportOutputType,\n\tTemplate extends ReportTemplateId,\n> = ReportTemplateParamsMap[Template] extends Record<string, never>\n\t? {\n\t\t\ttype: OutputType;\n\t\t\ttemplate: Template;\n\t\t\ttemplateParams?: ReportTemplateParamsMap[Template];\n\t\t}\n\t: {\n\t\t\ttype: OutputType;\n\t\t\ttemplate: Template;\n\t\t\ttemplateParams: ReportTemplateParamsMap[Template];\n\t\t};\n\ntype ReportOutputForType<OutputType extends ReportOutputType> =\n\t| ReportOutputEntry<OutputType, \"sales_playbook\">\n\t| ReportOutputEntry<OutputType, \"general_report\">\n\t| ReportOutputEntry<OutputType, \"hiring_report\">\n\t| ReportOutputEntry<OutputType, \"profile_alignment\">;\n\nexport type ReportOutput =\n\t| ReportOutputForType<\"markdown\">\n\t| ReportOutputForType<\"json\">\n\t| ReportOutputForType<\"pdf\">\n\t| ReportOutputForType<\"url\">;\n\n/**\n * Report output configuration constrained to a specific output type.\n * When T is a specific literal like \"markdown\", only markdown output configs are allowed.\n * When T is the full union (ReportOutputType), all output configs are allowed.\n *\n * @example\n * ```typescript\n * type MarkdownOutput = ReportOutputFor<\"markdown\">; // Only markdown configs\n * type AnyOutput = ReportOutputFor<ReportOutputType>; // All configs (same as ReportOutput)\n * ```\n */\nexport type ReportOutputFor<T extends ReportOutputType> = T extends \"markdown\"\n\t? ReportOutputForType<\"markdown\">\n\t: T extends \"json\"\n\t\t? ReportOutputForType<\"json\">\n\t\t: T extends \"pdf\"\n\t\t\t? ReportOutputForType<\"pdf\">\n\t\t\t: T extends \"url\"\n\t\t\t\t? ReportOutputForType<\"url\">\n\t\t\t\t: ReportOutput;\n\nexport type TargetStrategy =\n\t| \"dominant\"\n\t| \"timerange\"\n\t| \"entity_id\"\n\t| \"magic_hint\";\n\nexport type TargetOnMiss = \"fallback_dominant\" | \"error\";\n\nexport type TargetTimeRange = {\n\t/**\n\t * Start time in seconds.\n\t * When omitted, starts from the beginning.\n\t */\n\tstartSeconds?: number;\n\t/**\n\t * End time in seconds.\n\t * When omitted, goes until the end.\n\t */\n\tendSeconds?: number;\n};\n\ntype TargetBase = {\n\t/**\n\t * Behavior when the entity is not found.\n\t */\n\tonMiss?: TargetOnMiss;\n\t/**\n\t * Tags to apply to the selected entity after job completion.\n\t *\n\t * Tags must be 1-64 characters, alphanumeric with underscores and hyphens only.\n\t * Maximum 10 tags per request.\n\t *\n\t * @example [\"interviewer\", \"sales-rep\", \"round-1\"]\n\t */\n\ttags?: string[];\n\t/**\n\t * Exclude speakers whose entities have ANY of these tags from selection.\n\t *\n\t * Useful for filtering out known interviewers, hosts, etc.\n\t *\n\t * @example [\"interviewer\", \"host\"]\n\t */\n\texcludeTags?: string[];\n};\n\nexport type TargetDominant = TargetBase & {\n\tstrategy: \"dominant\";\n};\n\nexport type TargetTimeRangeStrategy = TargetBase & {\n\tstrategy: \"timerange\";\n\ttimeRange: TargetTimeRange;\n};\n\nexport type TargetEntityId = TargetBase & {\n\tstrategy: \"entity_id\";\n\tentityId: string;\n};\n\nexport type TargetMagicHint = TargetBase & {\n\tstrategy: \"magic_hint\";\n\thint: string;\n};\n\nexport type TargetSelector =\n\t| TargetDominant\n\t| TargetTimeRangeStrategy\n\t| TargetEntityId\n\t| TargetMagicHint;\n\nexport type TargetStrategyMap = {\n\tdominant: TargetDominant;\n\ttimerange: TargetTimeRangeStrategy;\n\tentity_id: TargetEntityId;\n\tmagic_hint: TargetMagicHint;\n};\n\nexport type TargetFor<Strategy extends TargetStrategy> =\n\tTargetStrategyMap[Strategy];\n\nexport type Usage = {\n\tcreditsUsed: number;\n\tcreditsDiscounted?: number;\n\tcreditsNetUsed: number;\n\tdurationMs?: number;\n\tmodelVersion?: string;\n};\n\nexport type JobStage =\n\t| \"uploaded\"\n\t| \"queued\"\n\t| \"transcoding\"\n\t| \"extracting\"\n\t| \"scoring\"\n\t| \"rendering\"\n\t| \"finalizing\";\n\nexport type JobStatus =\n\t| \"queued\"\n\t| \"running\"\n\t| \"succeeded\"\n\t| \"failed\"\n\t| \"canceled\";\n\nexport type JobCreditReservation = {\n\treservedCredits: number | null;\n\treservationStatus: \"active\" | \"released\" | \"applied\" | null;\n};\n\nexport type Job = {\n\tid: string;\n\ttype: \"report.generate\";\n\tstatus: JobStatus;\n\tstage?: JobStage;\n\tprogress?: number; // 0..1\n\tcreatedAt: string;\n\tupdatedAt: string;\n\treportId?: string;\n\tusage?: Usage;\n\tcredits?: JobCreditReservation;\n\treleasedCredits?: number | null;\n\terror?: {\n\t\tcode: string;\n\t\tmessage: string;\n\t\tdetails?: JsonValue;\n\t\tretryable?: boolean;\n\t};\n\trequestId?: string;\n};\n\nexport type JobEvent =\n\t| { type: \"status\"; job: Job }\n\t| { type: \"stage\"; stage: JobStage; progress?: number; job: Job }\n\t| { type: \"log\"; message: string; ts: string }\n\t| { type: \"terminal\"; job: Job };\n\nexport type Subject = {\n\tid?: string;\n\texternalRef?: string;\n\tmetadata?: Record<string, JsonValue>;\n};\n\nexport type WebhookConfig = {\n\turl: string;\n\theaders?: Record<string, string>;\n};\n\nexport type ReportCreateJobRequest<\n\tT extends ReportOutputType = ReportOutputType,\n> = {\n\tsubject?: Subject;\n\t/**\n\t * Reference to already-uploaded media.\n\t *\n\t * Note: Report job creation requires a `mediaId`. To start from a remote URL or local bytes,\n\t * use helper methods like `reports.createJobFromUrl()` / `reports.createJobFromFile()`.\n\t */\n\tmedia: MediaIdRef;\n\toutput: ReportOutputFor<T>;\n\t/**\n\t * Select the target entity for analysis.\n\t *\n\t * @defaultValue `{ strategy: \"dominant\" }` - analyzes the dominant speaker\n\t */\n\ttarget?: TargetSelector;\n\toptions?: {\n\t\tlanguage?: string;\n\t\ttimezone?: string;\n\t\tincludeMetrics?: boolean;\n\t\tincludeRawModelOutput?: boolean;\n\t};\n\t/**\n\t * Webhook to call when the job completes or fails.\n\t *\n\t * @example\n\t * webhook: {\n\t * url: \"https://example.com/webhooks/mappa\",\n\t * headers: { \"X-Custom-Header\": \"value\" }\n\t * }\n\t */\n\twebhook?: WebhookConfig;\n\tidempotencyKey?: string;\n\trequestId?: string;\n};\n\nexport type ReportBase = {\n\tid: string;\n\tcreatedAt: string;\n\tjobId?: string;\n\tsubject?: Subject;\n\tmedia: { url?: string; mediaId?: string };\n\tentity: {\n\t\tid: string;\n\t\ttags: string[];\n\t};\n\tusage?: Usage;\n\tmetrics?: Record<string, JsonValue>;\n\traw?: JsonValue;\n};\n\nexport type MarkdownReport = ReportBase & {\n\toutput: { type: \"markdown\"; template: ReportTemplateId };\n\tmarkdown: string;\n};\n\nexport type JsonReport = ReportBase & {\n\toutput: { type: \"json\"; template: ReportTemplateId };\n\tsections: Array<{\n\t\tsection_title: string;\n\t\tsection_content: JsonValue;\n\t}>;\n};\n\nexport type PdfReport = ReportBase & {\n\toutput: { type: \"pdf\"; template: ReportTemplateId };\n\tmarkdown: string;\n\tpdfUrl: string;\n};\n\nexport type UrlReport = ReportBase & {\n\toutput: { type: \"url\"; template: ReportTemplateId };\n\tmarkdown: string;\n\tsections: Array<{\n\t\tsection_title: string;\n\t\tsection_content: JsonValue;\n\t}>;\n\treportUrl: string;\n};\n\nexport type Report = MarkdownReport | JsonReport | PdfReport | UrlReport;\n\n/**\n * Maps an output type to its corresponding report type.\n * Used for type-safe inference in generate methods.\n *\n * @example\n * ```typescript\n * type R = ReportForOutputType<\"markdown\">; // MarkdownReport\n * type R = ReportForOutputType<\"json\">; // JsonReport\n * type R = ReportForOutputType<ReportOutputType>; // Report (union)\n * ```\n */\nexport type ReportForOutputType<T extends ReportOutputType> =\n\tT extends \"markdown\"\n\t\t? MarkdownReport\n\t\t: T extends \"json\"\n\t\t\t? JsonReport\n\t\t\t: T extends \"pdf\"\n\t\t\t\t? PdfReport\n\t\t\t\t: T extends \"url\"\n\t\t\t\t\t? UrlReport\n\t\t\t\t\t: Report;\n\nexport type ReportJobReceipt<T extends ReportOutputType = ReportOutputType> = {\n\tjobId: string;\n\tstatus: \"queued\" | \"running\";\n\tstage?: JobStage;\n\testimatedWaitSec?: number;\n\trequestId?: string;\n\thandle?: ReportRunHandle<T>;\n};\n\nexport type FeedbackReceipt = {\n\tid: string;\n\tcreatedAt: string;\n\ttarget: { reportId?: string; jobId?: string };\n\trating: \"thumbs_up\" | \"thumbs_down\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\";\n\ttags?: string[];\n\tcomment?: string;\n\tcredits: {\n\t\teligible: boolean;\n\t\treason?: string;\n\t\tdiscountApplied: number;\n\t\tnetUsed: number;\n\t};\n};\n\nexport type MediaObject = {\n\tmediaId: string;\n\tcreatedAt: string;\n\tcontentType: string;\n\tfilename?: string;\n\tsizeBytes?: number;\n};\n\nexport type MediaProcessingStatus =\n\t| \"PENDING\"\n\t| \"PROCESSING\"\n\t| \"COMPLETED\"\n\t| \"FAILED\";\n\nexport type MediaRetention = {\n\texpiresAt: string | null;\n\tdaysRemaining: number | null;\n\tlocked: boolean;\n};\n\nexport type MediaFile = {\n\tmediaId: string;\n\tcreatedAt: string;\n\tcontentType: string;\n\tfilename: string | null;\n\tsizeBytes: number | null;\n\tdurationSeconds: number | null;\n\tprocessingStatus: MediaProcessingStatus;\n\tlastUsedAt: string | null;\n\tretention: MediaRetention;\n};\n\nexport type FileDeleteReceipt = {\n\tmediaId: string;\n\tdeleted: true;\n};\n\nexport type RetentionLockResult = {\n\tmediaId: string;\n\tretentionLock: boolean;\n\tmessage: string;\n};\n\nexport type CursorPaginationParams = {\n\tlimit?: number;\n\tcursor?: string;\n};\n\nexport type OffsetPaginationParams = {\n\tlimit?: number;\n\toffset?: number;\n};\n\nexport type CursorPage<T> = {\n\tdata: T[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\nexport type OffsetPage<T> = {\n\tdata: T[];\n\tpagination: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\ttotal: number;\n\t};\n};\n\nexport type CreditBalance = {\n\tbalance: number;\n\treserved: number;\n\tavailable: number;\n};\n\nexport type CreditTransactionType =\n\t| \"PURCHASE\"\n\t| \"SUBSCRIPTION_GRANT\"\n\t| \"PROMO_GRANT\"\n\t| \"USAGE\"\n\t| \"REFUND\"\n\t| \"FEEDBACK_DISCOUNT\"\n\t| \"ADJUSTMENT\"\n\t| \"EXPIRATION\";\n\nexport type CreditTransaction = {\n\tid: string;\n\ttype: CreditTransactionType;\n\tamount: number;\n\tcreatedAt: string;\n\teffectiveAt: string;\n\texpiresAt: string | null;\n\tjobId: string | null;\n\tjob?: {\n\t\tid: string;\n\t\tstatus: string;\n\t\tcreatedAt: string;\n\t};\n};\n\nexport type CreditUsage = {\n\tjobId: string;\n\tcreditsUsed: number;\n\tcreditsDiscounted?: number;\n\tcreditsNetUsed: number;\n\tdurationMs?: number;\n\tmodelVersion?: string;\n};\n\n/**\n * Options for waiting on job completion.\n */\nexport type WaitOptions = {\n\t/**\n\t * Maximum time to wait before failing.\n\t *\n\t * @defaultValue 300000\n\t */\n\ttimeoutMs?: number;\n\n\t/**\n\t * Optional callback invoked on meaningful job state transitions.\n\t */\n\tonEvent?: (event: JobEvent) => void;\n\n\t/**\n\t * Abort signal used to cancel waiting.\n\t */\n\tsignal?: AbortSignal;\n};\n\n// Forward decl to avoid circular imports; implemented in reports resource.\nexport type ReportRunHandle<T extends ReportOutputType = ReportOutputType> = {\n\tjobId: string;\n\tstream(opts?: {\n\t\tsignal?: AbortSignal;\n\t\tonEvent?: (e: JobEvent) => void;\n\t}): AsyncIterable<JobEvent>;\n\twait(opts?: WaitOptions): Promise<ReportForOutputType<T>>;\n\tcancel(): Promise<Job>;\n\tjob(): Promise<Job>;\n\treport(): Promise<ReportForOutputType<T> | null>;\n};\n\n/**\n * Type guard for MarkdownReport.\n */\nexport function isMarkdownReport(report: Report): report is MarkdownReport {\n\treturn report.output.type === \"markdown\";\n}\n\n/**\n * Type guard for JsonReport.\n */\nexport function isJsonReport(report: Report): report is JsonReport {\n\treturn report.output.type === \"json\";\n}\n\n/**\n * Type guard for PdfReport.\n */\nexport function isPdfReport(report: Report): report is PdfReport {\n\treturn report.output.type === \"pdf\";\n}\n\n/**\n * Type guard for UrlReport.\n */\nexport function isUrlReport(report: Report): report is UrlReport {\n\treturn report.output.type === \"url\";\n}\n\nexport type Entity = {\n\tid: string;\n\ttags: string[];\n\tcreatedAt: string;\n\tmediaCount: number;\n\tlastSeenAt: string | null;\n};\n\nexport type EntityTagsResult = {\n\tentityId: string;\n\ttags: string[];\n};\n\nexport type ListEntitiesOptions = CursorPaginationParams & {\n\t/**\n\t * Filter entities by tags.\n\t * Entities must have ALL specified tags (AND logic).\n\t */\n\ttags?: string[];\n};\n\nexport type ListEntitiesResponse = {\n\tentities: Entity[];\n\tcursor?: string;\n\thasMore: boolean;\n};\n\n/**\n * Type guard to check if a report has entity information.\n * Always returns true since entity is always present in reports.\n */\nexport function hasEntity(report: Report): report is Report & {\n\tentity: { id: string; tags: string[] };\n} {\n\treturn report.entity !== undefined && report.entity !== null;\n}\n","/**\n * Mappa Node SDK\n *\n * This module is the public entrypoint for the package. It re-exports:\n * - {@link Mappa} (the main client)\n * - Error types from {@link \"$/errors\"}\n * - Public TypeScript types from {@link \"$/types\"}\n */\nexport * from \"$/errors\";\nexport { Mappa } from \"$/Mappa\";\nexport type * from \"$/types\";\nexport {\n\thasEntity,\n\tisJsonReport,\n\tisMarkdownReport,\n\tisPdfReport,\n\tisUrlReport,\n} from \"$/types\";\n\nimport { InsufficientCreditsError, MappaError } from \"$/errors\";\n\n/**\n * Type guard for catching SDK errors.\n */\nexport function isMappaError(err: unknown): err is MappaError {\n\treturn err instanceof MappaError;\n}\n\n/**\n * Type guard for insufficient credits errors.\n *\n * @example\n * ```typescript\n * try {\n * await mappa.reports.createJob({ ... });\n * } catch (err) {\n * if (isInsufficientCreditsError(err)) {\n * console.log(`Need ${err.required} credits, have ${err.available}`);\n * }\n * }\n * ```\n */\nexport function isInsufficientCreditsError(\n\terr: unknown,\n): err is InsufficientCreditsError {\n\treturn err instanceof InsufficientCreditsError;\n}\n"],"mappings":"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"}
|