Skip to content

Commit ca3bbf1

Browse files
authored
v0.6.52: data retention, docs updates, slack manifest generator, security hardening, contact page, 404 page, access control, SES, SNS
2 parents 5f56e46 + c2529c3 commit ca3bbf1

1,025 files changed

Lines changed: 95394 additions & 29037 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/rules/global.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Global Standards
22

33
## Logging
4-
Import `createLogger` from `sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log`.
4+
Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log`. Inside API routes wrapped with `withRouteHandler`, loggers automatically include the request ID.
5+
6+
## API Route Handlers
7+
All API route handlers must be wrapped with `withRouteHandler` from `@/lib/core/utils/with-route-handler`. Never export a bare `async function GET/POST/...` — always use `export const METHOD = withRouteHandler(...)`.
58

69
## Comments
710
Use TSDoc for documentation. No `====` separators. No non-TSDoc comments.

.claude/rules/sim-testing.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,20 @@ it('reads a row', async () => {
217217
```
218218

219219
**Default chains supported:**
220-
- `select()/selectDistinct()/selectDistinctOn() → from() → where()/innerJoin()/leftJoin() → where() → limit()/orderBy()/returning()/groupBy()`
220+
- `select()/selectDistinct()/selectDistinctOn() → from() → where()/innerJoin()/leftJoin() → where() → limit()/orderBy()/returning()/groupBy()/for()`
221221
- `insert() → values() → returning()/onConflictDoUpdate()/onConflictDoNothing()`
222-
- `update() → set() → where() → limit()/orderBy()/returning()`
223-
- `delete() → where() → limit()/orderBy()/returning()`
222+
- `update() → set() → where() → limit()/orderBy()/returning()/for()`
223+
- `delete() → where() → limit()/orderBy()/returning()/for()`
224224
- `db.execute()` resolves `[]`
225225
- `db.transaction(cb)` calls cb with `dbChainMock.db`
226226

227+
`.for('update')` (Postgres row-level locking) is supported on `where`
228+
builders. It returns a thenable with `.limit` / `.orderBy` / `.returning` /
229+
`.groupBy` attached, so both `await .where().for('update')` (terminal) and
230+
`await .where().for('update').limit(1)` (chained) work. Override the terminal
231+
result with `dbChainMockFns.for.mockResolvedValueOnce([...])`; for the chained
232+
form, mock the downstream terminal (e.g. `dbChainMockFns.limit.mockResolvedValueOnce([...])`).
233+
227234
All terminals default to `Promise.resolve([])`. Override per-test with `dbChainMockFns.<terminal>.mockResolvedValueOnce(...)`.
228235

229236
Use `resetDbChainMock()` in `beforeEach` only when tests replace wiring with `.mockReturnValue` / `.mockResolvedValue` (permanent). Tests using only `...Once` variants don't need it.

CLAUDE.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ You are a professional software engineer. All code must follow best practices: a
44

55
## Global Standards
66

7-
- **Logging**: Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log`
7+
- **Logging**: Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log`. Inside API routes wrapped with `withRouteHandler`, loggers automatically include the request ID — no manual `withMetadata({ requestId })` needed
8+
- **API Route Handlers**: All API route handlers (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) must be wrapped with `withRouteHandler` from `@/lib/core/utils/with-route-handler`. This provides request ID tracking, automatic error logging for 4xx/5xx responses, and unhandled error catching. See "API Route Pattern" section below
89
- **Comments**: Use TSDoc for documentation. No `====` separators. No non-TSDoc comments
910
- **Styling**: Never update global styles. Keep all styling local to components
1011
- **ID Generation**: Never use `crypto.randomUUID()`, `nanoid`, or `uuid` package. Use `generateId()` (UUID v4) or `generateShortId()` (compact) from `@sim/utils/id`
@@ -93,6 +94,41 @@ export function Component({ requiredProp, optionalProp = false }: ComponentProps
9394

9495
Extract when: 50+ lines, used in 2+ files, or has own state/logic. Keep inline when: < 10 lines, single use, purely presentational.
9596

97+
## API Route Pattern
98+
99+
Every API route handler must be wrapped with `withRouteHandler`. This sets up `AsyncLocalStorage`-based request context so all loggers in the request lifecycle automatically include the request ID.
100+
101+
```typescript
102+
import { createLogger } from '@sim/logger'
103+
import type { NextRequest } from 'next/server'
104+
import { NextResponse } from 'next/server'
105+
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
106+
107+
const logger = createLogger('MyAPI')
108+
109+
// Simple route
110+
export const GET = withRouteHandler(async (request: NextRequest) => {
111+
logger.info('Handling request') // automatically includes {requestId=...}
112+
return NextResponse.json({ ok: true })
113+
})
114+
115+
// Route with params
116+
export const DELETE = withRouteHandler(async (
117+
request: NextRequest,
118+
{ params }: { params: Promise<{ id: string }> }
119+
) => {
120+
const { id } = await params
121+
return NextResponse.json({ deleted: id })
122+
})
123+
124+
// Composing with other middleware (withRouteHandler wraps the outermost layer)
125+
export const POST = withRouteHandler(withAdminAuth(async (request) => {
126+
return NextResponse.json({ ok: true })
127+
}))
128+
```
129+
130+
Never export a bare `async function GET/POST/...` — always use `export const METHOD = withRouteHandler(...)`.
131+
96132
## Hooks
97133

98134
```typescript

apps/docs/components/icons.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4681,6 +4681,17 @@ export function IAMIcon(props: SVGProps<SVGSVGElement>) {
46814681
)
46824682
}
46834683

4684+
export function IdentityCenterIcon(props: SVGProps<SVGSVGElement>) {
4685+
return (
4686+
<svg {...props} viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'>
4687+
<path
4688+
d='M13.694,14.8194562 C14.376,14.1374562 14.376,13.0294562 13.694,12.3474562 C13.353,12.0074562 12.906,11.8374562 12.459,11.8374562 C12.01,11.8374562 11.563,12.0074562 11.222,12.3474562 C10.542,13.0284562 10.542,14.1384562 11.222,14.8194562 C11.905,15.5014562 13.013,15.4994562 13.694,14.8194562 M14.718,15.1374562 L18.703,19.1204562 L17.996,19.8274562 L16.868,18.6994562 L15.793,19.7754562 L15.086,19.0684562 L16.161,17.9924562 L14.011,15.8444562 C13.545,16.1654562 13.003,16.3294562 12.458,16.3294562 C11.755,16.3294562 11.051,16.0624562 10.515,15.5264562 C9.445,14.4554562 9.445,12.7124562 10.515,11.6404562 C11.586,10.5714562 13.329,10.5694562 14.401,11.6404562 C15.351,12.5904562 15.455,14.0674562 14.718,15.1374562 M20,12.1014562 C20,14.1684562 18.505,15.0934562 17.023,15.0934562 L17.023,14.0934562 C17.487,14.0934562 19,13.9494562 19,12.1014562 C19,11.0044562 18.353,10.3894562 16.905,10.1084562 C16.68,10.0654562 16.514,9.87545615 16.501,9.64845615 C16.446,8.74445615 15.987,8.11245615 15.384,8.11245615 C15.084,8.11245615 14.854,8.24245615 14.616,8.54645615 C14.506,8.68845615 14.324,8.75945615 14.147,8.73245615 C13.968,8.70545615 13.818,8.58445615 13.755,8.41445615 C13.577,7.94345615 13.211,7.43345615 12.723,6.97745615 C12.231,6.50945615 10.883,5.50745615 8.972,6.27345615 C7.885,6.70545615 7.034,7.94945615 7.034,9.10745615 C7.034,9.23545615 7.043,9.36245615 7.058,9.48845615 C7.061,9.50945615 7.062,9.53045615 7.062,9.55145615 C7.062,9.79945615 6.882,10.0064562 6.645,10.0464562 C5.886,10.2394562 5,10.7454562 5,12.0554562 L5.005,12.2104562 C5.069,13.3254562 6.252,13.9954562 7.358,13.9984562 L8,13.9984562 L8,14.9984562 L7.357,14.9984562 C5.536,14.9944562 4.095,13.8194562 4.006,12.2644562 C4.003,12.1944562 4,12.1244562 4,12.0554562 C4,10.6944562 4.752,9.64845615 6.035,9.18845615 C6.034,9.16145615 6.034,9.13445615 6.034,9.10745615 C6.034,7.54345615 7.138,5.92545615 8.602,5.34345615 C10.298,4.66545615 12.095,5.00345615 13.409,6.24945615 C13.706,6.52745615 14.076,6.92645615 14.372,7.41345615 C14.673,7.21245615 15.008,7.11245615 15.384,7.11245615 C16.257,7.11245615 17.231,7.77145615 17.458,9.20745615 C19.145,9.63245615 20,10.6054562 20,12.1014562'
4689+
fill='#FFFFFF'
4690+
/>
4691+
</svg>
4692+
)
4693+
}
4694+
46844695
export function STSIcon(props: SVGProps<SVGSVGElement>) {
46854696
return (
46864697
<svg {...props} viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'>
@@ -4699,6 +4710,24 @@ export function STSIcon(props: SVGProps<SVGSVGElement>) {
46994710
)
47004711
}
47014712

4713+
export function SESIcon(props: SVGProps<SVGSVGElement>) {
4714+
return (
4715+
<svg {...props} viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'>
4716+
<defs>
4717+
<linearGradient x1='0%' y1='100%' x2='100%' y2='0%' id='sesGradient'>
4718+
<stop stopColor='#BD0816' offset='0%' />
4719+
<stop stopColor='#FF5252' offset='100%' />
4720+
</linearGradient>
4721+
</defs>
4722+
<rect fill='url(#sesGradient)' width='80' height='80' />
4723+
<path
4724+
d='M57,60.999875 C57,59.373846 55.626,57.9998214 54,57.9998214 C52.374,57.9998214 51,59.373846 51,60.999875 C51,62.625904 52.374,63.9999286 54,63.9999286 C55.626,63.9999286 57,62.625904 57,60.999875 L57,60.999875 Z M40,59.9998571 C38.374,59.9998571 37,61.3738817 37,62.9999107 C37,64.6259397 38.374,65.9999643 40,65.9999643 C41.626,65.9999643 43,64.6259397 43,62.9999107 C43,61.3738817 41.626,59.9998571 40,59.9998571 L40,59.9998571 Z M26,57.9998214 C24.374,57.9998214 23,59.373846 23,60.999875 C23,62.625904 24.374,63.9999286 26,63.9999286 C27.626,63.9999286 29,62.625904 29,60.999875 C29,59.373846 27.626,57.9998214 26,57.9998214 L26,57.9998214 Z M28.605,42.9995536 L51.395,42.9995536 L43.739,36.1104305 L40.649,38.7584778 C40.463,38.9194807 40.23,38.9994821 39.999,38.9994821 C39.768,38.9994821 39.535,38.9194807 39.349,38.7584778 L36.26,36.1104305 L28.605,42.9995536 Z M27,28.1732888 L27,41.7545313 L34.729,34.7984071 L27,28.1732888 Z M51.297,26.9992678 L28.703,26.9992678 L39.999,36.6824408 L51.297,26.9992678 Z M53,41.7545313 L53,28.1732888 L45.271,34.7974071 L53,41.7545313 Z M59,60.999875 C59,63.7099234 56.71,65.9999643 54,65.9999643 C51.29,65.9999643 49,63.7099234 49,60.999875 C49,58.6308327 50.75,56.5837961 53,56.1057876 L53,52.9997321 L41,52.9997321 L41,58.1058233 C43.25,58.5838319 45,60.6308684 45,62.9999107 C45,65.7099591 42.71,68 40,68 C37.29,68 35,65.7099591 35,62.9999107 C35,60.6308684 36.75,58.5838319 39,58.1058233 L39,52.9997321 L27,52.9997321 L27,56.1057876 C29.25,56.5837961 31,58.6308327 31,60.999875 C31,63.7099234 28.71,65.9999643 26,65.9999643 C23.29,65.9999643 21,63.7099234 21,60.999875 C21,58.6308327 22.75,56.5837961 25,56.1057876 L25,51.9997143 C25,51.4477044 25.447,50.9996964 26,50.9996964 L39,50.9996964 L39,44.9995893 L26,44.9995893 C25.447,44.9995893 25,44.5515813 25,43.9995714 L25,25.99925 C25,25.4472401 25.447,24.9992321 26,24.9992321 L54,24.9992321 C54.553,24.9992321 55,25.4472401 55,25.99925 L55,43.9995714 C55,44.5515813 54.553,44.9995893 54,44.9995893 L41,44.9995893 L41,50.9996964 L54,50.9996964 C54.553,50.9996964 55,51.4477044 55,51.9997143 L55,56.1057876 C57.25,56.5837961 59,58.6308327 59,60.999875 L59,60.999875 Z M68,39.9995 C68,45.9066055 66.177,51.5597064 62.727,56.3447919 L61.104,55.174771 C64.307,50.7316916 66,45.4845979 66,39.9995 C66,25.664244 54.337,14.0000357 40.001,14.0000357 C25.664,14.0000357 14,25.664244 14,39.9995 C14,45.4845979 15.693,50.7316916 18.896,55.174771 L17.273,56.3447919 C13.823,51.5597064 12,45.9066055 12,39.9995 C12,24.5612243 24.561,12 39.999,12 C55.438,12 68,24.5612243 68,39.9995 L68,39.9995 Z'
4725+
fill='#FFFFFF'
4726+
/>
4727+
</svg>
4728+
)
4729+
}
4730+
47024731
export function SecretsManagerIcon(props: SVGProps<SVGSVGElement>) {
47034732
return (
47044733
<svg {...props} viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'>

apps/docs/components/ui/icon-mapping.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import {
9191
HuggingFaceIcon,
9292
HunterIOIcon,
9393
IAMIcon,
94+
IdentityCenterIcon,
9495
ImageIcon,
9596
IncidentioIcon,
9697
InfisicalIcon,
@@ -152,6 +153,7 @@ import {
152153
RootlyIcon,
153154
S3Icon,
154155
SalesforceIcon,
156+
SESIcon,
155157
SearchIcon,
156158
SecretsManagerIcon,
157159
SendgridIcon,
@@ -294,6 +296,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
294296
huggingface: HuggingFaceIcon,
295297
hunter: HunterIOIcon,
296298
iam: IAMIcon,
299+
identity_center: IdentityCenterIcon,
297300
image_generator: ImageIcon,
298301
imap: MailServerIcon,
299302
incidentio: IncidentioIcon,
@@ -370,6 +373,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
370373
sentry: SentryIcon,
371374
serper: SerperIcon,
372375
servicenow: ServiceNowIcon,
376+
ses: SESIcon,
373377
sftp: SftpIcon,
374378
sharepoint: MicrosoftSharepointIcon,
375379
shopify: ShopifyIcon,

0 commit comments

Comments
 (0)