Skip to content

feat: typed customFields generics + optional companyId#22

Merged
priosshrsth merged 3 commits into
mainfrom
feat/customfields-generics
Jul 14, 2026
Merged

feat: typed customFields generics + optional companyId#22
priosshrsth merged 3 commits into
mainfrom
feat/customfields-generics

Conversation

@priosshrsth

Copy link
Copy Markdown
Collaborator

Summary

  • Typed customFields generics: createAssemblyKit / AssemblyKit now accept optional TClientCustomFields and TCompanyCustomFields generics that flow through kit.clients.* and kit.companies.*. Defaults to Record<string, unknown> so existing callers are unaffected.
  • Optional companyId in tokens: client tokens no longer require companyId. Schema refine now requires only internalUserId or clientId; isClientUser and ensureIsClient updated accordingly.
  • Dependency bumps: @typescript/native-preview to latest dev build; transport updated for ky 2.x prefixUrlprefix rename. AGENTS.md regenerated by vp config post-bump.

Usage (new generic)

// Single shape applied to both clients and companies
const kit = createAssemblyKit<{ roles: string[] }>({ apiKey, workspaceId });
const c = await kit.clients.retrieve("id");
c.customFields; // { roles: string[] } | null | undefined

// Different shapes per resource
const kit = createAssemblyKit<{ roles: string[] }, { industry: string }>(opts);

Both generics are optional — passing none keeps the previous Record<string, unknown> behavior.

Test plan

  • bun run check passes (lint, format, types — isolatedDeclarations enabled)
  • bun run test — all 172 existing tests pass; added a positive case for clientId-only client tokens and flipped the negative case to companyId-only
  • Verify in a downstream consumer that kit.clients.retrieve() infers the supplied customFields shape

🤖 Generated with Claude Code

priosshrsth and others added 3 commits May 5, 2026 11:10
- @typescript/native-preview 20260405.1 -> 20260505.1
- AGENTS.md regenerated by `vp config` after vite-plus bump
- ky 2.x renamed `prefixUrl` to `prefix` — update transport options accordingly

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Token validation previously required `clientId + companyId` together for
client tokens. `companyId` is now fully optional alongside `clientId`:

- TokenPayloadSchema refine: requires only `internalUserId` or `clientId`
- AssemblyToken.isClientUser: checks only `clientId`
- ensureIsClient error message updated
- Tests adjusted: client token with only `clientId` is accepted; flipped
  the rejection case to "companyId-only without clientId" instead

`AssemblyKit` already delegates to `AssemblyToken` for these checks, so
the relaxation flows through automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add optional generic parameters to `AssemblyKit` / `createAssemblyKit` so
consumers can type the `customFields` shape returned from clients and
companies endpoints:

```ts
const kit = createAssemblyKit<{ roles: string[] }>({ apiKey, workspaceId });
const c = await kit.clients.retrieve("id");
//        ^? customFields: { roles: string[] } | null | undefined
```

- `AssemblyKit<TClientCustomFields, TCompanyCustomFields = TClientCustomFields>`
  with both defaulting to `Record<string, unknown>` (fully backward compatible)
- `ClientsResource<T>` / `CompaniesResource<T>` thread the generic through
  `list`, `listAll`, `retrieve`, `create`, `update`
- `ClientsResponse<T>` / `CompaniesResponse<T>` are now generic
- Runtime Zod schemas unchanged — generics only narrow at type level
- Consumer-facing CLAUDE.md documents the new pattern

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@priosshrsth
priosshrsth merged commit dbc0b98 into main Jul 14, 2026
5 checks passed
@priosshrsth
priosshrsth deleted the feat/customfields-generics branch July 14, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant