@signa-so/sdk
v0.21.0
Published
Official TypeScript SDK for the Signa trademark intelligence API
Readme
@signa-so/sdk
Official TypeScript SDK for the Signa trademark intelligence API.
Installation
npm install @signa-so/sdkQuick Start
import Signa from '@signa-so/sdk';
const signa = new Signa({ api_key: 'sig_xxx' });
// Retrieve a trademark
const tm = await signa.trademarks.retrieve('tm_abc123');
// Search trademarks (POST with structured filters)
const results = await signa.trademarks.search({ q: 'nike', filters: { offices: ['US'] } });
// Text search via GET
const searched = await signa.trademarks.list({ q: 'nike', offices: 'US' });
// Exact marks, excluding one owner (lists go on the wire as repeated keys)
const variants = await signa.trademarks.list({ mark_text_is: ['nike', 'nikey'], owner_id_not: ['own_xxx'] });
// List with auto-pagination
const page = await signa.trademarks.list({ limit: 50 });
for (const tm of page.data) {
console.log(tm.mark_text);
}Configuration
const signa = new Signa({
api_key: 'sig_xxx', // Required (or set SIGNA_API_KEY env var)
base_url: 'https://api.signa.so', // Default
timeout: 30_000, // 30s default
max_retries: 2, // Automatic retry with backoff
debug: false, // Log request/response details
fetch: customFetch, // Custom fetch implementation
});Resources
All resources follow the same pattern: .retrieve(id), .list(params), plus resource-specific methods.
signa.trademarks
await signa.trademarks.retrieve('tm_xxx');
await signa.trademarks.retrieve('tm_xxx', { include: ['office_extensions'] });
await signa.trademarks.list({ offices: ['US'], status_stage: 'registered', limit: 50 });
await signa.trademarks.events('tm_xxx');signa.owners
await signa.owners.retrieve('own_xxx');
await signa.owners.list({ q: 'Nike', country_code: 'US' });
await signa.owners.trademarks('own_xxx');signa.attorneys
await signa.attorneys.retrieve('att_xxx');
await signa.attorneys.list({ q: 'Smith' });
await signa.attorneys.trademarks('att_xxx');signa.firms
await signa.firms.retrieve('firm_xxx');
await signa.firms.list({ q: 'Baker McKenzie' });
await signa.firms.attorneys('firm_xxx');
await signa.firms.trademarks('firm_xxx');signa.proceedings
await signa.proceedings.retrieve('prc_xxx');
await signa.proceedings.list({ trademark_id: 'tm_xxx' });signa.trademarks.search() (POST)
For structured filters, mark_text operators, exclusions and aggregations.
q ranks through the similarity channels; Presets.knockout and
Presets.clearance spread into any search request:
import Signa, { Presets } from '@signa-so/sdk';
await signa.trademarks.search({
q: 'nike',
...Presets.clearance,
filters: { offices: ['US'], status_primary: 'active', nice_classes: [25, 35], mark_text: { starts_with: ['ni'] } },
exclude: { owner_id: ['own_xxx'] },
options: { aggregations: ['status_stage', 'office_code'], include_total: true },
limit: 20,
});Upgrading from 0.16 or earlier: see the 0.17.0 migration table in CHANGELOG.md.
signa.references
await signa.references.classifications(); // Nice classes
await signa.references.offices(); // Trademark offices
await signa.references.jurisdictions(); // Jurisdictions
await signa.references.eventTypes(); // Event typesError Handling
All API errors throw typed exceptions for instanceof checks:
try {
await signa.trademarks.retrieve('tm_invalid');
} catch (err) {
if (err instanceof Signa.NotFoundError) {
console.log('Not found:', err.message);
} else if (err instanceof Signa.RateLimitError) {
console.log('Rate limited, retry after:', err.retryAfter);
} else if (err instanceof Signa.AuthenticationError) {
console.log('Bad API key');
}
}Error hierarchy:
| Class | HTTP Status | Description |
|-------|-------------|-------------|
| SignaError | — | Base class (network errors, timeouts) |
| SignaAPIError | Any | Base for all API errors |
| BadRequestError | 400 | Invalid parameters |
| AuthenticationError | 401 | Missing or invalid API key |
| PermissionError | 403 | Insufficient scope |
| NotFoundError | 404 | Resource not found |
| RateLimitError | 429 | Rate limit exceeded |
| InternalServerError | 500 | Server error |
| ConnectionError | — | Network connectivity failure |
| TimeoutError | — | Request timeout |
Pagination
List endpoints return a SignaList with cursor-based pagination:
const page = await signa.trademarks.list({ limit: 100 });
console.log(page.data); // Trademark[]
console.log(page.has_more); // boolean
console.log(page.next_cursor); // string | nullType Generation
The SDK auto-generates types from the API's OpenAPI spec:
bun run generate:types # Regenerate from API OpenAPI spec
bun run check:types-sync # Verify types are up-to-date (CI check)Scripts
bun run build # Compile TypeScript
bun run test # Run tests (uses msw for API mocking)
bun run dev # Watch mode
bun run typecheck # Type checkPublishing a release
Releases go to npm through the npm Trusted Publisher (OIDC) — GitHub
Actions proves its identity to npm at publish time and attaches a signed
provenance attestation. No npm token, no OTP, nothing stored anywhere.
Do NOT publish from a laptop with npm publish; account 2FA blocks it and
npm is retiring bypass-2FA tokens (account changes Aug 2026, direct
publishing Jan 2027).
Release procedure:
On
main(via a normal PR): bumpversioninpackages/sdk/package.jsonand date the corresponding heading inCHANGELOG.md. CI's "Check SDK types sync" gate guarantees the committed generated types match the API spec — publishing relies on this (see note below).GitHub → Actions → "Publish SDK" → Run workflow (branch
main), or:gh workflow run "Publish SDK" --ref main -f dry_run=true # pack only, sanity check gh workflow run "Publish SDK" --ref main # real publishThe workflow no-ops if the version is already on npm, so re-running is always safe. Verify with
npm view @signa-so/sdk version.
Configuration lives in two places:
- Repo:
.github/workflows/publish-sdk.yml(the only workflow allowed to publish). - npm: npmjs.com →
@signa-so/sdk→ Settings → Trusted Publisher (signa-so/signa, workflowpublish-sdk.yml; the trusted publisher must be re-registered for thesigna-soowner after the repo transfer). Publishing access is "Require two-factor authentication or a granular access token with bypass 2fa enabled" — but with the trusted publisher, no token is ever needed.
Note: the workflow builds with build:publish (compile only, no type
regeneration) because regenerating types imports the whole api workspace
graph, which needs built workspace deps a fresh CI checkout doesn't have
(@signa/db exports dist/). The committed generated types are enforced
current on every PR by the types-sync CI gate, so this is safe by
construction.
Requirements
- Node.js >= 18 (uses native
fetch) - MIT License
