Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e08fb02
perf(trigger): cap concurrency on background DB tasks (#5231)
TheodoreSpeaks Jun 27, 2026
3c6c6b1
improvement(webhooks): add trigger-age instrumentation + guard env de…
waleedlatif1 Jun 27, 2026
6264cba
fix(connectors): harden Zendesk connector against SSRF (#5237)
waleedlatif1 Jun 27, 2026
845a627
perf(db): per-role Postgres connection-pool profiles (#5232)
TheodoreSpeaks Jun 27, 2026
b8a197b
fix(security): cap KB document download size to prevent memory-exhaus…
waleedlatif1 Jun 27, 2026
37962a0
fix(file-parsers): guard OOXML parsers against decompression-bomb mem…
waleedlatif1 Jun 27, 2026
0420fee
chore(data-drains): remove settings callout and unused InfoNote compo…
waleedlatif1 Jun 27, 2026
b2d43c1
fix(copilot): gate post-tool output writes behind write permission (#…
waleedlatif1 Jun 27, 2026
9b66b40
fix(mcp): pin public IP-literal server URLs to block SSRF redirect by…
waleedlatif1 Jun 27, 2026
ac95a27
fix(security): gate credential-set invitation listing to admins and d…
waleedlatif1 Jun 27, 2026
2554725
improvement(execution): stop rewriting execution snapshots on reuse +…
waleedlatif1 Jun 27, 2026
2686f04
perf(dev): SIM_DEV_MINIMAL_REGISTRY mode to slash local dev-server RA…
TheodoreSpeaks Jun 27, 2026
d493263
improvement(clickhouse): expand block templates and skills, normalize…
waleedlatif1 Jun 27, 2026
b8d0b4f
fix(sso): keep an exit affordance in edit mode when clean (#5247)
waleedlatif1 Jun 27, 2026
7a2103e
improvement(logs): move per-block progress markers to Redis to cut wr…
waleedlatif1 Jun 27, 2026
3e03f8c
fix(webhooks): cast json provider_config for atomic jsonb merge (#5249)
waleedlatif1 Jun 28, 2026
3766582
fix(webhooks): run inactive deployment-version cleanup inline on depl…
waleedlatif1 Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions .claude/commands/add-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,17 +600,20 @@ export const ServiceV2Block: BlockConfig = {

## Registering Blocks

After creating the block, remind the user to:
1. Import in `apps/sim/blocks/registry.ts`
2. Add to the `registry` object (alphabetically):
After creating the block, remind the user to register it in `apps/sim/blocks/registry-maps.ts` (the data maps live here; `registry.ts` holds only the accessor functions). Add the import and an entry to each map alphabetically:

```typescript
import { ServiceBlock } from '@/blocks/blocks/service'
import { ServiceBlock, ServiceBlockMeta } from '@/blocks/blocks/service'

export const registry: Record<string, BlockConfig> = {
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
// ... existing blocks ...
service: ServiceBlock,
}

export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
// ... existing metas ...
service: ServiceBlockMeta,
}
```

## Complete Example
Expand Down Expand Up @@ -840,7 +843,7 @@ Derive templates from the service's real use cases. Each prompt should name a co
- [ ] Tools.access lists all tool IDs (snake_case)
- [ ] Tools.config.tool returns correct tool ID (snake_case)
- [ ] Outputs match tool outputs
- [ ] Block registered in registry.ts
- [ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
- [ ] If icon missing: asked user to provide SVG
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`
Expand Down
18 changes: 13 additions & 5 deletions .claude/commands/add-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,17 +364,25 @@ export const tools: Record<string, ToolConfig> = {
}
```

### Block Registry (`apps/sim/blocks/registry.ts`)
### Block Registry (`apps/sim/blocks/registry-maps.ts`)

The data maps (`BLOCK_REGISTRY` + `BLOCK_META_REGISTRY`) live in `registry-maps.ts`; `registry.ts` holds only the accessor functions. Add the import and an entry to each map alphabetically:

```typescript
// Add import (alphabetically)
import { {Service}Block } from '@/blocks/blocks/{service}'
import { {Service}Block, {Service}BlockMeta } from '@/blocks/blocks/{service}'

// Add to registry (alphabetically)
export const registry: Record<string, BlockConfig> = {
// Add to the config map (alphabetically)
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
// ... existing blocks ...
{service}: {Service}Block,
}

// Add to the catalog-meta map (alphabetically)
export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
// ... existing metas ...
{service}: {Service}BlockMeta,
}
```

### Trigger Registry (`apps/sim/triggers/registry.ts`) - If triggers exist
Expand Down Expand Up @@ -443,7 +451,7 @@ If creating V2 versions (API-aligned outputs):
- [ ] Configured tools.access with all tool IDs
- [ ] Configured tools.config.tool selector
- [ ] Defined outputs matching tool outputs
- [ ] Registered block in `blocks/registry.ts`
- [ ] Registered block + meta in `blocks/registry-maps.ts` (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
- [ ] If triggers: set `triggers.enabled` and `triggers.available`
- [ ] If triggers: spread trigger subBlocks with `getTrigger()`
- [ ] Exported `{Service}BlockMeta` with at least 7 templates
Expand Down
4 changes: 2 additions & 2 deletions .claude/commands/validate-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Read **every** file for the integration — do not skip any:
apps/sim/tools/{service}/ # All tool files, types.ts, index.ts
apps/sim/blocks/blocks/{service}.ts # Block definition
apps/sim/tools/registry.ts # Tool registry entries for this service
apps/sim/blocks/registry.ts # Block registry entry for this service
apps/sim/blocks/registry-maps.ts # Block + meta registry entry (BLOCK_REGISTRY / BLOCK_META_REGISTRY)
apps/sim/components/icons.tsx # Icon definition
apps/sim/lib/auth/auth.ts # OAuth config — should use getCanonicalScopesForProvider()
apps/sim/lib/oauth/oauth.ts # OAuth provider config — single source of truth for scopes
Expand Down Expand Up @@ -190,7 +190,7 @@ For **each tool** in `tools.access`:
- [ ] `bgColor` uses the service's brand color hex
- [ ] `icon` references the correct icon component from `@/components/icons`
- [ ] `authMode` is set correctly (`AuthMode.OAuth` or `AuthMode.ApiKey`)
- [ ] Block is registered in `blocks/registry.ts` alphabetically
- [ ] Block + meta are registered in `blocks/registry-maps.ts` (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`) alphabetically

### BlockMeta
- [ ] `{Service}BlockMeta` is exported in the same file as the block
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/sim-integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The full authoring instructions — tool/block/icon/trigger scaffolding, SubBloc

## Hard rules (don't get these wrong)

- Tool IDs are `snake_case` (`service_action`). Register tools in `tools/registry.ts`, blocks in `blocks/registry.ts` (alphabetically), triggers in `triggers/registry.ts`.
- Tool IDs are `snake_case` (`service_action`). Register tools in `tools/registry.ts`, blocks in `blocks/registry-maps.ts` (the `BLOCK_REGISTRY` config map + `BLOCK_META_REGISTRY` catalog-meta map, alphabetically — `blocks/registry.ts` holds only the accessor functions), triggers in `triggers/registry.ts`.
- Type coercions (`Number()`, etc.) belong in `tools.config.params` (runs at execution, after variable resolution) — never in `tools.config.tool` (runs at serialization; coercing there destroys dynamic `<Block.output>` references).
- `canonicalParamId` must NOT match any subblock's `id`, must be unique per operation/condition context, and all subblocks in a canonical group must share the same `required` status. The `inputs` section and the params function reference canonical IDs, not raw subblock IDs.
- Blocks must also set the catalog/UI metadata fields `integrationType`, `tags`, `authMode`, `docsLink`, and export a `{Service}BlockMeta` — see the `/add-block` skill's BlockMeta section for details.
41 changes: 41 additions & 0 deletions .claude/rules/sim-settings-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,46 @@ Adding a new settings page:
Conditional items become array spreads: `...(canManage ? [{…}] : [])`. Never
hand-roll the `<DropdownMenu>` + `<MoreHorizontal>` trigger per page.

## Save / Discard + unsaved-changes guard

Any settings surface with editable state uses **one** shared stack — never
hand-roll a Save button, a Discard button, a `beforeunload`, or an "Unsaved
changes" modal:

- **`SaveDiscardActions`** (`…/components/save-discard-actions/save-discard-actions`)
— the canonical dirty-gated **Discard + Save** chip pair. Renders nothing when
`!dirty`; otherwise a fragment so it composes beside sibling chips (a detail
view's Delete / Remove override, a Share chip). Props: `dirty`, `saving`,
`onSave`, `onDiscard`, `saveDisabled?`, `saveLabel?`, `savingLabel?`. Put it in
the `SettingsPanel actions` slot (top-level pages) or the detail header bar.
- **`useSettingsUnsavedGuard({ isDirty })`** (`…/settings/hooks/use-settings-unsaved-guard`)
— syncs the page's local `isDirty` into the shared `useSettingsDirtyStore` (so
the sidebar's **section-switch** confirm + the centralized `beforeunload` both
apply for free) and returns `{ showUnsavedModal, setShowUnsavedModal, guardBack,
confirmDiscard }` for a detail view's **in-view back** chip.
- **Top-level pages** (whitelabeling, sso): call it **unassigned** —
`useSettingsUnsavedGuard({ isDirty: hasChanges })` — they only need the
store-sync; the sidebar/`beforeunload` do the rest.
- **Detail sub-views** (data-retention, access-control group-detail): route the
back chip through `onClick={() => guard.guardBack(closeFn)}` and render the
shared `<UnsavedChangesModal open={guard.showUnsavedModal}
onOpenChange={guard.setShowUnsavedModal} onDiscard={guard.confirmDiscard} />`
(from `@/app/workspace/[workspaceId]/components/credential-detail`). The
in-view header **Discard** chip (via `SaveDiscardActions onDiscard`) is a
*reset to original* — distinct from the back-confirm's discard, which leaves.
- **`useSettingsBeforeUnload`** is mounted **once** in the settings shell
(`settings/[section]/settings.tsx`) — never add a per-page `beforeunload`.
- **Dirty *computation* stays local** (shapes differ: field-compare vs
normalize+stringify) — only how dirty is *consumed* is shared. Derive it (a
`const`/`useMemo`), never store it in `useState`.
- **CRITICAL — rules of hooks:** call `useSettingsUnsavedGuard(...)`
**unconditionally, before every early-return gate** (entitlement / loading /
not-entitled `return <SettingsEmptyState>`). A hook placed after a gate is
skipped on gated renders and crashes.
- The route-based credential detail keeps its own `useUnsavedChangesGuard` (it
guards real `router.push` navigation + browser Back via a history sentinel);
it already shares `UnsavedChangesModal`, so copy stays unified.

## Detail sub-views (the one exception)

A drill-down view reached from a list row (selected MCP server, workflow MCP
Expand All @@ -119,5 +159,6 @@ A settings page is design-system-clean when:
- [ ] Header chips are in `actions`; a standalone search is in the `search` prop.
- [ ] Its `NavigationItem` has an accurate, consistent-length `description`.
- [ ] Detail sub-views and entitlement/loading gates keep their own chrome (intentional).
- [ ] If it has editable state: Save/Discard go through `SaveDiscardActions`, dirty is wired via `useSettingsUnsavedGuard` (called before any early-return gate), and there is **no** hand-rolled Save button / `beforeunload` / "Unsaved changes" modal.
- [ ] No business logic, handlers, or conditional rendering changed by the migration.
- [ ] `tsc`, `biome`, and the page's tests pass.
15 changes: 14 additions & 1 deletion .claude/skills/add-settings-page/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ Key paths:
bar, scroll region, content column, or title block. Put header buttons in
`actions`, a standalone search in `search={{ value, onChange, placeholder }}`,
and the page content as `children`. Modals go beside the panel inside a `<>`.
4. **Verify:** `cd apps/sim && bunx tsc --noEmit`; `bunx biome check --write <file>`.
4. **If the page has editable state**, wire the shared save/discard stack — put
`SaveDiscardActions` (dirty-gated Discard+Save chips) in `actions`, and call
`useSettingsUnsavedGuard({ isDirty })` **before any early-return gate**.
Detail sub-views additionally route the back chip through
`guard.guardBack(closeFn)` and render the shared `UnsavedChangesModal`. Never
hand-roll a Save button, a `beforeunload`, or an "Unsaved changes" modal —
they're centralized. See the "Save / Discard + unsaved-changes guard" section
in `.claude/rules/sim-settings-pages.md`.
5. **Verify:** `cd apps/sim && bunx tsc --noEmit`; `bunx biome check --write <file>`.

## Mode B — Audit existing settings pages

Expand All @@ -44,6 +52,11 @@ For each page component, confirm the checklist in `.claude/rules/sim-settings-pa
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/' 'apps/sim/ee/'`
3. Confirm each page imports `SettingsPanel` and that its `NavigationItem` has an
accurate `description` of consistent length with its peers.
- Editable pages: confirm Save/Discard go through `SaveDiscardActions` and
dirty is wired via `useSettingsUnsavedGuard` (called before early-return
gates) — flag any hand-rolled Save button, `beforeunload`, or unsaved modal.
`git grep -n "beforeunload" -- 'apps/sim/**/settings/' 'apps/sim/ee/'`
should only hit the centralized `use-settings-before-unload.ts`.
4. When migrating a page, change ONLY the structural shell→`SettingsPanel` swap:
move header chips to `actions`, the standalone search to `search`, delete the
`<h1>` title block, replace the three closing `</div>` (column/scroll/shell)
Expand Down
15 changes: 9 additions & 6 deletions .cursor/commands/add-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,17 +608,20 @@ export const ServiceV2Block: BlockConfig = {

## Registering Blocks

After creating the block, remind the user to:
1. Import in `apps/sim/blocks/registry.ts`
2. Add to the `registry` object (alphabetically):
After creating the block, remind the user to register it in `apps/sim/blocks/registry-maps.ts` (the data maps live here; `registry.ts` holds only the accessor functions). Add the import and an entry to each map alphabetically:

```typescript
import { ServiceBlock } from '@/blocks/blocks/service'
import { ServiceBlock, ServiceBlockMeta } from '@/blocks/blocks/service'

export const registry: Record<string, BlockConfig> = {
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
// ... existing blocks ...
service: ServiceBlock,
}

export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
// ... existing metas ...
service: ServiceBlockMeta,
}
```

## Complete Example
Expand Down Expand Up @@ -847,7 +850,7 @@ Derive templates from the service's real use cases. Each prompt should name a co
- [ ] Tools.access lists all tool IDs (snake_case)
- [ ] Tools.config.tool returns correct tool ID (snake_case)
- [ ] Outputs match tool outputs
- [ ] Block registered in registry.ts
- [ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
- [ ] If icon missing: asked user to provide SVG
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`
Expand Down
18 changes: 13 additions & 5 deletions .cursor/commands/add-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,25 @@ export const tools: Record<string, ToolConfig> = {
}
```

### Block Registry (`apps/sim/blocks/registry.ts`)
### Block Registry (`apps/sim/blocks/registry-maps.ts`)

The data maps (`BLOCK_REGISTRY` + `BLOCK_META_REGISTRY`) live in `registry-maps.ts`; `registry.ts` holds only the accessor functions. Add the import and an entry to each map alphabetically:

```typescript
// Add import (alphabetically)
import { {Service}Block } from '@/blocks/blocks/{service}'
import { {Service}Block, {Service}BlockMeta } from '@/blocks/blocks/{service}'

// Add to registry (alphabetically)
export const registry: Record<string, BlockConfig> = {
// Add to the config map (alphabetically)
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
// ... existing blocks ...
{service}: {Service}Block,
}

// Add to the catalog-meta map (alphabetically)
export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
// ... existing metas ...
{service}: {Service}BlockMeta,
}
```

### Trigger Registry (`apps/sim/triggers/registry.ts`) - If triggers exist
Expand Down Expand Up @@ -416,7 +424,7 @@ If creating V2 versions (API-aligned outputs):
- [ ] Configured tools.access with all tool IDs
- [ ] Configured tools.config.tool selector
- [ ] Defined outputs matching tool outputs
- [ ] Registered block in `blocks/registry.ts`
- [ ] Registered block + meta in `blocks/registry-maps.ts` (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
- [ ] If triggers: set `triggers.enabled` and `triggers.available`
- [ ] If triggers: spread trigger subBlocks with `getTrigger()`

Expand Down
4 changes: 2 additions & 2 deletions .cursor/commands/validate-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Read **every** file for the integration — do not skip any:
apps/sim/tools/{service}/ # All tool files, types.ts, index.ts
apps/sim/blocks/blocks/{service}.ts # Block definition
apps/sim/tools/registry.ts # Tool registry entries for this service
apps/sim/blocks/registry.ts # Block registry entry for this service
apps/sim/blocks/registry-maps.ts # Block + meta registry entry (BLOCK_REGISTRY / BLOCK_META_REGISTRY)
apps/sim/components/icons.tsx # Icon definition
apps/sim/lib/auth/auth.ts # OAuth config — should use getCanonicalScopesForProvider()
apps/sim/lib/oauth/oauth.ts # OAuth provider config — single source of truth for scopes
Expand Down Expand Up @@ -185,7 +185,7 @@ For **each tool** in `tools.access`:
- [ ] `bgColor` uses the service's brand color hex
- [ ] `icon` references the correct icon component from `@/components/icons`
- [ ] `authMode` is set correctly (`AuthMode.OAuth` or `AuthMode.ApiKey`)
- [ ] Block is registered in `blocks/registry.ts` alphabetically
- [ ] Block + meta are registered in `blocks/registry-maps.ts` (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`) alphabetically

### BlockMeta
- [ ] `{Service}BlockMeta` is exported in the same file as the block
Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/sim-integrations.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The full authoring instructions — tool/block/icon/trigger scaffolding, SubBloc

## Hard rules (don't get these wrong)

- Tool IDs are `snake_case` (`service_action`). Register tools in `tools/registry.ts`, blocks in `blocks/registry.ts` (alphabetically), triggers in `triggers/registry.ts`.
- Tool IDs are `snake_case` (`service_action`). Register tools in `tools/registry.ts`, blocks in `blocks/registry-maps.ts` (the `BLOCK_REGISTRY` config map + `BLOCK_META_REGISTRY` catalog-meta map, alphabetically — `blocks/registry.ts` holds only the accessor functions), triggers in `triggers/registry.ts`.
- Type coercions (`Number()`, etc.) belong in `tools.config.params` (runs at execution, after variable resolution) — never in `tools.config.tool` (runs at serialization; coercing there destroys dynamic `<Block.output>` references).
- `canonicalParamId` must NOT match any subblock's `id`, must be unique per operation/condition context, and all subblocks in a canonical group must share the same `required` status. The `inputs` section and the params function reference canonical IDs, not raw subblock IDs.
- Blocks must also set the catalog/UI metadata fields `integrationType`, `tags`, `authMode`, `docsLink`, and export a `{Service}BlockMeta` — see the `/add-block` skill's BlockMeta section for details.
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ New integrations are built in order: **Tools** → **Block** → **Icon** → (o

Two hard rules that the skills assume:

- **Tool IDs are `snake_case`** (`service_action`) and must be registered in `tools/registry.ts`; blocks register in `blocks/registry.ts` (alphabetically).
- **Tool IDs are `snake_case`** (`service_action`) and must be registered in `tools/registry.ts`; blocks register in `blocks/registry-maps.ts` — the `BLOCK_REGISTRY` config map and `BLOCK_META_REGISTRY` catalog-meta map (alphabetically). `blocks/registry.ts` holds only the accessor functions (`getBlock`, `getAllBlocks`, …).
- **`tools.config.tool` runs during serialization (before variable resolution)** — never do `Number()` or other type coercions there, or dynamic references like `<Block.output>` are destroyed. Put all type coercions in `tools.config.params`, which runs during execution after variables resolve.

For the full authoring instructions — SubBlock property tables, `condition`/`dependsOn`/`required`/`mode`/`canonicalParamId` syntax, required block metadata (`integrationType`, `tags`, `authMode`, `docsLink`, `{Service}BlockMeta`), file-input/`normalizeFileInput` patterns, and checklists — use the skills: `/add-integration` (end-to-end), `/add-tools`, `/add-block`, `/add-trigger`.
Expand Down
3 changes: 2 additions & 1 deletion apps/realtime/src/database/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ import { env } from '@/env'
const logger = createLogger('SocketDatabase')

const connectionString = env.DATABASE_URL
// Realtime process footprint = this socketDb pool + the shared @sim/db pool.
const socketDb = drizzle(
instrumentPoolClient(
postgres(connectionString, {
prepare: false,
idle_timeout: 10,
connect_timeout: 20,
max: 15,
max: 10,
onnotice: () => {},
connection: { application_name: process.env.DB_APP_NAME ?? 'sim-realtime' },
}),
Expand Down
1 change: 1 addition & 0 deletions apps/realtime/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const EnvSchema = z.object({
NEXT_PUBLIC_APP_URL: z.string().url(),
ALLOWED_ORIGINS: z.string().optional(),
PORT: z.coerce.number().int().positive().default(3002),
SIM_DB_ROLE: z.enum(['web', 'trigger', 'realtime']).optional(),
DISABLE_AUTH: z
.string()
.optional()
Expand Down
14 changes: 13 additions & 1 deletion apps/sim/app/api/credential-sets/[id]/invite/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,20 @@ export const GET = withRouteHandler(
return NextResponse.json({ error: 'Credential set not found' }, { status: 404 })
}

if (result.role !== 'admin' && result.role !== 'owner') {
return NextResponse.json({ error: 'Admin or owner permissions required' }, { status: 403 })
}

const invitations = await db
.select()
.select({
id: credentialSetInvitation.id,
credentialSetId: credentialSetInvitation.credentialSetId,
email: credentialSetInvitation.email,
status: credentialSetInvitation.status,
expiresAt: credentialSetInvitation.expiresAt,
createdAt: credentialSetInvitation.createdAt,
invitedBy: credentialSetInvitation.invitedBy,
})
.from(credentialSetInvitation)
.where(eq(credentialSetInvitation.credentialSetId, id))

Expand Down
Loading
Loading