OUT-4067: migrate to assembly-js node sdk - #74
Conversation
Replace deprecated copilot-node-sdk with @assembly-js/node-sdk. - Scope CopilotAPI by workspace key (workspaceId/apiKey) with no request token, so long invoice syncs don't fail on token expiry - Create the SDK client lazily and reuse it per instance - Decode the request token via getAssemblyTokenPayload; retry and return null on failure so auth maps it to a typed error - Drop the dead constructor try/catch and the redundant token decode in the home page (use user.portalId) - Require deliveryTargets/email fields on notifications to match the SDK Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Mock the Assembly SDK to decode tokens (or fall back to the seeded portal), keeping its broken ESM build out of the test graph - Assert each portal builds a CopilotAPI scoped to its own workspaceId - Assert failed-sync retries hit each portal's own Xero tenant, never another portal's Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThe PR migrates the Copilot integration from the deprecated SDK to
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains. No blocking failure remains. Important Files Changed
Sequence DiagramsequenceDiagram
participant R as Request or Retry
participant U as User.authenticate
participant A as Assembly SDK
participant C as CopilotAPI
participant X as Workspace API
R->>U: Request token
U->>A: Decode token payload
A-->>U: workspaceId and internalUserId
U->>C: Construct with workspaceId
C->>A: Lazily initialize workspace-scoped client
C->>X: Perform workspace operation
X-->>C: Validated resource response
Reviews (3): Last reviewed commit: "refactor(OUT-4067): fold env-mode preced..." | Re-trigger Greptile |
The workspace-scoped keyless auth path (new CopilotAPI(portalId)) only authorizes when ASSEMBLY_ENV/COPILOT_ENV is a keyless mode; otherwise the SDK throws at the first API call. Validate it at boot so a misconfigured runtime fails fast with a clear message instead of 500ing every request. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@greptileai review PR |
| ASSEMBLY_ENV: z.string().optional(), | ||
| COPILOT_ENV: z.string().optional(), |
There was a problem hiding this comment.
Let's just use ASSEMBLY_ENV here. and use z.enum or nativeEnum to limit the values. No need for superRefine.
There was a problem hiding this comment.
Done — collapsed it to a single ASSEMBLY_ENV field with z.enum and dropped the superRefine.
| } | ||
| }) | ||
|
|
||
| const env = ServerEnvSchema.parse(process.env) |
There was a problem hiding this comment.
| const env = ServerEnvSchema.parse(process.env) | |
| const env = ServerEnvSchema.parse({...process.env, ASSEMBLY_ENV: process.env.ASSEMBLY_ENV || process.env.COPILOT_ENV}) |
I suggest we set the priority based on the code in assembly sdk. Otherwise relying on two envs might cause some discrepancy.
There was a problem hiding this comment.
Applied this. One tweak: went with ?? instead of || to match the SDK’s getEnvMode exactly — with || an empty-string ASSEMBLY_ENV would silently fall back to COPILOT_ENV here while the SDK would still reject it.
Merge ASSEMBLY_ENV/COPILOT_ENV once at parse time (matching the SDK's getEnvMode) and validate the single value with z.enum, replacing the cross-field superRefine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@greptileai review changes |
Summary
Replaces the deprecated
copilot-node-sdkwith@assembly-js/node-sdk.The new SDK enforces request-token expiry, which breaks long-running syncs (invoice sync especially). To avoid that,
CopilotAPIis scoped by the workspace API key (workspaceId/apiKey) and passes no request token — the workspace key does not expire. The request token is only used briefly at auth time to decode the workspace payload.Changes
CopilotAPI: instantiate@assembly-js/node-sdkscoped byworkspaceId/apiKey; create the client lazily and reuse it per instance.getAssemblyTokenPayload(retried, returnsnullon failure → typedCopilotInvalidTokenError); removed the now-dead constructor try/catch and the redundant second decode on the home page (useuser.portalId).deliveryTargetsand emailheader/subject/titleare now required, matching the SDK's types.copilot-node-sdkdependency.Cross-portal safety
The SDK isolates per-request credentials via
AsyncLocalStorage, so concurrent portals can't bleed state on shared serverless instances (Fluid Compute) or persistent workers (trigger.dev). Every code path — webhook, home page, and the batch retry — derivesworkspaceIdfrom its own token; nothing is shared across portals.New regression tests lock this in:
CopilotAPIscoped to its ownworkspaceId;Testing
pnpm typecheck✅pnpm lint✅pnpm test✅ 63/63 (6× clean full-suite runs — no flakiness)pnpm build✅🤖 Generated with Claude Code