Releases: OpenSaasAU/stack
Release list
@opensaas/stack-ui@0.26.0
@opensaas/stack-ui@0.26.0
@opensaas/stack-tiptap@0.26.0
@opensaas/stack-tiptap@0.26.0
@opensaas/stack-storage@0.26.0
@opensaas/stack-storage-vercel@0.26.0
@opensaas/stack-storage-vercel@0.26.0
@opensaas/stack-storage-s3@0.26.0
@opensaas/stack-storage-s3@0.26.0
@opensaas/stack-rag@0.26.0
@opensaas/stack-rag@0.26.0
@opensaas/stack-core@0.26.0
Minor Changes
-
#616
322d5b6Thanks @borisno2! - Addcontext.transaction()— an interactive, hook-firing transactionYou can now run multiple access-checked
context.db.*operations atomically in one transaction while preserving the access/hook boundary (unlike rawprisma.$transaction, which bypasses both). The callback receives a full context whosedb.*operations enforce access control and run list/field hooks, but persist against a single interactive transaction — so a throw anywhere rolls the whole transaction back.Options (notably
isolationLevel, plusmaxWait/timeout) pass through to Prisma, and serialization failures (PrismaP2034) propagate to the caller so you own the retry loop. This makes concurrency-sensitive invariants such as a capacity gate enforceable:async function bookSlot(context, slotId) { for (let attempt = 0; attempt < 5; attempt++) { try { return await context.transaction( async (tx) => { const count = await tx.db.booking.count({ where: { slotId } }) if (count >= CAPACITY) return { booked: false } return { booked: true, item: await tx.db.booking.create({ data: { slotId } }) } }, { isolationLevel: 'Serializable' }, ) } catch (err) { // Serialization failures propagate — retry is caller-owned. if (err && typeof err === 'object' && 'code' in err && err.code === 'P2034') continue throw err } } throw new Error('exceeded retry budget') }
Nested
context.dbwrites inside the callback join the outer transaction. NewStackContext,TransactionOptions, andTransactionIsolationLeveltypes are exported from@opensaas/stack-core. See ADR-0012.
Patch Changes
-
#620
0be254eThanks @borisno2! - Apply a field's defaultValue to omitted inputs before create validation (resolve-then-validate, matching Keystone), so isRequired + defaultValue no longer fails on create.Note: because an omitted-but-defaulted field is now filled into
resolvedDatabefore validation, that field's create-side field-levelbeforeOperation/afterOperationhooks (gated on the field key being present inresolvedData) now fire for defaulted fields where they previously would not.
@opensaas/stack-cli@0.26.0
@opensaas/stack-auth@0.26.0
@opensaas/stack-auth@0.26.0
@opensaas/stack-ui@0.25.0
Patch Changes
-
#607
61547beThanks @borisno2! - Fixui.listView.initialSortapplying sort client-side instead of as a DB-levelorderByPreviously,
initialSortwas applied to the already-fetched page in memory, meaning a 500-row list withinitialSort: { field: 'sentAt', direction: 'desc' }would only show the 50 most recent rows of the current page rather than the 50 most recent rows overall. The sort is now passed asorderBytofindManyso pagination and sorting compose correctly.Column-header clicks also now navigate with a
?sort=field:directionURL param (instead of mutating local state), so subsequent sorts are also DB-level and work correctly across pages.