{"_id":"@cogover/sdk","_rev":"4-5cc46df192d8d16bb363e7fee0365c57","name":"@cogover/sdk","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.0":{"name":"@cogover/sdk","version":"0.1.0","keywords":["cogover","sdk","typescript"],"license":"MIT","_id":"@cogover/sdk@0.1.0","maintainers":[{"name":"cogover","email":"product-managers@cogover.com"}],"dist":{"shasum":"87b351994b903b5123308cb320f293f84b781dd4","tarball":"https://registry.npmjs.org/@cogover/sdk/-/sdk-0.1.0.tgz","fileCount":7,"integrity":"sha512-LUZR8K3lXlDn9ySdHrG4x60aRrxJ17NZHwMuCi4ATNr5fZ+8KlvDZqWogIP2ZjTCusyRwBuEkmdOGgCcFfZzzA==","signatures":[{"sig":"MEUCIQDiIPulpaPmY1FOKgbNUiXJ806CHGjRyTXFu6QxW2FrxwIgSaBexB8z80tSK+HMXmUTAezbxM4dOvh4RXt/eFVOOcA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4982},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"1dad30c91b927d33156b6324a47fe5113d7c53bd","scripts":{"test":"npm run build && node --test","build":"npm run clean && tsc -p tsconfig.json && npm run build:runtime","check":"npm run typecheck && npm test","clean":"node ./scripts/clean.mjs","prepack":"npm run check","typecheck":"tsc -p tsconfig.json --noEmit","pack:dry-run":"npm pack --dry-run --ignore-scripts","build:runtime":"node ./scripts/build-runtime-module.mjs"},"_npmUser":{"name":"cogover","email":"product-managers@cogover.com"},"_npmVersion":"11.17.0","description":"TypeScript SDK for customer code running on Cogover","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1787854817828_0.3733022067250449","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@cogover/sdk","version":"0.1.1","keywords":["cogover","sdk","typescript"],"license":"MIT","_id":"@cogover/sdk@0.1.1","maintainers":[{"name":"cogover","email":"product-managers@cogover.com"}],"dist":{"shasum":"32f3dc335e129d5e6ada2e6936abd9c4a75d8523","tarball":"https://registry.npmjs.org/@cogover/sdk/-/sdk-0.1.1.tgz","fileCount":7,"integrity":"sha512-9orD9pStUUWSpQT8YVmZ2LshR/ZgZPJmG7TdoFIohU/JfseD9JfNb7rjl2UdQ/rC423FFf30A8qh5UPFiasM9Q==","signatures":[{"sig":"MEUCIBPuiMlGO1KCmhcDohbx6ifgfuWHWIHSIytCRFR/fx21AiEAzkwJmsZFiStT+D+hKLma7FWn1VtxxvKyLfr6on1uZ4o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4538},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"ed753ed0ae38c1fa5fbe7762227dab9e7e76aa21","scripts":{"test":"npm run build && node --test","build":"npm run clean && tsc -p tsconfig.json && npm run build:runtime","check":"npm run typecheck && npm test","clean":"node ./scripts/clean.mjs","prepack":"npm run check","typecheck":"tsc -p tsconfig.json --noEmit","pack:dry-run":"npm pack --dry-run --ignore-scripts","build:runtime":"node ./scripts/build-runtime-module.mjs"},"_npmUser":{"name":"cogover","email":"product-managers@cogover.com"},"_npmVersion":"11.17.0","description":"TypeScript SDK for customer code running on Cogover","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.1_1787855355105_0.4605245613398614","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@cogover/sdk","version":"0.1.2","keywords":["cogover","sdk","typescript"],"license":"MIT","_id":"@cogover/sdk@0.1.2","maintainers":[{"name":"cogover","email":"product-managers@cogover.com"}],"dist":{"shasum":"07e7b1c192038af865719d17ead028bc99ee2588","tarball":"https://registry.npmjs.org/@cogover/sdk/-/sdk-0.1.2.tgz","fileCount":7,"integrity":"sha512-WRs9CKRQJ18Z/p1bhwRVZkNRY/D4TZO2AVdvxfcSo1QNSMzWVH8nZBIsMHP14Ik58DyCG1vCCsMFt+qfJmEWGA==","signatures":[{"sig":"MEYCIQCZuK6l6TeQUm2MFg3e05JJKesn15o8kBo3cI0O4P+e/wIhAORJfQw9I6r+c1S9yRPuOVYHa2lWiKVm1oj56OkkROFQ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4447},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"ed753ed0ae38c1fa5fbe7762227dab9e7e76aa21","scripts":{"test":"npm run build && node --test","build":"npm run clean && tsc -p tsconfig.json && npm run build:runtime","check":"npm run typecheck && npm test","clean":"node ./scripts/clean.mjs","prepack":"npm run check","typecheck":"tsc -p tsconfig.json --noEmit","pack:dry-run":"npm pack --dry-run --ignore-scripts","build:runtime":"node ./scripts/build-runtime-module.mjs"},"_npmUser":{"name":"cogover","email":"product-managers@cogover.com"},"_npmVersion":"11.17.0","description":"TypeScript SDK for customer code running on Cogover","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.2_1787855668998_0.045679289413198765","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@cogover/sdk","version":"0.5.0","description":"TypeScript SDK for developing Custom Backend Modules on Cogover","type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"bin":{"cogover-generate-workspace-types":"scripts/generate-workspace-types.mjs"},"scripts":{"clean":"node ./scripts/clean.mjs","build":"npm run clean && tsc -p tsconfig.json && npm run build:runtime","build:runtime":"node ./scripts/build-runtime-module.mjs","generate:workspace-types":"node ./scripts/generate-workspace-types.mjs","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit","typecheck:dist":"tsc -p tsconfig.dist-test.json --noEmit","test":"npm run build && npm run typecheck:dist && node --test","check":"npm run typecheck && npm test","pack:dry-run":"npm pack --dry-run --ignore-scripts","prepack":"npm run check"},"engines":{"node":">=18"},"keywords":["cogover","sdk","typescript"],"license":"MIT","publishConfig":{"access":"public"},"devDependencies":{"esbuild":"0.28.2","typescript":"7.0.2"},"gitHead":"9ef8032dfa044b9fb3b171856c3e591126d2dd63","_id":"@cogover/sdk@0.5.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-dlyqFANlxxpNc/f9zREn7Ser8hyOm4Y79kT7hIHB/dbFu+an03YpUNaZHMUAz7Lie3npgfL0FHIIIoXizr2Q+Q==","shasum":"dd8f6be16a77dfa9de542ea8cd16000356705b7c","tarball":"https://registry.npmjs.org/@cogover/sdk/-/sdk-0.5.0.tgz","fileCount":45,"unpackedSize":129624,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCZUiAV0VNFwZvR4Cq7VasoZsdZPG36qq4zKv0OPENv1wIhAI0GqG5Du8tSSACFtTJsNrQsE88b3O3mAcuJKoQzqrH/"}]},"_npmUser":{"name":"cogover","email":"product-managers@cogover.com"},"directories":{},"maintainers":[{"name":"cogover","email":"product-managers@cogover.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.5.0_1788541797624_0.76345156048036"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-27T18:20:17.613Z","modified":"2026-09-04T17:09:57.925Z","0.1.0":"2026-08-27T18:20:17.950Z","0.1.1":"2026-08-27T18:29:15.257Z","0.1.2":"2026-08-27T18:34:29.141Z","0.5.0":"2026-09-04T17:09:57.774Z"},"license":"MIT","keywords":["cogover","sdk","typescript"],"description":"TypeScript SDK for developing Custom Backend Modules on Cogover","maintainers":[{"name":"cogover","email":"product-managers@cogover.com"}],"readme":"# `@cogover/sdk`\n\nThe TypeScript SDK for developing **Custom Backend Modules** on Cogover. These\nmodules run server-side business logic, work with workspace data, expose HTTP\nroutes, and connect to external services. They are separate from Custom Frontend\nModules, which implement user interfaces.\n\nThe package includes type declarations for IDE autocomplete, inline\ndocumentation, and type checking.\n\n## Requirements\n\n- Node.js 18 or later.\n- A TypeScript project using ECMAScript Modules (ESM).\n\n## Installation\n\n```bash\nnpm install @cogover/sdk\n```\n\n## Quick start\n\nThis example assumes that the generated `workspace.d.ts` declares the `order`\nObject and the fields used below. See [Workspace types](#workspace-types).\n\n```typescript\nimport { defineScript, NotFoundError } from \"@cogover/sdk\";\n\ninterface Input { recordId: string }\ninterface Output { recordId: string; total: number }\n\nexport default defineScript<Input, Output>(async ({ input, data, log }) => {\n  const orders = data.object(\"order\");\n  const order = await orders.records.get(input.recordId, {\n    fields: [\"subtotal\", \"tax\", \"status\"],\n  });\n  if (!order) throw new NotFoundError(\"order\", input.recordId);\n\n  const total = (order.fields.subtotal ?? 0) + (order.fields.tax ?? 0);\n  await orders.records.update(order.id, { status: \"processed\", total });\n  log.info(\"Order processed\", { recordId: order.id, total });\n  return { recordId: order.id, total };\n});\n```\n\n`defineScript` parses the input JSON, provides invocation metadata and scoped\ndata, schema, logging, state, and lock APIs, waits for the async handler, and\nserializes its result. Cogover authentication credentials are not exposed to\nproject code, and Cogover enforces the configured permissions and limits on\ncapability calls.\n\n## Current identity and workspace\n\n`context.invocation` is an immutable snapshot of the invocation identity and\ncurrent workspace that Cogover already resolved for this execution. The identity\nmay represent an authenticated user or a system invocation. Reading it is\nsynchronous and does not make a data API request:\n\n```typescript\nexport default defineScript(({ invocation }) => {\n  if (invocation.identity === \"system\") {\n    return { workspaceId: invocation.workspace.id, user: null };\n  }\n  return {\n    workspaceId: invocation.workspace.id,\n    workspaceName: invocation.workspace.name,\n    accountId: invocation.user.accountId,\n    personnelId: invocation.user.membership.personnelId,\n  };\n});\n```\n\nThe `identity` discriminant narrows `user` to a public `CurrentUser` for user\ninvocations and to `null` for system invocations. Only the documented profile,\nmembership, locale, and workspace fields are included. Raw authentication data\nand Cogover credentials are never exposed.\n\n## Full HTTP routes and responses\n\n```typescript\nimport { createRouter } from \"@cogover/sdk\";\n\nconst router = createRouter();\nrouter.get(\"/orders/:orderId\", ({ request, response }) => response.json({\n  orderId: request.params.orderId,\n  expand: request.query.expand,\n}));\nrouter.post<{ description: string }, object>(\"/orders\", ({ request, response }) =>\n  response.json({ description: request.body.description }, { status: 201 }));\nrouter.put(\"/orders/:orderId\", ({ request }) => ({ orderId: request.params.orderId }));\nrouter.patch(\"/orders/:orderId\", ({ request }) => ({ orderId: request.params.orderId }));\nrouter.delete(\"/orders/:orderId\", ({ response }) => response.empty());\nexport default router.toHandler();\n```\n\nRoutes support GET, POST, PUT, PATCH, and DELETE. `request` exposes `method`, `path`,\ndecoded `params`, repeated-value-aware `query`, safe lower-case `headers`, and JSON\n`body`. Authentication headers are never exposed. Plain return values are JSON with\nHTTP 200. `response.json`, `text`, `bytes`, `empty`, and `redirect` provide explicit\nstatus, safe response headers, and text/binary bodies. Missing routes return 404;\nunsupported methods return 405. Existing `defineScript()` projects continue at `/`.\nThe complete router contract is included in `docs/en/api-reference.md`.\n\n## Outbound HTTP with `fetch`\n\nCogover provides a Fetch-compatible function for calling an external HTTPS API.\nThe request always goes through Cogover's managed network layer; it does not grant\nproject code unrestricted network access.\n\n```typescript\nimport { defineScript, fetch } from \"@cogover/sdk\";\n\ninterface Input {\n  externalToken: string;\n  orderId: string;\n}\n\nexport default defineScript<Input>(async ({ input }) => {\n  const response = await fetch(\"https://api.example.com/v1/orders\", {\n    method: \"POST\",\n    headers: {\n      authorization: `Bearer ${input.externalToken}`,\n      \"content-type\": \"application/json\",\n    },\n    body: JSON.stringify({ id: input.orderId }),\n    timeoutMs: 5_000,\n  });\n  return response.json();\n});\n```\n\nV1 supports public HTTPS URLs on port 443 and the methods GET, HEAD, POST, PUT,\nPATCH, and DELETE. Requests and buffered responses have platform limits. Redirects,\ncookie jars, streaming, WebSocket, URL credentials, IP-literal hosts, custom proxy,\ndispatcher, agent, DNS, and TLS settings are not supported. A failed mutating request\nmay already have reached the remote API, so use the remote API's idempotency mechanism\nand do not retry blindly.\n\n## Record API\n\nAn Object client exposes `records.get`, `records.list`, `records.create`,\n`records.update`, `records.batchInsert`, `records.batchUpdate`,\n`records.upsertByUniqueField`, and `records.deleteMany`. List filters are built from typed\nfield references, so scripts do not provide transport-specific field metadata or\nresponse envelopes.\n\nCogover normalizes service values to the declared SDK types: booleans become\n`true`/`false`, and lookup/reference values are reduced to\n`{ id, name, objectSlug }` so nested record fields are not exposed. For writes,\nreference fields accept either a record ID or a `RecordReference`; only the ID is\nsent to the Record API.\n\n```typescript\nimport { and, defineScript } from \"@cogover/sdk\";\n\nexport default defineScript(async ({ data }) => {\n  const orders = data.object(\"order\");\n  return orders.records.list({\n    where: and(\n      orders.fields.status.in([\"new\", \"nurturing\"]),\n      orders.fields.is_active.eq(true),\n      orders.fields.total.gte(1_000_000),\n    ),\n    orderBy: [orders.fields.updated.desc()],\n    limit: 50,\n  });\n});\n```\n\nBatch writes are best-effort per row. Check `result.success` or every entry in\n`result.results`; a successful request envelope does not mean every row succeeded.\nBusiness upsert accepts one `matchBy` field that must be configured as a single-field\nunique key. It returns `{ id, created }` and requires both create and update permission.\n\n```typescript\nconst inserted = await orders.records.batchInsert([\n  { name: \"Order A\", external_id: \"EXT-1\" },\n  { name: \"Order B\", external_id: \"EXT-2\" },\n]);\nconst firstInserted = inserted.results[0];\nif (!firstInserted?.success || !firstInserted.id) {\n  throw new Error(firstInserted?.msg ?? \"Order A could not be created\");\n}\n\nconst updated = await orders.records.batchUpdate([\n  { id: firstInserted.id, fields: { status: \"processing\" } },\n]);\nif (!updated.success) throw new Error(\"The order could not be updated\");\n\nconst upserted = await orders.records.upsertByUniqueField(\"external_id\", {\n  external_id: \"EXT-1\",\n  name: \"Order A from ERP\",\n});\n```\n\nAPI failures are unwrapped into `NotFoundError`, `ValidationError`,\n`PermissionDeniedError`, `RateLimitError`, or `CogoverApiError`.\nUnique-key conflicts are returned as `ValidationError` with\n`details.reason === \"UNIQUE_KEY_VIOLATION\"`, plus the safe `objectSlug` and\n`fieldSlug`; the rejected field value is not echoed in the public error.\n\nUncaught SDK errors return a safe HTTP error response: invalid input and blocked\noutbound requests → 400; state conflicts and lock errors → 409; oversized outbound\nrequests → 413; permission denied → 403; not found → 404; unsupported methods →\n405; rate limits → 429; unavailable state, lock, or outbound HTTP services → 503;\noversized or failed remote responses → 502; outbound timeouts → 504; and other\ndata API failures → 422. The response includes `code`, `msg`, `r` (HTTP status),\nand `writesMayHaveCompleted` when relevant. Earlier writes are not rolled back;\nnever retry writes automatically. Unknown script errors and resource-limit\nfailures use a generic 422 response.\n\n## Record execution identities\n\nBy default, `data.object(\"order\")` uses the invocation's identity. Approved scripts\ncan explicitly select a personnel identity or system access:\n\n```typescript\nconst delegatedOrders = data.asUser(personnelId).object(\"order\");\nconst record = await delegatedOrders.records.get(recordId, { fields: [\"description\"] });\nconst page = await delegatedOrders.records.list({ fields: [\"description\"], limit: 20 });\nawait data.asUser(personnelId).object(\"order\").records.update(order.id, changes);\nawait data.asSystem().object(\"order\").records.update(order.id, changes);\n```\n\nBoth methods return new immutable clients and preserve workspace typing. `asUser`\naccepts a personnel ID (not an account ID) and supports the full record API, including\nbatch writes and business upsert. Reads apply that user's permissions and approved field restrictions;\nread access must be approved separately from writes. `asSystem` supports the\nfull record API, including in authenticated public scripts, without changing the\noriginal caller or existing clients.\n\nAdministrator approval is required for the project version, callers, target users,\nobjects, operations, and fields. Unauthorized operations fail without falling back\nto another identity. System access bypasses the caller's record permissions, so\nprivileged scripts must validate their business inputs and record scope. These\nmethods never accept credentials or a workspace override.\n\n## Project state and distributed locks\n\nUse project state for small durable JSON checkpoints and coordination values. State\nis scoped to the workspace and project, survives new project versions, supports TTL\nand compare-and-set, and limits each serialized value to 32 KiB.\n\n```typescript\nexport default defineScript(async ({ state }) => {\n  const sync = state.namespace(\"inventory-sync\");\n  const current = await sync.get<{ cursor: string }>(\"cursor\");\n  return sync.set(\"cursor\", { cursor: \"next-page\" }, {\n    expectedVersion: current?.version ?? 0,\n    ttlSeconds: 3600,\n  });\n});\n```\n\nDistributed locks provide project-scoped token leases for short critical sections.\n`withLock` releases in `finally`; manual leases support renew/release and expose a\nfencing token. A lease does not auto-renew and locks do not replace idempotency or\nprovide exactly-once execution.\n\n```typescript\nexport default defineScript(async ({ locks }) =>\n  locks.withLock(\"INV-1\", { namespace: \"invoice\", waitMs: 500 }, async lease => {\n    await processInvoice(\"INV-1\", lease.fencingToken);\n    return { processed: true };\n  }));\n```\n\nState conflicts throw `StateConflictError`; failed lock acquisition and lost leases\nuse `LockUnavailableError` and `LockLostError`.\n\n## Workspace types\n\n`WorkspaceObjects` is an open interface augmented by a generated declaration for\nthe current Workspace. Generate a declaration from an Object Info JSON response:\n\n```bash\nnpx cogover-generate-workspace-types objects.json workspace.d.ts\n```\n\nThe declaration makes object slugs, field slugs, value types, and choice option\nslugs available to TypeScript. `schema.object(slug)` is read-only; Object and\nfield mutation are intentionally not part of this SDK.\n\n## TypeScript\n\nType declarations are included in the package. Add the generated `workspace.d.ts`\nto the TypeScript project.\n\nRecommended `tsconfig.json` options:\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"strict\": true,\n    \"noEmit\": true,\n    \"skipLibCheck\": true\n  }\n}\n```\n\n## Additional documentation\n\nThe installed package includes an English usage guide at\n`docs/en/usage-guide.md` and the complete API reference at\n`docs/en/api-reference.md`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}