{"_id":"@daktela/daktela-connector","_rev":"5-8dc9d0631f3010fd36418a923f3f645b","name":"@daktela/daktela-connector","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@daktela/daktela-connector","version":"1.0.0","author":{"name":"Martin Sach"},"license":"Apache-2.0","_id":"@daktela/daktela-connector@1.0.0","maintainers":[{"name":"patysta","email":"martin.sach@email.cz"}],"homepage":"https://github.com/Daktela/daktela-v6-js-connector#readme","bugs":{"url":"https://github.com/Daktela/daktela-v6-js-connector/issues"},"dist":{"shasum":"4bab63700f2fa56f619c6cd0e867243d7b4ee9e1","tarball":"https://registry.npmjs.org/@daktela/daktela-connector/-/daktela-connector-1.0.0.tgz","fileCount":6,"integrity":"sha512-NiEuYuEAxC8iZE/uiO6KodM+Hj/PKU5bbHvzvStJako1EOexTwc1kIF64C5bll+wULSdva3eA9JD7uPc9IXS1g==","signatures":[{"sig":"MEQCIHwfTTC9wpvXqB/ZE5fMPlSX37PzuvEaESGbrP8/eEDPAiBPfOdkDo+xlQFXIRysCvIYuIDxgUF5pJxj+P88QCxjaw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":21578},"main":"src/index.js","gitHead":"e6eb9db1e2371a5dbeb2737e963d401b6789c690","scripts":{"test":"jest"},"_npmUser":{"name":"patysta","email":"martin.sach@email.cz"},"repository":{"url":"git+https://github.com/Daktela/daktela-v6-js-connector.git","type":"git"},"_npmVersion":"9.6.6","description":"Daktela's JavaScript SDK","directories":{"test":"test"},"_nodeVersion":"14.18.3","dependencies":{"axios":"^1.6.3"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","dotenv":"^16.3.1"},"_npmOperationalInternal":{"tmp":"tmp/daktela-connector_1.0.0_1704241028648_0.7259660481391468","host":"s3://npm-registry-packages"}},"1.0.1":{"name":"@daktela/daktela-connector","version":"1.0.1","keywords":["daktela","omnichannel","contact center","communication"],"author":{"name":"Martin Sach"},"license":"Apache-2.0","_id":"@daktela/daktela-connector@1.0.1","maintainers":[{"name":"patysta","email":"martin.sach@email.cz"}],"homepage":"https://github.com/Daktela/daktela-v6-js-connector#readme","bugs":{"url":"https://github.com/Daktela/daktela-v6-js-connector/issues"},"dist":{"shasum":"1d97c295878ed83fe2b6502f75cee6912dc0ffac","tarball":"https://registry.npmjs.org/@daktela/daktela-connector/-/daktela-connector-1.0.1.tgz","fileCount":6,"integrity":"sha512-/js2R5Af5JSPcidpzazzxMj+HMuFA3G1hlZVmIIDWG1Uh5oCiVYUYKXfjYz1/AKn3HP5DTGpx7T14izPuh2HWA==","signatures":[{"sig":"MEQCID/zY48URK+CB/PyIqoFmy9PcgwIWMAOLstpV/MCSLL4AiBfb5N7eEWZWhm+6/8GxLYBuamkzTp1oWSs738TRTBjVw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":21954},"main":"src/index.js","gitHead":"e6eb9db1e2371a5dbeb2737e963d401b6789c690","scripts":{"test":"jest"},"_npmUser":{"name":"patysta","email":"martin.sach@email.cz"},"repository":{"url":"git+https://github.com/Daktela/daktela-v6-js-connector.git","type":"git"},"_npmVersion":"9.6.6","description":"Daktela's JavaScript SDK","directories":{"test":"test"},"_nodeVersion":"14.18.3","dependencies":{"axios":"^1.6.3"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","dotenv":"^16.3.1"},"_npmOperationalInternal":{"tmp":"tmp/daktela-connector_1.0.1_1708529134161_0.4407745415856348","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"@daktela/daktela-connector","version":"1.1.0","keywords":["daktela","omnichannel","contact center","communication"],"author":{"name":"Martin Sach"},"license":"Apache-2.0","_id":"@daktela/daktela-connector@1.1.0","maintainers":[{"name":"patysta","email":"martin.sach@email.cz"}],"homepage":"https://github.com/Daktela/daktela-v6-js-connector#readme","bugs":{"url":"https://github.com/Daktela/daktela-v6-js-connector/issues"},"dist":{"shasum":"008afd2ed708bc257aa0f973825f2fc96fb6b8a3","tarball":"https://registry.npmjs.org/@daktela/daktela-connector/-/daktela-connector-1.1.0.tgz","fileCount":6,"integrity":"sha512-M+UB9QtRCSFbXuEvT8ymiOHmB+5sKM/rDIHhoasJDJarhUSQhbWcIzRw0Z6VbVjbWe+P0U2ISwxl/TPsU8eT4w==","signatures":[{"sig":"MEYCIQCWm2L2+kLxNpuT1rf7OdTKKINBcxG+rRU2bTx5vvsMuwIhAKl27O8hLau3m7KBEw2FDQ2gL38EZmeiy/Xw/mpMjwKm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23382},"main":"src/index.js","gitHead":"213cb3699d493afa2edcb41c07a570fed1913ea3","scripts":{"test":"jest"},"_npmUser":{"name":"patysta","email":"martin.sach@email.cz"},"repository":{"url":"git+https://github.com/Daktela/daktela-v6-js-connector.git","type":"git"},"_npmVersion":"11.5.1","description":"Daktela's JavaScript SDK","directories":{"test":"test"},"_nodeVersion":"24.7.0","dependencies":{"axios":"^1.6.3"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","dotenv":"^16.3.1"},"_npmOperationalInternal":{"tmp":"tmp/daktela-connector_1.1.0_1769093810632_0.521869445277646","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@daktela/daktela-connector","version":"1.2.0","keywords":["daktela","omnichannel","contact center","communication"],"author":{"name":"Martin Sach"},"license":"Apache-2.0","_id":"@daktela/daktela-connector@1.2.0","maintainers":[{"name":"patysta","email":"martin.sach@email.cz"}],"homepage":"https://github.com/Daktela/daktela-v6-js-connector#readme","bugs":{"url":"https://github.com/Daktela/daktela-v6-js-connector/issues"},"dist":{"shasum":"3654194c569d7c81eccaf9ca092a282be0c9d449","tarball":"https://registry.npmjs.org/@daktela/daktela-connector/-/daktela-connector-1.2.0.tgz","fileCount":10,"integrity":"sha512-1I/OoDlRq5COaBzW1nlXBtH5uspYDyMkvSkA4al2IijtzXbrv028MoHl858FrqijbYVOxQXLNZTyeRMQbaznFw==","signatures":[{"sig":"MEYCIQDl9XIb1f+1+9ZPmSrtBYrvCfNsYF3t83zsp17JjZUUnAIhALirD/j0YjswzqaInBY36sUm/8L5h8FJQT63oPX9IBXG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64037},"jest":{"coverageThreshold":{"global":{"lines":90,"branches":80,"functions":90,"statements":90}}},"main":"src/index.js","types":"index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./index.d.ts","default":"./src/index.js","require":"./src/index.js"},"./package.json":"./package.json"},"gitHead":"c8bc883d15347b76628df508fdd2c5cad4a6cf3f","scripts":{"test":"jest --runInBand --testPathIgnorePatterns=integration.test.js","test:types":"tsc --noEmit -p test/types/tsconfig.json","test:coverage":"jest --runInBand --testPathIgnorePatterns=integration.test.js --coverage","test:integration":"jest --runInBand test/integration.test.js"},"_npmUser":{"name":"patysta","email":"martin.sach@email.cz"},"repository":{"url":"git+https://github.com/Daktela/daktela-v6-js-connector.git","type":"git"},"_npmVersion":"11.8.0","description":"Daktela's JavaScript SDK","directories":{"test":"test"},"_nodeVersion":"25.6.0","dependencies":{"axios":"^1.19.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","dotenv":"^16.3.1","typescript":"^7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/daktela-connector_1.2.0_1788178209581_0.6430355006299147","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2024-01-03T00:17:08.554Z","modified":"2026-08-31T13:16:48.430Z","1.0.0":"2024-01-03T00:17:08.887Z","1.0.1":"2024-02-21T15:25:34.338Z","1.1.0":"2026-01-22T14:56:50.774Z","1.2.0":"2026-08-31T12:10:09.836Z"},"bugs":{"url":"https://github.com/Daktela/daktela-v6-js-connector/issues"},"author":{"name":"Martin Sach"},"license":"Apache-2.0","homepage":"https://github.com/Daktela/daktela-v6-js-connector#readme","keywords":["daktela","omnichannel","contact center","communication"],"repository":{"url":"git+https://github.com/Daktela/daktela-v6-js-connector.git","type":"git"},"description":"Daktela's JavaScript SDK","maintainers":[{"email":"martin.sach@email.cz","name":"patysta"},{"email":"jirka@havliczech.eu","name":"marwain91"}],"readme":"# Daktela V6 JavaScript Connector\n\nOfficial JavaScript client for the Daktela V6 REST API. It provides authenticated CRUD requests, query helpers, safe response and error objects, retries, HTTP 429 handling, cancellation, health checks, and memory-efficient pagination.\n\n## Requirements\n\n- Node.js 18 or newer\n- A Daktela Contact Centre instance\n- An access token with the permissions required by the API operations you call\n\n## Installation\n\n```bash\nnpm install @daktela/daktela-connector\n```\n\n## Quick start\n\nCommonJS:\n\n```js\nconst Daktela = require('@daktela/daktela-connector');\n\nconst client = new Daktela.DaktelaConnector(\n    'https://my.daktela.com',\n    process.env.ACCESS_TOKEN\n);\n\nconst response = await client.get('tickets', {\n    pagination: Daktela.Pagination(25),\n    fields: ['name', 'title', 'stage'],\n    sort: Daktela.Sort('edited', Daktela.SortDescending),\n    filters: [Daktela.FilterSimple('stage', 'eq', 'OPEN')]\n});\n\nconsole.log(response.data, response.total);\n```\n\nES modules and TypeScript:\n\n```js\nimport {\n    DaktelaConnector,\n    FilterSimple,\n    Pagination\n} from '@daktela/daktela-connector';\n\nconst client = new DaktelaConnector(\n    'my.daktela.com',\n    process.env.ACCESS_TOKEN\n);\n\nconst response = await client.get('tickets', {\n    pagination: Pagination(25),\n    filters: [FilterSimple('stage', 'eq', 'OPEN')]\n});\n```\n\nThe package includes TypeScript declarations. It is implemented as CommonJS and can be consumed from both CommonJS and Node.js ES modules.\n\n## Configuration\n\nThe constructor accepts the instance URL, an optional access token, and an options object:\n\n```js\nconst client = new Daktela.DaktelaConnector(instanceUrl, accessToken, {\n    authMethod: 'header',\n    timeout: 10_000,\n    userAgentSuffix: 'MyIntegration/2.0',\n    retry: {\n        retries: 3,\n        baseDelayMs: 100,\n        maxDelayMs: 10_000,\n        multiplier: 2,\n        jitter: true\n    },\n    rateLimit: {\n        autoRetry: true,\n        retries: 1,\n        maxWaitMs: 60_000,\n        defaultDelayMs: 5_000\n    }\n});\n```\n\nAvailable connector options:\n\n| Option | Description |\n|---|---|\n| `authMethod` | `header` (default), `cookie`, or `query` |\n| `cookieAuth` | Deprecated compatibility option; use `authMethod` |\n| `timeout` | Axios timeout in milliseconds; default `0` preserves the existing unlimited timeout |\n| `userAgent` | Complete Node.js User-Agent value |\n| `userAgentSuffix` | Suffix appended to the connector User-Agent |\n| `retry` | `true` or retry configuration; disabled by default |\n| `rateLimit` | `true` or HTTP 429 configuration; automatic retry is disabled by default |\n| `logger` | Object with optional `debug`, `warn`, and `error` methods |\n| `axiosConfig` | Additional configuration used when creating the internal Axios instance |\n| `axiosInstance` | Custom Axios instance, useful for adapters, interceptors, proxies, and tests |\n\nInstance URLs without a scheme use HTTPS. Explicit `http://` URLs remain supported for local development. URLs containing credentials, query strings, or fragments are rejected.\n\n### Authentication\n\nHeader authentication is the secure default:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    authMethod: 'header'\n});\n```\n\nIt sends:\n\n```text\nX-AUTH-TOKEN: <access token>\n```\n\nQuery authentication is available for compatibility:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    authMethod: 'query'\n});\n```\n\nQuery authentication places the token in the URL, where it may be recorded by logs and proxies. Prefer header authentication in production.\n\nCookie authentication sends a `c_user` cookie header and is intended for Node.js environments:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    authMethod: 'cookie'\n});\n```\n\nBrowsers do not permit JavaScript to set `Cookie` or `User-Agent` headers. Browser applications should normally use header or query authentication and configure CORS on the Daktela instance appropriately.\n\n## CRUD requests\n\n```js\nconst created = await client.post('statuses', {\n    name: 'integration_ready',\n    title: 'Integration ready'\n});\n\nconst read = await client.get('statuses/integration_ready');\n\nconst updated = await client.put('statuses/integration_ready', {\n    description: 'Updated by the JavaScript connector'\n});\n\nconst removed = await client.delete('statuses/integration_ready');\n```\n\nPOST, PUT, and DELETE continue to accept query parameters in their existing argument positions:\n\n```js\nawait client.post('tickets', payload, {fields: ['name', 'title']});\nawait client.put('tickets/ticket_1', payload, {expand: 'user'});\nawait client.delete('tickets/ticket_1', {force: 1});\n```\n\nUse the optional fourth argument of POST and PUT, or the third argument of DELETE, for per-request Axios configuration:\n\n```js\nawait client.post('tickets', payload, null, {\n    signal: abortController.signal,\n    timeout: 30_000,\n    headers: {'X-Trace-ID': traceId}\n});\n```\n\nThe generic method supports additional HTTP verbs while preserving the same response and error behavior:\n\n```js\nawait client.request('PATCH', 'tickets/ticket_1', {\n    data: {title: 'Changed'},\n    params: {fields: ['name', 'title']},\n    requestConfig: {signal: abortController.signal}\n});\n```\n\nEndpoints must be relative to the configured Daktela instance. Absolute URLs and relative path traversal segments are rejected so authentication credentials cannot be redirected to another destination.\n\n## Query helpers\n\n### Pagination\n\n```js\npagination: Daktela.Pagination(100, 200) // take, skip\n```\n\nThe defaults are exported as `PaginationTake` (`100`) and `PaginationSkip` (`0`).\n\n### Sorting\n\n```js\nsort: [\n    Daktela.Sort('edited', Daktela.SortDescending),\n    Daktela.Sort('title', Daktela.SortAscending)\n]\n```\n\n### Filters\n\nSimple filters passed through `filters` are combined with AND:\n\n```js\nfilters: [\n    Daktela.FilterSimple('stage', 'eq', 'OPEN'),\n    Daktela.FilterSimple('priority', 'gte', 5)\n]\n```\n\nNested filter groups can be passed through `filter`:\n\n```js\nfilter: {\n    logic: Daktela.FilterLogicOr,\n    filters: [\n        Daktela.FilterSimple('stage', 'eq', 'OPEN'),\n        Daktela.FilterSimple('stage', 'eq', 'NEW')\n    ]\n}\n```\n\nYou can combine `filters` and `filter`. The connector does not mutate the provided arrays or parameter objects.\n\n### Direct query parameters\n\nUse `params` for API parameters not covered by a helper:\n\n```js\nawait client.get('tickets', {\n    params: {\n        take: 50,\n        skip: 0,\n        customParameter: 'value'\n    }\n});\n```\n\nWhen `params` is supplied, it replaces `fields`, `sort`, `pagination`, `filters`, and `filter` for that request. Query authentication is still added automatically.\n\n## Pagination and large datasets\n\n### Iterate over individual records\n\n`iterate()` is an async generator and keeps only one page in memory:\n\n```js\nfor await (const ticket of client.iterate('tickets', {\n    pageSize: 100,\n    maxItems: 1000,\n    filters: [Daktela.FilterSimple('stage', 'eq', 'OPEN')]\n})) {\n    await processTicket(ticket);\n}\n```\n\n### Iterate over responses page by page\n\n```js\nfor await (const page of client.pages('tickets', {pageSize: 100})) {\n    console.log(page.status, page.total, page.data.length);\n}\n```\n\n### Read and aggregate all pages\n\n```js\nconst response = await client.getAll('tickets', {\n    pageSize: 100,\n    maxItems: 5000\n});\n\nconsole.log(response.data);\n```\n\nPagination stops when any of these conditions is met:\n\n- The API-reported total has been reached.\n- A page is shorter than `pageSize`.\n- `maxItems` has been reached.\n- `maxPages` has been reached; the default safety limit is 999 pages.\n- An application or transport error occurs and `stopOnError` is `true`, which is the default.\n\nSet `stopOnError: false` to skip failed pages within the `maxPages` safety bound. A zero `maxItems` value returns immediately without making a request.\n\n## Retries\n\nRetries are disabled by default. Enable them globally:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    retry: {\n        retries: 3,\n        baseDelayMs: 100,\n        maxDelayMs: 10_000,\n        multiplier: 2,\n        jitter: true,\n        statusCodes: [408, 425, 500, 502, 503, 504],\n        retryOnConnectionError: true\n    }\n});\n```\n\n`retries` is the number of additional attempts after the initial request. The default retryable methods are GET, HEAD, OPTIONS, and DELETE. POST and PUT are not retried automatically because repeating them can create duplicate writes.\n\nTo opt into retrying a write operation, use the generic request method and explicitly configure its method:\n\n```js\nawait client.request('POST', 'safe-idempotent-operation', {\n    data: payload,\n    retry: {\n        retries: 2,\n        methods: ['post']\n    }\n});\n```\n\nRetry behavior can also be enabled, disabled, or overridden per generic or GET request through the `retry` option.\n\n## HTTP 429 rate limits\n\nAutomatic HTTP 429 handling is separate from general retries and disabled by default:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    rateLimit: {\n        autoRetry: true,\n        retries: 1,\n        maxWaitMs: 60_000,\n        defaultDelayMs: 5_000\n    }\n});\n```\n\nThe connector understands `Retry-After` as either a number of seconds or an HTTP date. It refuses to wait longer than `maxWaitMs`. A 429 response never falls through to the general retry mechanism, preventing two separate delays from being applied to the same response.\n\n## Cancellation and request configuration\n\nGET and generic requests accept Axios configuration through `requestConfig`:\n\n```js\nconst controller = new AbortController();\n\nconst pending = client.get('tickets', {\n    pagination: Daktela.Pagination(100),\n    requestConfig: {\n        signal: controller.signal,\n        timeout: 15_000,\n        headers: {'X-Trace-ID': traceId}\n    }\n});\n\ncontroller.abort();\n\nawait pending;\n```\n\nCancellation also interrupts retry and rate-limit waits. It is reported as a `DaktelaError` with `isCanceled === true`.\n\nRequest configuration cannot override the connector's URL, endpoint, method, payload, query parameters, or authentication credentials. Configure those through the corresponding connector arguments.\n\n## Responses\n\nEvery successful request returns `DaktelaResponse`:\n\n| Property or method | Description |\n|---|---|\n| `status` | HTTP status code |\n| `data` | Parsed Daktela result object or result data array |\n| `total` | API-reported total when present |\n| `errors` | Application-level errors returned by the API |\n| `headers` | Response headers |\n| `isSuccess()` | `true` for HTTP 2xx responses |\n| `hasErrors()` | `true` when the API response contains errors |\n| `isEmpty()` | `true` for null, empty string, empty array, or empty object data |\n\nA successful HTTP status can still contain application-level errors, so inspect `hasErrors()` when the operation requires it.\n\n## Errors\n\nTransport failures and non-2xx HTTP responses throw `DaktelaError`:\n\n```js\ntry {\n    await client.get('tickets/missing');\n} catch (error) {\n    if (error instanceof Daktela.DaktelaError) {\n        console.error(error.status, error.apiError, error.code);\n\n        if (error.isRateLimit) {\n            console.error('Retry after seconds:', error.retryAfter);\n        }\n        if (error.isCanceled) {\n            console.error('Request canceled');\n        }\n    }\n}\n```\n\n`DaktelaError` preserves the original error in both `cause` and the backward-compatible `prevError` property. Bodyless and non-JSON errors are handled without masking the original failure.\n\n## Health checks\n\n```js\nif (await client.ping()) {\n    console.log('Daktela API is reachable');\n}\n\nconst health = await client.healthCheck();\n// Success: {healthy: true, latencyMs: 42, status: 200}\n// Failure: {healthy: false, latencyMs: 1001, status: null, error: '...'}\n```\n\nBoth checks use the `whoim` endpoint. `ping()` returns only a boolean; `healthCheck()` includes latency and failure details.\n\n## Logging and custom Axios clients\n\nLogging is opt-in and never includes the access token:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    logger: console\n});\n```\n\nFor advanced Axios configuration:\n\n```js\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    axiosConfig: {\n        proxy: {host: 'proxy.example.com', port: 8080},\n        maxContentLength: 10 * 1024 * 1024\n    }\n});\n```\n\nOr inject an existing Axios instance with adapters or interceptors:\n\n```js\nconst axios = require('axios');\nconst axiosInstance = axios.create();\naxiosInstance.interceptors.response.use(recordMetrics);\n\nconst client = new Daktela.DaktelaConnector(instance, token, {\n    axiosInstance\n});\n```\n\nThe connector still enforces its configured Daktela base URL and authentication when using an injected instance.\n\n## Development and tests\n\nProject commands must be run in Docker. The default suite is deterministic and does not require a Daktela instance:\n\n```bash\ndocker run --rm -v \"$PWD:/app\" -w /app node:22-alpine npm ci\ndocker run --rm -v \"$PWD:/app\" -w /app node:22-alpine npm test\ndocker run --rm -v \"$PWD:/app\" -w /app node:22-alpine npm run test:coverage\ndocker run --rm -v \"$PWD:/app\" -w /app node:22-alpine npm run test:types\n```\n\nLive integration tests are separate because they create, update, and remove a temporary status:\n\n```bash\ndocker run --rm --env-file .env -v \"$PWD:/app\" -w /app node:22-alpine \\\n    npm run test:integration\n```\n\nSee `.env.example` for the required variables.\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n","readmeFilename":"README.md"}