diff --git a/CHANGELOG.md b/CHANGELOG.md index 7edec0d3..c831a48b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,27 @@ # Changelog -## 0.13.3 +## 0.13.5 -### New Features +### Bug Fixes -- **WorkOS `organizations.deleteOrganization`** — the WorkOS emulator now supports the SDK's org delete (`DELETE /organizations/:id`), returning 204 No Content like the real API. Deletion cascades to the organization's memberships, so a subsequent `getOrganization` 404s and the org drops out of `listOrganizationMemberships`, matching real WorkOS. +- **WorkOS `authorization.listOrganizationRoles`** — the WorkOS emulator now serves organization roles on the Authorization-API path (`GET /authorization/organizations/:id/roles`) the v10 Node SDK calls, alongside the legacy `GET /organizations/:id/roles`. Before this, `authorization.listOrganizationRoles` hit a 404, so any app loading an org's roles (a members page role picker, for example) got a 500. +## 0.13.4 + +### New Features + +- **WorkOS invitation revocation on pending-membership delete** — deleting a pending organization membership now revokes the matching outstanding invitation, so seat counts stay coherent (a deleted pending member frees its seat instead of leaving a dangling invite). + +## 0.13.3 + +### New Features + +- **WorkOS `organizations.deleteOrganization`** — the WorkOS emulator now supports the SDK's org delete (`DELETE /organizations/:id`), returning 204 No Content like the real API. Deletion cascades to the organization's memberships, so a subsequent `getOrganization` 404s and the org drops out of `listOrganizationMemberships`, matching real WorkOS. + ## 0.13.2 ### New Features diff --git a/packages/@emulators/adapter-next/package.json b/packages/@emulators/adapter-next/package.json index 55e53d73..885607c4 100644 --- a/packages/@emulators/adapter-next/package.json +++ b/packages/@emulators/adapter-next/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/adapter-next", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/apple/package.json b/packages/@emulators/apple/package.json index 1d10e07d..305dd67a 100644 --- a/packages/@emulators/apple/package.json +++ b/packages/@emulators/apple/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/apple", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/autumn/package.json b/packages/@emulators/autumn/package.json index 46119b27..51d53f6e 100644 --- a/packages/@emulators/autumn/package.json +++ b/packages/@emulators/autumn/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/autumn", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/aws/package.json b/packages/@emulators/aws/package.json index 3299556e..d3d9c995 100644 --- a/packages/@emulators/aws/package.json +++ b/packages/@emulators/aws/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/aws", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/clerk/package.json b/packages/@emulators/clerk/package.json index f192960a..241d0b99 100644 --- a/packages/@emulators/clerk/package.json +++ b/packages/@emulators/clerk/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/clerk", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/cloudflare/package.json b/packages/@emulators/cloudflare/package.json index 5d8c3d4b..e28a58f8 100644 --- a/packages/@emulators/cloudflare/package.json +++ b/packages/@emulators/cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/cloudflare", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/cloudflare/src/__tests__/worker.test.ts b/packages/@emulators/cloudflare/src/__tests__/worker.test.ts index 31eed99a..b2e51484 100644 --- a/packages/@emulators/cloudflare/src/__tests__/worker.test.ts +++ b/packages/@emulators/cloudflare/src/__tests__/worker.test.ts @@ -10,7 +10,7 @@ describe("cloudflare worker routing", () => { }; const passedThrough: string[] = []; const realFetch = globalThis.fetch; - globalThis.fetch = (async (input: RequestInfo | URL) => { + globalThis.fetch = (async (input: Request | string | URL) => { passedThrough.push(input instanceof Request ? input.url : String(input)); return new Response("docs site"); }) as typeof fetch; diff --git a/packages/@emulators/cloudflare/src/durable-object.ts b/packages/@emulators/cloudflare/src/durable-object.ts index aaa4d81f..b69d966d 100644 --- a/packages/@emulators/cloudflare/src/durable-object.ts +++ b/packages/@emulators/cloudflare/src/durable-object.ts @@ -212,9 +212,9 @@ export class EmulatorDurableObject { private async readLedger(legacyLedger: LedgerSnapshot | undefined): Promise { const meta = await this.state.storage.get(LEDGER_META_KEY); if (!meta) return legacyLedger; - const entries = ( - await inBatches(meta.ids, (id) => this.state.storage.get(ledgerEntryKey(id))) - ).filter((entry): entry is LedgerEntry => entry != null); + const entries = (await inBatches(meta.ids, (id) => this.state.storage.get(ledgerEntryKey(id)))).filter( + (entry): entry is LedgerEntry => entry != null, + ); return { entries, counter: meta.counter }; } diff --git a/packages/@emulators/core/package.json b/packages/@emulators/core/package.json index 72507e51..9b638a31 100644 --- a/packages/@emulators/core/package.json +++ b/packages/@emulators/core/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/core", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/github/package.json b/packages/@emulators/github/package.json index 6dda45eb..1e6f9531 100644 --- a/packages/@emulators/github/package.json +++ b/packages/@emulators/github/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/github", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/gitlab/package.json b/packages/@emulators/gitlab/package.json index 5d8a94cb..56bfc6e4 100644 --- a/packages/@emulators/gitlab/package.json +++ b/packages/@emulators/gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/gitlab", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/google/package.json b/packages/@emulators/google/package.json index 35190361..bf3faceb 100644 --- a/packages/@emulators/google/package.json +++ b/packages/@emulators/google/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/google", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/mcp/package.json b/packages/@emulators/mcp/package.json index 04ea3439..10e93c2b 100644 --- a/packages/@emulators/mcp/package.json +++ b/packages/@emulators/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/mcp", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/microsoft/package.json b/packages/@emulators/microsoft/package.json index 8f3ec494..09e4aa8c 100644 --- a/packages/@emulators/microsoft/package.json +++ b/packages/@emulators/microsoft/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/microsoft", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/microsoft/src/routes/graph.ts b/packages/@emulators/microsoft/src/routes/graph.ts index 71ad9fbe..e352f86a 100644 --- a/packages/@emulators/microsoft/src/routes/graph.ts +++ b/packages/@emulators/microsoft/src/routes/graph.ts @@ -450,10 +450,7 @@ export function graphRoutes({ app, store, baseUrl }: RouteContext): void { id: event.graph_id, summary: `Created event '${event.subject}'`, }); - c.header( - "Location", - `${baseUrl}/v1.0/users('${user.email}')/events('${event.graph_id}')`, - ); + c.header("Location", `${baseUrl}/v1.0/users('${user.email}')/events('${event.graph_id}')`); return c.json( { "@odata.context": `${baseUrl}/v1.0/$metadata#users('${encodeURIComponent(user.email)}')/events/$entity`, @@ -472,7 +469,10 @@ export function graphRoutes({ app, store, baseUrl }: RouteContext): void { const eventId = c.req.param("id"); const event = findEvent(ms.events.findBy("user_email", user.email), eventId); if (!event) { - return malformedEventId(c, eventId) ?? graphError(c, 404, "ErrorItemNotFound", "The specified object was not found in the store."); + return ( + malformedEventId(c, eventId) ?? + graphError(c, 404, "ErrorItemNotFound", "The specified object was not found in the store.") + ); } const calendarRef = ms.calendars.findOneBy("graph_id", event.calendar_id); return c.json({ diff --git a/packages/@emulators/mongoatlas/package.json b/packages/@emulators/mongoatlas/package.json index 9f39de30..4684fd64 100644 --- a/packages/@emulators/mongoatlas/package.json +++ b/packages/@emulators/mongoatlas/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/mongoatlas", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/okta/package.json b/packages/@emulators/okta/package.json index c4ac3d1e..f132b0ea 100644 --- a/packages/@emulators/okta/package.json +++ b/packages/@emulators/okta/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/okta", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/posthog/package.json b/packages/@emulators/posthog/package.json index 2dbedc60..96318a54 100644 --- a/packages/@emulators/posthog/package.json +++ b/packages/@emulators/posthog/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/posthog", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/resend/package.json b/packages/@emulators/resend/package.json index 8df4c288..bcc14628 100644 --- a/packages/@emulators/resend/package.json +++ b/packages/@emulators/resend/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/resend", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/slack/package.json b/packages/@emulators/slack/package.json index c0be3052..5fb9180e 100644 --- a/packages/@emulators/slack/package.json +++ b/packages/@emulators/slack/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/slack", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/spotify/package.json b/packages/@emulators/spotify/package.json index 27499efc..6656049f 100644 --- a/packages/@emulators/spotify/package.json +++ b/packages/@emulators/spotify/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/spotify", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/stripe/package.json b/packages/@emulators/stripe/package.json index 3283d43a..0354f914 100644 --- a/packages/@emulators/stripe/package.json +++ b/packages/@emulators/stripe/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/stripe", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/vercel/package.json b/packages/@emulators/vercel/package.json index 2bf13b46..e036270d 100644 --- a/packages/@emulators/vercel/package.json +++ b/packages/@emulators/vercel/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/vercel", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/workos/package.json b/packages/@emulators/workos/package.json index a4ce4ebf..61c8a642 100644 --- a/packages/@emulators/workos/package.json +++ b/packages/@emulators/workos/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/workos", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/@emulators/workos/src/__tests__/workos.test.ts b/packages/@emulators/workos/src/__tests__/workos.test.ts index 2d316b03..b3b1f976 100644 --- a/packages/@emulators/workos/src/__tests__/workos.test.ts +++ b/packages/@emulators/workos/src/__tests__/workos.test.ts @@ -126,6 +126,14 @@ describe("workos emulator with the real @workos-inc/node SDK", () => { } }); + it("lists organization roles through the SDK's Authorization surface", async () => { + const org = await workos.organizations.createOrganization({ name: "Roles Org" }); + // The v10 SDK calls /authorization/organizations/:id/roles; the emulator + // must serve that path, not only the legacy /organizations/:id/roles. + const roles = await workos.authorization.listOrganizationRoles(org.id); + expect(roles.data.map((role) => role.slug).sort()).toEqual(["admin", "member"]); + }); + it("deletes an organization and cascades its memberships", async () => { const code = await signInAndGetCode("dana@example.com"); const auth = await workos.userManagement.authenticateWithCode({ @@ -203,9 +211,7 @@ describe("workos emulator with the real @workos-inc/node SDK", () => { const invitations = await workos.userManagement.listInvitations({ organizationId: org.id, }); - expect(invitations.data.find((candidate) => candidate.id === invitation.id)?.state).toBe( - "revoked", - ); + expect(invitations.data.find((candidate) => candidate.id === invitation.id)?.state).toBe("revoked"); }); it("round-trips vault objects through workos.vault", async () => { diff --git a/packages/@emulators/workos/src/routes/organizations.ts b/packages/@emulators/workos/src/routes/organizations.ts index d9545a73..003cce7e 100644 --- a/packages/@emulators/workos/src/routes/organizations.ts +++ b/packages/@emulators/workos/src/routes/organizations.ts @@ -1,4 +1,4 @@ -import type { RouteContext } from "@emulators/core"; +import type { Context, RouteContext } from "@emulators/core"; import { getWorkosStore } from "../store.js"; import { listEnvelope, serializeOrganization, workosError, workosId } from "../helpers.js"; @@ -47,7 +47,11 @@ export function organizationRoutes(ctx: RouteContext): void { return c.body(null, 204); }); - app.get("/organizations/:id/roles", (c) => { + // Organization roles. The legacy path is `/organizations/:id/roles`; the + // WorkOS Node SDK v10 (`authorization.listOrganizationRoles`) calls the + // Authorization-API path `/authorization/organizations/:id/roles`. Serve + // both from one handler so either SDK generation resolves. + const organizationRoles = (c: Context) => { const organization = ws().organizations.findOneBy("workos_id", c.req.param("id")); if (!organization) return workosError(c, 404, "entity_not_found", "Organization not found."); const now = new Date().toISOString(); @@ -64,7 +68,9 @@ export function organizationRoutes(ctx: RouteContext): void { updated_at: now, }); return c.json(listEnvelope([role("admin", "Admin"), role("member", "Member")])); - }); + }; + app.get("/organizations/:id/roles", organizationRoles); + app.get("/authorization/organizations/:id/roles", organizationRoles); // Domain-verification portal link (cloud's org routes call this). app.post("/portal/generate_link", async (c) => { diff --git a/packages/@emulators/x/package.json b/packages/@emulators/x/package.json index acb98f33..81575859 100644 --- a/packages/@emulators/x/package.json +++ b/packages/@emulators/x/package.json @@ -1,6 +1,6 @@ { "name": "@emulators/x", - "version": "0.13.4", + "version": "0.13.5", "license": "Apache-2.0", "type": "module", "main": "./dist/index.js", diff --git a/packages/emulate/package.json b/packages/emulate/package.json index ef9878fb..4a5feee5 100644 --- a/packages/emulate/package.json +++ b/packages/emulate/package.json @@ -1,6 +1,6 @@ { "name": "@executor-js/emulate", - "version": "0.13.4", + "version": "0.13.5", "description": "Local drop-in replacement services for CI and no-network sandboxes", "license": "Apache-2.0", "type": "module",