{"_id":"@davidoost/eva-lightweight-sdk","_rev":"5-6e4fcfdd05e82f8fa334526d2aff42ae","name":"@davidoost/eva-lightweight-sdk","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.0":{"name":"@davidoost/eva-lightweight-sdk","version":"1.0.0","_id":"@davidoost/eva-lightweight-sdk@1.0.0","maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"bin":{"eva-generate":"scripts/generate.js"},"dist":{"shasum":"b960d47d021f0031824b08c5a63a2c01fdea14c8","tarball":"https://registry.npmjs.org/@davidoost/eva-lightweight-sdk/-/eva-lightweight-sdk-1.0.0.tgz","fileCount":10,"integrity":"sha512-bFHN7Ieq1n3hGi8Pqr3MF3Yg+1m+vIW6Eb5Fzk488uyZGdkNlhMqqoDDzFGWnGkF2zrjShCJPiVbE+hXdP1u/w==","signatures":[{"sig":"MEYCIQD0XSeea8aJE+Eg3g1YW10vULgpHrZxk4rLtYVhLZh90AIhAIOVtpfoXXnDP1DJWzMZ0jVR4eoKFtJw8lmO0Pd0S9Th","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":91718},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"9fa9e8cf4a4281a51995329a6b085e5108650c32","scripts":{"dev":"tsup --watch","build":"tsup","codegen":"node scripts/codegen.mjs","typecheck":"tsc --noEmit","codegen:setup":"mkdir -p bin && curl -L -o bin/sdk-generator https://github.com/new-black/eva-apispec/releases/download/tools/1.0.207/sdk-generator-osx-x64 && chmod +x bin/sdk-generator"},"_npmUser":{"name":"davidoost","email":"davidoost3@gmail.com"},"_npmVersion":"11.16.0","description":"Lightweight SDK for the EVA OMS API","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eva-lightweight-sdk_1.0.0_1784627669517_0.35209438023160544","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@davidoost/eva-lightweight-sdk","version":"1.0.1","_id":"@davidoost/eva-lightweight-sdk@1.0.1","maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"bin":{"eva-generate":"scripts/generate.js"},"dist":{"shasum":"4f630a78989dd8099fb129a4f8149a9e680f1793","tarball":"https://registry.npmjs.org/@davidoost/eva-lightweight-sdk/-/eva-lightweight-sdk-1.0.1.tgz","fileCount":10,"integrity":"sha512-osrqVIDbck0wyY24BetjRzGsXd6oxxy0C8FdjKl72golkCsin8yOw1xZMqnEQTztp8CBBnrXOqY/Oukq2N7HzA==","signatures":[{"sig":"MEQCIFZQP58jz4Tourm/HLeXjv7Yso+RIywIpXy/Q6V7EUJSAiBIy2/9+LCFGR9N0CES5ugq/L6AgKit8uLOcm6KfQGiyw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":89115},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"9fa9e8cf4a4281a51995329a6b085e5108650c32","scripts":{"dev":"tsup --watch","build":"tsup","codegen":"node scripts/codegen.mjs","typecheck":"tsc --noEmit","codegen:setup":"mkdir -p bin && curl -L -o bin/sdk-generator https://github.com/new-black/eva-apispec/releases/download/tools/1.0.207/sdk-generator-osx-x64 && chmod +x bin/sdk-generator"},"_npmUser":{"name":"davidoost","email":"davidoost3@gmail.com"},"_npmVersion":"11.16.0","description":"Lightweight SDK for the EVA OMS API","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eva-lightweight-sdk_1.0.1_1784629097190_0.04688998533027644","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@davidoost/eva-lightweight-sdk","version":"1.0.2","_id":"@davidoost/eva-lightweight-sdk@1.0.2","maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"bin":{"eva-generate":"scripts/generate.js"},"dist":{"shasum":"01b2c709bd84804ddc4b6b24754fd810796fe72a","tarball":"https://registry.npmjs.org/@davidoost/eva-lightweight-sdk/-/eva-lightweight-sdk-1.0.2.tgz","fileCount":10,"integrity":"sha512-Yb3L3pu3yw/nOuLicxqVq7sxUszFxe1gufVo6whNaE4OJtDjiZRAWR/OSXCnNMkYct+wUn0NBmBdJx4IfcZYJw==","signatures":[{"sig":"MEYCIQCebD97cOcord/S1pqc9RXoDvp2r5dccUnGQjU6a3HnTQIhAIVMr4DPLiCFsNJa9b+UJhtz82AbIpfM0i1oAT39Ps3F","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":89737},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"9fa9e8cf4a4281a51995329a6b085e5108650c32","scripts":{"dev":"tsup --watch","build":"tsup","codegen":"node scripts/codegen.mjs","typecheck":"tsc --noEmit","codegen:setup":"mkdir -p bin && curl -L -o bin/sdk-generator https://github.com/new-black/eva-apispec/releases/download/tools/1.0.207/sdk-generator-osx-x64 && chmod +x bin/sdk-generator"},"_npmUser":{"name":"davidoost","email":"davidoost3@gmail.com"},"_npmVersion":"11.16.0","description":"Lightweight SDK for the EVA OMS API","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eva-lightweight-sdk_1.0.2_1784629411246_0.17894262185999277","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@davidoost/eva-lightweight-sdk","version":"1.0.3","_id":"@davidoost/eva-lightweight-sdk@1.0.3","maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"bin":{"eva-generate":"scripts/generate.js"},"dist":{"shasum":"2630b255ef9dab9eb95c249472b9443dcb8170cd","tarball":"https://registry.npmjs.org/@davidoost/eva-lightweight-sdk/-/eva-lightweight-sdk-1.0.3.tgz","fileCount":10,"integrity":"sha512-qiql/5HP2un5VfdXtEhjrofPO9N5u9dyRwip3No3o4i/2+QCmERiW2IA1yPEC3KeCJCGzpQqXXklDJ/lp4op3g==","signatures":[{"sig":"MEUCIQC7agNj80OaX1xzJ883LYG4YxHVYBl9TzcBIv6csMTgOAIgRP/H0zf4897VJBWWBT+kYpDo/yC+pmDS1PwmKewaBpQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":90976},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"9fa9e8cf4a4281a51995329a6b085e5108650c32","scripts":{"dev":"tsup --watch","build":"tsup","codegen":"node scripts/codegen.mjs","typecheck":"tsc --noEmit","codegen:setup":"mkdir -p bin && curl -L -o bin/sdk-generator https://github.com/new-black/eva-apispec/releases/download/tools/1.0.207/sdk-generator-osx-x64 && chmod +x bin/sdk-generator"},"_npmUser":{"name":"davidoost","email":"davidoost3@gmail.com"},"_npmVersion":"11.16.0","description":"Lightweight SDK for the EVA OMS API","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eva-lightweight-sdk_1.0.3_1784630229796_0.8297148977611932","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@davidoost/eva-lightweight-sdk","version":"1.0.4","description":"Lightweight SDK for the EVA OMS API","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","codegen":"node scripts/codegen.mjs","codegen:setup":"mkdir -p bin && curl -L -o bin/sdk-generator https://github.com/new-black/eva-apispec/releases/download/tools/1.0.207/sdk-generator-osx-x64 && chmod +x bin/sdk-generator"},"devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"bin":{"eva-generate":"scripts/generate.js"},"gitHead":"9fa9e8cf4a4281a51995329a6b085e5108650c32","_id":"@davidoost/eva-lightweight-sdk@1.0.4","_nodeVersion":"22.19.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-wepGu6I1w4KSnKtmzQrblT7zVAB07MjEwRl8AqAu6FykJJimTRC4vpdOqI5CRW9PUCYcWIXEFEw0fCsEuxeqTw==","shasum":"f96b360d0bb6f92c65807e03ce0401c3a20404ee","tarball":"https://registry.npmjs.org/@davidoost/eva-lightweight-sdk/-/eva-lightweight-sdk-1.0.4.tgz","fileCount":10,"unpackedSize":92962,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBoFQ+GC9lS1+D0giItCap43Y1N6BkGojf/PFp1Lj9veAiAR0/mt0WS/9sELKgIGL1gJz6QYrGlq5a/acXtgLRjlNA=="}]},"_npmUser":{"name":"davidoost","email":"davidoost3@gmail.com"},"directories":{},"maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eva-lightweight-sdk_1.0.4_1784633445062_0.7013495139899821"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-21T09:54:29.398Z","modified":"2026-07-21T11:30:45.391Z","1.0.0":"2026-07-21T09:54:29.666Z","1.0.1":"2026-07-21T10:18:17.322Z","1.0.2":"2026-07-21T10:23:31.380Z","1.0.3":"2026-07-21T10:37:09.946Z","1.0.4":"2026-07-21T11:30:45.248Z"},"description":"Lightweight SDK for the EVA OMS API","maintainers":[{"name":"davidoost","email":"davidoost3@gmail.com"}],"readme":"# @davidoost/eva-lightweight-sdk\n\nLightweight, framework-agnostic SDK for the [EVA OMS](https://newblack.io) API. Works in Node, browsers, and edge runtimes — no framework dependencies.\n\nTypes are generated into **your project** against your specific EVA environment, so you always have accurate types for your exact EVA instance and you're never blocked by a slow SDK release.\n\n---\n\n## Quick start\n\n```bash\nnpm install @davidoost/eva-lightweight-sdk\n```\n\nThen follow the [Setup](#setup) section below.\n\n> **Migrating from `@davidoost/eva-nextjs-sdk`?** See [Migration](#migration) at the bottom.\n\n---\n\n## Setup\n\n### 1. Create `eva.config.ts`\n\nCreate `eva.config.ts` at your **project root**. This is the single source of truth for both the generate CLI and the generated client:\n\n```typescript\nimport type { EvaConfig } from '@davidoost/eva-lightweight-sdk';\n\nexport default {\n  baseUrl: 'https://api.euw.your-store.eva-online.cloud',\n  organizationUnitId: 1,\n} satisfies EvaConfig;\n```\n\nYou can use environment variables directly in the config:\n\n```typescript\nimport type { EvaConfig } from '@davidoost/eva-lightweight-sdk';\n\nexport default {\n  baseUrl: process.env.NEXT_PUBLIC_EVA_BASE_URL!,\n  organizationUnitId: Number(process.env.EVA_ORGANIZATION_UNIT_ID),\n} satisfies EvaConfig;\n```\n\n### 2. Generate types\n\n```bash\nnpx @davidoost/eva-lightweight-sdk generate\n```\n\nThis downloads the [eva-apispec](https://github.com/new-black/eva-apispec) generator binary (cached in `node_modules/.cache/`), runs it against your EVA environment, and writes the following into your project:\n\n```\nlib/eva/\n  client.ts              ← your typed createClient(), pre-wired to eva.config.ts\n  generated/\n    service-map.ts       ← maps service names to classes\n    eva-services-core/   ← request/response types per assembly\n    eva-services-*/\n```\n\n**Commit the generated files** — they are part of your project, not build artifacts. Re-run when your EVA environment updates.\n\n### 3. Configure path aliases (optional but recommended)\n\nAdd a path alias so imports stay clean across your project:\n\n**`tsconfig.json`:**\n```json\n{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@eva\": [\"./lib/eva/client\"]\n    }\n  }\n}\n```\n\nThen import from `@eva` instead of a relative path:\n\n```typescript\nimport { createClient } from '@eva';\n```\n\n### 4. Use the client\n\nImport `createClient` from your generated `lib/eva/client.ts` and pass a `scope`:\n\n```typescript\nimport { createClient } from '@/lib/eva/client';\n\n// scope: 'public' — no auth, public endpoints only\nconst client = createClient({ scope: 'public' });\nconst products = await client.SearchProducts({ Query: 'roses' });\n\n// scope: 'user' — authenticated with a user token\nconst client = createClient({ scope: 'user', token });\nconst order = await client.GetOrder({ ID: 123 });\n\n// scope: 'api' — authenticated with an API key, full access\nconst client = createClient({ scope: 'api', apiKey: process.env.EVA_API_KEY! });\nconst data = await client.GetUsers({});\n```\n\n`baseUrl` and `organizationUnitId` are read from `eva.config.ts` automatically. Override them per client when needed:\n\n```typescript\nconst client = createClient({ scope: 'user', token, baseUrl: 'https://api.euw.staging.eva-online.cloud' });\n```\n\n---\n\n## `eva.config.ts` reference\n\n```typescript\nimport type { EvaConfig } from '@davidoost/eva-lightweight-sdk';\n\nexport default {\n  // Runtime — used by the generated client\n  baseUrl: 'https://api.euw.your-store.eva-online.cloud',\n  organizationUnitId: 1,\n  defaultHeaders: { 'X-My-Header': 'value' },\n  debug: false,\n\n  // Generator — used by the generate CLI command\n  generate: {\n    output: 'lib/eva',                    // default: 'lib/eva'\n    useStringIds: true,                   // default: true\n    removeDeprecatedServices: true,       // default: true\n    removeDeprecatedProperties: true,     // default: true\n    removeEmptyTypes: false,              // default: false\n    removeInheritance: false,             // default: false\n    removeErrors: false,                  // default: false\n    removeEventExports: true,             // default: true\n    removeDatalakeExports: true,          // default: true\n  },\n} satisfies EvaConfig;\n```\n\n**`generate` options:**\n\n| Option | Default | Description |\n|---|---|---|\n| `output` | `'lib/eva'` | Output directory for generated files |\n| `useStringIds` | `true` | Use string IDs instead of numeric longs — the future EVA standard |\n| `removeDeprecatedServices` | `true` | Remove deprecated services |\n| `removeDeprecatedProperties` | `true` | Remove deprecated properties from types |\n| `removeEmptyTypes` | `false` | Remove types that have no properties |\n| `removeInheritance` | `false` | Flatten type hierarchies — inlines parent properties, removes `extends` |\n| `removeErrors` | `false` | Remove error type information |\n| `removeEventExports` | `true` | Remove event export types |\n| `removeDatalakeExports` | `true` | Remove data lake export types |\n\nCLI flags override config values when provided:\n\n| Flag | Config key | Description |\n|---|---|---|\n| `--base-url <url>` | `baseUrl` | EVA environment to generate types for |\n| `--output <dir>` | `generate.output` | Where to write the generated files |\n\n---\n\n## Client options\n\n`scope` is required and determines the auth mode. All other options default to values from `eva.config.ts`:\n\n| Option | Type | Description |\n|---|---|---|\n| `scope` | `'public' \\| 'user' \\| 'api'` | **Required.** Determines auth mode and service access level. |\n| `baseUrl` | `string` | Base URL of your EVA environment. Read from `eva.config.ts` if omitted. |\n| `organizationUnitId` | `number` | Sent as `EVA-Requested-OrganizationUnitID` on every request. |\n| `onResponseHeaders` | `(headers: Headers) => void \\| Promise<void>` | Called with every response's `Headers` — useful for capturing `EVA-App-Token`. |\n\n**`scope: 'user'`** additional options:\n\n| Option | Type | Description |\n|---|---|---|\n| `token` | `string` | Static auth token for this client instance. |\n| `getToken` | `() => string \\| undefined \\| Promise<string \\| undefined>` | Called before each request. Takes precedence over `token`. Use when the token can change between requests. |\n\n**`scope: 'api'`** additional options:\n\n| Option | Type | Description |\n|---|---|---|\n| `apiKey` | `string` | **Required.** EVA API key, sent as `Authorization: Bearer`. |\n\n---\n\n## Authentication\n\nLogin and logout are standard EVA services. Call them with a `user` scoped client:\n\n```typescript\nconst client = createClient({ scope: 'user' });\n\nconst res = await client.Login({\n  EmailAddress: 'user@example.com',\n  Password: 'secret',\n});\n\nconst token = res.User?.AuthenticationToken;\n// store the token however suits your app (cookie, localStorage, server session, etc.)\n\nawait client.Logout({});\n```\n\n### Dynamic token\n\nUse `getToken` when the token is stored somewhere that may change between requests:\n\n```typescript\nconst client = createClient({\n  scope: 'user',\n  getToken: () => cookieStore.get('eva_token'),\n});\n```\n\n### Capturing the app token\n\nEVA returns an `EVA-App-Token` header on responses, which enables anonymous guest sessions. Persist it using `onResponseHeaders`:\n\n```typescript\nconst client = createClient({\n  scope: 'public',\n  onResponseHeaders: (headers) => {\n    const appToken = headers.get('EVA-App-Token');\n    if (appToken) yourStorage.set('eva_app_token', appToken);\n  },\n});\n```\n\n---\n\n## Using with Next.js\n\nThe SDK has no Next.js dependency but integrates cleanly. A typical pattern:\n\n**`lib/eva-client.ts`** — a shared helper that resolves the token from cookies:\n\n```typescript\nimport { cookies } from 'next/headers';\nimport { createClient } from '@/lib/eva/client';\n\nexport async function getServerClient() {\n  const cookieStore = await cookies();\n  const token = cookieStore.get('eva_token')?.value;\n  return createClient({ scope: 'user', token });\n}\n\nexport function getPublicClient() {\n  return createClient({ scope: 'public' });\n}\n```\n\n**Server Component:**\n\n```typescript\nimport { getServerClient } from '@/lib/eva-client';\n\nexport default async function OrderPage({ params }) {\n  const client = await getServerClient();\n  const order = await client.GetOrder({ ID: Number(params.id) });\n  return <div>{order.ID}</div>;\n}\n```\n\n**Server Action — login:**\n\n```typescript\n'use server';\nimport { cookies } from 'next/headers';\nimport { createClient } from '@/lib/eva/client';\n\nexport async function login(email: string, password: string) {\n  const client = createClient({ scope: 'user' });\n  const res = await client.Login({ EmailAddress: email, Password: password });\n  const token = res.User?.AuthenticationToken;\n  if (token) {\n    const cookieStore = await cookies();\n    cookieStore.set('eva_token', token, { httpOnly: true, path: '/' });\n  }\n}\n\nexport async function logout() {\n  const cookieStore = await cookies();\n  cookieStore.delete('eva_token');\n}\n```\n\n**Client Component** — the SDK is safe to use in the browser. Pass a token down as a prop or fetch it from an API route:\n\n```typescript\n'use client';\nimport { createClient } from '@/lib/eva/client';\n\nexport function SearchBar() {\n  const handleSearch = async (query: string) => {\n    const client = createClient({ scope: 'public' });\n    const results = await client.SearchProducts({ Query: query });\n  };\n}\n```\n\n---\n\n## Debug mode\n\nSet `debug: true` in `eva.config.ts` to log all requests and responses. Auth tokens are redacted automatically.\n\n```\n[eva-sdk] POST https://api.euw.your-store.eva-online.cloud/message/SearchProducts\n[eva-sdk] Headers: { EVA-User-Agent: 'eva-lightweight-sdk/1.0.1', Authorization: 'Bearer [redacted]' }\n[eva-sdk] Body: {\"Query\":\"roses\"}\n[eva-sdk] 200 OK — https://api.euw.your-store.eva-online.cloud/message/SearchProducts\n[eva-sdk] Response headers: { content-type: 'application/json', ... }\n```\n\n---\n\n## Product types\n\nEVA product data is schema-less at the API level. Use `asProduct` to cast to a typed interface:\n\n```typescript\nimport { asProduct } from '@davidoost/eva-lightweight-sdk';\n\nconst response = await client.GetProductDetail({ ProductID: 123 });\nconst product  = asProduct(response.Result);\n\nproduct?.display_value;  // string\nproduct?.display_price;  // number\nproduct?.primary_image;  // { Url?, Blob?, Name?, Type? }\n```\n\n**Standard fields on `EvaProduct`:**\n\n| Field | Type | Description |\n|---|---|---|\n| `product_id` | `number` | EVA internal product ID |\n| `backend_id` | `string?` | External / backend identifier |\n| `display_value` | `string` | Product name |\n| `slug` | `string?` | URL-friendly slug |\n| `barcode` | `string?` | Barcode |\n| `custom_id` | `string?` | Custom identifier |\n| `product_type` | `number?` | `1` Simple · `2` Bundle · `4` Configurable · `8` Variant |\n| `logical_level` | `number?` | `0` root configurable · `1` variant |\n| `primary_image` | `object?` | `{ Url, Blob, Name, Type }` |\n| `media` | `object?` | Gallery, swatches, image count |\n| `category_names` | `string[]?` | Category names |\n| `category_paths` | `string[][]?` | Full category paths |\n| `brand_name` | `string?` | Brand display name |\n| `brand_id` | `number?` | EVA brand ID |\n| `display_price` | `number?` | Current selling price |\n| `original_price` | `number?` | List price before discounts |\n| `discount_percentage` | `number?` | e.g. `25` for 25% off |\n\n### Custom product properties\n\nDeclare your EVA-configured properties once — all `asProduct()` calls pick them up automatically:\n\n```typescript\n// eva.d.ts (anywhere in your project)\nimport '@davidoost/eva-lightweight-sdk';\n\ndeclare module '@davidoost/eva-lightweight-sdk' {\n  interface EvaProductExtension {\n    colour?: string;\n    size_label?: string;\n  }\n}\n```\n\n---\n\n## Explicit `call()` API\n\nUse `call()` when you need to reference a service by class rather than by name:\n\n```typescript\nimport { SvcGetOrder } from '@/lib/eva/generated/eva-services-core';\n\nconst order = await client.call(SvcGetOrder, { ID: 123 });\n```\n\n---\n\n## Keeping types up to date\n\nRe-run the generate command whenever your EVA environment updates:\n\n```bash\nnpx @davidoost/eva-lightweight-sdk generate\n```\n\nThe generator binary is cached in `node_modules/.cache/eva-sdk-generator/` and auto-updates to the latest [eva-apispec](https://github.com/new-black/eva-apispec) release.\n\nTypes are environment-specific — your `lib/eva/generated/` only contains services enabled for your EVA instance.\n\n---\n\n## Migration\n\n**From `@davidoost/eva-nextjs-sdk`:**\n\n```bash\nnpm uninstall @davidoost/eva-nextjs-sdk\nnpm install @davidoost/eva-lightweight-sdk\n```\n\nUpdate all imports:\n\n```diff\n- import { ... } from '@davidoost/eva-nextjs-sdk'\n+ import { ... } from '@davidoost/eva-lightweight-sdk'\n```\n\nCreate `eva.config.ts` at your project root (see [Setup](#setup)), then re-run `generate`:\n\n```bash\nnpx @davidoost/eva-lightweight-sdk generate\n```\n\nThe new SDK has no built-in cookie management or Next.js middleware — token persistence is your app's responsibility. See [Using with Next.js](#using-with-nextjs) above for a complete example.\n","readmeFilename":"README.md"}