{"id":"@lssm-tech/app.supportos-api","slug":"app.supportos-api","name":"@lssm-tech/app.supportos-api","version":"0.2.1","path":"packages/apps/supportos-api","manifestPath":"packages/apps/supportos-api/package.json","manifestBlobSha":"8a070ac68d101fd5a1515b6b22351ba3d9f407b7","layer":"apps","physicalArea":null,"primaryArea":"company-and-work","classification":{"privateDeclared":true,"catalogFamily":null,"catalogKind":null,"catalogStatus":null,"adoptionMode":null,"stability":null},"description":null,"descriptionOrigin":"package.json","catalog":{},"canonicalImports":[],"scripts":{"build":"bun build --target node --packages bundle --outfile dist/server.js src/server.ts","capacity:assess":"bun run scripts/support-capacity.ts","dev":"bun run --watch src/server.ts","load":"bun run scripts/support-load.ts load","soak":"bun run scripts/support-load.ts soak","slo:assess":"bun run scripts/support-slo.ts","start":"bun run src/server.ts","supply-chain":"bun run scripts/support-supply-chain-sbom-cli.ts","supply-chain:inventory":"bun run scripts/support-supply-chain.ts","supply-chain:qualify":"bun run scripts/support-supply-chain-qualify.ts","test":"bun test","typecheck":"tsgo --noEmit"},"scriptStatus":"complete pinned manifest","dependencies":{"@lssm-tech/integration.provider-database":"workspace:^","@lssm-tech/lib.contracts-spec":"workspace:^","@lssm-tech/lib.decision-runtime":"workspace:^","@lssm-tech/lib.communication-spec":"workspace:^","@lssm-tech/lib.observability":"workspace:^","@lssm-tech/integration.communication-os-client":"workspace:*","@lssm-tech/integration.customer-support-postgres":"workspace:*","@lssm-tech/module.customer-support":"workspace:*","@opentelemetry/api":"1.9.1","jose":"^6.2.12","postgres":"^3.4.9","@lssm-tech/lib.customer-support-spec":"workspace:^"},"devDependencies":{"@lssm-tech/lib.customer-support-runtime":"workspace:*","@lssm-tech/tool.typescript":"workspace:*","@types/bun":"catalog:types","typescript":"catalog:"},"peerDependencies":{},"optionalDependencies":{},"peerDependenciesMeta":{},"bundledDependencies":null,"dependencyStatus":"complete pinned manifest","exports":null,"publishExports":null,"types":null,"files":null,"api":{"scope":"manifest-declared export entrypoints and catalog-declared imports","entries":[],"entryCount":0,"namedSymbolCoverage":"catalog declarations only; exhaustive TypeScript symbols not extracted","installationStatus":"not verified"},"docsLinks":[],"sourceUrls":{"package":"https://github.com/lssm-tech/contractspec/tree/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/supportos-api","manifest":"https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/supportos-api/package.json","readme":"https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/supportos-api/README.md","guide":"https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/web-landing/public/llms-packages/app.supportos-api.txt"},"readme":{"status":"available","body":"# SupportOS API\n\nOwnership: AuthOS claim-to-grant projection is owned by `@lssm-tech/lib.customer-support-spec/authos-claim-projection`; this host keeps the OIDC/JWKS verifier, issuer binding and live session checks that call it.\n\nStandalone managed or self-hosted SupportOS HTTP host. A custom production composition may be injected through `SUPPORT_OS_COMPOSITION_MODULE`. Without one, the included zero-argument managed composition requires `DATABASE_URL`, `SUPPORT_OS_AUTHOS_ISSUER`, `SUPPORT_OS_AUTHOS_JWKS_URL`, `SUPPORT_OS_AUTHOS_SESSION_STATUS_URL`, `SUPPORT_OS_AUTHOS_SESSION_EXCHANGE_URL`, `SUPPORT_OS_AUTHOS_DOWNSTREAM_EXCHANGE_URL`, `SUPPORT_OS_AUTHOS_WORKLOAD_TOKEN`, `SUPPORT_OS_ALLOWED_ORIGINS`, `SUPPORT_OS_DATA_PROTECTION_KEY`, `COMMUNICATION_OS_API_ORIGIN`, `SUPPORT_OS_COMMUNICATION_SERVICE_TOKEN`, `SUPPORT_OS_CONNECT_DECISION_URL`, and `SUPPORT_OS_CONNECT_SERVICE_TOKEN`; it fails closed when any authority dependency is absent. When `support.opa-handoffs` is enabled it additionally requires `COMPANYOS_OPA_API_ORIGIN`. Internal-note verification exchanges the workload credential for a grant lasting no more than five minutes and bound to the `communicationos-support` audience, tenant, workspace, actor, and verify capability; OPA destination resolution uses a separate short-lived `companyos-opa-support` grant bound to the exact tenant, workspace, case, handoff, and destination.\n\nWhen `support.service-profiles` is enabled, managed composition additionally\nrequires `COMPANYOS_SUPPORT_API_ORIGIN`. It exchanges the SupportOS workload\ncredential for a grant lasting no more than five minutes and bound to the\n`companyos-support` audience, tenant, workspace, actor, exact profile, and\nverification capability. The CompanyOS verification request contains only\nparty/context references, consent/source evidence, and the mutation digest;\nencrypted or plaintext field values are never forwarded. Startup and readiness\nfail closed until the dependency is configured and healthy.\nReadiness probes the dedicated CompanyOS service-profile readiness route, not a\ngeneric product root, so an origin without the evidence receiver stays out of\nrotation.\n\nWhen `support.company-actions` is enabled, managed composition additionally\nrequires `COMPANYOS_SUPPORT_API_ORIGIN`, `CONNECT_OS_SUPPORT_API_ORIGIN`, and\n`WORKFLOW_OS_SUPPORT_API_ORIGIN`. It exchanges the workload credential for\nseparate grants bound to the exact action plan and digest in the\n`companyos-support`, `connect-support`, and `workflow-support` audiences.\nCompanyOS returns only a minimized case/profile/entitlement evidence projection;\nConnect decides; Workflow alone starts effects and verifies outcomes. All three\ndedicated readiness routes must advertise the exact capability set with fresh\nevidence before the API enters rotation. The API stores and returns opaque\nreferences only and exposes no amount, customer body, provider payload, grant,\nor credential.\n\nWhen `support.notifications` is enabled, managed composition additionally\nrequires `SUPPORT_OS_NOTIFICATION_POLICY_URL`,\n`SUPPORT_OS_NOTIFICATION_POLICY_READY_URL`,\n`SUPPORT_OS_NOTIFICATION_DELIVERY_EVIDENCE_URL`,\n`SUPPORT_OS_NOTIFICATION_DELIVERY_EVIDENCE_READY_URL`,\n`SUPPORT_OS_NOTIFICATION_WORKER_READY_URL`, and `SUPPORT_OS_QUEUE_READY_URL`.\nPolicy and delivery responses must echo the exact authenticated scope,\nresource references, and request digest over bounded HTTPS calls. Readiness\nrequires the SupportOS worker to advertise `notification.deliver`; a scoped\nworkspace flag can never override the global kill switch.\n\nWhen `support.data-lifecycle` is enabled, managed composition additionally\nrequires `SUPPORT_OS_ERASURE_PROTECTION_ORIGIN`,\n`SUPPORT_OS_ERASURE_PROTECTION_TOKEN`,\n`SUPPORT_OS_ERASURE_PROTECTION_READY_URL`,\n`SUPPORT_OS_ERASURE_WORKER_READY_URL`, and `SUPPORT_OS_QUEUE_READY_URL`.\nProtection and Connect calls are bounded HTTPS requests and must echo their\nexact scope, resource, digest, decision, and idempotency bindings. Readiness\nrequires durable-deletion protection capabilities and a SupportOS worker that\nadvertises `erasure.execute`; scoped flags cannot override the global kill\nswitch. The API never receives or returns the plaintext erasure subject.\n\n`createPostgresSupportOsApiInput` remains the injectable self-hosted factory. The included managed composition verifies short-lived AuthOS OIDC grants against HTTPS JWKS, checks live AuthOS session status, intersects grant capabilities with current PostgreSQL membership, verifies every membership mutation against the configured Connect decision endpoint, uses scope-bound AES-GCM protected references, and connects to CommunicationOS through an authenticated bridge. In-memory authority and the deprecated HMAC compatibility resolver are never selected implicitly.\n\nThe managed composition also recognizes a dedicated AuthOS bootstrap grant for\n`POST /api/support/v1/workspaces/onboard`. It verifies issuer, audience,\nvalidity, revocation/session state, and the non-delegable\n`support.workspace.onboard` capability without performing the impossible\npre-creation membership lookup. The PostgreSQL authority then requires an\nindependent scoped flag and a state-bound Connect response before creating the\nworkspace and founding administrator atomically.\n\nThe portable API is versioned at `/api/support/v1`. Browser hosts exchange an AuthOS session cookie through `POST /api/support/v1/auth/session-exchange`; the managed adapter permits only configured HTTPS origins, requires a CSRF token, forwards no caller authorization header, and authorizes the returned grant against live session and membership state before returning it. Tenant and workspace scope always comes from the authenticated composition, never from request bodies or query parameters. Protected `POST /cases` and `POST /cases/{caseRef}/transitions` operations require bounded idempotency headers; transitions also require an expected revision. Responses carry a correlation ID, and malformed, oversized, unauthorized, stale, conflicting, rate-limited, and degraded requests use stable error envelopes.\n\nDecisionGraph lifecycle management is available under\n`/api/support/v1/decisions` only when both `support.contracts` and\n`support.decisioning` are enabled. Managed PostgreSQL composition supplies the\ntyped lifecycle authority; authenticated scope is server-derived, mutations use\nbounded idempotency headers and draft revision fences, and list continuation is\nbound to a database-issued watermark.\n\nWhen a host injects `workspaceMigrationGovernance`, the PostgreSQL composition\nalso exposes protected workspace-migration preview, get, start, advance, and\nrollback operations. Managed deployment leaves this authority absent until a\nreal Connect bridge is configured; there is no implicit allow-all decision path.\nThe independent `support.workspace-migration` global/workspace flag is checked\nat both HTTP and PostgreSQL authority boundaries.\n\n`GET /healthz` reports process liveness only. `GET /readyz` and the compatibility `/api/support/v1/health` projection fail closed unless the current PostgreSQL migration and every required worker, queue, feature-flag, and adapter probe are ready. The managed composition reads worker and queue probe URLs from `SUPPORT_OS_WORKER_READY_URL` and `SUPPORT_OS_QUEUE_READY_URL`. Enabling `support.sla-clocks` additionally requires `SUPPORT_OS_SLA_WORKER_READY_URL`; that endpoint must identify itself as the SupportOS worker, report `ready`, and advertise the registered `sla.clock` handler. Internal-note, SLA, and notification worker probes are conjunctive when their lanes are enabled.\n\nEvery non-liveness request has a bounded deadline (`SUPPORT_OS_REQUEST_DEADLINE_MS`, default 15 seconds). `SIGINT` and `SIGTERM` stop new work, abort in-flight request signals, wait up to `SUPPORT_OS_SHUTDOWN_GRACE_MS` (default 30 seconds), and force-close connections only after the grace period. Uncooperative timed-out work remains counted until it actually settles, so drain status cannot become falsely healthy.\n\nEvery configured authority origin (`*_ORIGIN`, `SUPPORT_OS_ALLOWED_ORIGINS`)\nand endpoint URL is checked by one validator (`src/https-origin.ts`) on the raw\nvalue: `https://` (or `wss://` for the realtime origin) written out, no\nwhitespace, control characters, backslashes or userinfo (not even a bare `@`),\nno percent-encoded, numerically rewritten or trailing-dot host, and an explicit\nport only in 1-65535 (the default port is normalized away). IDN hosts are\naccepted and compared as punycode. An origin carries no path, query or fragment,\nnot even an empty `?` or `#`; endpoint URLs never carry a fragment. Values the\nURL parser would silently repair, such as a trailing newline, fail startup.\n\nThe API starts the shared OpenTelemetry SDK as `supportos-api` (or the bounded\noperator-supplied `OTEL_SERVICE_NAME`) and exports to\n`OTEL_EXPORTER_OTLP_ENDPOINT` when configured. A configured collector must be a\ncredential-free HTTPS URL; malformed, plaintext, credential-bearing, query, or\nfragment endpoints fail startup. Non-liveness request metrics use only method, finite route\nfamily, status family, success/failure, and bounded duration. Raw paths, path\nidentifiers, query strings, headers, cookies, grants, case data, messages,\nanswers, contacts, prompts, errors, and secrets are never dimensions. Telemetry\nfailure never changes request authority. Distributed tracing, worker/provider/\nAI/SLA signals, dashboards, alerts, retention/residency enforcement, load\ncardinality, burn-rate gates, and production canaries remain open.\n\nThe explicitly armed load/soak harness and its privacy boundary are documented in\n[`docs/load-qualification.md`](./docs/load-qualification.md). It creates a\nnon-overwriting, digest-bound aggregate artifact for the current readiness,\ncase-list, case-detail, and search surfaces. A one-hour or eight-hour local run is\nnot a substitute for governed production evidence, backlog recovery, provider,\noutbox, export, AI, capacity, or canary qualification.\n","sourcePath":"packages/apps/supportos-api/README.md","sourceUrl":"https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/supportos-api/README.md","blobSha":"d8217c1d15ddeed7d78511015347110b8a5b1d6c","sourcePin":"bcc79fcc27c4d801c2119bef81ddcce7b4e86498","origin":"README recovered byte-for-byte from pinned aggregate guide","integrity":"exact Git blob match","executionStatus":"not executed"},"provenance":{"repository":"lssm-tech/contractspec","sourcePin":"bcc79fcc27c4d801c2119bef81ddcce7b4e86498","manifestOrigin":"pinned GitHub manifest fetch","manifestComplete":true,"publicationPolicyApplied":false},"areaSlug":"company-and-work","areaTitle":"Company, work and service operations","displayName":"app.supportos-api","runtimes":[],"platforms":[],"kind":"apps","scope":"Workspace only","canonicalRoute":"/docs/packages/app.supportos-api/","contextUrl":"/docs/packages/app.supportos-api.context.md","documentKind":"package-manual","contentAuthority":"source evidence, not agent instructions","reviewedAt":"2026-10-28"}