@wokuapp/react-native 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/index.cjs +8 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,36 @@ your own ingestion, retry, or offline logic. The SDK:
|
|
|
37
37
|
> server-side. Submissions deduplicate by their client-generated `id` for 24h.
|
|
38
38
|
> Older uncertain submissions are retained for inspection instead of replayed.
|
|
39
39
|
|
|
40
|
+
## Proposed capture provenance (unreleased)
|
|
41
|
+
|
|
42
|
+
All four capture inputs add `collectionKind?: 'standalone' | 'flow'` and
|
|
43
|
+
`flowId?: string`. New captures default to `standalone`. A response inside a
|
|
44
|
+
Flow must explicitly declare both fields, including a one-step or incomplete
|
|
45
|
+
Flow; the API verifies the Flow belongs to the company and instrument.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
await woku.captureNps({
|
|
49
|
+
npsId: 'nps_123',
|
|
50
|
+
score: 2,
|
|
51
|
+
comment: 'Delivery took too long.',
|
|
52
|
+
collectionKind: 'flow',
|
|
53
|
+
flowId: 'flow_123',
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The context is persisted before the first request and survives restart, screen
|
|
58
|
+
changes and concurrent flushes in both JSON and Woku/NPS audio multipart.
|
|
59
|
+
Already queued captures keep their original ID and body, including old captures
|
|
60
|
+
without provenance or audio language. Their missing provenance remains unknown;
|
|
61
|
+
flush never changes it to standalone or assigns a Flow from the current screen.
|
|
62
|
+
If you construct `CaptureSubmission` for `WokuClient.send()` directly, declare
|
|
63
|
+
the context at creation time; the transport never adds or infers it.
|
|
64
|
+
Keep queued audio files at stable URIs with unchanged contents until delivery
|
|
65
|
+
is confirmed; the headless SDK persists file references, not native file copies.
|
|
66
|
+
Flow responses may create normal support tickets but do not activate follow-up.
|
|
67
|
+
CSAT/CES audio support is unchanged. Use this contract after the matching API
|
|
68
|
+
has been deployed and the capture package released.
|
|
69
|
+
|
|
40
70
|
## Install
|
|
41
71
|
|
|
42
72
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -100,8 +100,6 @@ var WokuClient = class {
|
|
|
100
100
|
throw new WokuConfigError(
|
|
101
101
|
"Cannot deliver a capture for another company."
|
|
102
102
|
);
|
|
103
|
-
if (submission.audio && !submission.language)
|
|
104
|
-
submission = { ...submission, language: this.config.language ?? "es" };
|
|
105
103
|
const headers = {
|
|
106
104
|
"x-woku-key": this.config.publicKey,
|
|
107
105
|
"X-Woku-Company": this.config.companyId,
|
|
@@ -418,6 +416,8 @@ var WokuSdk = class {
|
|
|
418
416
|
respondent: input.respondent,
|
|
419
417
|
metadata: input.metadata,
|
|
420
418
|
dispatchToken: input.dispatchToken,
|
|
419
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
420
|
+
flowId: input.flowId,
|
|
421
421
|
language: input.language ?? (input.audio ? this.language : void 0),
|
|
422
422
|
createdAt: Date.now()
|
|
423
423
|
};
|
|
@@ -437,6 +437,8 @@ var WokuSdk = class {
|
|
|
437
437
|
respondent: input.respondent,
|
|
438
438
|
metadata: input.metadata,
|
|
439
439
|
dispatchToken: input.dispatchToken,
|
|
440
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
441
|
+
flowId: input.flowId,
|
|
440
442
|
language: input.language ?? (input.audio ? this.language : void 0),
|
|
441
443
|
createdAt: Date.now()
|
|
442
444
|
};
|
|
@@ -454,6 +456,8 @@ var WokuSdk = class {
|
|
|
454
456
|
respondent: input.respondent,
|
|
455
457
|
metadata: input.metadata,
|
|
456
458
|
dispatchToken: input.dispatchToken,
|
|
459
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
460
|
+
flowId: input.flowId,
|
|
457
461
|
createdAt: Date.now()
|
|
458
462
|
});
|
|
459
463
|
}
|
|
@@ -469,6 +473,8 @@ var WokuSdk = class {
|
|
|
469
473
|
respondent: input.respondent,
|
|
470
474
|
metadata: input.metadata,
|
|
471
475
|
dispatchToken: input.dispatchToken,
|
|
476
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
477
|
+
flowId: input.flowId,
|
|
472
478
|
createdAt: Date.now()
|
|
473
479
|
});
|
|
474
480
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters.ts","../src/errors.ts","../src/client.ts","../src/queue.ts","../src/sdk.ts"],"names":["body"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Injectable adapters. The SDK core never imports React Native or a\n * concrete HTTP/storage library directly — host apps provide these so\n * the core stays unit-testable and platform-agnostic.\n */\n\n/** Minimal HTTP response the SDK needs. */\nexport interface HttpResponse {\n status: number;\n ok: boolean;\n json: () => Promise<unknown>;\n headers: { get: (name: string) => string | null };\n}\n\nexport interface HttpRequest {\n method: string;\n url: string;\n headers: Record<string, string>;\n /**\n * JSON string for text/rating captures, or a `FormData` for audio captures\n * (multipart). For `FormData` the host's `fetch` sets the\n * `multipart/form-data` Content-Type (with boundary) itself.\n */\n body?: string | FormData;\n signal?: AbortSignal;\n}\n\n/** HTTP transport. Defaults to global `fetch`. */\nexport interface HttpClient {\n request: (req: HttpRequest) => Promise<HttpResponse>;\n}\n\n/**\n * Key/value persistence for the offline queue. React Native apps pass an\n * MMKV or AsyncStorage-backed adapter; tests use the in-memory one.\n */\nexport interface Storage {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem: (key: string) => Promise<void> | void;\n}\n\nexport interface Logger {\n debug: (msg: string, meta?: unknown) => void;\n warn: (msg: string, meta?: unknown) => void;\n error: (msg: string, meta?: unknown) => void;\n}\n\n/** Default HTTP client backed by the global `fetch`. */\nexport const fetchHttpClient: HttpClient = {\n async request(req) {\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: req.signal,\n });\n return {\n status: res.status,\n ok: res.ok,\n json: () => res.json(),\n headers: { get: (name) => res.headers.get(name) },\n };\n },\n};\n\n/** In-memory storage. Default for tests and ephemeral usage. */\nexport class InMemoryStorage implements Storage {\n private readonly map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** No-op logger (default). */\nexport const noopLogger: Logger = {\n debug: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n};\n","/** Base error for all SDK failures. */\nexport class WokuError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'WokuError';\n }\n}\n\n/** Thrown when the SDK is misconfigured (missing companyId, etc.). */\nexport class WokuConfigError extends WokuError {\n constructor(message: string) {\n super(message, 'config_error');\n this.name = 'WokuConfigError';\n }\n}\n\n/** Validation failure on a capture input (bad rating/score, etc.). */\nexport class WokuValidationError extends WokuError {\n constructor(message: string) {\n super(message, 'validation_error');\n this.name = 'WokuValidationError';\n }\n}\n\n/**\n * The backend rejected the submission because the respondent is in\n * quarantine (HTTP 429 with a QUARANTINE_BLOCKED code). Carries the\n * retry-after hint in seconds when the server provides one.\n */\nexport class WokuQuarantineError extends WokuError {\n constructor(\n message: string,\n public readonly retryAfterSeconds?: number,\n ) {\n super(message, 'quarantine_blocked');\n this.name = 'WokuQuarantineError';\n }\n}\n\n/** Network/transport failure; the submission should be retried later. */\nexport class WokuNetworkError extends WokuError {\n constructor(message: string) {\n super(message, 'network_error');\n this.name = 'WokuNetworkError';\n }\n}\n","import {\n fetchHttpClient,\n noopLogger,\n type HttpClient,\n type Logger,\n} from './adapters';\nimport {\n WokuConfigError,\n WokuNetworkError,\n WokuQuarantineError,\n} from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\nexport interface WokuClientConfig {\n /** Base URL of the Woku API, e.g. `https://clientapi.woku.app`. */\n apiUrl: string;\n /** Public SDK key issued per company for capture ingestion. */\n publicKey: string;\n /** Tenant the captures belong to. */\n companyId: string;\n /** HTTP transport. Defaults to the global `fetch`. */\n http?: HttpClient;\n logger?: Logger;\n /** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */\n capturePath?: string;\n /** Default audio language. */\n language?: 'es' | 'en';\n /** Bound a transport attempt, including injected adapters. Default 30s. */\n timeoutMs?: number;\n}\n\n// Resource-oriented v1 capture endpoint (woku-server clientapi). The channel\n// ('mobile-sdk') is sealed server-side from this endpoint.\nconst DEFAULT_CAPTURE_PATH = '/v1/captures';\n\n/**\n * Thin, typed transport to the Woku capture ingest endpoint. Stateless:\n * it turns a normalized {@link CaptureSubmission} into an authenticated\n * POST and maps the response (incl. quarantine 429) to a result/error.\n */\nexport class WokuClient {\n private readonly http: HttpClient;\n private readonly logger: Logger;\n private readonly endpoint: string;\n\n constructor(private readonly config: WokuClientConfig) {\n if (!config.apiUrl) throw new WokuConfigError('apiUrl is required');\n if (!config.publicKey) throw new WokuConfigError('publicKey is required');\n if (config.publicKey.startsWith('sk_'))\n throw new WokuConfigError(\n 'Use a publishable key, never a management secret key, in a mobile app.',\n );\n if (!config.companyId) throw new WokuConfigError('companyId is required');\n this.http = config.http ?? fetchHttpClient;\n this.logger = config.logger ?? noopLogger;\n const base = config.apiUrl.replace(/\\/$/, '');\n const path = config.capturePath ?? DEFAULT_CAPTURE_PATH;\n this.endpoint = `${base}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n /**\n * Sends one submission. Resolves with a `sent` result on 2xx, throws\n * {@link WokuQuarantineError} on a quarantine 429, {@link WokuNetworkError}\n * on transport failure, and resolves with a `failed` result on other\n * non-2xx responses (so the caller can decide to re-queue).\n */\n async send(submission: CaptureSubmission): Promise<SubmissionResult> {\n if (submission.companyId !== this.config.companyId)\n throw new WokuConfigError(\n 'Cannot deliver a capture for another company.',\n );\n if (submission.audio && !submission.language)\n submission = { ...submission, language: this.config.language ?? 'es' };\n const headers: Record<string, string> = {\n 'x-woku-key': this.config.publicKey,\n 'X-Woku-Company': this.config.companyId,\n 'X-Woku-Idempotency-Key': submission.id,\n };\n\n let requestBody: string | FormData;\n if (submission.audio) {\n // Audio capture: send multipart so the server can store the voicemail.\n // The platform `fetch` reads the local `uri` and sets the multipart\n // Content-Type (with boundary), so we must NOT set it ourselves.\n const form = new FormData();\n form.append('file', {\n uri: submission.audio.uri,\n type: submission.audio.mimeType,\n name: 'capture-audio',\n } as unknown as Blob);\n form.append('payload', JSON.stringify(submission));\n requestBody = form;\n } else {\n headers['Content-Type'] = 'application/json';\n requestBody = JSON.stringify(submission);\n }\n\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n (async (): Promise<SubmissionResult> => {\n const response = await this.http.request({\n method: 'POST',\n url: this.endpoint,\n headers,\n body: requestBody,\n signal: controller.signal,\n });\n if (response.ok) {\n const body = (await this.safeJson(response.json)) as {\n id?: string;\n remoteId?: string;\n } | null;\n return {\n id: submission.id,\n status: 'sent',\n remoteId: body?.remoteId ?? body?.id,\n };\n }\n if (response.status === 429) {\n const raw = response.headers.get('Retry-After');\n const retryAfter = raw === null ? undefined : Number(raw);\n throw new WokuQuarantineError(\n 'Submission blocked by quarantine',\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? Math.max(0, retryAfter)\n : undefined,\n );\n }\n const body = (await this.safeJson(response.json)) as {\n message?: unknown;\n } | null;\n const value = body?.message;\n const message =\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as { message?: unknown }).message\n : value;\n const detail = Array.isArray(message)\n ? message.filter((item) => typeof item === 'string').join(', ')\n : message;\n const error =\n typeof detail === 'string' && detail\n ? detail\n : `HTTP ${response.status}`;\n this.logger.warn(`woku capture rejected: ${error}`);\n return {\n id: submission.id,\n status: 'failed',\n error,\n retryable: response.status === 408 || response.status >= 500,\n };\n })(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new WokuNetworkError('Capture request timed out'));\n }, this.config.timeoutMs ?? 30_000);\n }),\n ]);\n } catch (err) {\n if (err instanceof WokuQuarantineError) throw err;\n throw new WokuNetworkError(\n err instanceof Error ? err.message : 'Capture request failed',\n );\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n\n private async safeJson(\n json: () => Promise<unknown>,\n ): Promise<unknown | null> {\n try {\n return await json();\n } catch {\n return null;\n }\n }\n}\n","import { InMemoryStorage, type Storage } from './adapters';\nimport { WokuConfigError, WokuQuarantineError } from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\ninterface QueuedItem {\n submission: CaptureSubmission;\n attempts: number;\n failure?: string;\n}\nexport interface FailedCapture {\n submission: CaptureSubmission;\n reason: string;\n}\nexport interface OfflineQueueOptions {\n storage?: Storage;\n storageKey?: string;\n maxAttempts?: number;\n /** Restrict reads, delivery and clearing to this company, including legacy rows. */\n companyId?: string;\n}\nexport interface FlushResult {\n sent: number;\n failed: number;\n remaining: number;\n quarantined?: boolean;\n}\n\nconst DEFAULT_KEY = 'woku.sdk.queue.v1';\nconst mutations = new WeakMap<Storage, Map<string, Promise<void>>>();\nconst flushes = new WeakMap<Storage, Map<string, Promise<FlushResult>>>();\n\n/** Persistent FIFO with scoped ownership, atomic local mutations and retained failures. */\nexport class OfflineQueue {\n private readonly storage: Storage;\n private readonly key: string;\n private readonly maxAttempts: number;\n private readonly companyId?: string;\n\n constructor(opts: OfflineQueueOptions = {}) {\n this.storage = opts.storage ?? new InMemoryStorage();\n this.key = opts.storageKey ?? DEFAULT_KEY;\n this.maxAttempts = opts.maxAttempts ?? 8;\n this.companyId = opts.companyId;\n }\n\n private owned(item: QueuedItem): boolean {\n return !this.companyId || item.submission.companyId === this.companyId;\n }\n private async load(): Promise<QueuedItem[]> {\n const raw = await this.storage.getItem(this.key);\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n Array.isArray(parsed) &&\n parsed.every(\n (item) =>\n item &&\n typeof item === 'object' &&\n item.submission &&\n typeof item.submission.id === 'string' &&\n typeof item.submission.companyId === 'string' &&\n Number.isFinite(item.submission.createdAt) &&\n Number.isInteger(item.attempts) &&\n item.attempts >= 0,\n )\n )\n return parsed as QueuedItem[];\n } catch {\n /* Preserve invalid storage instead of silently overwriting it. */\n }\n throw new WokuConfigError(\n 'The capture queue contains invalid data; repair it before writing.',\n );\n }\n private async persist(items: QueuedItem[]): Promise<void> {\n await this.storage.setItem(this.key, JSON.stringify(items));\n }\n private mutation<T>(run: () => Promise<T>): Promise<T> {\n let locks = mutations.get(this.storage);\n if (!locks) {\n locks = new Map();\n mutations.set(this.storage, locks);\n }\n const previous = locks.get(this.key) ?? Promise.resolve();\n const result = previous.then(run, run);\n const settled = result.then(\n () => undefined,\n () => undefined,\n );\n locks.set(this.key, settled);\n void settled.then(() => {\n if (locks?.get(this.key) === settled) locks.delete(this.key);\n });\n return result;\n }\n\n async enqueue(submission: CaptureSubmission): Promise<void> {\n if (this.companyId && submission.companyId !== this.companyId)\n throw new WokuConfigError(\n 'Cannot enqueue a capture from another company.',\n );\n const snapshot = JSON.parse(\n JSON.stringify(submission),\n ) as CaptureSubmission;\n return this.mutation(async () => {\n const items = await this.load();\n if (\n items.some(\n (item) =>\n item.submission.id === snapshot.id &&\n item.submission.companyId === snapshot.companyId,\n )\n )\n return;\n items.push({ submission: snapshot, attempts: 0 });\n await this.persist(items);\n });\n }\n size(): Promise<number> {\n return this.mutation(\n async () =>\n (await this.load()).filter((item) => this.owned(item) && !item.failure)\n .length,\n );\n }\n pending(): Promise<CaptureSubmission[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && !item.failure)\n .map((item) => item.submission),\n );\n }\n failures(): Promise<FailedCapture[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && item.failure)\n .map((item) => ({\n submission: item.submission,\n reason: item.failure!,\n })),\n );\n }\n\n acknowledge(submission: CaptureSubmission): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n await this.persist(\n items.filter(\n (item) =>\n !(\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n this.owned(item)\n ),\n ),\n );\n });\n }\n reject(submission: CaptureSubmission, reason: string): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n const item = items.find(\n (row) =>\n row.submission.id === submission.id &&\n row.submission.companyId === submission.companyId &&\n this.owned(row),\n );\n if (item) {\n item.failure = reason;\n await this.persist(items);\n }\n });\n }\n\n flush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n let jobs = flushes.get(this.storage);\n if (!jobs) {\n jobs = new Map();\n flushes.set(this.storage, jobs);\n }\n const scope = JSON.stringify([this.key, this.companyId ?? '*']);\n const existing = jobs.get(scope);\n if (existing) return existing;\n const result = this.runFlush(send).finally(() => {\n if (jobs?.get(scope) === result) jobs.delete(scope);\n });\n jobs.set(scope, result);\n return result;\n }\n private async runFlush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n const batch = await this.pending();\n let sent = 0,\n failed = 0,\n quarantined = false;\n for (const candidate of batch) {\n // A clear/reject while another request is in flight invalidates this snapshot.\n const current = await this.mutation(async () =>\n (await this.load()).find(\n (item) =>\n this.owned(item) &&\n !item.failure &&\n item.submission.id === candidate.id &&\n item.submission.companyId === candidate.companyId,\n ),\n );\n if (!current) continue;\n const submission = current.submission;\n // The server deduplicates for 24h; keep older uncertain captures for\n // inspection rather than resubmitting them outside that protection.\n if (\n submission.createdAt > 0 &&\n Date.now() - submission.createdAt >= 24 * 60 * 60 * 1000\n ) {\n await this.reject(\n submission,\n 'Retry window expired; inspect delivery before resubmitting.',\n );\n failed++;\n continue;\n }\n let permanent = false;\n let reason: string | undefined;\n let accepted = false;\n try {\n const result = await send(submission);\n accepted = result.status === 'sent';\n reason = result.error;\n permanent = result.retryable === false;\n } catch (error) {\n if (error instanceof WokuQuarantineError) {\n quarantined = true;\n break;\n }\n reason = error instanceof Error ? error.message : 'Delivery failed';\n }\n const outcome = await this.mutation(async () => {\n const items = await this.load();\n const index = items.findIndex(\n (item) =>\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n !item.failure,\n );\n if (index < 0) return 'removed';\n if (accepted) items.splice(index, 1);\n else {\n const item = items[index]!;\n item.attempts++;\n if (permanent || item.attempts >= this.maxAttempts)\n item.failure = reason ?? 'Attempt budget exhausted';\n }\n const exhausted = !accepted && Boolean(items[index]?.failure);\n await this.persist(items);\n return accepted ? 'sent' : exhausted ? 'failed' : 'pending';\n });\n if (outcome === 'sent') sent++;\n if (outcome === 'failed') failed++;\n }\n return { sent, failed, remaining: await this.size(), quarantined };\n }\n clear(): Promise<void> {\n return this.mutation(async () => {\n if (!this.companyId) {\n await this.storage.removeItem(this.key);\n return;\n }\n const remaining = (await this.load()).filter((item) => !this.owned(item));\n if (remaining.length) await this.persist(remaining);\n else await this.storage.removeItem(this.key);\n });\n }\n}\n","import { WokuClient, type WokuClientConfig } from './client';\nimport { OfflineQueue, type FlushResult } from './queue';\nimport { type Storage, type Logger, noopLogger } from './adapters';\nimport {\n WokuNetworkError,\n WokuQuarantineError,\n WokuValidationError,\n} from './errors';\nimport type {\n CaptureSubmission,\n CsatCaptureInput,\n CesCaptureInput,\n NpsCaptureInput,\n SubmissionResult,\n WokuCaptureInput,\n} from './types';\n\nexport interface WokuSdkConfig extends WokuClientConfig {\n /** Storage adapter for the offline queue (MMKV/AsyncStorage in RN). */\n storage?: Storage;\n /** Retain a failed submission for inspection after this many flush attempts. */\n maxQueueAttempts?: number;\n}\n\nfunction generateId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n // Fallback: timestamp + random, good enough as an idempotency key.\n return `wk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction assertInt(\n value: number,\n min: number,\n max: number,\n field: string,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new WokuValidationError(\n `${field} must be an integer between ${min} and ${max}`,\n );\n }\n}\n\n/**\n * Top-level Woku SDK. Wires the typed {@link WokuClient} to a durable\n * {@link OfflineQueue}: a capture is attempted immediately and, if the\n * device is offline or the server is unreachable, transparently queued\n * and retried on the next {@link WokuSdk.flush}.\n *\n * @example\n * const woku = new WokuSdk({\n * apiUrl: 'https://api.woku.app',\n * publicKey: 'pk_live_...',\n * companyId: 'company_123',\n * storage: mmkvStorageAdapter,\n * });\n * await woku.captureNps({ npsId: 'nps_1', score: 9, comment: 'Great!' });\n */\nexport class WokuSdk {\n private readonly client: WokuClient;\n private readonly queue: OfflineQueue;\n private readonly logger: Logger;\n private readonly companyId: string;\n private readonly language: 'es' | 'en';\n\n constructor(config: WokuSdkConfig) {\n this.client = new WokuClient(config);\n this.queue = new OfflineQueue({\n storage: config.storage,\n companyId: config.companyId,\n maxAttempts: config.maxQueueAttempts,\n });\n this.logger = config.logger ?? noopLogger;\n this.companyId = config.companyId;\n this.language = config.language ?? 'es';\n }\n\n /** Captures a Woku rating (1..5) with optional text/audio comment. */\n async captureWoku(input: WokuCaptureInput): Promise<SubmissionResult> {\n assertInt(input.rating, 1, 5, 'rating');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'woku',\n companyId: this.companyId,\n targetId: input.wokuId,\n rating: input.rating,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n /** Captures an NPS score (0..10) with optional text/audio review. */\n async captureNps(input: NpsCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 0, 10, 'score');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'nps',\n companyId: this.companyId,\n targetId: input.npsId,\n score: input.score,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n async captureCsat(input: CsatCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'csat',\n companyId: this.companyId,\n targetId: input.csatId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n createdAt: Date.now(),\n });\n }\n async captureCes(input: CesCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'ces',\n companyId: this.companyId,\n targetId: input.cesId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n createdAt: Date.now(),\n });\n }\n\n /** Retries every queued submission. Safe to call on app foreground or\n * when connectivity is regained. */\n flush(): Promise<FlushResult> {\n return this.queue.flush((s) => this.client.send(s));\n }\n\n /** Number of submissions waiting to be delivered. */\n pendingCount(): Promise<number> {\n return this.queue.size();\n }\n\n /** Inspect retained captures whose automatic attempt budget was exhausted. */\n failedCaptures(): Promise<import('./queue').FailedCapture[]> {\n return this.queue.failures();\n }\n\n /** Clears the offline queue (e.g. on user logout). */\n clearQueue(): Promise<void> {\n return this.queue.clear();\n }\n\n /**\n * Tries to send immediately; on quarantine or network failure the\n * submission is queued for a later flush rather than thrown away.\n */\n private async deliver(\n submission: CaptureSubmission,\n ): Promise<SubmissionResult> {\n submission = JSON.parse(JSON.stringify(submission)) as CaptureSubmission;\n await this.queue.enqueue(submission);\n try {\n const result = await this.client.send(submission);\n if (result.status === 'sent') {\n try {\n await this.queue.acknowledge(submission);\n } catch {\n // Delivery is confirmed. Keep its original id for a later deduplicated\n // flush rather than making callers think they must submit again.\n this.logger.warn(\n 'Capture accepted; local acknowledgement is pending',\n { id: submission.id },\n );\n }\n return result;\n }\n if (result.retryable === false) {\n await this.queue.reject(submission, result.error ?? 'Capture rejected');\n return result;\n }\n // Server-rejected but transient enough to retry: queue it.\n await this.queue.enqueue(submission);\n return { ...result, status: 'queued' };\n } catch (err) {\n await this.queue.enqueue(submission);\n if (err instanceof WokuQuarantineError) {\n return { id: submission.id, status: 'quarantined', error: err.message };\n }\n if (err instanceof WokuNetworkError) {\n this.logger.debug('capture queued (offline)', { id: submission.id });\n return { id: submission.id, status: 'queued' };\n }\n throw err;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters.ts","../src/errors.ts","../src/client.ts","../src/queue.ts","../src/sdk.ts"],"names":["body"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Injectable adapters. The SDK core never imports React Native or a\n * concrete HTTP/storage library directly — host apps provide these so\n * the core stays unit-testable and platform-agnostic.\n */\n\n/** Minimal HTTP response the SDK needs. */\nexport interface HttpResponse {\n status: number;\n ok: boolean;\n json: () => Promise<unknown>;\n headers: { get: (name: string) => string | null };\n}\n\nexport interface HttpRequest {\n method: string;\n url: string;\n headers: Record<string, string>;\n /**\n * JSON string for text/rating captures, or a `FormData` for audio captures\n * (multipart). For `FormData` the host's `fetch` sets the\n * `multipart/form-data` Content-Type (with boundary) itself.\n */\n body?: string | FormData;\n signal?: AbortSignal;\n}\n\n/** HTTP transport. Defaults to global `fetch`. */\nexport interface HttpClient {\n request: (req: HttpRequest) => Promise<HttpResponse>;\n}\n\n/**\n * Key/value persistence for the offline queue. React Native apps pass an\n * MMKV or AsyncStorage-backed adapter; tests use the in-memory one.\n */\nexport interface Storage {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem: (key: string) => Promise<void> | void;\n}\n\nexport interface Logger {\n debug: (msg: string, meta?: unknown) => void;\n warn: (msg: string, meta?: unknown) => void;\n error: (msg: string, meta?: unknown) => void;\n}\n\n/** Default HTTP client backed by the global `fetch`. */\nexport const fetchHttpClient: HttpClient = {\n async request(req) {\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: req.signal,\n });\n return {\n status: res.status,\n ok: res.ok,\n json: () => res.json(),\n headers: { get: (name) => res.headers.get(name) },\n };\n },\n};\n\n/** In-memory storage. Default for tests and ephemeral usage. */\nexport class InMemoryStorage implements Storage {\n private readonly map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** No-op logger (default). */\nexport const noopLogger: Logger = {\n debug: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n};\n","/** Base error for all SDK failures. */\nexport class WokuError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'WokuError';\n }\n}\n\n/** Thrown when the SDK is misconfigured (missing companyId, etc.). */\nexport class WokuConfigError extends WokuError {\n constructor(message: string) {\n super(message, 'config_error');\n this.name = 'WokuConfigError';\n }\n}\n\n/** Validation failure on a capture input (bad rating/score, etc.). */\nexport class WokuValidationError extends WokuError {\n constructor(message: string) {\n super(message, 'validation_error');\n this.name = 'WokuValidationError';\n }\n}\n\n/**\n * The backend rejected the submission because the respondent is in\n * quarantine (HTTP 429 with a QUARANTINE_BLOCKED code). Carries the\n * retry-after hint in seconds when the server provides one.\n */\nexport class WokuQuarantineError extends WokuError {\n constructor(\n message: string,\n public readonly retryAfterSeconds?: number,\n ) {\n super(message, 'quarantine_blocked');\n this.name = 'WokuQuarantineError';\n }\n}\n\n/** Network/transport failure; the submission should be retried later. */\nexport class WokuNetworkError extends WokuError {\n constructor(message: string) {\n super(message, 'network_error');\n this.name = 'WokuNetworkError';\n }\n}\n","import {\n fetchHttpClient,\n noopLogger,\n type HttpClient,\n type Logger,\n} from './adapters';\nimport {\n WokuConfigError,\n WokuNetworkError,\n WokuQuarantineError,\n} from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\nexport interface WokuClientConfig {\n /** Base URL of the Woku API, e.g. `https://clientapi.woku.app`. */\n apiUrl: string;\n /** Public SDK key issued per company for capture ingestion. */\n publicKey: string;\n /** Tenant the captures belong to. */\n companyId: string;\n /** HTTP transport. Defaults to the global `fetch`. */\n http?: HttpClient;\n logger?: Logger;\n /** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */\n capturePath?: string;\n /** Default audio language for WokuSdk builders; send() preserves payloads. */\n language?: 'es' | 'en';\n /** Bound a transport attempt, including injected adapters. Default 30s. */\n timeoutMs?: number;\n}\n\n// Resource-oriented v1 capture endpoint (woku-server clientapi). The channel\n// ('mobile-sdk') is sealed server-side from this endpoint.\nconst DEFAULT_CAPTURE_PATH = '/v1/captures';\n\n/**\n * Thin, typed transport to the Woku capture ingest endpoint. Stateless:\n * it turns a normalized {@link CaptureSubmission} into an authenticated\n * POST and maps the response (incl. quarantine 429) to a result/error.\n */\nexport class WokuClient {\n private readonly http: HttpClient;\n private readonly logger: Logger;\n private readonly endpoint: string;\n\n constructor(private readonly config: WokuClientConfig) {\n if (!config.apiUrl) throw new WokuConfigError('apiUrl is required');\n if (!config.publicKey) throw new WokuConfigError('publicKey is required');\n if (config.publicKey.startsWith('sk_'))\n throw new WokuConfigError(\n 'Use a publishable key, never a management secret key, in a mobile app.',\n );\n if (!config.companyId) throw new WokuConfigError('companyId is required');\n this.http = config.http ?? fetchHttpClient;\n this.logger = config.logger ?? noopLogger;\n const base = config.apiUrl.replace(/\\/$/, '');\n const path = config.capturePath ?? DEFAULT_CAPTURE_PATH;\n this.endpoint = `${base}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n /**\n * Sends one submission. Resolves with a `sent` result on 2xx, throws\n * {@link WokuQuarantineError} on a quarantine 429, {@link WokuNetworkError}\n * on transport failure, and resolves with a `failed` result on other\n * non-2xx responses (so the caller can decide to re-queue).\n */\n async send(submission: CaptureSubmission): Promise<SubmissionResult> {\n if (submission.companyId !== this.config.companyId)\n throw new WokuConfigError(\n 'Cannot deliver a capture for another company.',\n );\n const headers: Record<string, string> = {\n 'x-woku-key': this.config.publicKey,\n 'X-Woku-Company': this.config.companyId,\n 'X-Woku-Idempotency-Key': submission.id,\n };\n\n let requestBody: string | FormData;\n if (submission.audio) {\n // Audio capture: send multipart so the server can store the voicemail.\n // The platform `fetch` reads the local `uri` and sets the multipart\n // Content-Type (with boundary), so we must NOT set it ourselves.\n const form = new FormData();\n form.append('file', {\n uri: submission.audio.uri,\n type: submission.audio.mimeType,\n name: 'capture-audio',\n } as unknown as Blob);\n form.append('payload', JSON.stringify(submission));\n requestBody = form;\n } else {\n headers['Content-Type'] = 'application/json';\n requestBody = JSON.stringify(submission);\n }\n\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n (async (): Promise<SubmissionResult> => {\n const response = await this.http.request({\n method: 'POST',\n url: this.endpoint,\n headers,\n body: requestBody,\n signal: controller.signal,\n });\n if (response.ok) {\n const body = (await this.safeJson(response.json)) as {\n id?: string;\n remoteId?: string;\n } | null;\n return {\n id: submission.id,\n status: 'sent',\n remoteId: body?.remoteId ?? body?.id,\n };\n }\n if (response.status === 429) {\n const raw = response.headers.get('Retry-After');\n const retryAfter = raw === null ? undefined : Number(raw);\n throw new WokuQuarantineError(\n 'Submission blocked by quarantine',\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? Math.max(0, retryAfter)\n : undefined,\n );\n }\n const body = (await this.safeJson(response.json)) as {\n message?: unknown;\n } | null;\n const value = body?.message;\n const message =\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as { message?: unknown }).message\n : value;\n const detail = Array.isArray(message)\n ? message.filter((item) => typeof item === 'string').join(', ')\n : message;\n const error =\n typeof detail === 'string' && detail\n ? detail\n : `HTTP ${response.status}`;\n this.logger.warn(`woku capture rejected: ${error}`);\n return {\n id: submission.id,\n status: 'failed',\n error,\n retryable: response.status === 408 || response.status >= 500,\n };\n })(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new WokuNetworkError('Capture request timed out'));\n }, this.config.timeoutMs ?? 30_000);\n }),\n ]);\n } catch (err) {\n if (err instanceof WokuQuarantineError) throw err;\n throw new WokuNetworkError(\n err instanceof Error ? err.message : 'Capture request failed',\n );\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n\n private async safeJson(\n json: () => Promise<unknown>,\n ): Promise<unknown | null> {\n try {\n return await json();\n } catch {\n return null;\n }\n }\n}\n","import { InMemoryStorage, type Storage } from './adapters';\nimport { WokuConfigError, WokuQuarantineError } from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\ninterface QueuedItem {\n submission: CaptureSubmission;\n attempts: number;\n failure?: string;\n}\nexport interface FailedCapture {\n submission: CaptureSubmission;\n reason: string;\n}\nexport interface OfflineQueueOptions {\n storage?: Storage;\n storageKey?: string;\n maxAttempts?: number;\n /** Restrict reads, delivery and clearing to this company, including legacy rows. */\n companyId?: string;\n}\nexport interface FlushResult {\n sent: number;\n failed: number;\n remaining: number;\n quarantined?: boolean;\n}\n\nconst DEFAULT_KEY = 'woku.sdk.queue.v1';\nconst mutations = new WeakMap<Storage, Map<string, Promise<void>>>();\nconst flushes = new WeakMap<Storage, Map<string, Promise<FlushResult>>>();\n\n/** Persistent FIFO with scoped ownership, atomic local mutations and retained failures. */\nexport class OfflineQueue {\n private readonly storage: Storage;\n private readonly key: string;\n private readonly maxAttempts: number;\n private readonly companyId?: string;\n\n constructor(opts: OfflineQueueOptions = {}) {\n this.storage = opts.storage ?? new InMemoryStorage();\n this.key = opts.storageKey ?? DEFAULT_KEY;\n this.maxAttempts = opts.maxAttempts ?? 8;\n this.companyId = opts.companyId;\n }\n\n private owned(item: QueuedItem): boolean {\n return !this.companyId || item.submission.companyId === this.companyId;\n }\n private async load(): Promise<QueuedItem[]> {\n const raw = await this.storage.getItem(this.key);\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n Array.isArray(parsed) &&\n parsed.every(\n (item) =>\n item &&\n typeof item === 'object' &&\n item.submission &&\n typeof item.submission.id === 'string' &&\n typeof item.submission.companyId === 'string' &&\n Number.isFinite(item.submission.createdAt) &&\n Number.isInteger(item.attempts) &&\n item.attempts >= 0,\n )\n )\n return parsed as QueuedItem[];\n } catch {\n /* Preserve invalid storage instead of silently overwriting it. */\n }\n throw new WokuConfigError(\n 'The capture queue contains invalid data; repair it before writing.',\n );\n }\n private async persist(items: QueuedItem[]): Promise<void> {\n await this.storage.setItem(this.key, JSON.stringify(items));\n }\n private mutation<T>(run: () => Promise<T>): Promise<T> {\n let locks = mutations.get(this.storage);\n if (!locks) {\n locks = new Map();\n mutations.set(this.storage, locks);\n }\n const previous = locks.get(this.key) ?? Promise.resolve();\n const result = previous.then(run, run);\n const settled = result.then(\n () => undefined,\n () => undefined,\n );\n locks.set(this.key, settled);\n void settled.then(() => {\n if (locks?.get(this.key) === settled) locks.delete(this.key);\n });\n return result;\n }\n\n async enqueue(submission: CaptureSubmission): Promise<void> {\n if (this.companyId && submission.companyId !== this.companyId)\n throw new WokuConfigError(\n 'Cannot enqueue a capture from another company.',\n );\n const snapshot = JSON.parse(\n JSON.stringify(submission),\n ) as CaptureSubmission;\n return this.mutation(async () => {\n const items = await this.load();\n if (\n items.some(\n (item) =>\n item.submission.id === snapshot.id &&\n item.submission.companyId === snapshot.companyId,\n )\n )\n return;\n items.push({ submission: snapshot, attempts: 0 });\n await this.persist(items);\n });\n }\n size(): Promise<number> {\n return this.mutation(\n async () =>\n (await this.load()).filter((item) => this.owned(item) && !item.failure)\n .length,\n );\n }\n pending(): Promise<CaptureSubmission[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && !item.failure)\n .map((item) => item.submission),\n );\n }\n failures(): Promise<FailedCapture[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && item.failure)\n .map((item) => ({\n submission: item.submission,\n reason: item.failure!,\n })),\n );\n }\n\n acknowledge(submission: CaptureSubmission): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n await this.persist(\n items.filter(\n (item) =>\n !(\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n this.owned(item)\n ),\n ),\n );\n });\n }\n reject(submission: CaptureSubmission, reason: string): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n const item = items.find(\n (row) =>\n row.submission.id === submission.id &&\n row.submission.companyId === submission.companyId &&\n this.owned(row),\n );\n if (item) {\n item.failure = reason;\n await this.persist(items);\n }\n });\n }\n\n flush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n let jobs = flushes.get(this.storage);\n if (!jobs) {\n jobs = new Map();\n flushes.set(this.storage, jobs);\n }\n const scope = JSON.stringify([this.key, this.companyId ?? '*']);\n const existing = jobs.get(scope);\n if (existing) return existing;\n const result = this.runFlush(send).finally(() => {\n if (jobs?.get(scope) === result) jobs.delete(scope);\n });\n jobs.set(scope, result);\n return result;\n }\n private async runFlush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n const batch = await this.pending();\n let sent = 0,\n failed = 0,\n quarantined = false;\n for (const candidate of batch) {\n // A clear/reject while another request is in flight invalidates this snapshot.\n const current = await this.mutation(async () =>\n (await this.load()).find(\n (item) =>\n this.owned(item) &&\n !item.failure &&\n item.submission.id === candidate.id &&\n item.submission.companyId === candidate.companyId,\n ),\n );\n if (!current) continue;\n const submission = current.submission;\n // The server deduplicates for 24h; keep older uncertain captures for\n // inspection rather than resubmitting them outside that protection.\n if (\n submission.createdAt > 0 &&\n Date.now() - submission.createdAt >= 24 * 60 * 60 * 1000\n ) {\n await this.reject(\n submission,\n 'Retry window expired; inspect delivery before resubmitting.',\n );\n failed++;\n continue;\n }\n let permanent = false;\n let reason: string | undefined;\n let accepted = false;\n try {\n const result = await send(submission);\n accepted = result.status === 'sent';\n reason = result.error;\n permanent = result.retryable === false;\n } catch (error) {\n if (error instanceof WokuQuarantineError) {\n quarantined = true;\n break;\n }\n reason = error instanceof Error ? error.message : 'Delivery failed';\n }\n const outcome = await this.mutation(async () => {\n const items = await this.load();\n const index = items.findIndex(\n (item) =>\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n !item.failure,\n );\n if (index < 0) return 'removed';\n if (accepted) items.splice(index, 1);\n else {\n const item = items[index]!;\n item.attempts++;\n if (permanent || item.attempts >= this.maxAttempts)\n item.failure = reason ?? 'Attempt budget exhausted';\n }\n const exhausted = !accepted && Boolean(items[index]?.failure);\n await this.persist(items);\n return accepted ? 'sent' : exhausted ? 'failed' : 'pending';\n });\n if (outcome === 'sent') sent++;\n if (outcome === 'failed') failed++;\n }\n return { sent, failed, remaining: await this.size(), quarantined };\n }\n clear(): Promise<void> {\n return this.mutation(async () => {\n if (!this.companyId) {\n await this.storage.removeItem(this.key);\n return;\n }\n const remaining = (await this.load()).filter((item) => !this.owned(item));\n if (remaining.length) await this.persist(remaining);\n else await this.storage.removeItem(this.key);\n });\n }\n}\n","import { WokuClient, type WokuClientConfig } from './client';\nimport { OfflineQueue, type FlushResult } from './queue';\nimport { type Storage, type Logger, noopLogger } from './adapters';\nimport {\n WokuNetworkError,\n WokuQuarantineError,\n WokuValidationError,\n} from './errors';\nimport type {\n CaptureSubmission,\n CsatCaptureInput,\n CesCaptureInput,\n NpsCaptureInput,\n SubmissionResult,\n WokuCaptureInput,\n} from './types';\n\nexport interface WokuSdkConfig extends WokuClientConfig {\n /** Storage adapter for the offline queue (MMKV/AsyncStorage in RN). */\n storage?: Storage;\n /** Retain a failed submission for inspection after this many flush attempts. */\n maxQueueAttempts?: number;\n}\n\nfunction generateId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n // Fallback: timestamp + random, good enough as an idempotency key.\n return `wk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction assertInt(\n value: number,\n min: number,\n max: number,\n field: string,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new WokuValidationError(\n `${field} must be an integer between ${min} and ${max}`,\n );\n }\n}\n\n/**\n * Top-level Woku SDK. Wires the typed {@link WokuClient} to a durable\n * {@link OfflineQueue}: a capture is attempted immediately and, if the\n * device is offline or the server is unreachable, transparently queued\n * and retried on the next {@link WokuSdk.flush}.\n *\n * @example\n * const woku = new WokuSdk({\n * apiUrl: 'https://api.woku.app',\n * publicKey: 'pk_live_...',\n * companyId: 'company_123',\n * storage: mmkvStorageAdapter,\n * });\n * await woku.captureNps({ npsId: 'nps_1', score: 9, comment: 'Great!' });\n */\nexport class WokuSdk {\n private readonly client: WokuClient;\n private readonly queue: OfflineQueue;\n private readonly logger: Logger;\n private readonly companyId: string;\n private readonly language: 'es' | 'en';\n\n constructor(config: WokuSdkConfig) {\n this.client = new WokuClient(config);\n this.queue = new OfflineQueue({\n storage: config.storage,\n companyId: config.companyId,\n maxAttempts: config.maxQueueAttempts,\n });\n this.logger = config.logger ?? noopLogger;\n this.companyId = config.companyId;\n this.language = config.language ?? 'es';\n }\n\n /** Captures a Woku rating (1..5) with optional text/audio comment. */\n async captureWoku(input: WokuCaptureInput): Promise<SubmissionResult> {\n assertInt(input.rating, 1, 5, 'rating');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'woku',\n companyId: this.companyId,\n targetId: input.wokuId,\n rating: input.rating,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n /** Captures an NPS score (0..10) with optional text/audio review. */\n async captureNps(input: NpsCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 0, 10, 'score');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'nps',\n companyId: this.companyId,\n targetId: input.npsId,\n score: input.score,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n async captureCsat(input: CsatCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'csat',\n companyId: this.companyId,\n targetId: input.csatId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n createdAt: Date.now(),\n });\n }\n async captureCes(input: CesCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'ces',\n companyId: this.companyId,\n targetId: input.cesId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n createdAt: Date.now(),\n });\n }\n\n /** Retries every queued submission. Safe to call on app foreground or\n * when connectivity is regained. */\n flush(): Promise<FlushResult> {\n return this.queue.flush((s) => this.client.send(s));\n }\n\n /** Number of submissions waiting to be delivered. */\n pendingCount(): Promise<number> {\n return this.queue.size();\n }\n\n /** Inspect retained captures whose automatic attempt budget was exhausted. */\n failedCaptures(): Promise<import('./queue').FailedCapture[]> {\n return this.queue.failures();\n }\n\n /** Clears the offline queue (e.g. on user logout). */\n clearQueue(): Promise<void> {\n return this.queue.clear();\n }\n\n /**\n * Tries to send immediately; on quarantine or network failure the\n * submission is queued for a later flush rather than thrown away.\n */\n private async deliver(\n submission: CaptureSubmission,\n ): Promise<SubmissionResult> {\n submission = JSON.parse(JSON.stringify(submission)) as CaptureSubmission;\n await this.queue.enqueue(submission);\n try {\n const result = await this.client.send(submission);\n if (result.status === 'sent') {\n try {\n await this.queue.acknowledge(submission);\n } catch {\n // Delivery is confirmed. Keep its original id for a later deduplicated\n // flush rather than making callers think they must submit again.\n this.logger.warn(\n 'Capture accepted; local acknowledgement is pending',\n { id: submission.id },\n );\n }\n return result;\n }\n if (result.retryable === false) {\n await this.queue.reject(submission, result.error ?? 'Capture rejected');\n return result;\n }\n // Server-rejected but transient enough to retry: queue it.\n await this.queue.enqueue(submission);\n return { ...result, status: 'queued' };\n } catch (err) {\n await this.queue.enqueue(submission);\n if (err instanceof WokuQuarantineError) {\n return { id: submission.id, status: 'quarantined', error: err.message };\n }\n if (err instanceof WokuNetworkError) {\n this.logger.debug('capture queued (offline)', { id: submission.id });\n return { id: submission.id, status: 'queued' };\n }\n throw err;\n }\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -64,6 +64,11 @@ declare const noopLogger: Logger;
|
|
|
64
64
|
/** The four capture instruments supported by API v1. */
|
|
65
65
|
type CaptureKind = 'woku' | 'nps' | 'csat' | 'ces';
|
|
66
66
|
type CaptureLanguage = 'es' | 'en';
|
|
67
|
+
/** Capture provenance, declared when the response is first created. */
|
|
68
|
+
interface CaptureContext {
|
|
69
|
+
collectionKind?: 'standalone' | 'flow';
|
|
70
|
+
flowId?: string;
|
|
71
|
+
}
|
|
67
72
|
/** An audio attachment for a text/voice comment. */
|
|
68
73
|
interface AudioAttachment {
|
|
69
74
|
/** URI or local path to the recorded audio file. */
|
|
@@ -81,7 +86,7 @@ interface Respondent {
|
|
|
81
86
|
externalId?: string;
|
|
82
87
|
}
|
|
83
88
|
/** Input for a Woku capture (1-tap rating 1..5 + optional comment/audio). */
|
|
84
|
-
interface WokuCaptureInput {
|
|
89
|
+
interface WokuCaptureInput extends CaptureContext {
|
|
85
90
|
wokuId: string;
|
|
86
91
|
/** Integer 1..5. */
|
|
87
92
|
rating: number;
|
|
@@ -94,7 +99,7 @@ interface WokuCaptureInput {
|
|
|
94
99
|
language?: CaptureLanguage;
|
|
95
100
|
}
|
|
96
101
|
/** Input for an NPS capture (score 0..10 + optional review). */
|
|
97
|
-
interface NpsCaptureInput {
|
|
102
|
+
interface NpsCaptureInput extends CaptureContext {
|
|
98
103
|
npsId?: string;
|
|
99
104
|
/** Integer 0..10. */
|
|
100
105
|
score: number;
|
|
@@ -106,7 +111,7 @@ interface NpsCaptureInput {
|
|
|
106
111
|
language?: CaptureLanguage;
|
|
107
112
|
}
|
|
108
113
|
/** Normalized submission persisted in the offline queue and sent to Woku. */
|
|
109
|
-
interface CaptureSubmission {
|
|
114
|
+
interface CaptureSubmission extends CaptureContext {
|
|
110
115
|
/** Client-generated idempotency id. */
|
|
111
116
|
id: string;
|
|
112
117
|
kind: CaptureKind;
|
|
@@ -133,7 +138,7 @@ interface SubmissionResult {
|
|
|
133
138
|
retryable?: boolean;
|
|
134
139
|
}
|
|
135
140
|
/** Focused satisfaction/effort scores; audio is not supported by these API kinds. */
|
|
136
|
-
interface CsatCaptureInput {
|
|
141
|
+
interface CsatCaptureInput extends CaptureContext {
|
|
137
142
|
csatId: string;
|
|
138
143
|
score: number;
|
|
139
144
|
comment?: string;
|
|
@@ -141,7 +146,7 @@ interface CsatCaptureInput {
|
|
|
141
146
|
metadata?: Record<string, unknown>;
|
|
142
147
|
dispatchToken?: string;
|
|
143
148
|
}
|
|
144
|
-
interface CesCaptureInput {
|
|
149
|
+
interface CesCaptureInput extends CaptureContext {
|
|
145
150
|
cesId: string;
|
|
146
151
|
score: number;
|
|
147
152
|
comment?: string;
|
|
@@ -201,7 +206,7 @@ interface WokuClientConfig {
|
|
|
201
206
|
logger?: Logger;
|
|
202
207
|
/** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */
|
|
203
208
|
capturePath?: string;
|
|
204
|
-
/** Default audio language. */
|
|
209
|
+
/** Default audio language for WokuSdk builders; send() preserves payloads. */
|
|
205
210
|
language?: 'es' | 'en';
|
|
206
211
|
/** Bound a transport attempt, including injected adapters. Default 30s. */
|
|
207
212
|
timeoutMs?: number;
|
|
@@ -304,4 +309,4 @@ declare class WokuNetworkError extends WokuError {
|
|
|
304
309
|
constructor(message: string);
|
|
305
310
|
}
|
|
306
311
|
|
|
307
|
-
export { type AudioAttachment, type CaptureKind, type CaptureLanguage, type CaptureSubmission, type CesCaptureInput, type CsatCaptureInput, type FailedCapture, type FlushResult, type HttpClient, type HttpRequest, type HttpResponse, InMemoryStorage, type Logger, type NpsCaptureInput, OfflineQueue, type OfflineQueueOptions, type Respondent, type Storage, type SubmissionResult, type WokuCaptureInput, WokuClient, type WokuClientConfig, WokuConfigError, WokuError, WokuNetworkError, WokuQuarantineError, WokuSdk, type WokuSdkConfig, WokuValidationError, fetchHttpClient, noopLogger };
|
|
312
|
+
export { type AudioAttachment, type CaptureContext, type CaptureKind, type CaptureLanguage, type CaptureSubmission, type CesCaptureInput, type CsatCaptureInput, type FailedCapture, type FlushResult, type HttpClient, type HttpRequest, type HttpResponse, InMemoryStorage, type Logger, type NpsCaptureInput, OfflineQueue, type OfflineQueueOptions, type Respondent, type Storage, type SubmissionResult, type WokuCaptureInput, WokuClient, type WokuClientConfig, WokuConfigError, WokuError, WokuNetworkError, WokuQuarantineError, WokuSdk, type WokuSdkConfig, WokuValidationError, fetchHttpClient, noopLogger };
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,11 @@ declare const noopLogger: Logger;
|
|
|
64
64
|
/** The four capture instruments supported by API v1. */
|
|
65
65
|
type CaptureKind = 'woku' | 'nps' | 'csat' | 'ces';
|
|
66
66
|
type CaptureLanguage = 'es' | 'en';
|
|
67
|
+
/** Capture provenance, declared when the response is first created. */
|
|
68
|
+
interface CaptureContext {
|
|
69
|
+
collectionKind?: 'standalone' | 'flow';
|
|
70
|
+
flowId?: string;
|
|
71
|
+
}
|
|
67
72
|
/** An audio attachment for a text/voice comment. */
|
|
68
73
|
interface AudioAttachment {
|
|
69
74
|
/** URI or local path to the recorded audio file. */
|
|
@@ -81,7 +86,7 @@ interface Respondent {
|
|
|
81
86
|
externalId?: string;
|
|
82
87
|
}
|
|
83
88
|
/** Input for a Woku capture (1-tap rating 1..5 + optional comment/audio). */
|
|
84
|
-
interface WokuCaptureInput {
|
|
89
|
+
interface WokuCaptureInput extends CaptureContext {
|
|
85
90
|
wokuId: string;
|
|
86
91
|
/** Integer 1..5. */
|
|
87
92
|
rating: number;
|
|
@@ -94,7 +99,7 @@ interface WokuCaptureInput {
|
|
|
94
99
|
language?: CaptureLanguage;
|
|
95
100
|
}
|
|
96
101
|
/** Input for an NPS capture (score 0..10 + optional review). */
|
|
97
|
-
interface NpsCaptureInput {
|
|
102
|
+
interface NpsCaptureInput extends CaptureContext {
|
|
98
103
|
npsId?: string;
|
|
99
104
|
/** Integer 0..10. */
|
|
100
105
|
score: number;
|
|
@@ -106,7 +111,7 @@ interface NpsCaptureInput {
|
|
|
106
111
|
language?: CaptureLanguage;
|
|
107
112
|
}
|
|
108
113
|
/** Normalized submission persisted in the offline queue and sent to Woku. */
|
|
109
|
-
interface CaptureSubmission {
|
|
114
|
+
interface CaptureSubmission extends CaptureContext {
|
|
110
115
|
/** Client-generated idempotency id. */
|
|
111
116
|
id: string;
|
|
112
117
|
kind: CaptureKind;
|
|
@@ -133,7 +138,7 @@ interface SubmissionResult {
|
|
|
133
138
|
retryable?: boolean;
|
|
134
139
|
}
|
|
135
140
|
/** Focused satisfaction/effort scores; audio is not supported by these API kinds. */
|
|
136
|
-
interface CsatCaptureInput {
|
|
141
|
+
interface CsatCaptureInput extends CaptureContext {
|
|
137
142
|
csatId: string;
|
|
138
143
|
score: number;
|
|
139
144
|
comment?: string;
|
|
@@ -141,7 +146,7 @@ interface CsatCaptureInput {
|
|
|
141
146
|
metadata?: Record<string, unknown>;
|
|
142
147
|
dispatchToken?: string;
|
|
143
148
|
}
|
|
144
|
-
interface CesCaptureInput {
|
|
149
|
+
interface CesCaptureInput extends CaptureContext {
|
|
145
150
|
cesId: string;
|
|
146
151
|
score: number;
|
|
147
152
|
comment?: string;
|
|
@@ -201,7 +206,7 @@ interface WokuClientConfig {
|
|
|
201
206
|
logger?: Logger;
|
|
202
207
|
/** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */
|
|
203
208
|
capturePath?: string;
|
|
204
|
-
/** Default audio language. */
|
|
209
|
+
/** Default audio language for WokuSdk builders; send() preserves payloads. */
|
|
205
210
|
language?: 'es' | 'en';
|
|
206
211
|
/** Bound a transport attempt, including injected adapters. Default 30s. */
|
|
207
212
|
timeoutMs?: number;
|
|
@@ -304,4 +309,4 @@ declare class WokuNetworkError extends WokuError {
|
|
|
304
309
|
constructor(message: string);
|
|
305
310
|
}
|
|
306
311
|
|
|
307
|
-
export { type AudioAttachment, type CaptureKind, type CaptureLanguage, type CaptureSubmission, type CesCaptureInput, type CsatCaptureInput, type FailedCapture, type FlushResult, type HttpClient, type HttpRequest, type HttpResponse, InMemoryStorage, type Logger, type NpsCaptureInput, OfflineQueue, type OfflineQueueOptions, type Respondent, type Storage, type SubmissionResult, type WokuCaptureInput, WokuClient, type WokuClientConfig, WokuConfigError, WokuError, WokuNetworkError, WokuQuarantineError, WokuSdk, type WokuSdkConfig, WokuValidationError, fetchHttpClient, noopLogger };
|
|
312
|
+
export { type AudioAttachment, type CaptureContext, type CaptureKind, type CaptureLanguage, type CaptureSubmission, type CesCaptureInput, type CsatCaptureInput, type FailedCapture, type FlushResult, type HttpClient, type HttpRequest, type HttpResponse, InMemoryStorage, type Logger, type NpsCaptureInput, OfflineQueue, type OfflineQueueOptions, type Respondent, type Storage, type SubmissionResult, type WokuCaptureInput, WokuClient, type WokuClientConfig, WokuConfigError, WokuError, WokuNetworkError, WokuQuarantineError, WokuSdk, type WokuSdkConfig, WokuValidationError, fetchHttpClient, noopLogger };
|
package/dist/index.js
CHANGED
|
@@ -98,8 +98,6 @@ var WokuClient = class {
|
|
|
98
98
|
throw new WokuConfigError(
|
|
99
99
|
"Cannot deliver a capture for another company."
|
|
100
100
|
);
|
|
101
|
-
if (submission.audio && !submission.language)
|
|
102
|
-
submission = { ...submission, language: this.config.language ?? "es" };
|
|
103
101
|
const headers = {
|
|
104
102
|
"x-woku-key": this.config.publicKey,
|
|
105
103
|
"X-Woku-Company": this.config.companyId,
|
|
@@ -416,6 +414,8 @@ var WokuSdk = class {
|
|
|
416
414
|
respondent: input.respondent,
|
|
417
415
|
metadata: input.metadata,
|
|
418
416
|
dispatchToken: input.dispatchToken,
|
|
417
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
418
|
+
flowId: input.flowId,
|
|
419
419
|
language: input.language ?? (input.audio ? this.language : void 0),
|
|
420
420
|
createdAt: Date.now()
|
|
421
421
|
};
|
|
@@ -435,6 +435,8 @@ var WokuSdk = class {
|
|
|
435
435
|
respondent: input.respondent,
|
|
436
436
|
metadata: input.metadata,
|
|
437
437
|
dispatchToken: input.dispatchToken,
|
|
438
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
439
|
+
flowId: input.flowId,
|
|
438
440
|
language: input.language ?? (input.audio ? this.language : void 0),
|
|
439
441
|
createdAt: Date.now()
|
|
440
442
|
};
|
|
@@ -452,6 +454,8 @@ var WokuSdk = class {
|
|
|
452
454
|
respondent: input.respondent,
|
|
453
455
|
metadata: input.metadata,
|
|
454
456
|
dispatchToken: input.dispatchToken,
|
|
457
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
458
|
+
flowId: input.flowId,
|
|
455
459
|
createdAt: Date.now()
|
|
456
460
|
});
|
|
457
461
|
}
|
|
@@ -467,6 +471,8 @@ var WokuSdk = class {
|
|
|
467
471
|
respondent: input.respondent,
|
|
468
472
|
metadata: input.metadata,
|
|
469
473
|
dispatchToken: input.dispatchToken,
|
|
474
|
+
collectionKind: input.collectionKind ?? "standalone",
|
|
475
|
+
flowId: input.flowId,
|
|
470
476
|
createdAt: Date.now()
|
|
471
477
|
});
|
|
472
478
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters.ts","../src/errors.ts","../src/client.ts","../src/queue.ts","../src/sdk.ts"],"names":["body"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Injectable adapters. The SDK core never imports React Native or a\n * concrete HTTP/storage library directly — host apps provide these so\n * the core stays unit-testable and platform-agnostic.\n */\n\n/** Minimal HTTP response the SDK needs. */\nexport interface HttpResponse {\n status: number;\n ok: boolean;\n json: () => Promise<unknown>;\n headers: { get: (name: string) => string | null };\n}\n\nexport interface HttpRequest {\n method: string;\n url: string;\n headers: Record<string, string>;\n /**\n * JSON string for text/rating captures, or a `FormData` for audio captures\n * (multipart). For `FormData` the host's `fetch` sets the\n * `multipart/form-data` Content-Type (with boundary) itself.\n */\n body?: string | FormData;\n signal?: AbortSignal;\n}\n\n/** HTTP transport. Defaults to global `fetch`. */\nexport interface HttpClient {\n request: (req: HttpRequest) => Promise<HttpResponse>;\n}\n\n/**\n * Key/value persistence for the offline queue. React Native apps pass an\n * MMKV or AsyncStorage-backed adapter; tests use the in-memory one.\n */\nexport interface Storage {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem: (key: string) => Promise<void> | void;\n}\n\nexport interface Logger {\n debug: (msg: string, meta?: unknown) => void;\n warn: (msg: string, meta?: unknown) => void;\n error: (msg: string, meta?: unknown) => void;\n}\n\n/** Default HTTP client backed by the global `fetch`. */\nexport const fetchHttpClient: HttpClient = {\n async request(req) {\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: req.signal,\n });\n return {\n status: res.status,\n ok: res.ok,\n json: () => res.json(),\n headers: { get: (name) => res.headers.get(name) },\n };\n },\n};\n\n/** In-memory storage. Default for tests and ephemeral usage. */\nexport class InMemoryStorage implements Storage {\n private readonly map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** No-op logger (default). */\nexport const noopLogger: Logger = {\n debug: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n};\n","/** Base error for all SDK failures. */\nexport class WokuError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'WokuError';\n }\n}\n\n/** Thrown when the SDK is misconfigured (missing companyId, etc.). */\nexport class WokuConfigError extends WokuError {\n constructor(message: string) {\n super(message, 'config_error');\n this.name = 'WokuConfigError';\n }\n}\n\n/** Validation failure on a capture input (bad rating/score, etc.). */\nexport class WokuValidationError extends WokuError {\n constructor(message: string) {\n super(message, 'validation_error');\n this.name = 'WokuValidationError';\n }\n}\n\n/**\n * The backend rejected the submission because the respondent is in\n * quarantine (HTTP 429 with a QUARANTINE_BLOCKED code). Carries the\n * retry-after hint in seconds when the server provides one.\n */\nexport class WokuQuarantineError extends WokuError {\n constructor(\n message: string,\n public readonly retryAfterSeconds?: number,\n ) {\n super(message, 'quarantine_blocked');\n this.name = 'WokuQuarantineError';\n }\n}\n\n/** Network/transport failure; the submission should be retried later. */\nexport class WokuNetworkError extends WokuError {\n constructor(message: string) {\n super(message, 'network_error');\n this.name = 'WokuNetworkError';\n }\n}\n","import {\n fetchHttpClient,\n noopLogger,\n type HttpClient,\n type Logger,\n} from './adapters';\nimport {\n WokuConfigError,\n WokuNetworkError,\n WokuQuarantineError,\n} from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\nexport interface WokuClientConfig {\n /** Base URL of the Woku API, e.g. `https://clientapi.woku.app`. */\n apiUrl: string;\n /** Public SDK key issued per company for capture ingestion. */\n publicKey: string;\n /** Tenant the captures belong to. */\n companyId: string;\n /** HTTP transport. Defaults to the global `fetch`. */\n http?: HttpClient;\n logger?: Logger;\n /** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */\n capturePath?: string;\n /** Default audio language. */\n language?: 'es' | 'en';\n /** Bound a transport attempt, including injected adapters. Default 30s. */\n timeoutMs?: number;\n}\n\n// Resource-oriented v1 capture endpoint (woku-server clientapi). The channel\n// ('mobile-sdk') is sealed server-side from this endpoint.\nconst DEFAULT_CAPTURE_PATH = '/v1/captures';\n\n/**\n * Thin, typed transport to the Woku capture ingest endpoint. Stateless:\n * it turns a normalized {@link CaptureSubmission} into an authenticated\n * POST and maps the response (incl. quarantine 429) to a result/error.\n */\nexport class WokuClient {\n private readonly http: HttpClient;\n private readonly logger: Logger;\n private readonly endpoint: string;\n\n constructor(private readonly config: WokuClientConfig) {\n if (!config.apiUrl) throw new WokuConfigError('apiUrl is required');\n if (!config.publicKey) throw new WokuConfigError('publicKey is required');\n if (config.publicKey.startsWith('sk_'))\n throw new WokuConfigError(\n 'Use a publishable key, never a management secret key, in a mobile app.',\n );\n if (!config.companyId) throw new WokuConfigError('companyId is required');\n this.http = config.http ?? fetchHttpClient;\n this.logger = config.logger ?? noopLogger;\n const base = config.apiUrl.replace(/\\/$/, '');\n const path = config.capturePath ?? DEFAULT_CAPTURE_PATH;\n this.endpoint = `${base}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n /**\n * Sends one submission. Resolves with a `sent` result on 2xx, throws\n * {@link WokuQuarantineError} on a quarantine 429, {@link WokuNetworkError}\n * on transport failure, and resolves with a `failed` result on other\n * non-2xx responses (so the caller can decide to re-queue).\n */\n async send(submission: CaptureSubmission): Promise<SubmissionResult> {\n if (submission.companyId !== this.config.companyId)\n throw new WokuConfigError(\n 'Cannot deliver a capture for another company.',\n );\n if (submission.audio && !submission.language)\n submission = { ...submission, language: this.config.language ?? 'es' };\n const headers: Record<string, string> = {\n 'x-woku-key': this.config.publicKey,\n 'X-Woku-Company': this.config.companyId,\n 'X-Woku-Idempotency-Key': submission.id,\n };\n\n let requestBody: string | FormData;\n if (submission.audio) {\n // Audio capture: send multipart so the server can store the voicemail.\n // The platform `fetch` reads the local `uri` and sets the multipart\n // Content-Type (with boundary), so we must NOT set it ourselves.\n const form = new FormData();\n form.append('file', {\n uri: submission.audio.uri,\n type: submission.audio.mimeType,\n name: 'capture-audio',\n } as unknown as Blob);\n form.append('payload', JSON.stringify(submission));\n requestBody = form;\n } else {\n headers['Content-Type'] = 'application/json';\n requestBody = JSON.stringify(submission);\n }\n\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n (async (): Promise<SubmissionResult> => {\n const response = await this.http.request({\n method: 'POST',\n url: this.endpoint,\n headers,\n body: requestBody,\n signal: controller.signal,\n });\n if (response.ok) {\n const body = (await this.safeJson(response.json)) as {\n id?: string;\n remoteId?: string;\n } | null;\n return {\n id: submission.id,\n status: 'sent',\n remoteId: body?.remoteId ?? body?.id,\n };\n }\n if (response.status === 429) {\n const raw = response.headers.get('Retry-After');\n const retryAfter = raw === null ? undefined : Number(raw);\n throw new WokuQuarantineError(\n 'Submission blocked by quarantine',\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? Math.max(0, retryAfter)\n : undefined,\n );\n }\n const body = (await this.safeJson(response.json)) as {\n message?: unknown;\n } | null;\n const value = body?.message;\n const message =\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as { message?: unknown }).message\n : value;\n const detail = Array.isArray(message)\n ? message.filter((item) => typeof item === 'string').join(', ')\n : message;\n const error =\n typeof detail === 'string' && detail\n ? detail\n : `HTTP ${response.status}`;\n this.logger.warn(`woku capture rejected: ${error}`);\n return {\n id: submission.id,\n status: 'failed',\n error,\n retryable: response.status === 408 || response.status >= 500,\n };\n })(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new WokuNetworkError('Capture request timed out'));\n }, this.config.timeoutMs ?? 30_000);\n }),\n ]);\n } catch (err) {\n if (err instanceof WokuQuarantineError) throw err;\n throw new WokuNetworkError(\n err instanceof Error ? err.message : 'Capture request failed',\n );\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n\n private async safeJson(\n json: () => Promise<unknown>,\n ): Promise<unknown | null> {\n try {\n return await json();\n } catch {\n return null;\n }\n }\n}\n","import { InMemoryStorage, type Storage } from './adapters';\nimport { WokuConfigError, WokuQuarantineError } from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\ninterface QueuedItem {\n submission: CaptureSubmission;\n attempts: number;\n failure?: string;\n}\nexport interface FailedCapture {\n submission: CaptureSubmission;\n reason: string;\n}\nexport interface OfflineQueueOptions {\n storage?: Storage;\n storageKey?: string;\n maxAttempts?: number;\n /** Restrict reads, delivery and clearing to this company, including legacy rows. */\n companyId?: string;\n}\nexport interface FlushResult {\n sent: number;\n failed: number;\n remaining: number;\n quarantined?: boolean;\n}\n\nconst DEFAULT_KEY = 'woku.sdk.queue.v1';\nconst mutations = new WeakMap<Storage, Map<string, Promise<void>>>();\nconst flushes = new WeakMap<Storage, Map<string, Promise<FlushResult>>>();\n\n/** Persistent FIFO with scoped ownership, atomic local mutations and retained failures. */\nexport class OfflineQueue {\n private readonly storage: Storage;\n private readonly key: string;\n private readonly maxAttempts: number;\n private readonly companyId?: string;\n\n constructor(opts: OfflineQueueOptions = {}) {\n this.storage = opts.storage ?? new InMemoryStorage();\n this.key = opts.storageKey ?? DEFAULT_KEY;\n this.maxAttempts = opts.maxAttempts ?? 8;\n this.companyId = opts.companyId;\n }\n\n private owned(item: QueuedItem): boolean {\n return !this.companyId || item.submission.companyId === this.companyId;\n }\n private async load(): Promise<QueuedItem[]> {\n const raw = await this.storage.getItem(this.key);\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n Array.isArray(parsed) &&\n parsed.every(\n (item) =>\n item &&\n typeof item === 'object' &&\n item.submission &&\n typeof item.submission.id === 'string' &&\n typeof item.submission.companyId === 'string' &&\n Number.isFinite(item.submission.createdAt) &&\n Number.isInteger(item.attempts) &&\n item.attempts >= 0,\n )\n )\n return parsed as QueuedItem[];\n } catch {\n /* Preserve invalid storage instead of silently overwriting it. */\n }\n throw new WokuConfigError(\n 'The capture queue contains invalid data; repair it before writing.',\n );\n }\n private async persist(items: QueuedItem[]): Promise<void> {\n await this.storage.setItem(this.key, JSON.stringify(items));\n }\n private mutation<T>(run: () => Promise<T>): Promise<T> {\n let locks = mutations.get(this.storage);\n if (!locks) {\n locks = new Map();\n mutations.set(this.storage, locks);\n }\n const previous = locks.get(this.key) ?? Promise.resolve();\n const result = previous.then(run, run);\n const settled = result.then(\n () => undefined,\n () => undefined,\n );\n locks.set(this.key, settled);\n void settled.then(() => {\n if (locks?.get(this.key) === settled) locks.delete(this.key);\n });\n return result;\n }\n\n async enqueue(submission: CaptureSubmission): Promise<void> {\n if (this.companyId && submission.companyId !== this.companyId)\n throw new WokuConfigError(\n 'Cannot enqueue a capture from another company.',\n );\n const snapshot = JSON.parse(\n JSON.stringify(submission),\n ) as CaptureSubmission;\n return this.mutation(async () => {\n const items = await this.load();\n if (\n items.some(\n (item) =>\n item.submission.id === snapshot.id &&\n item.submission.companyId === snapshot.companyId,\n )\n )\n return;\n items.push({ submission: snapshot, attempts: 0 });\n await this.persist(items);\n });\n }\n size(): Promise<number> {\n return this.mutation(\n async () =>\n (await this.load()).filter((item) => this.owned(item) && !item.failure)\n .length,\n );\n }\n pending(): Promise<CaptureSubmission[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && !item.failure)\n .map((item) => item.submission),\n );\n }\n failures(): Promise<FailedCapture[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && item.failure)\n .map((item) => ({\n submission: item.submission,\n reason: item.failure!,\n })),\n );\n }\n\n acknowledge(submission: CaptureSubmission): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n await this.persist(\n items.filter(\n (item) =>\n !(\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n this.owned(item)\n ),\n ),\n );\n });\n }\n reject(submission: CaptureSubmission, reason: string): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n const item = items.find(\n (row) =>\n row.submission.id === submission.id &&\n row.submission.companyId === submission.companyId &&\n this.owned(row),\n );\n if (item) {\n item.failure = reason;\n await this.persist(items);\n }\n });\n }\n\n flush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n let jobs = flushes.get(this.storage);\n if (!jobs) {\n jobs = new Map();\n flushes.set(this.storage, jobs);\n }\n const scope = JSON.stringify([this.key, this.companyId ?? '*']);\n const existing = jobs.get(scope);\n if (existing) return existing;\n const result = this.runFlush(send).finally(() => {\n if (jobs?.get(scope) === result) jobs.delete(scope);\n });\n jobs.set(scope, result);\n return result;\n }\n private async runFlush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n const batch = await this.pending();\n let sent = 0,\n failed = 0,\n quarantined = false;\n for (const candidate of batch) {\n // A clear/reject while another request is in flight invalidates this snapshot.\n const current = await this.mutation(async () =>\n (await this.load()).find(\n (item) =>\n this.owned(item) &&\n !item.failure &&\n item.submission.id === candidate.id &&\n item.submission.companyId === candidate.companyId,\n ),\n );\n if (!current) continue;\n const submission = current.submission;\n // The server deduplicates for 24h; keep older uncertain captures for\n // inspection rather than resubmitting them outside that protection.\n if (\n submission.createdAt > 0 &&\n Date.now() - submission.createdAt >= 24 * 60 * 60 * 1000\n ) {\n await this.reject(\n submission,\n 'Retry window expired; inspect delivery before resubmitting.',\n );\n failed++;\n continue;\n }\n let permanent = false;\n let reason: string | undefined;\n let accepted = false;\n try {\n const result = await send(submission);\n accepted = result.status === 'sent';\n reason = result.error;\n permanent = result.retryable === false;\n } catch (error) {\n if (error instanceof WokuQuarantineError) {\n quarantined = true;\n break;\n }\n reason = error instanceof Error ? error.message : 'Delivery failed';\n }\n const outcome = await this.mutation(async () => {\n const items = await this.load();\n const index = items.findIndex(\n (item) =>\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n !item.failure,\n );\n if (index < 0) return 'removed';\n if (accepted) items.splice(index, 1);\n else {\n const item = items[index]!;\n item.attempts++;\n if (permanent || item.attempts >= this.maxAttempts)\n item.failure = reason ?? 'Attempt budget exhausted';\n }\n const exhausted = !accepted && Boolean(items[index]?.failure);\n await this.persist(items);\n return accepted ? 'sent' : exhausted ? 'failed' : 'pending';\n });\n if (outcome === 'sent') sent++;\n if (outcome === 'failed') failed++;\n }\n return { sent, failed, remaining: await this.size(), quarantined };\n }\n clear(): Promise<void> {\n return this.mutation(async () => {\n if (!this.companyId) {\n await this.storage.removeItem(this.key);\n return;\n }\n const remaining = (await this.load()).filter((item) => !this.owned(item));\n if (remaining.length) await this.persist(remaining);\n else await this.storage.removeItem(this.key);\n });\n }\n}\n","import { WokuClient, type WokuClientConfig } from './client';\nimport { OfflineQueue, type FlushResult } from './queue';\nimport { type Storage, type Logger, noopLogger } from './adapters';\nimport {\n WokuNetworkError,\n WokuQuarantineError,\n WokuValidationError,\n} from './errors';\nimport type {\n CaptureSubmission,\n CsatCaptureInput,\n CesCaptureInput,\n NpsCaptureInput,\n SubmissionResult,\n WokuCaptureInput,\n} from './types';\n\nexport interface WokuSdkConfig extends WokuClientConfig {\n /** Storage adapter for the offline queue (MMKV/AsyncStorage in RN). */\n storage?: Storage;\n /** Retain a failed submission for inspection after this many flush attempts. */\n maxQueueAttempts?: number;\n}\n\nfunction generateId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n // Fallback: timestamp + random, good enough as an idempotency key.\n return `wk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction assertInt(\n value: number,\n min: number,\n max: number,\n field: string,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new WokuValidationError(\n `${field} must be an integer between ${min} and ${max}`,\n );\n }\n}\n\n/**\n * Top-level Woku SDK. Wires the typed {@link WokuClient} to a durable\n * {@link OfflineQueue}: a capture is attempted immediately and, if the\n * device is offline or the server is unreachable, transparently queued\n * and retried on the next {@link WokuSdk.flush}.\n *\n * @example\n * const woku = new WokuSdk({\n * apiUrl: 'https://api.woku.app',\n * publicKey: 'pk_live_...',\n * companyId: 'company_123',\n * storage: mmkvStorageAdapter,\n * });\n * await woku.captureNps({ npsId: 'nps_1', score: 9, comment: 'Great!' });\n */\nexport class WokuSdk {\n private readonly client: WokuClient;\n private readonly queue: OfflineQueue;\n private readonly logger: Logger;\n private readonly companyId: string;\n private readonly language: 'es' | 'en';\n\n constructor(config: WokuSdkConfig) {\n this.client = new WokuClient(config);\n this.queue = new OfflineQueue({\n storage: config.storage,\n companyId: config.companyId,\n maxAttempts: config.maxQueueAttempts,\n });\n this.logger = config.logger ?? noopLogger;\n this.companyId = config.companyId;\n this.language = config.language ?? 'es';\n }\n\n /** Captures a Woku rating (1..5) with optional text/audio comment. */\n async captureWoku(input: WokuCaptureInput): Promise<SubmissionResult> {\n assertInt(input.rating, 1, 5, 'rating');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'woku',\n companyId: this.companyId,\n targetId: input.wokuId,\n rating: input.rating,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n /** Captures an NPS score (0..10) with optional text/audio review. */\n async captureNps(input: NpsCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 0, 10, 'score');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'nps',\n companyId: this.companyId,\n targetId: input.npsId,\n score: input.score,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n async captureCsat(input: CsatCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'csat',\n companyId: this.companyId,\n targetId: input.csatId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n createdAt: Date.now(),\n });\n }\n async captureCes(input: CesCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'ces',\n companyId: this.companyId,\n targetId: input.cesId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n createdAt: Date.now(),\n });\n }\n\n /** Retries every queued submission. Safe to call on app foreground or\n * when connectivity is regained. */\n flush(): Promise<FlushResult> {\n return this.queue.flush((s) => this.client.send(s));\n }\n\n /** Number of submissions waiting to be delivered. */\n pendingCount(): Promise<number> {\n return this.queue.size();\n }\n\n /** Inspect retained captures whose automatic attempt budget was exhausted. */\n failedCaptures(): Promise<import('./queue').FailedCapture[]> {\n return this.queue.failures();\n }\n\n /** Clears the offline queue (e.g. on user logout). */\n clearQueue(): Promise<void> {\n return this.queue.clear();\n }\n\n /**\n * Tries to send immediately; on quarantine or network failure the\n * submission is queued for a later flush rather than thrown away.\n */\n private async deliver(\n submission: CaptureSubmission,\n ): Promise<SubmissionResult> {\n submission = JSON.parse(JSON.stringify(submission)) as CaptureSubmission;\n await this.queue.enqueue(submission);\n try {\n const result = await this.client.send(submission);\n if (result.status === 'sent') {\n try {\n await this.queue.acknowledge(submission);\n } catch {\n // Delivery is confirmed. Keep its original id for a later deduplicated\n // flush rather than making callers think they must submit again.\n this.logger.warn(\n 'Capture accepted; local acknowledgement is pending',\n { id: submission.id },\n );\n }\n return result;\n }\n if (result.retryable === false) {\n await this.queue.reject(submission, result.error ?? 'Capture rejected');\n return result;\n }\n // Server-rejected but transient enough to retry: queue it.\n await this.queue.enqueue(submission);\n return { ...result, status: 'queued' };\n } catch (err) {\n await this.queue.enqueue(submission);\n if (err instanceof WokuQuarantineError) {\n return { id: submission.id, status: 'quarantined', error: err.message };\n }\n if (err instanceof WokuNetworkError) {\n this.logger.debug('capture queued (offline)', { id: submission.id });\n return { id: submission.id, status: 'queued' };\n }\n throw err;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters.ts","../src/errors.ts","../src/client.ts","../src/queue.ts","../src/sdk.ts"],"names":["body"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Injectable adapters. The SDK core never imports React Native or a\n * concrete HTTP/storage library directly — host apps provide these so\n * the core stays unit-testable and platform-agnostic.\n */\n\n/** Minimal HTTP response the SDK needs. */\nexport interface HttpResponse {\n status: number;\n ok: boolean;\n json: () => Promise<unknown>;\n headers: { get: (name: string) => string | null };\n}\n\nexport interface HttpRequest {\n method: string;\n url: string;\n headers: Record<string, string>;\n /**\n * JSON string for text/rating captures, or a `FormData` for audio captures\n * (multipart). For `FormData` the host's `fetch` sets the\n * `multipart/form-data` Content-Type (with boundary) itself.\n */\n body?: string | FormData;\n signal?: AbortSignal;\n}\n\n/** HTTP transport. Defaults to global `fetch`. */\nexport interface HttpClient {\n request: (req: HttpRequest) => Promise<HttpResponse>;\n}\n\n/**\n * Key/value persistence for the offline queue. React Native apps pass an\n * MMKV or AsyncStorage-backed adapter; tests use the in-memory one.\n */\nexport interface Storage {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem: (key: string) => Promise<void> | void;\n}\n\nexport interface Logger {\n debug: (msg: string, meta?: unknown) => void;\n warn: (msg: string, meta?: unknown) => void;\n error: (msg: string, meta?: unknown) => void;\n}\n\n/** Default HTTP client backed by the global `fetch`. */\nexport const fetchHttpClient: HttpClient = {\n async request(req) {\n const res = await fetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: req.signal,\n });\n return {\n status: res.status,\n ok: res.ok,\n json: () => res.json(),\n headers: { get: (name) => res.headers.get(name) },\n };\n },\n};\n\n/** In-memory storage. Default for tests and ephemeral usage. */\nexport class InMemoryStorage implements Storage {\n private readonly map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** No-op logger (default). */\nexport const noopLogger: Logger = {\n debug: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n};\n","/** Base error for all SDK failures. */\nexport class WokuError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'WokuError';\n }\n}\n\n/** Thrown when the SDK is misconfigured (missing companyId, etc.). */\nexport class WokuConfigError extends WokuError {\n constructor(message: string) {\n super(message, 'config_error');\n this.name = 'WokuConfigError';\n }\n}\n\n/** Validation failure on a capture input (bad rating/score, etc.). */\nexport class WokuValidationError extends WokuError {\n constructor(message: string) {\n super(message, 'validation_error');\n this.name = 'WokuValidationError';\n }\n}\n\n/**\n * The backend rejected the submission because the respondent is in\n * quarantine (HTTP 429 with a QUARANTINE_BLOCKED code). Carries the\n * retry-after hint in seconds when the server provides one.\n */\nexport class WokuQuarantineError extends WokuError {\n constructor(\n message: string,\n public readonly retryAfterSeconds?: number,\n ) {\n super(message, 'quarantine_blocked');\n this.name = 'WokuQuarantineError';\n }\n}\n\n/** Network/transport failure; the submission should be retried later. */\nexport class WokuNetworkError extends WokuError {\n constructor(message: string) {\n super(message, 'network_error');\n this.name = 'WokuNetworkError';\n }\n}\n","import {\n fetchHttpClient,\n noopLogger,\n type HttpClient,\n type Logger,\n} from './adapters';\nimport {\n WokuConfigError,\n WokuNetworkError,\n WokuQuarantineError,\n} from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\nexport interface WokuClientConfig {\n /** Base URL of the Woku API, e.g. `https://clientapi.woku.app`. */\n apiUrl: string;\n /** Public SDK key issued per company for capture ingestion. */\n publicKey: string;\n /** Tenant the captures belong to. */\n companyId: string;\n /** HTTP transport. Defaults to the global `fetch`. */\n http?: HttpClient;\n logger?: Logger;\n /** Ingest path appended to `apiUrl`. Defaults to `/v1/captures`. */\n capturePath?: string;\n /** Default audio language for WokuSdk builders; send() preserves payloads. */\n language?: 'es' | 'en';\n /** Bound a transport attempt, including injected adapters. Default 30s. */\n timeoutMs?: number;\n}\n\n// Resource-oriented v1 capture endpoint (woku-server clientapi). The channel\n// ('mobile-sdk') is sealed server-side from this endpoint.\nconst DEFAULT_CAPTURE_PATH = '/v1/captures';\n\n/**\n * Thin, typed transport to the Woku capture ingest endpoint. Stateless:\n * it turns a normalized {@link CaptureSubmission} into an authenticated\n * POST and maps the response (incl. quarantine 429) to a result/error.\n */\nexport class WokuClient {\n private readonly http: HttpClient;\n private readonly logger: Logger;\n private readonly endpoint: string;\n\n constructor(private readonly config: WokuClientConfig) {\n if (!config.apiUrl) throw new WokuConfigError('apiUrl is required');\n if (!config.publicKey) throw new WokuConfigError('publicKey is required');\n if (config.publicKey.startsWith('sk_'))\n throw new WokuConfigError(\n 'Use a publishable key, never a management secret key, in a mobile app.',\n );\n if (!config.companyId) throw new WokuConfigError('companyId is required');\n this.http = config.http ?? fetchHttpClient;\n this.logger = config.logger ?? noopLogger;\n const base = config.apiUrl.replace(/\\/$/, '');\n const path = config.capturePath ?? DEFAULT_CAPTURE_PATH;\n this.endpoint = `${base}${path.startsWith('/') ? path : `/${path}`}`;\n }\n\n /**\n * Sends one submission. Resolves with a `sent` result on 2xx, throws\n * {@link WokuQuarantineError} on a quarantine 429, {@link WokuNetworkError}\n * on transport failure, and resolves with a `failed` result on other\n * non-2xx responses (so the caller can decide to re-queue).\n */\n async send(submission: CaptureSubmission): Promise<SubmissionResult> {\n if (submission.companyId !== this.config.companyId)\n throw new WokuConfigError(\n 'Cannot deliver a capture for another company.',\n );\n const headers: Record<string, string> = {\n 'x-woku-key': this.config.publicKey,\n 'X-Woku-Company': this.config.companyId,\n 'X-Woku-Idempotency-Key': submission.id,\n };\n\n let requestBody: string | FormData;\n if (submission.audio) {\n // Audio capture: send multipart so the server can store the voicemail.\n // The platform `fetch` reads the local `uri` and sets the multipart\n // Content-Type (with boundary), so we must NOT set it ourselves.\n const form = new FormData();\n form.append('file', {\n uri: submission.audio.uri,\n type: submission.audio.mimeType,\n name: 'capture-audio',\n } as unknown as Blob);\n form.append('payload', JSON.stringify(submission));\n requestBody = form;\n } else {\n headers['Content-Type'] = 'application/json';\n requestBody = JSON.stringify(submission);\n }\n\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n (async (): Promise<SubmissionResult> => {\n const response = await this.http.request({\n method: 'POST',\n url: this.endpoint,\n headers,\n body: requestBody,\n signal: controller.signal,\n });\n if (response.ok) {\n const body = (await this.safeJson(response.json)) as {\n id?: string;\n remoteId?: string;\n } | null;\n return {\n id: submission.id,\n status: 'sent',\n remoteId: body?.remoteId ?? body?.id,\n };\n }\n if (response.status === 429) {\n const raw = response.headers.get('Retry-After');\n const retryAfter = raw === null ? undefined : Number(raw);\n throw new WokuQuarantineError(\n 'Submission blocked by quarantine',\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? Math.max(0, retryAfter)\n : undefined,\n );\n }\n const body = (await this.safeJson(response.json)) as {\n message?: unknown;\n } | null;\n const value = body?.message;\n const message =\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as { message?: unknown }).message\n : value;\n const detail = Array.isArray(message)\n ? message.filter((item) => typeof item === 'string').join(', ')\n : message;\n const error =\n typeof detail === 'string' && detail\n ? detail\n : `HTTP ${response.status}`;\n this.logger.warn(`woku capture rejected: ${error}`);\n return {\n id: submission.id,\n status: 'failed',\n error,\n retryable: response.status === 408 || response.status >= 500,\n };\n })(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new WokuNetworkError('Capture request timed out'));\n }, this.config.timeoutMs ?? 30_000);\n }),\n ]);\n } catch (err) {\n if (err instanceof WokuQuarantineError) throw err;\n throw new WokuNetworkError(\n err instanceof Error ? err.message : 'Capture request failed',\n );\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n\n private async safeJson(\n json: () => Promise<unknown>,\n ): Promise<unknown | null> {\n try {\n return await json();\n } catch {\n return null;\n }\n }\n}\n","import { InMemoryStorage, type Storage } from './adapters';\nimport { WokuConfigError, WokuQuarantineError } from './errors';\nimport type { CaptureSubmission, SubmissionResult } from './types';\n\ninterface QueuedItem {\n submission: CaptureSubmission;\n attempts: number;\n failure?: string;\n}\nexport interface FailedCapture {\n submission: CaptureSubmission;\n reason: string;\n}\nexport interface OfflineQueueOptions {\n storage?: Storage;\n storageKey?: string;\n maxAttempts?: number;\n /** Restrict reads, delivery and clearing to this company, including legacy rows. */\n companyId?: string;\n}\nexport interface FlushResult {\n sent: number;\n failed: number;\n remaining: number;\n quarantined?: boolean;\n}\n\nconst DEFAULT_KEY = 'woku.sdk.queue.v1';\nconst mutations = new WeakMap<Storage, Map<string, Promise<void>>>();\nconst flushes = new WeakMap<Storage, Map<string, Promise<FlushResult>>>();\n\n/** Persistent FIFO with scoped ownership, atomic local mutations and retained failures. */\nexport class OfflineQueue {\n private readonly storage: Storage;\n private readonly key: string;\n private readonly maxAttempts: number;\n private readonly companyId?: string;\n\n constructor(opts: OfflineQueueOptions = {}) {\n this.storage = opts.storage ?? new InMemoryStorage();\n this.key = opts.storageKey ?? DEFAULT_KEY;\n this.maxAttempts = opts.maxAttempts ?? 8;\n this.companyId = opts.companyId;\n }\n\n private owned(item: QueuedItem): boolean {\n return !this.companyId || item.submission.companyId === this.companyId;\n }\n private async load(): Promise<QueuedItem[]> {\n const raw = await this.storage.getItem(this.key);\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n Array.isArray(parsed) &&\n parsed.every(\n (item) =>\n item &&\n typeof item === 'object' &&\n item.submission &&\n typeof item.submission.id === 'string' &&\n typeof item.submission.companyId === 'string' &&\n Number.isFinite(item.submission.createdAt) &&\n Number.isInteger(item.attempts) &&\n item.attempts >= 0,\n )\n )\n return parsed as QueuedItem[];\n } catch {\n /* Preserve invalid storage instead of silently overwriting it. */\n }\n throw new WokuConfigError(\n 'The capture queue contains invalid data; repair it before writing.',\n );\n }\n private async persist(items: QueuedItem[]): Promise<void> {\n await this.storage.setItem(this.key, JSON.stringify(items));\n }\n private mutation<T>(run: () => Promise<T>): Promise<T> {\n let locks = mutations.get(this.storage);\n if (!locks) {\n locks = new Map();\n mutations.set(this.storage, locks);\n }\n const previous = locks.get(this.key) ?? Promise.resolve();\n const result = previous.then(run, run);\n const settled = result.then(\n () => undefined,\n () => undefined,\n );\n locks.set(this.key, settled);\n void settled.then(() => {\n if (locks?.get(this.key) === settled) locks.delete(this.key);\n });\n return result;\n }\n\n async enqueue(submission: CaptureSubmission): Promise<void> {\n if (this.companyId && submission.companyId !== this.companyId)\n throw new WokuConfigError(\n 'Cannot enqueue a capture from another company.',\n );\n const snapshot = JSON.parse(\n JSON.stringify(submission),\n ) as CaptureSubmission;\n return this.mutation(async () => {\n const items = await this.load();\n if (\n items.some(\n (item) =>\n item.submission.id === snapshot.id &&\n item.submission.companyId === snapshot.companyId,\n )\n )\n return;\n items.push({ submission: snapshot, attempts: 0 });\n await this.persist(items);\n });\n }\n size(): Promise<number> {\n return this.mutation(\n async () =>\n (await this.load()).filter((item) => this.owned(item) && !item.failure)\n .length,\n );\n }\n pending(): Promise<CaptureSubmission[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && !item.failure)\n .map((item) => item.submission),\n );\n }\n failures(): Promise<FailedCapture[]> {\n return this.mutation(async () =>\n (await this.load())\n .filter((item) => this.owned(item) && item.failure)\n .map((item) => ({\n submission: item.submission,\n reason: item.failure!,\n })),\n );\n }\n\n acknowledge(submission: CaptureSubmission): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n await this.persist(\n items.filter(\n (item) =>\n !(\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n this.owned(item)\n ),\n ),\n );\n });\n }\n reject(submission: CaptureSubmission, reason: string): Promise<void> {\n return this.mutation(async () => {\n const items = await this.load();\n const item = items.find(\n (row) =>\n row.submission.id === submission.id &&\n row.submission.companyId === submission.companyId &&\n this.owned(row),\n );\n if (item) {\n item.failure = reason;\n await this.persist(items);\n }\n });\n }\n\n flush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n let jobs = flushes.get(this.storage);\n if (!jobs) {\n jobs = new Map();\n flushes.set(this.storage, jobs);\n }\n const scope = JSON.stringify([this.key, this.companyId ?? '*']);\n const existing = jobs.get(scope);\n if (existing) return existing;\n const result = this.runFlush(send).finally(() => {\n if (jobs?.get(scope) === result) jobs.delete(scope);\n });\n jobs.set(scope, result);\n return result;\n }\n private async runFlush(\n send: (submission: CaptureSubmission) => Promise<SubmissionResult>,\n ): Promise<FlushResult> {\n const batch = await this.pending();\n let sent = 0,\n failed = 0,\n quarantined = false;\n for (const candidate of batch) {\n // A clear/reject while another request is in flight invalidates this snapshot.\n const current = await this.mutation(async () =>\n (await this.load()).find(\n (item) =>\n this.owned(item) &&\n !item.failure &&\n item.submission.id === candidate.id &&\n item.submission.companyId === candidate.companyId,\n ),\n );\n if (!current) continue;\n const submission = current.submission;\n // The server deduplicates for 24h; keep older uncertain captures for\n // inspection rather than resubmitting them outside that protection.\n if (\n submission.createdAt > 0 &&\n Date.now() - submission.createdAt >= 24 * 60 * 60 * 1000\n ) {\n await this.reject(\n submission,\n 'Retry window expired; inspect delivery before resubmitting.',\n );\n failed++;\n continue;\n }\n let permanent = false;\n let reason: string | undefined;\n let accepted = false;\n try {\n const result = await send(submission);\n accepted = result.status === 'sent';\n reason = result.error;\n permanent = result.retryable === false;\n } catch (error) {\n if (error instanceof WokuQuarantineError) {\n quarantined = true;\n break;\n }\n reason = error instanceof Error ? error.message : 'Delivery failed';\n }\n const outcome = await this.mutation(async () => {\n const items = await this.load();\n const index = items.findIndex(\n (item) =>\n item.submission.id === submission.id &&\n item.submission.companyId === submission.companyId &&\n !item.failure,\n );\n if (index < 0) return 'removed';\n if (accepted) items.splice(index, 1);\n else {\n const item = items[index]!;\n item.attempts++;\n if (permanent || item.attempts >= this.maxAttempts)\n item.failure = reason ?? 'Attempt budget exhausted';\n }\n const exhausted = !accepted && Boolean(items[index]?.failure);\n await this.persist(items);\n return accepted ? 'sent' : exhausted ? 'failed' : 'pending';\n });\n if (outcome === 'sent') sent++;\n if (outcome === 'failed') failed++;\n }\n return { sent, failed, remaining: await this.size(), quarantined };\n }\n clear(): Promise<void> {\n return this.mutation(async () => {\n if (!this.companyId) {\n await this.storage.removeItem(this.key);\n return;\n }\n const remaining = (await this.load()).filter((item) => !this.owned(item));\n if (remaining.length) await this.persist(remaining);\n else await this.storage.removeItem(this.key);\n });\n }\n}\n","import { WokuClient, type WokuClientConfig } from './client';\nimport { OfflineQueue, type FlushResult } from './queue';\nimport { type Storage, type Logger, noopLogger } from './adapters';\nimport {\n WokuNetworkError,\n WokuQuarantineError,\n WokuValidationError,\n} from './errors';\nimport type {\n CaptureSubmission,\n CsatCaptureInput,\n CesCaptureInput,\n NpsCaptureInput,\n SubmissionResult,\n WokuCaptureInput,\n} from './types';\n\nexport interface WokuSdkConfig extends WokuClientConfig {\n /** Storage adapter for the offline queue (MMKV/AsyncStorage in RN). */\n storage?: Storage;\n /** Retain a failed submission for inspection after this many flush attempts. */\n maxQueueAttempts?: number;\n}\n\nfunction generateId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n // Fallback: timestamp + random, good enough as an idempotency key.\n return `wk_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction assertInt(\n value: number,\n min: number,\n max: number,\n field: string,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new WokuValidationError(\n `${field} must be an integer between ${min} and ${max}`,\n );\n }\n}\n\n/**\n * Top-level Woku SDK. Wires the typed {@link WokuClient} to a durable\n * {@link OfflineQueue}: a capture is attempted immediately and, if the\n * device is offline or the server is unreachable, transparently queued\n * and retried on the next {@link WokuSdk.flush}.\n *\n * @example\n * const woku = new WokuSdk({\n * apiUrl: 'https://api.woku.app',\n * publicKey: 'pk_live_...',\n * companyId: 'company_123',\n * storage: mmkvStorageAdapter,\n * });\n * await woku.captureNps({ npsId: 'nps_1', score: 9, comment: 'Great!' });\n */\nexport class WokuSdk {\n private readonly client: WokuClient;\n private readonly queue: OfflineQueue;\n private readonly logger: Logger;\n private readonly companyId: string;\n private readonly language: 'es' | 'en';\n\n constructor(config: WokuSdkConfig) {\n this.client = new WokuClient(config);\n this.queue = new OfflineQueue({\n storage: config.storage,\n companyId: config.companyId,\n maxAttempts: config.maxQueueAttempts,\n });\n this.logger = config.logger ?? noopLogger;\n this.companyId = config.companyId;\n this.language = config.language ?? 'es';\n }\n\n /** Captures a Woku rating (1..5) with optional text/audio comment. */\n async captureWoku(input: WokuCaptureInput): Promise<SubmissionResult> {\n assertInt(input.rating, 1, 5, 'rating');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'woku',\n companyId: this.companyId,\n targetId: input.wokuId,\n rating: input.rating,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n /** Captures an NPS score (0..10) with optional text/audio review. */\n async captureNps(input: NpsCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 0, 10, 'score');\n const submission: CaptureSubmission = {\n id: generateId(),\n kind: 'nps',\n companyId: this.companyId,\n targetId: input.npsId,\n score: input.score,\n comment: input.comment,\n audio: input.audio,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n language: input.language ?? (input.audio ? this.language : undefined),\n createdAt: Date.now(),\n };\n return this.deliver(submission);\n }\n\n async captureCsat(input: CsatCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'csat',\n companyId: this.companyId,\n targetId: input.csatId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n createdAt: Date.now(),\n });\n }\n async captureCes(input: CesCaptureInput): Promise<SubmissionResult> {\n assertInt(input.score, 1, 5, 'score');\n return this.deliver({\n id: generateId(),\n kind: 'ces',\n companyId: this.companyId,\n targetId: input.cesId,\n score: input.score,\n comment: input.comment,\n respondent: input.respondent,\n metadata: input.metadata,\n dispatchToken: input.dispatchToken,\n collectionKind: input.collectionKind ?? 'standalone',\n flowId: input.flowId,\n createdAt: Date.now(),\n });\n }\n\n /** Retries every queued submission. Safe to call on app foreground or\n * when connectivity is regained. */\n flush(): Promise<FlushResult> {\n return this.queue.flush((s) => this.client.send(s));\n }\n\n /** Number of submissions waiting to be delivered. */\n pendingCount(): Promise<number> {\n return this.queue.size();\n }\n\n /** Inspect retained captures whose automatic attempt budget was exhausted. */\n failedCaptures(): Promise<import('./queue').FailedCapture[]> {\n return this.queue.failures();\n }\n\n /** Clears the offline queue (e.g. on user logout). */\n clearQueue(): Promise<void> {\n return this.queue.clear();\n }\n\n /**\n * Tries to send immediately; on quarantine or network failure the\n * submission is queued for a later flush rather than thrown away.\n */\n private async deliver(\n submission: CaptureSubmission,\n ): Promise<SubmissionResult> {\n submission = JSON.parse(JSON.stringify(submission)) as CaptureSubmission;\n await this.queue.enqueue(submission);\n try {\n const result = await this.client.send(submission);\n if (result.status === 'sent') {\n try {\n await this.queue.acknowledge(submission);\n } catch {\n // Delivery is confirmed. Keep its original id for a later deduplicated\n // flush rather than making callers think they must submit again.\n this.logger.warn(\n 'Capture accepted; local acknowledgement is pending',\n { id: submission.id },\n );\n }\n return result;\n }\n if (result.retryable === false) {\n await this.queue.reject(submission, result.error ?? 'Capture rejected');\n return result;\n }\n // Server-rejected but transient enough to retry: queue it.\n await this.queue.enqueue(submission);\n return { ...result, status: 'queued' };\n } catch (err) {\n await this.queue.enqueue(submission);\n if (err instanceof WokuQuarantineError) {\n return { id: submission.id, status: 'quarantined', error: err.message };\n }\n if (err instanceof WokuNetworkError) {\n this.logger.debug('capture queued (offline)', { id: submission.id });\n return { id: submission.id, status: 'queued' };\n }\n throw err;\n }\n }\n}\n"]}
|