diff --git a/.changeset/unlisted-records.md b/.changeset/unlisted-records.md deleted file mode 100644 index f5c1a43..0000000 --- a/.changeset/unlisted-records.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -'@haverstack/core': minor -'@haverstack/sqlite-shared': minor -'@haverstack/record-adapter-sqlite': minor -'@haverstack/adapter-local': minor -'@haverstack/wire-types': minor -'@haverstack/adapter-api': minor -'@haverstack/conformance-fixtures': minor ---- - -Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. - -`StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing -about who may read a record, only whether it is enumerable. A record with `unlistedAt` set -is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered -`query()` and the change feed by default — the same posture soft delete already has. - -- `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so - there is no window where it exists and is briefly enumerable. -- `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like - `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely - read one already found. -- `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or - subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but - the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but - ownership, so no grant or delegation carries it. -- The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted - emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record - is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like - `undelete`. Every other transition — created unlisted, an edit while already unlisted, a - purge of a record that was never listed — needs no special-casing, since it falls out of - checking the record's current state. - -See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted -transition. diff --git a/packages/adapter-api/CHANGELOG.md b/packages/adapter-api/CHANGELOG.md index b24f870..273990b 100644 --- a/packages/adapter-api/CHANGELOG.md +++ b/packages/adapter-api/CHANGELOG.md @@ -1,5 +1,40 @@ # @haverstack/adapter-api +## 0.14.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/core@0.15.0 + - @haverstack/wire-types@0.14.0 + ## 0.13.0 ### Minor Changes diff --git a/packages/adapter-api/package.json b/packages/adapter-api/package.json index 51aacdb..8258baf 100644 --- a/packages/adapter-api/package.json +++ b/packages/adapter-api/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/adapter-api", - "version": "0.13.0", + "version": "0.14.0", "description": "Remote server adapter for Haverstack", "type": "module", "exports": { diff --git a/packages/adapter-local/CHANGELOG.md b/packages/adapter-local/CHANGELOG.md index 3075961..ca893f7 100644 --- a/packages/adapter-local/CHANGELOG.md +++ b/packages/adapter-local/CHANGELOG.md @@ -1,5 +1,41 @@ # @haverstack/adapter-local +## 0.14.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/blob-adapter-disk@0.13.0 + - @haverstack/core@0.15.0 + - @haverstack/record-adapter-sqlite@0.7.0 + ## 0.13.0 ### Minor Changes diff --git a/packages/adapter-local/package.json b/packages/adapter-local/package.json index b3d93b3..289c4ef 100644 --- a/packages/adapter-local/package.json +++ b/packages/adapter-local/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/adapter-local", - "version": "0.13.0", + "version": "0.14.0", "description": "Local (SQLite + disk) stack adapter for Haverstack", "type": "module", "engines": { diff --git a/packages/blob-adapter-disk/CHANGELOG.md b/packages/blob-adapter-disk/CHANGELOG.md index f3bb56c..e318f89 100644 --- a/packages/blob-adapter-disk/CHANGELOG.md +++ b/packages/blob-adapter-disk/CHANGELOG.md @@ -1,5 +1,16 @@ # @haverstack/blob-adapter-disk +## 0.13.0 + +### Minor Changes + +- Released for a breaking change in `@haverstack/core`. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/core@0.15.0 + ## 0.12.0 ### Minor Changes diff --git a/packages/blob-adapter-disk/package.json b/packages/blob-adapter-disk/package.json index 0a560b2..922e043 100644 --- a/packages/blob-adapter-disk/package.json +++ b/packages/blob-adapter-disk/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/blob-adapter-disk", - "version": "0.12.0", + "version": "0.13.0", "description": "Disk blob adapter for Haverstack", "type": "module", "exports": { diff --git a/packages/commons/CHANGELOG.md b/packages/commons/CHANGELOG.md index 857eb06..bc80d73 100644 --- a/packages/commons/CHANGELOG.md +++ b/packages/commons/CHANGELOG.md @@ -1,5 +1,16 @@ # @haverstack/commons +## 0.7.0 + +### Minor Changes + +- Released for a breaking change in `@haverstack/core`. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/core@0.15.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/commons/package.json b/packages/commons/package.json index d571cce..3368be2 100644 --- a/packages/commons/package.json +++ b/packages/commons/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/commons", - "version": "0.6.0", + "version": "0.7.0", "description": "Canonical Schema Commons type definitions for Haverstack — register commons types exactly as written", "type": "module", "exports": { diff --git a/packages/conformance-fixtures/CHANGELOG.md b/packages/conformance-fixtures/CHANGELOG.md index 487bca1..8ed2093 100644 --- a/packages/conformance-fixtures/CHANGELOG.md +++ b/packages/conformance-fixtures/CHANGELOG.md @@ -1,5 +1,39 @@ # @haverstack/conformance-fixtures +## 0.8.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/wire-types@0.14.0 + ## 0.7.0 ### Minor Changes diff --git a/packages/conformance-fixtures/package.json b/packages/conformance-fixtures/package.json index 6ffe164..8d02072 100644 --- a/packages/conformance-fixtures/package.json +++ b/packages/conformance-fixtures/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/conformance-fixtures", - "version": "0.7.0", + "version": "0.8.0", "description": "Request/response fixtures for the Stack API wire protocol, shared between adapter-api and server implementations", "type": "module", "exports": { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index b0e70d4..cc25d46 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,34 @@ # @haverstack/core +## 0.15.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + ## 0.14.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 201c69a..9f6160f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/core", - "version": "0.14.0", + "version": "0.15.0", "description": "Core library for Haverstack — portable personal data stack", "type": "module", "exports": { diff --git a/packages/record-adapter-sqlite/CHANGELOG.md b/packages/record-adapter-sqlite/CHANGELOG.md index 06e63b6..915c9f9 100644 --- a/packages/record-adapter-sqlite/CHANGELOG.md +++ b/packages/record-adapter-sqlite/CHANGELOG.md @@ -1,5 +1,39 @@ # @haverstack/record-adapter-sqlite +## 0.7.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/core@0.15.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/record-adapter-sqlite/package.json b/packages/record-adapter-sqlite/package.json index 6ac5a11..61700ec 100644 --- a/packages/record-adapter-sqlite/package.json +++ b/packages/record-adapter-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/record-adapter-sqlite", - "version": "0.6.0", + "version": "0.7.0", "description": "Native SQLite (node:sqlite) record adapter for Haverstack — Node's built-in engine, no native compilation", "type": "module", "engines": { diff --git a/packages/wire-types/CHANGELOG.md b/packages/wire-types/CHANGELOG.md index 060468b..a55ea5d 100644 --- a/packages/wire-types/CHANGELOG.md +++ b/packages/wire-types/CHANGELOG.md @@ -1,5 +1,39 @@ # @haverstack/wire-types +## 0.14.0 + +### Minor Changes + +- [#209](https://github.com/haverstack/core/pull/209) [`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f) Thanks [@cuibonobo](https://github.com/cuibonobo)! - Add an `unlisted` state for records — reachable by ID, absent from enumeration by default. + + `StackRecord.unlistedAt` is a native field, orthogonal to `permissions`: it says nothing + about who may read a record, only whether it is enumerable. A record with `unlistedAt` set + is reachable by `get()` for anyone who may already read it, and excluded from an unfiltered + `query()` and the change feed by default — the same posture soft delete already has. + - `stack.create(typeId, content, { unlisted: true })` creates a record already unlisted, so + there is no window where it exists and is briefly enumerable. + - `stack.setUnlisted(id, unlisted)` toggles it on an existing record, gated exactly like + `setPermissions()` under `ScopedStack` — both decide who can discover a record, not merely + read one already found. + - `RecordFilter.includeUnlisted` and `SubscribeOptions.includeUnlisted` opt a query or + subscription back in. Unlike `includeDeleted`, `includeUnlisted` is refused to everyone but + the stack owner acting alone under `ScopedStack` — enumeration standing rests on nothing but + ownership, so no grant or delegation carries it. + - The change feed matches `query()`'s exclusion, with one exception: marking a record unlisted + emits a dedicated `unlist` op (kind `deleted`) so a subscriber that already knows the record + is told to drop it; relisting emits `list` (kind `changed`), an ordinary upsert like + `undelete`. Every other transition — created unlisted, an edit while already unlisted, a + purge of a record that was never listed — needs no special-casing, since it falls out of + checking the record's current state. + + See docs/spec/access-control.md § Unlisted records and docs/spec/events.md § The unlisted + transition. + +### Patch Changes + +- Updated dependencies [[`9edf5d0`](https://github.com/haverstack/core/commit/9edf5d02925fc6db3d829c21e23150abf15d8a8f)]: + - @haverstack/core@0.15.0 + ## 0.13.0 ### Minor Changes diff --git a/packages/wire-types/package.json b/packages/wire-types/package.json index 5ab1b8d..fd42aca 100644 --- a/packages/wire-types/package.json +++ b/packages/wire-types/package.json @@ -1,6 +1,6 @@ { "name": "@haverstack/wire-types", - "version": "0.13.0", + "version": "0.14.0", "description": "HTTP wire types and serialization for Haverstack", "type": "module", "exports": {