JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [
"async",
"client-library",
"javascript",
"nodejs",
"npm",
"sdk",
"type-safe",
"typescript",
"webhook"
],
"is_fork": false,
"size_kb": 1069,
"has_wiki": true,
"homepage": "https://spooled.cloud",
"languages": {
"Shell": 1352,
"JavaScript": 3032,
"TypeScript": 590021
},
"pushed_at": "2026-07-19T14:47:15Z",
"created_at": "2025-12-09T14:06:40Z",
"owner_type": "Organization",
"updated_at": "2026-07-19T14:47:18Z",
"description": "Official Node.js/TypeScript SDK for Spooled. Type-safe, async/await support for Express, Next.js, vanilla Node.js. Retry logic, circuit breaker.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "Apache-2.0",
"default_branch": "main",
"license_spdx_raw": "Apache-2.0",
"primary_language": "TypeScript",
"significant_languages": [
"TypeScript"
]
},
"owner": {
"blog": "https://spooled.cloud",
"name": "Spooled Cloud",
"type": "Organization",
"login": "Spooled-Cloud",
"company": null,
"location": "Canada",
"followers": 3,
"avatar_url": "https://avatars.githubusercontent.com/u/248554435?v=4",
"created_at": "2025-12-08T20:51:10Z",
"is_verified": null,
"public_repos": 8,
"account_age_days": 228
},
"license": {
"state": "standard",
"spdx_id": "Apache-2.0",
"raw_spdx": "Apache-2.0",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v1.0.40",
"kind": "patch",
"published_at": "2026-07-19T14:47:54Z"
},
{
"tag": "v1.0.37",
"kind": "patch",
"published_at": "2026-07-14T20:58:51Z"
},
{
"tag": "v1.0.36",
"kind": "patch",
"published_at": "2026-07-13T17:06:55Z"
}
],
"recent_commits": [
{
"oid": "06d0f5ddad724239cef7b8b598fb0fbaa45779c0",
"body": "Worker detail typing (queueNames/updatedAt, nullable workerType/version), gRPC unary timeout + error mapping, worker progress debug output, example typecheck coverage.",
"is_bot": false,
"headline": "chore(release): 1.0.40",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-19T14:47:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fe3b91372234fdac0dc80788b5fdedb21f2630e3",
"body": "… notes\n\nWorker.workerType and Worker.version are serialized as explicit null by the\nbackend when unset; type them string | null so strict consumers handle the\nruntime value. Correct the KB parity/findings notes that claimed the backend\npersists job progress for the Go SDK — no such endpoint exists.",
"is_bot": false,
"headline": "fix(types): model backend nulls on Worker and correct progress parity…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-19T13:40:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "79cde52234a9336b933695c641a088118a3f8193",
"body": "Match backend REST worker detail public fields so TypeScript consumers see multi-queue membership and last update timestamps.",
"is_bot": false,
"headline": "fix(workers): type queueNames and updatedAt",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-17T14:03:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e7ea82f2a77e09e84dab0f046337757babe440be",
"body": null,
"is_bot": false,
"headline": "fix(examples): sync workflow contracts",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-16T20:36:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b0dcda8aae315897936fc1da2e72feb73dc8f353",
"body": "Pass configured timeouts to unary gRPC calls and map gRPC statuses into SDK errors for consistent caller behavior.",
"is_bot": false,
"headline": "fix(grpc): apply Node unary deadlines",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-16T19:34:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8b205dc946bfd20ee7919ffe4fb25ce6d6601065",
"body": "Align the repo with its declared Prettier gate so format checks\npass before publish or release verification.",
"is_bot": false,
"headline": "style: format Node SDK",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-16T18:38:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "237bcb404d38e863810fbe48caaa08d7c2bb839f",
"body": "Publish diagnostics must avoid exposing token-bearing npm config\nwhile keeping release docs aligned with 1.0.39.",
"is_bot": false,
"headline": "ci: stop printing npm config",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-16T18:35:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9677aeeeab1b79442df96ee2f97e493e88e520e5",
"body": "tsup flattens loader into dist/index.js so ../../proto pointed above the package root and client.grpc threw ENOENT. Try ../proto then ../../proto.",
"is_bot": false,
"headline": "fix(grpc): resolve proto path from bundled dist (1.0.39)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-15T02:20:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "89effaa886fb7befc41b9c5a5757ed1460d331c7",
"body": null,
"is_bot": false,
"headline": "docs(ai): refresh knowledge versions to live 0.1.107 / SDK tips",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-15T02:08:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b33eb15ae612e5948814be3b6a001b25a768d743",
"body": null,
"is_bot": false,
"headline": "chore(agents): add alwaysApply KB sync Cursor rule",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-15T01:18:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "724f36f6b6b389373232d32407e974837c4fe306",
"body": "Avoid proto-loader zero defaults on maxRetries/timeoutSeconds. KB sync rule.",
"is_bot": false,
"headline": "fix(grpc): omit unset enqueue ints; release 1.0.38",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-15T01:18:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0d9cdc8d79753620a032a0649cf693509733264e",
"body": null,
"is_bot": false,
"headline": "docs(ai): add SDK knowledge base and contract notes",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-15T01:13:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ef99d4959f4ad85454915ffae3da61ffcb2394db",
"body": "Sync npm/runtime version surfaces after gRPC certs doc cleanup.",
"is_bot": false,
"headline": "chore(release): prepare v1.0.37",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-14T20:55:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4d3a61194de259928b0b662b89cbc95da57f3213",
"body": "Point at Compose-generated grpc_tls volume instead.",
"is_bot": false,
"headline": "docs(grpc): stop recommending historical ./certs/ PEMs",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-14T20:05:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "907f88306c9539bc800981f81736d84534ed81c3",
"body": null,
"is_bot": false,
"headline": "chore(release): prepare v1.0.36",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-13T17:01:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cbef824ee81abc9002b0dbcd999a621dae5d3d42",
"body": "Convert plain JavaScript payload/result objects to google.protobuf.Struct before unary gRPC calls and decode Struct responses back to plain objects. This prevents enqueue/complete payloads from serializing as empty objects.",
"is_bot": false,
"headline": "fix(grpc): encode Struct payloads",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-13T15:51:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "be5e2ee0de34b508fa4a8fcb6e4837798b4ce681",
"body": "Preserve Node 18 installs by using EventSource 3, reject failed WebSocket upgrades instead of leaving connect pending, keep reconnect attempts alive after token acquisition failures, and prevent custom retry predicates from replaying unsafe writes.",
"is_bot": false,
"headline": "fix(realtime): keep reconnects safe",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-13T15:49:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "af4828c32c5c8db48ea34c7d976857b27f98e036",
"body": null,
"is_bot": false,
"headline": "fix(release): verify npm artifact identity",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-12T18:42:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f74bbb60e9c3bea30b615b1aa7b05670d70ab6d3",
"body": null,
"is_bot": false,
"headline": "docs: align SDK contracts and examples",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-12T17:38:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "268b1af9c4422bc7bda171de59389be8b21645e9",
"body": null,
"is_bot": false,
"headline": "fix(worker): fence overlapping lease executions",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-12T15:19:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "93ff7ec8b6a1cf83538f5fa3f020fc0abaf837f7",
"body": "The claim response now surfaces the backend's lease_id fencing token\n(ClaimedJob.leaseId), and the worker echoes it on complete/fail/heartbeat\nso a stale lease — even from the same worker after a reclaim — is rejected\nby the server with 409 LEASE_EXPIRED instead of silently winning. Requires\nbackend\n[…]\nDKs keep the legacy worker_id fence. Proto updated with the\nlease_id fields (Job=19, Complete=4, Fail=5, RenewLease=4) for gRPC parity.\n\nAlso fixes the stale hardcoded worker default version (1.0.26).",
"is_bot": false,
"headline": "feat(worker,jobs): capture and echo lease_id fencing token (audit F9)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-11T20:51:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ba7435acbc886a8409123c352b79aa3175614b61",
"body": "…n-JSON error text\n\nThe realtime API was broken against the live backend:\n\n- The backend serializes RealtimeEvent with the PascalCase enum variant name\n as the `type` tag (JobCompleted, JobStatusChange, QueueStats, ...), but the\n SDK dispatched typed handlers by dotted names (job.completed, ...), \n[…]\ner-Agent synced from a stale 1.0.31 to 1.0.33.\n\nAdds unit tests for PascalCase->dotted dispatch, prompt (ack-free) subscribe\nwith the {cmd,queue,job_id} shape, and non-JSON error message preservation.",
"is_bot": false,
"headline": "fix(realtime): align typed events + subscribe to backend; preserve no…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-09T20:44:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6f5d92bffb495426fa7edf5afbbe497011894fac",
"body": "…CI runs Node 20)",
"is_bot": false,
"headline": "ci: pin npm@11 for Trusted Publishing (npm@latest 12+ needs Node 22, …",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-09T04:09:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7a8dab6d61de102f7b60b272b94062de943b2dc7",
"body": null,
"is_bot": false,
"headline": "chore(release): trim credentials (v1.0.32)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-09T03:58:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1d0bddc1a1542364858e2be2af5c8d85aab967e9",
"body": "undici's fetch rejects `Authorization: Bearer <key>\\n` with an opaque\n`TypeError: HeaderValue` error, and users routinely load keys from\n`.env` files that carry a trailing newline. resolveConfig now normalizes\napiKey, accessToken, refreshToken, and adminKey (treating an all-\nwhitespace value as unde\n[…]\no match the Go, PHP, and Python SDKs.\n\nAdds unit tests covering trailing newline, surrounding whitespace,\nwhitespace-only inputs, and a check that the resulting Authorization\nheader contains no CR/LF.",
"is_bot": false,
"headline": "fix: trim whitespace from API keys and tokens in resolveConfig",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-09T03:38:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dd124229d12808dd6c6366aa2d7150bbc7b5503f",
"body": "… cron 5-field note",
"is_bot": false,
"headline": "docs(readme): quota error is now 429 + code QUOTA_EXCEEDED (was 403);…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-09T02:35:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a0c964659af1b4eb6c57495fac06d4f9498c16dc",
"body": null,
"is_bot": false,
"headline": "chore: sync SDK_VERSION/User-Agent to 1.0.31",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-08T13:55:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "984741ead199830675924bb552ae2b922c2bb725",
"body": "The token provider passed to client.realtime() minted a fresh JWT via\nPOST /api/v1/auth/login on every (re)connect. Under a reconnect storm this\ntripped the login rate limit (429) and realtime could never recover.\n\nThe client now caches the JWT at the client level (shared across reconnects)\nand reus\n[…]\nrevoked token is replaced\ninstead of replayed into a reconnect loop.\n\nAdds unit tests for the login-count/expiry/force-refresh behavior and the\nJWT exp decoding, and for the WS auth-failure detection.",
"is_bot": false,
"headline": "fix(realtime): cache JWT across WebSocket reconnects (1.0.31)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-08T13:49:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1548f97a7d52e1d707f55e31caba479f6b5a07c2",
"body": "…ect was off by default\n\nSame root cause as the debug TypeError: autoReconnect/maxReconnectAttempts/\nreconnectDelay/maxReconnectDelay were defaulted before the ...options spread, so\nthe undefined values SpooledRealtime forwards overwrote them. autoReconnect\nresolved to undefined (falsy), disabling reconnect despite the documented default\nof true. Defaults now applied after the spread. +6 regression tests.",
"is_bot": false,
"headline": "fix(realtime): reconnect defaults clobbered by undefined; auto-reconn…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-08T11:20:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b8485f270a1d9e1a122cc3d02de9825ed03d6087",
"body": "…emplate (v1.0.30)\n\nclient.realtime() threw `TypeError: this.options.debug is not a function`\non connect for any client built without a `debug` option — the normal,\ndefault case — leaving realtime unusable out of the box.\n\nRoot cause: SpooledRealtime forwards `debug: undefined`, and the WebSocket\nan\n[…]\nion tests covering WebSocket and SSE clients (and the\nSpooledRealtime wrapper) constructed with no debug option and with an\nexplicit `debug: undefined`, asserting debug is callable and does not throw.",
"is_bot": false,
"headline": "fix(realtime): make debug always callable; document schedule payloadT…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-08T11:17:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "23e722734b52955c14de117d4ded6665dcea7d42",
"body": "…y (v1.0.29)\n\nRemediation from a multi-agent SDK bug hunt (verified against the live backend).\nRealtime WebSocket now authenticates via a JWT in ?token= (was an ignored\nheader), SSE uses the correct query param, opaque job payloads are transmitted\nverbatim, non-idempotent POSTs are not blindly retried, the circuit breaker no\nlonger trips on client 4xx, and Retry-After is honored. See CHANGELOG for the\nfull list.",
"is_bot": false,
"headline": "fix: realtime auth, payload preservation, retry/circuit-breaker safet…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-08T07:39:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6d81d76fa69261d69c3df41e9149ff79d3221ada",
"body": "Bump to 1.0.28. Resolve high-severity advisories via npm audit fix and correct the API key prefix and error-handling examples in the README.",
"is_bot": false,
"headline": "chore(release): dependency security fixes & README corrections (v1.0.28)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-07T13:30:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "664d823a0f11a96119e7aed25f1fc98674e64cbe",
"body": "- API keys are sp_live_/sp_test_ (sk_ is legacy-accepted only); all\n examples updated.\n- The error-handling snippets imported LimitExceededError and read\n error.current/limit/upgradeTo — none of which exist. Plan-limit\n responses are HTTP 403 and surface as AuthorizationError; examples\n now use the real classes and fields.\n\nAudit ref: audit-memos/09-consistency.md C2/C9 (R16).",
"is_bot": false,
"headline": "docs: fix key prefix and error-handling examples in README",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-07T05:32:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5022c497fd351e5345b8323758e3aac76b98345a",
"body": "Bumps within existing semver ranges (lockfile only):\n- @grpc/grpc-js 1.14.3 -> 1.14.4\n- protobufjs 7.5.6 -> 7.6.5 (DoS via recursive descriptor expansion,\n Any expansion DoS, property shadowing)\n- ws 8.20.0 -> 8.21.0 (uninitialized memory disclosure, fragment DoS)\n- vite (dev) to a patched 8.x\n\nnpm audit is clean; unit tests and build pass.\n\nAudit ref: audit-memos/11-secrets-deps.md (R8).",
"is_bot": false,
"headline": "fix(deps): resolve high-severity advisories via npm audit fix",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-07-07T04:39:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4b5a9d9a401c864a910541ecdeb05180563bc824",
"body": "Release content:\n- Bump @spooled/sdk to 1.0.27.\n- Refresh safe direct runtime and development dependencies, including ws and Vitest tooling.\n- Fix SSE client EventSource leak: handleDisconnect now calls close() before\n nulling the reference, preventing duplicate connections on reconnect.\n- Replace \n[…]\n generation.\n\nCI updates:\n- Update publish workflow to actions/checkout@v6 and actions/setup-node@v6.\n\nVerified: npm ci; npm run lint; npm run typecheck; npm run build; npm test; npm audit --omit=dev.",
"is_bot": false,
"headline": "chore: refresh Node SDK dependencies and fix SSE leak (v1.0.27)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2026-05-05T22:16:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3d75f03a50c1a3589cfa1490ab9a5d31cdd40b84",
"body": null,
"is_bot": false,
"headline": "Update README.md",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-29T15:45:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f1fbf59f2a0c3e6e661e9d6440f5de94e3a57f26",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.26",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-21T17:06:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a80ebfcae958a6359f787389aaa2e71fdf775676",
"body": "…require",
"is_bot": false,
"headline": "fix: ESM compatibility for WebSocket - use dynamic import instead of …",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-21T16:34:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cb4a564fcdf92b816bb28658c49aea7afaa952ea",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.25",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-21T16:05:54Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4dbb77f8b54d6681fa047647ea24a9d06cc6247d",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.24",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-21T16:05:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ad5b0b4513eb2da2add5afebaebc4c857890bf9c",
"body": null,
"is_bot": false,
"headline": "docs: add Live Demo (SpriteForge) link",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-21T15:51:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8cb0881feea5a20cafd87c0020b0c82b0bd74c61",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.23",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-20T19:34:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f8f058a3d8bb0552fbc8c88d9c381c19be326ef6",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.22",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-20T19:20:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57e6bdf5e45bc1b76f31dd29fe529f8ee5eee4ce",
"body": "- Accept API keys starting with sp_ in addition to sk_ prefix\n- Use dynamic import for eventsource package (ESM compatibility)\n- Pass authorization header via custom fetch function (eventsource v4+ API)",
"is_bot": false,
"headline": "fix: support sp_ API key prefix and ESM-compatible eventsource import",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-20T12:04:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4e32808ef41967bf17513df1536872dc5fd57f99",
"body": "This reverts commit ba6d6aaefc546f57f7913f00e74828fa3f5f5499.",
"is_bot": false,
"headline": "Revert \"docs: note backend plan limit env vars in .env.example\"",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-20T00:55:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ba6d6aaefc546f57f7913f00e74828fa3f5f5499",
"body": null,
"is_bot": false,
"headline": "docs: note backend plan limit env vars in .env.example",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-20T00:51:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7af3f9ded8c4e633bc688de050bd7541bfef535c",
"body": "- Add tag parameter to ListJobsParams type\n- Update docs with tag filter examples",
"is_bot": false,
"headline": "feat: add tag filtering support for job listing",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-19T23:43:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "157d8f23b09db220891cf32168da5a87122f9c87",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.21",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-19T01:26:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5bb90a83bfd28008883c7ea28cc11b36a7f9acc5",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.20",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-18T23:45:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "136427864421c1907097856cdda6bdaa3aa1f38c",
"body": null,
"is_bot": false,
"headline": "chore: remove hardcoded keys from tests/scripts",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-18T23:39:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "62cc334fbeaae3c72db3940761e517b96668fbc9",
"body": null,
"is_bot": false,
"headline": "docs: link to backend real-world examples",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-18T22:35:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "80c19082ae9c38884616f4639f727f2db613e3ea",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.19",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-18T10:59:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6bd430245fad5e6f8d4f7ecbdfe9365401ade055",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.15",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T23:00:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5afa4b13615ea30c1d387141335b362b42c22a1b",
"body": "Cloudflare Tunnel requires HTTPS for HTTP/2 (gRPC).\nRemoved incorrect plaintext HTTP option.",
"is_bot": false,
"headline": "docs: fix Cloudflare Tunnel docs - HTTP/2 requires HTTPS",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T22:45:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "867e1211d0cefc1f36dbbbce220539fe81d68bd8",
"body": "- Add optimized configuration (disable internal TLS)\n- Clarify legacy vs optimized setup options",
"is_bot": false,
"headline": "docs: update gRPC guide with Cloudflare Tunnel optimization",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T22:40:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d941cba1a3e7e7ca5d985cd29562a7a132514189",
"body": null,
"is_bot": false,
"headline": "docs: update README with optimized gRPC configuration example",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T22:33:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c7459dd6004142dba731709020e221673b39814d",
"body": null,
"is_bot": false,
"headline": "fix: update test scripts",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T22:19:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3d2e7f624bd5ab4e1cd8ceef2f69243a614a7545",
"body": null,
"is_bot": false,
"headline": "fix: upgrade local tests",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T20:44:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1c9f193dd8411d7ba187ab72e3ee0023973b888c",
"body": "Test script now uses TLS for production (port 443 or grpc.spooled domain)\nand insecure for localhost/127.0.0.1",
"is_bot": false,
"headline": "fix: auto-detect gRPC TLS based on address",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T12:20:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2c51fcb395280e6b2b21552cc3af8eb46f239357",
"body": "…-resource\n\n- Add getWebhookToken(), regenerateWebhookToken(), clearWebhookToken() to OrganizationsResource\n- Add WebhookTokenResponse type\n- Expand WorkflowJobOperations with list(), get(), getStatus() methods\n- Add WorkflowJob and WorkflowJobStatus types\n- Add integration tests for webhook token and workflow jobs features\n- Bump version to 1.0.17",
"is_bot": false,
"headline": "feat: add organization webhook token management and workflow jobs sub…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T05:09:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "17837f0f080a13a78edc080592e9da2d70410d39",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.16",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T03:22:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7fc0df598f092f91186f0cbfc024efd2e277f756",
"body": null,
"is_bot": false,
"headline": "chore(release): v0.1.15",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-17T01:07:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "89ae5b7ff7e8140b3d9b5bef085f33e265bd9388",
"body": "- Document how to enable TLS on self-hosted gRPC with Cloudflare Tunnel\n- Add Cloudflare Tunnel configuration steps\n- Document how to disable TLS for local development",
"is_bot": false,
"headline": "docs: Add gRPC TLS configuration for Cloudflare Tunnel",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T15:40:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "687a636552ae3244f21ee40b63b8e4b5d8e112a5",
"body": null,
"is_bot": false,
"headline": "fix: remove import.meta usage from test-production.ts",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T13:55:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57a36654c444f025c020ec208790dc5b42ecfe9a",
"body": "- Add scripts/test-production.ts wrapper for running test-local.ts against\n production (api.spooled.cloud)\n- Skips stress tests by default to avoid noisy production runs\n- Supports --full flag to enable all tests\n- Add SKIP_STRESS option to test-local.ts for fine-grained control",
"is_bot": false,
"headline": "feat: add production test runner script",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T13:44:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e21118e88cbb76a2d060ca0dfd864e95682359d6",
"body": "- Update gRPC client example to use :443\n- Fix unit test cloud address to :443\n- Document GRPC_ADDRESS usage for local vs cloud",
"is_bot": false,
"headline": "docs: standardize Spooled Cloud gRPC endpoint to grpc.spooled.cloud:443",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T13:07:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "97e8cff03e34c84c644a2f1ee3f723d8f855ef43",
"body": "- Add cleanupOldJobs() before gRPC, worker, webhook, and edge case tests\n- Reduce job counts in stress tests to fit free tier limits (10 jobs)\n- Add cleanup after job creation tests\n- Fix tier limit tests to use JWT instead of raw API key",
"is_bot": false,
"headline": "fix: add job cleanup to tests for free tier compatibility",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T12:20:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c21356179ff222b27cb567b3530f247f19e23e93",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.14",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T05:41:54Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7dfe1e9415b396355ff8333d17cf7033353a34ab",
"body": "Add client.workflows.retry(id) to retry failed workflows:\n- Resets all failed/deadletter jobs back to pending\n- Clears retry counts and error messages\n- Updates workflow status from failed to running\n\nUpdates:\n- SDK workflows resource with retry method\n- API_CONTRACT.md with new endpoint\n- resources.md and workflows.md docs\n- Unit tests for retry\n- Integration tests for retry",
"is_bot": false,
"headline": "feat: add workflow retry method",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T05:40:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "912112ff4275335aab590397ce08add4747486b4",
"body": "- Fix JobHandler return type by casting payload.step to String\n- Add explicit type assertions for worker and grpcClient cleanup\n- Use Number() for stats.total comparison\n- Add missing queueName to updateConfig params\n- Use planTier instead of plan for BillingStatus\n- Replace worker.isRunning with worker.getState()\n- Add explicit array type annotations for Promise.all",
"is_bot": false,
"headline": "fix: resolve TypeScript errors in test-local.ts",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T05:20:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "320302ff949f15f64e29424943fb73ac41c83b46",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.13",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T05:12:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "070171eac8ba676063918e18ca8439900ef0174d",
"body": "Updated docs:\n- getting-started.md: Add plan limits, DLQ, webhooks, organization management sections\n- grpc.md: Add performance metrics (~28x speedup), plan limit enforcement\n- resources.md: Add new methods (webhooks.retryDelivery, auth methods, org methods)\n\nNew sections:\n- Plan Limits table with e\n[…]\nLetter Queue operations (list, retry, purge)\n- Webhooks (retryDelivery)\n- Authentication (startEmailLogin, checkEmail, login, refresh, validate)\n\nAll documentation now reflects current implementation.",
"is_bot": false,
"headline": "docs: update SDK documentation with new features and improvements",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T04:44:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "70f3889493d3d59666d103adfad55a4a23bfac19",
"body": "- Add Organization Management section (getUsage, generateSlug, checkSlug)\n- Add Webhooks section (create, retryDelivery, getDeliveries)\n- Add Dead Letter Queue operations (list, retry, purge)\n- Add API Key Management section\n- Add Billing & Subscriptions section\n- Add Authentication section (email l\n[…]\needup)\n- Add LimitExceededError to error handling examples\n- Document limit enforcement across all endpoints (HTTP, gRPC, workflows, schedules, DLQ)\n\nAll features reflect current implementation state.",
"is_bot": false,
"headline": "docs: update README with new SDK features and performance improvements",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T04:37:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "38ab2477c1d87d6f2155d7ad1a0a4cf47d347cd9",
"body": "- Major expansion of test-local.ts with comprehensive endpoint coverage\n- Add missing auth resource methods\n- Add organization resource methods\n- Add webhook resource methods",
"is_bot": false,
"headline": "feat: expand test suite and add missing resource methods",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T04:18:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fb2bc70a806a1e780907ba72c512264f9a03bf7f",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.12",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T00:21:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "811861452cc1a8df06bd0958def08079c30849dc",
"body": null,
"is_bot": false,
"headline": "test: add comprehensive local test suite and bootstrap script",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-16T00:03:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "504138553c89acbbfbe88722d75b48826510a659",
"body": "…agement, admin, email)\n\n- Add metrics endpoint test (port 9090)\n- Add WebSocket connectivity test\n- Add organization management tests (check-slug, generate-slug, list)\n- Add admin endpoints tests (skipped without ADMIN_KEY)\n- Add email login flow tests\n- Fix SDK type issues (statusCode, array returns)\n- Total: 114 tests covering all HTTP API endpoints except gRPC",
"is_bot": false,
"headline": "feat(test): add remaining endpoint tests (metrics, websocket, org man…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T20:37:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1423d1ceb6c9ee459ae82ca1ada49023b83e9945",
"body": "- Add test-local.ts with 106 tests covering all major API endpoints\n- Tests: health, dashboard, org, API keys, jobs (CRUD/bulk/lifecycle/DLQ)\n- Tests: queues, workers, webhooks, schedules, workflows\n- Tests: billing, authentication, registration, worker integration\n- Tests: edge cases, error handling, webhook E2E delivery\n- Add verify-production.ts for interactive production verification\n- gRPC tests skipped by default (server binding issue)",
"is_bot": false,
"headline": "feat(test): comprehensive test suite covering 105+ API endpoints",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T20:32:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2cca647102cc0a9a5252cb2fad968824ef2a718c",
"body": "Tests all API endpoints and SDK features:\n- Health, Dashboard, Organizations, API Keys\n- Jobs: CRUD, bulk, lifecycle, failure/retry, DLQ\n- Queues: list, pause/resume\n- Workers: register, heartbeat, deregister\n- Webhooks: CRUD, test, delivery\n- Schedules: CRUD, pause/resume, trigger, history\n- Workflows: dependencies, cancel\n- Authentication: login, validate, refresh, logout\n- SpooledWorker integration\n- Edge cases and error handling\n\nUsage: API_KEY=sk_test_... npx tsx scripts/test-local.ts",
"is_bot": false,
"headline": "feat: add comprehensive test suite (87 tests)",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T18:40:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9e50e03727125b7c43e11450a2dd9eec0406a9a7",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.11",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T14:37:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "49c9fdd0f8b32247fd18a02bdf437658d82ec2a7",
"body": "- Add wsUrl config option for explicit WebSocket URL (defaults to derived from baseUrl)\n- Update RealtimeConnectionOptions to support both baseUrl (SSE) and wsUrl (WebSocket)\n- Add comprehensive self-hosted configuration section in docs\n- Update configuration.md with all endpoint options and URL derivation table\n- Update grpc.md with self-hosted gRPC examples\n- Update API_CONTRACT.md with base URL reference table\n- Update README.md with self-hosted hint in quick start example",
"is_bot": false,
"headline": "feat: add custom endpoint support for self-hosted deployments",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T14:28:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7269c1d1efe684ed2c8c01347095bde6938fe921",
"body": null,
"is_bot": false,
"headline": "docs: update API_CONTRACT.md with webhook token management endpoints",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T13:29:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7e55296c275d29e27e2e5fb1317cbc9ff35b7b82",
"body": null,
"is_bot": false,
"headline": "docs: add webhook configuration examples to API_CONTRACT.md",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T13:21:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d80de9c38183fd7c577b588cb651b0c7d31c42c1",
"body": "…ook endpoints\n\n- Removed references to GitHub and Stripe webhook endpoints\n- Added note that custom webhooks provide flexible alternative\n- Documented billing webhook for subscription events",
"is_bot": false,
"headline": "docs: update API_CONTRACT.md to reflect removal of GitHub/Stripe webh…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T13:19:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b3d2f7f23854bb8a8c03f14d8043a779228490ee",
"body": "- Add docs/getting-started.md - installation and first steps\n- Add docs/configuration.md - all config options\n- Add docs/workers.md - SpooledWorker deep dive\n- Add docs/workflows.md - DAG and workflow patterns\n- Add docs/grpc.md - high-performance gRPC guide\n- Add docs/resources.md - complete API re\n[…]\nexamples/workflow-dag.ts - complex workflow example\n- Add examples/grpc-streaming.ts - gRPC streaming example\n- Update README.md with documentation links and cleaner structure\n- Bump version to 1.0.10",
"is_bot": false,
"headline": "docs: add comprehensive documentation and examples",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:46:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9502a709b4b8da7ab06a35e0e65c856ee823c1f6",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.9 - fix repo URL case for provenance validation",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:24:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3d7910b102fce2b6b87789d7c36f419c314732da",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.8",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:21:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "46132d5ac5b923b88d324dcccf727955501c8b05",
"body": "…est for OIDC)",
"is_bot": false,
"headline": "ci(publish): revert to standard setup-node registry-url config (clean…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:20:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e2c5eda97f1d4bfa8b84c8d789bae7e59b3d4dcb",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.7",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:16:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fe3aeb5e050f37b82cc6f6d28e1c224f29b73bc2",
"body": "…Token to trigger OIDC",
"is_bot": false,
"headline": "ci(publish): fix ENEEDAUTH - configure .npmrc in home with empty auth…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:15:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "231fe81e2c6fae1091363c0ca03f05a57c3104e6",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.6",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:13:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b2ec0ea6d70cecd2c6f0153f7a2624d7e94b14d2",
"body": "…y auth injection",
"is_bot": false,
"headline": "ci(publish): fix E404 - remove setup-node registry-url to avoid legac…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:12:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f3009da5a5c2303db8b9659358ab9e26fe0a5664",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.5",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:09:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "960f33d01c9c98229214948c3956b1daae06970e",
"body": "…pm >= 11.5.1)",
"is_bot": false,
"headline": "ci(publish): upgrade npm to latest for Trusted Publishing (requires n…",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:08:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1ffd76dedc90451450fcfc01bf74f6a986af14f8",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.4",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:04:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1dee10007b4162771990702759cc7387f5ce372a",
"body": null,
"is_bot": false,
"headline": "ci(publish): fix OIDC auth - remove token placeholder from .npmrc",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T03:03:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "029ba3ddaa7a0e814d0ee5b64ca12e23418e90a2",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.3",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T02:59:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2e982262294ee4329c43cbbce94cbab6e816f385",
"body": null,
"is_bot": false,
"headline": "ci(publish): avoid setup-node npmrc token config; rely on OIDC",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T02:57:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a552eabde922b9e50a6d227f76720ee7d1ef6900",
"body": null,
"is_bot": false,
"headline": "chore(release): v1.0.2",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T02:51:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0a7cc66535ba629da727b05ab2cb72868823de30",
"body": null,
"is_bot": false,
"headline": "ci: fix publish workflow yaml parsing",
"author_name": "Yevhen Salitrynskyi",
"author_login": "ysalitrynskyi",
"committed_at": "2025-12-15T02:47:43Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 3,
"commits_last_year": 110,
"latest_release_at": "2026-07-19T14:47:54Z",
"latest_release_tag": "v1.0.40",
"releases_from_tags": false,
"days_since_last_push": 5,
"active_weeks_last_year": 8,
"days_since_latest_release": 5,
"mean_days_between_releases": 3
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 50,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "@spooled/sdk",
"exists": true,
"license": "Apache-2.0",
"keywords": [
"spooled",
"job-queue",
"task-queue",
"background-jobs",
"webhooks",
"cron",
"scheduler",
"workflow"
],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/@spooled/sdk",
"is_deprecated": false,
"latest_version": "1.0.40",
"repository_url": "https://github.com/Spooled-Cloud/spooled-sdk-nodejs",
"versions_count": 30,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": 1,
"monthly_downloads": 2076,
"first_published_at": "2025-12-15T02:41:00.638000Z",
"latest_published_at": "2026-07-19T14:48:12.294000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 5
}
]
},
"popularity": {
"forks": 0,
"stars": 5,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": null,
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [
"proto/spooled.proto"
],
"has_devcontainer": false,
"typecheck_configs": [
"tsconfig.json"
],
"toolchain_manifests": [],
"largest_source_bytes": 137922,
"source_files_sampled": 96,
"oversized_source_files": 1,
"agent_instruction_files": [
".cursor/rules/kb-sync.mdc",
"AGENTS.md"
],
"agent_instruction_max_bytes": 502
},
"dependencies": {
"manifests": [
"package.json"
],
"advisories": {
"error": null,
"scope": "published_package",
"source": "osv",
"findings": [],
"collected": true,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 36,
"malicious_count": 0,
"assessed_package": "npm:@spooled/sdk@1.0.40",
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"npm"
],
"dependencies": [
{
"name": "@grpc/grpc-js",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^1.14.3"
},
{
"name": "@grpc/proto-loader",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^0.8.0"
},
{
"name": "eventsource",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^3.0.7"
},
{
"name": "ws",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^8.20.0"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "ysalitrynskyi",
"commits": 110,
"avatar_url": "https://avatars.githubusercontent.com/u/25203302?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"publish.yml"
],
"has_docs_dir": true,
"linter_configs": [
"eslint.config.js"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"package-lock.json"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 3,
"reason": "branch protection is not maximal on development and all release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 6,
"reason": "project has 2 contributing companies or organizations -- score normalized to 6",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 2,
"reason": "dependency not pinned by hash detected -- score normalized to 2",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 10,
"reason": "GitHub workflow tokens follow principle of least privilege",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 7,
"reason": "3 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "06d0f5ddad724239cef7b8b598fb0fbaa45779c0",
"ran_at": "2026-07-25T12:41:44Z",
"aggregate_score": 5.3,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-19T14:48:17Z",
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/Spooled-Cloud/spooled-sdk-nodejs",
"host": "github.com",
"name": "spooled-sdk-nodejs",
"owner": "Spooled-Cloud"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"security": 62,
"vitality": 82,
"community": 35,
"governance": 36,
"engineering": 88
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 82,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 70,
"inputs": {
"commits_last_year": 110,
"human_commit_share": 1,
"days_since_last_push": 5,
"active_weeks_last_year": 8
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 5 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 5
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "8/52 weeks with commits",
"points": 5.5,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 8
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "110 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 110
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 100,
"inputs": {
"releases_count": 3,
"latest_release_tag": "v1.0.40",
"releases_from_tags": false,
"days_since_latest_release": 5,
"mean_days_between_releases": 3
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "3 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 3
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 5 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 5
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~3 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 3
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 5,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 5 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 5
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 35,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"forks": 0,
"stars": 5,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "5 stars",
"points": 9.8,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 5
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (Apache-2.0)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "Apache-2.0"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 55,
"inputs": {
"packages": [
"@spooled/sdk"
],
"dependents": null,
"ecosystems": "npm",
"total_downloads": null,
"monthly_downloads": 2076
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "2,076 downloads/month across npm",
"points": 44.2,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 2076,
"ecosystems": "npm"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 36,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 16,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 2 contributing companies or organizations -- score normalized to 6",
"points": 6,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution",
"pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"merged_prs": 0,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "no decided pull requests or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_decided_prs_or_data",
"params": {}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": null,
"notes": [],
"value": 42,
"inputs": {
"followers": 3,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "Spooled-Cloud",
"public_repos": 8,
"account_age_days": 228
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "organization-owned",
"points": 30,
"status": "met",
"details": [
{
"code": "owner_organization",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "3 followers of Spooled-Cloud",
"points": 4.3,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 3,
"login": "Spooled-Cloud"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "8 public repos, account ~0 yr old",
"points": 8.2,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 8
}
},
{
"code": "account_age_years",
"params": {
"years": 0
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"@spooled/sdk"
],
"ecosystems": "npm",
"any_deprecated": false,
"min_days_since_publish": 5
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on npm",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "npm"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 5 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 5
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "30 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 30
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "excellent",
"name": "Engineering Quality",
"value": 88,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 80,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "1 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 1
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": "eslint.config.js",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "eslint.config.js"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "excellent",
"name": "Documentation",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"topics": [
"async",
"client-library",
"javascript",
"nodejs",
"npm",
"sdk",
"type-safe",
"typescript",
"webhook"
],
"has_wiki": true,
"homepage": "https://spooled.cloud",
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://spooled.cloud",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "9 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 9
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "moderate",
"name": "Security",
"value": 62,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "moderate",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 53,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 5.3
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection is not maximal on development and all release branches",
"points": 2.2,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 2 contributing companies or organizations -- score normalized to 6",
"points": 1.5,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 2",
"points": 1,
"status": "partial",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "GitHub workflow tokens follow principle of least privilege",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "3 existing vulnerabilities detected",
"points": 5.2,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "dependency_advisories",
"band": "excellent",
"name": "Dependency advisories",
"note": "Excluded from scoring (no data or not applicable): No advisories left outstanding. Remaining weights renormalized. Matched the npm:@spooled/sdk@1.0.40 runtime dependency closure — what installing the published package pulls in — 36 packages. Reachability is not analyzed.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"no_advisories_left_outstanding"
]
}
},
{
"code": "weights_renormalized",
"params": {}
},
{
"code": "advisories_scope_published",
"params": {
"package": "npm:@spooled/sdk@1.0.40",
"assessed": 36
}
},
{
"code": "advisories_reachability",
"params": {}
}
],
"value": 100,
"inputs": {
"source": "osv",
"advisories": 0,
"affected_packages": 0,
"assessed_packages": 36,
"unassessed_packages": 0,
"affected_by_severity": "none",
"direct_affected_packages": 0
},
"components": [
{
"key": "direct_dependencies_free_of_known_advisories",
"name": "Direct dependencies free of known advisories",
"detail": "no direct dependency carries a known advisory",
"points": 35,
"status": "met",
"details": [
{
"code": "no_direct_advisories",
"params": {}
}
],
"max_points": 35
},
{
"key": "indirect_dependencies_free_of_known_advisories",
"name": "Indirect dependencies free of known advisories",
"detail": "no indirect dependency carries a known advisory",
"points": 25,
"status": "met",
"details": [
{
"code": "no_indirect_advisories",
"params": {}
}
],
"max_points": 25
},
{
"key": "no_advisories_left_outstanding",
"name": "No advisories left outstanding",
"detail": "no advisory carries a publication date",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_no_publication_date",
"params": {}
}
],
"max_points": 40
}
]
},
{
"key": "malicious_dependencies",
"band": "excellent",
"name": "Malicious dependencies",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"source": "osv",
"meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
"packages": [],
"red_flag": false,
"assessed_packages": 36,
"malicious_packages": 0,
"direct_malicious_packages": 0,
"withdrawn_malicious_packages": 0,
"installable_malicious_packages": 0
},
"components": [
{
"key": "no_dependency_reported_as_a_malicious_package",
"name": "No dependency reported as a malicious package",
"detail": "no dependency is reported as a malicious package",
"points": 100,
"status": "met",
"details": [
{
"code": "no_malicious_dependencies",
"params": {}
}
],
"max_points": 100
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 3
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 75,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.98,
"agent_instruction_files": [
".cursor/rules/kb-sync.mdc",
"AGENTS.md"
],
"agent_instruction_max_bytes": 502
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": ".cursor/rules/kb-sync.mdc, AGENTS.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".cursor/rules/kb-sync.mdc, AGENTS.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "98 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 98,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 56,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"package-lock.json"
],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [
"tsconfig.json"
],
"agent_commit_share": 0,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": "eslint.config.js",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "eslint.config.js"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 2",
"points": 2,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 99,
"inputs": {
"primary_language": "TypeScript",
"largest_source_bytes": 137922,
"source_files_sampled": 96,
"oversized_source_files": 1
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "TypeScript (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "TypeScript"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "1/96 source files over 60KB",
"points": 54.4,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 96,
"oversized": 1
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "good",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 80,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": [
"proto/spooled.proto"
]
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": "proto/spooled.proto",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "proto/spooled.proto"
}
}
],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
],
"report_type": "repository",
"generated_at": "2026-07-25T12:41:51.168877Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/s/Spooled-Cloud/spooled-sdk-nodejs.svg",
"full_name": "Spooled-Cloud/spooled-sdk-nodejs",
"license_state": "standard",
"license_spdx": "Apache-2.0"
}