diff --git a/.changeset/gentle-otters-fold.md b/.changeset/gentle-otters-fold.md deleted file mode 100644 index 0e02d9b0..00000000 --- a/.changeset/gentle-otters-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@opensaas/stack-core': patch ---- - -Fix `needs` declarations being dropped beneath a caller-named relation that revisits a list (e.g. `include: { author: { include: { posts: true } } }`, or a self-referential `parent`), which left the revisited list's computed fields resolving over `undefined`. diff --git a/.changeset/one-hop-scopes-relations.md b/.changeset/one-hop-scopes-relations.md deleted file mode 100644 index 9263b3da..00000000 --- a/.changeset/one-hop-scopes-relations.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@opensaas/stack-core': minor ---- - -Naming a relation in an `include` now fetches only that relation's own columns and stops, at every level — not just the root. This completes ADR-0024 (a bare read fetches scalars, never relations): reaching a relation's own relations means naming them too, e.g. `include: { author: { include: { organization: true } } }` rather than relying on `include: { author: true }` to pull `organization` in automatically. A relation nobody named (caller `include`, fragment `query`, or a field's `needs`) never has its list's operation-level `query` access evaluated at all. - -**This is a silent break — detect it before you upgrade.** An `include` that named a relation bare and read past it (`item.[0].`) now gets `undefined` for the unnamed part, with no error. Grep your codebase for `include: {` calls whose consumers read a second hop off a bare-named relation, and add the deeper relation explicitly: - -```typescript -// Before: relied on `author` auto-expanding its own `organization` relation -const post = await context.db.post.findUnique({ - where: { id }, - include: { author: true }, -}) -post.author.organization // silently undefined now - -// After: name the relation you actually need -const post = await context.db.post.findUnique({ - where: { id }, - include: { author: { include: { organization: true } } }, -}) -post.author.organization // present -``` - -`AccessScopeDepthExceededError` (thrown when an `include` names a relation past `READ_INCLUDE_MAX_DEPTH`) keeps its type, fields, and throw sites — only its message wording changed, from describing an inability to scope to describing a cost refusal, since the depth cap is now a cost limit rather than a security boundary (nothing walks the relationship graph unprompted anymore). diff --git a/.changeset/silent-hooks-compute-once.md b/.changeset/silent-hooks-compute-once.md deleted file mode 100644 index 7a1904fd..00000000 --- a/.changeset/silent-hooks-compute-once.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -'@opensaas/stack-core': minor ---- - -A computed field — any field carrying a `resolveOutput` hook, virtual or not — is now computed if and only if a read is actually going to return it. A fragment `query` that selects three fields no longer runs every `resolveOutput` on the list and discards the rest: an unselected field's field-level read access is never evaluated and its hook never runs. Its declared relations (`needs`, ADR-0025) are fetched under exactly the same condition, folded recursively at every nesting level — a nested fragment selecting a subset computes only that subset, while a nested `include` still computes every computed field at that level, matching bare and `include`-based reads, which are unaffected: they still compute every computed field on the list, exactly as before. See ADR-0027. - -**This is a silent break — detect it before you upgrade, the same way ADR-0024's and ADR-0026's were.** Two independent behaviors changed with no thrown error: - -1. **A hook's `item` never carries another computed field's resolved output, on any read path.** Previously a virtual field received the already-assembled, already-resolved object, so a virtual field could read an _earlier-declared_ virtual (or any field carrying its own `resolveOutput`, e.g. a `password()`'s wrapper or a formatted display field) and see its resolved value — working only by declaration order, with reordering two fields silently changing the result. Now every computed field's hook sees only the row's stored columns and its own declared dependencies; reaching for a sibling that is itself computed finds nothing there (or its raw stored form, never the wrapped/resolved value), the same as reaching for a field that was never declared. **Grep your config for a `resolveOutput` whose `item` reads a field that is itself computed** — virtual fields reading other virtual fields, or a hook reading a stored field that carries its own `resolveOutput` (a password wrapper, a formatted date) — and recompute from the shared stored columns instead of relying on another field's hook having already run. -2. **A field's hook no longer runs just because it's on the list — only because a read selects it.** If you relied on a `resolveOutput` hook running for a side effect (logging, cache warming) on every read regardless of a fragment's own field selection, that side effect now only fires when the fragment actually names the field. **Grep for a fragment `query` that intentionally omits a field whose hook you were relying on for a side effect**, and select that field explicitly (or move the side effect to a hook that isn't projection-gated, e.g. `afterOperation`). - -A hookless virtual field (one with `access.read` but no `resolveOutput`) no longer has its read access evaluated at all on any read — such a field can never produce output, so under this rule it does no work at all. - -```typescript -// Before: `displayName` (declared after `fullNameCached`) could read the -// latter's resolved value purely because of declaration order. -User: list({ - fields: { - firstName: text(), - lastName: text(), - fullNameCached: virtual({ - type: 'string', - hooks: { resolveOutput: ({ item }) => `${item.firstName} ${item.lastName}` }, - }), - displayName: virtual({ - type: 'string', - // item.fullNameCached is now always undefined here — recompute from - // the shared stored columns instead. - hooks: { resolveOutput: ({ item }) => `${item.fullNameCached} (${item.firstName[0]}.)` }, - }), - }, -}) - -// After: compute from the stored columns both fields actually share. -displayName: virtual({ - type: 'string', - hooks: { - resolveOutput: ({ item }) => `${item.firstName} ${item.lastName} (${item.firstName[0]}.)`, - }, -}), -``` diff --git a/.changeset/tidy-otters-infer.md b/.changeset/tidy-otters-infer.md deleted file mode 100644 index d02a6100..00000000 --- a/.changeset/tidy-otters-infer.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@opensaas/stack-auth': minor ---- - -`buildBetterAuthOptions()` and `createAuth()` now accept an optional third argument — your app's `betterAuthPlugins` array, the same array passed to `authPlugin({ betterAuthPlugins })` — so the returned options/`Auth` type carries the literal plugin tuple instead of the widened `BetterAuthOptions`/`Auth`. Without this, `betterAuth()` constructed from the widened return loses plugin-derived `auth.api.*` endpoints (e.g. `emailOTP()`'s `signInEmailOTP`) and a `customSession()` plugin's replaced session shape. - -```typescript -export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins }) - -export const auth = betterAuth({ - ...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)), -}) -// auth.api.signInEmailOTP is now typed, and auth.api.getSession() returns your customSession() shape. -``` - -The supplied tuple is for typing only — the plugin array used at runtime is always the one resolved from `authPlugin({ betterAuthPlugins })`. Passing a tuple that isn't the same plugin instances in the same order throws, naming the mismatch, so the two can't silently drift apart. Calling either function with no third argument is unchanged — same widened return type, same runtime options, fully backwards compatible. - -Also, `AuthConfig`/`NormalizedAuthConfig`'s `betterAuthPlugins` field is now typed as better-auth's own `BetterAuthPlugin[]` instead of `any[]`. diff --git a/.changeset/warm-sessions-project.md b/.changeset/warm-sessions-project.md deleted file mode 100644 index 633ba4a1..00000000 --- a/.changeset/warm-sessions-project.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@opensaas/stack-auth': minor -'@opensaas/stack-cli': minor ---- - -Fix `getSessionFromAuth` to project `sessionFields` from the _resolved_ better-auth session instead of only its `user` sub-object. A `customSession` plugin's replaced shape with no `user` key is now correctly treated as a signed-in session (never misreported as anonymous), and a session-only field (e.g. the admin plugin's `impersonatedBy`) is now resolvable. Errors from the underlying session lookup now propagate instead of silently becoming `null`, and a `sessionFields` entry that can't be resolved is omitted and logs a warning (once per field, per process) instead of vanishing silently. - -The scaffolded `getSession()` — the CLI feature generator's `lib/auth.ts` template, and `examples/starter-auth`/`examples/auth-demo` — now call this single shared helper, reading `sessionFields` from the resolved config at runtime instead of baking a field list in at generation time. `examples/auth-demo`'s `getSession()` also now correctly returns `null` for an anonymous visitor (previously returned a truthy object of `undefined` values). - -```typescript -authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] }) -``` - -```typescript -// lib/auth.ts -export async function getSession() { - const resolvedConfig = await config - const authConfig = resolvedConfig._pluginData?.auth as NormalizedAuthConfig | undefined - const sessionFields = authConfig?.sessionFields ?? ['userId', 'email', 'name'] - return getSessionFromAuth(auth, sessionFields, await headers()) -} -``` diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 1371a413..e7c332e3 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,42 @@ # @opensaas/stack-auth +## 0.38.0 + +### Minor Changes + +- [#888](https://github.com/OpenSaasAU/stack/pull/888) [`8183827`](https://github.com/OpenSaasAU/stack/commit/8183827ec65d6cfd7153028f84057ab65dfdc7dd) Thanks [@borisno2](https://github.com/borisno2)! - `buildBetterAuthOptions()` and `createAuth()` now accept an optional third argument — your app's `betterAuthPlugins` array, the same array passed to `authPlugin({ betterAuthPlugins })` — so the returned options/`Auth` type carries the literal plugin tuple instead of the widened `BetterAuthOptions`/`Auth`. Without this, `betterAuth()` constructed from the widened return loses plugin-derived `auth.api.*` endpoints (e.g. `emailOTP()`'s `signInEmailOTP`) and a `customSession()` plugin's replaced session shape. + + ```typescript + export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins }) + + export const auth = betterAuth({ + ...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)), + }) + // auth.api.signInEmailOTP is now typed, and auth.api.getSession() returns your customSession() shape. + ``` + + The supplied tuple is for typing only — the plugin array used at runtime is always the one resolved from `authPlugin({ betterAuthPlugins })`. Passing a tuple that isn't the same plugin instances in the same order throws, naming the mismatch, so the two can't silently drift apart. Calling either function with no third argument is unchanged — same widened return type, same runtime options, fully backwards compatible. + + Also, `AuthConfig`/`NormalizedAuthConfig`'s `betterAuthPlugins` field is now typed as better-auth's own `BetterAuthPlugin[]` instead of `any[]`. + +- [#889](https://github.com/OpenSaasAU/stack/pull/889) [`b9b9357`](https://github.com/OpenSaasAU/stack/commit/b9b935719774b01a81cfd2082387b76806c1a484) Thanks [@borisno2](https://github.com/borisno2)! - Fix `getSessionFromAuth` to project `sessionFields` from the _resolved_ better-auth session instead of only its `user` sub-object. A `customSession` plugin's replaced shape with no `user` key is now correctly treated as a signed-in session (never misreported as anonymous), and a session-only field (e.g. the admin plugin's `impersonatedBy`) is now resolvable. Errors from the underlying session lookup now propagate instead of silently becoming `null`, and a `sessionFields` entry that can't be resolved is omitted and logs a warning (once per field, per process) instead of vanishing silently. + + The scaffolded `getSession()` — the CLI feature generator's `lib/auth.ts` template, and `examples/starter-auth`/`examples/auth-demo` — now call this single shared helper, reading `sessionFields` from the resolved config at runtime instead of baking a field list in at generation time. `examples/auth-demo`'s `getSession()` also now correctly returns `null` for an anonymous visitor (previously returned a truthy object of `undefined` values). + + ```typescript + authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] }) + ``` + + ```typescript + // lib/auth.ts + export async function getSession() { + const resolvedConfig = await config + const authConfig = resolvedConfig._pluginData?.auth as NormalizedAuthConfig | undefined + const sessionFields = authConfig?.sessionFields ?? ['userId', 'email', 'name'] + return getSessionFromAuth(auth, sessionFields, await headers()) + } + ``` + ## 0.37.0 ### Minor Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 4aa2457f..c99d5643 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-auth", - "version": "0.37.0", + "version": "0.38.0", "description": "Better-auth integration for OpenSaas Stack", "type": "module", "main": "./dist/index.js", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6d039130..f3d24152 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,32 @@ # @opensaas/stack-cli +## 0.38.0 + +### Minor Changes + +- [#889](https://github.com/OpenSaasAU/stack/pull/889) [`b9b9357`](https://github.com/OpenSaasAU/stack/commit/b9b935719774b01a81cfd2082387b76806c1a484) Thanks [@borisno2](https://github.com/borisno2)! - Fix `getSessionFromAuth` to project `sessionFields` from the _resolved_ better-auth session instead of only its `user` sub-object. A `customSession` plugin's replaced shape with no `user` key is now correctly treated as a signed-in session (never misreported as anonymous), and a session-only field (e.g. the admin plugin's `impersonatedBy`) is now resolvable. Errors from the underlying session lookup now propagate instead of silently becoming `null`, and a `sessionFields` entry that can't be resolved is omitted and logs a warning (once per field, per process) instead of vanishing silently. + + The scaffolded `getSession()` — the CLI feature generator's `lib/auth.ts` template, and `examples/starter-auth`/`examples/auth-demo` — now call this single shared helper, reading `sessionFields` from the resolved config at runtime instead of baking a field list in at generation time. `examples/auth-demo`'s `getSession()` also now correctly returns `null` for an anonymous visitor (previously returned a truthy object of `undefined` values). + + ```typescript + authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] }) + ``` + + ```typescript + // lib/auth.ts + export async function getSession() { + const resolvedConfig = await config + const authConfig = resolvedConfig._pluginData?.auth as NormalizedAuthConfig | undefined + const sessionFields = authConfig?.sessionFields ?? ['userId', 'email', 'name'] + return getSessionFromAuth(auth, sessionFields, await headers()) + } + ``` + +### Patch Changes + +- Updated dependencies [[`b21d8b2`](https://github.com/OpenSaasAU/stack/commit/b21d8b2af43f7a2a7ea10a89cfb39140a856bd68), [`b21d8b2`](https://github.com/OpenSaasAU/stack/commit/b21d8b2af43f7a2a7ea10a89cfb39140a856bd68), [`17eb72f`](https://github.com/OpenSaasAU/stack/commit/17eb72f0a9a4b7508e3f318da66bb8d4c6cbd705)]: + - @opensaas/stack-core@0.38.0 + ## 0.37.0 ### Minor Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 1e37e0b7..c7ea104a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-cli", - "version": "0.37.0", + "version": "0.38.0", "description": "CLI tools for OpenSaas Stack", "type": "module", "main": "./dist/index.js", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index dcabd934..e69c8149 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,73 @@ # @opensaas/stack-core +## 0.38.0 + +### Minor Changes + +- [#873](https://github.com/OpenSaasAU/stack/pull/873) [`b21d8b2`](https://github.com/OpenSaasAU/stack/commit/b21d8b2af43f7a2a7ea10a89cfb39140a856bd68) Thanks [@borisno2](https://github.com/borisno2)! - Naming a relation in an `include` now fetches only that relation's own columns and stops, at every level — not just the root. This completes ADR-0024 (a bare read fetches scalars, never relations): reaching a relation's own relations means naming them too, e.g. `include: { author: { include: { organization: true } } }` rather than relying on `include: { author: true }` to pull `organization` in automatically. A relation nobody named (caller `include`, fragment `query`, or a field's `needs`) never has its list's operation-level `query` access evaluated at all. + + **This is a silent break — detect it before you upgrade.** An `include` that named a relation bare and read past it (`item.[0].`) now gets `undefined` for the unnamed part, with no error. Grep your codebase for `include: {` calls whose consumers read a second hop off a bare-named relation, and add the deeper relation explicitly: + + ```typescript + // Before: relied on `author` auto-expanding its own `organization` relation + const post = await context.db.post.findUnique({ + where: { id }, + include: { author: true }, + }) + post.author.organization // silently undefined now + + // After: name the relation you actually need + const post = await context.db.post.findUnique({ + where: { id }, + include: { author: { include: { organization: true } } }, + }) + post.author.organization // present + ``` + + `AccessScopeDepthExceededError` (thrown when an `include` names a relation past `READ_INCLUDE_MAX_DEPTH`) keeps its type, fields, and throw sites — only its message wording changed, from describing an inability to scope to describing a cost refusal, since the depth cap is now a cost limit rather than a security boundary (nothing walks the relationship graph unprompted anymore). + +- [#890](https://github.com/OpenSaasAU/stack/pull/890) [`17eb72f`](https://github.com/OpenSaasAU/stack/commit/17eb72f0a9a4b7508e3f318da66bb8d4c6cbd705) Thanks [@list({](https://github.com/list({)! - A computed field — any field carrying a `resolveOutput` hook, virtual or not — is now computed if and only if a read is actually going to return it. A fragment `query` that selects three fields no longer runs every `resolveOutput` on the list and discards the rest: an unselected field's field-level read access is never evaluated and its hook never runs. Its declared relations (`needs`, ADR-0025) are fetched under exactly the same condition, folded recursively at every nesting level — a nested fragment selecting a subset computes only that subset, while a nested `include` still computes every computed field at that level, matching bare and `include`-based reads, which are unaffected: they still compute every computed field on the list, exactly as before. See ADR-0027. + + **This is a silent break — detect it before you upgrade, the same way ADR-0024's and ADR-0026's were.** Two independent behaviors changed with no thrown error: + + 1. **A hook's `item` never carries another computed field's resolved output, on any read path.** Previously a virtual field received the already-assembled, already-resolved object, so a virtual field could read an _earlier-declared_ virtual (or any field carrying its own `resolveOutput`, e.g. a `password()`'s wrapper or a formatted display field) and see its resolved value — working only by declaration order, with reordering two fields silently changing the result. Now every computed field's hook sees only the row's stored columns and its own declared dependencies; reaching for a sibling that is itself computed finds nothing there (or its raw stored form, never the wrapped/resolved value), the same as reaching for a field that was never declared. **Grep your config for a `resolveOutput` whose `item` reads a field that is itself computed** — virtual fields reading other virtual fields, or a hook reading a stored field that carries its own `resolveOutput` (a password wrapper, a formatted date) — and recompute from the shared stored columns instead of relying on another field's hook having already run. + 2. **A field's hook no longer runs just because it's on the list — only because a read selects it.** If you relied on a `resolveOutput` hook running for a side effect (logging, cache warming) on every read regardless of a fragment's own field selection, that side effect now only fires when the fragment actually names the field. **Grep for a fragment `query` that intentionally omits a field whose hook you were relying on for a side effect**, and select that field explicitly (or move the side effect to a hook that isn't projection-gated, e.g. `afterOperation`). + + A hookless virtual field (one with `access.read` but no `resolveOutput`) no longer has its read access evaluated at all on any read — such a field can never produce output, so under this rule it does no work at all. + + ```typescript + // Before: `displayName` (declared after `fullNameCached`) could read the + // latter's resolved value purely because of declaration order. + + fields: { + firstName: text(), + lastName: text(), + fullNameCached: virtual({ + type: 'string', + hooks: { resolveOutput: ({ item }) => `${item.firstName} ${item.lastName}` }, + }), + displayName: virtual({ + type: 'string', + // item.fullNameCached is now always undefined here — recompute from + // the shared stored columns instead. + hooks: { resolveOutput: ({ item }) => `${item.fullNameCached} (${item.firstName[0]}.)` }, + }), + }, + }) + + // After: compute from the stored columns both fields actually share. + displayName: virtual({ + type: 'string', + hooks: { + resolveOutput: ({ item }) => `${item.firstName} ${item.lastName} (${item.firstName[0]}.)`, + }, + }), + ``` + +### Patch Changes + +- [#873](https://github.com/OpenSaasAU/stack/pull/873) [`b21d8b2`](https://github.com/OpenSaasAU/stack/commit/b21d8b2af43f7a2a7ea10a89cfb39140a856bd68) Thanks [@borisno2](https://github.com/borisno2)! - Fix `needs` declarations being dropped beneath a caller-named relation that revisits a list (e.g. `include: { author: { include: { posts: true } } }`, or a self-referential `parent`), which left the revisited list's computed fields resolving over `undefined`. + ## 0.37.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 55256056..9c382164 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-core", - "version": "0.37.0", + "version": "0.38.0", "description": "Core stack for OpenSaas - schema definition, access control, and runtime utilities", "type": "module", "main": "./dist/index.js", diff --git a/packages/rag/CHANGELOG.md b/packages/rag/CHANGELOG.md index 8c8852af..d95d2c55 100644 --- a/packages/rag/CHANGELOG.md +++ b/packages/rag/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-rag +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/rag/package.json b/packages/rag/package.json index fb95bd35..30fe5009 100644 --- a/packages/rag/package.json +++ b/packages/rag/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-rag", - "version": "0.37.0", + "version": "0.38.0", "description": "RAG and AI embeddings integration for OpenSaas Stack", "type": "module", "main": "./dist/index.js", diff --git a/packages/storage-s3/CHANGELOG.md b/packages/storage-s3/CHANGELOG.md index efbbf4f6..e3ce88fb 100644 --- a/packages/storage-s3/CHANGELOG.md +++ b/packages/storage-s3/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-storage-s3 +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 4afe13a5..aa894b2e 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-storage-s3", - "version": "0.37.0", + "version": "0.38.0", "description": "AWS S3 storage provider for OpenSaas Stack file uploads", "type": "module", "exports": { diff --git a/packages/storage-vercel/CHANGELOG.md b/packages/storage-vercel/CHANGELOG.md index b458812a..2b806f7a 100644 --- a/packages/storage-vercel/CHANGELOG.md +++ b/packages/storage-vercel/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-storage-vercel +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/storage-vercel/package.json b/packages/storage-vercel/package.json index 28a46149..969fc820 100644 --- a/packages/storage-vercel/package.json +++ b/packages/storage-vercel/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-storage-vercel", - "version": "0.37.0", + "version": "0.38.0", "description": "Vercel Blob storage provider for OpenSaas Stack file uploads", "type": "module", "exports": { diff --git a/packages/storage/CHANGELOG.md b/packages/storage/CHANGELOG.md index f701c81a..c35113be 100644 --- a/packages/storage/CHANGELOG.md +++ b/packages/storage/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-storage +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/storage/package.json b/packages/storage/package.json index a5aa2c32..44035647 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-storage", - "version": "0.37.0", + "version": "0.38.0", "description": "File and image upload field types with pluggable storage providers for OpenSaas Stack", "type": "module", "exports": { diff --git a/packages/tiptap/CHANGELOG.md b/packages/tiptap/CHANGELOG.md index dc049e69..d450ace4 100644 --- a/packages/tiptap/CHANGELOG.md +++ b/packages/tiptap/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-tiptap +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/tiptap/package.json b/packages/tiptap/package.json index 581d3411..b5d27afb 100644 --- a/packages/tiptap/package.json +++ b/packages/tiptap/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-tiptap", - "version": "0.37.0", + "version": "0.38.0", "description": "Tiptap rich text editor integration for OpenSaas Stack", "type": "module", "main": "./dist/index.js", diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md index a56cd43b..e4125e5c 100644 --- a/packages/ui/CHANGELOG.md +++ b/packages/ui/CHANGELOG.md @@ -1,5 +1,7 @@ # @opensaas/stack-ui +## 0.38.0 + ## 0.37.0 ## 0.36.0 diff --git a/packages/ui/package.json b/packages/ui/package.json index 2fa8a1f7..8d68a5ab 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opensaas/stack-ui", - "version": "0.37.0", + "version": "0.38.0", "description": "Composable React UI components for OpenSaas Stack", "type": "module", "main": "./dist/index.js",