@drakkar.software/octospaces-sdk 0.1.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,200 @@
1
+ # Changelog — @drakkar.software/octospaces-sdk
2
+
3
+ ## 0.4.1 (2026-06-12)
4
+
5
+ ### Breaking changes
6
+
7
+ - **Space-wide keyring restored.** `nodeKeyringName`, `nodeKeyringPull`, `nodeKeyringPush`
8
+ are removed. Replaced by `keyringName`, `keyringPull`, `keyringPush` (one keyring per
9
+ space, at `spaces/{spaceId}/_keyring`, collection `spacekeyring`).
10
+ - **`nodeMemberScope` no longer includes `'nodekeyring'`** — collections is now
11
+ `['objinv']` only. Use `spaceMemberScope` when the bearer also needs to decrypt enc
12
+ content (they need `spacekeyring` + `spaces/{spaceId}/**` path).
13
+ - **`OBJECT_COLLECTIONS` updated**: `'nodekeyring'` → `'spacekeyring'`.
14
+
15
+ ### Added
16
+
17
+ - **`keyringName(spaceId)`** — base path for `addCollectionRecipient` calls.
18
+ - **`keyringPull(spaceId)` / `keyringPush(spaceId)`** — pull/push paths for the
19
+ space-wide keyring at `spaces/{spaceId}/_keyring`.
20
+ - **`addDeviceToSpaceKeyring(session, spaceId, device)`** — add a paired device's KEM
21
+ key to a space's keyring. Call after device pairing for each space the new device
22
+ should decrypt. ONE call per space unlocks all `enc` nodes.
23
+
24
+ ### Changed
25
+
26
+ - **`inviteToSpace`** now adds the invitee to the space-wide keyring (if it exists) so
27
+ they can decrypt `enc` nodes from the start. Silently skips if the keyring doesn't
28
+ exist yet (no enc nodes in the space).
29
+ - **`createSpaceInviteLink`** adds the ephemeral KEM to the space keyring (if it exists).
30
+ - **`inviteToNode(enc=true)`** adds the invitee to the SPACE keyring (not a per-node
31
+ keyring) — granting decryption access to ALL enc nodes in the space.
32
+ - **`createNodeInviteLink(enc=true)`** uses `spaceMemberScope` for the cap (so the bearer
33
+ can reach the space keyring) and adds the ephemeral KEM to the space keyring.
34
+ - **`getNodeAccess`** / **`buildNodeAccess`** open the SPACE keyring (not a per-node
35
+ keyring) when `node.enc` is true.
36
+ - **`startDevicePairing`** comment updated — post-pairing call `addDeviceToSpaceKeyring`
37
+ rather than `inviteToNode` per enc node.
38
+
39
+ ### Semantic note
40
+
41
+ The space keyring is coarse-grained: any keyring-holder with reach can decrypt ALL
42
+ `enc` nodes in the space. Inviting someone to one `enc` node grants them the space key
43
+ and thus access to all enc content. Per-node E2EE isolation requires per-node keyrings
44
+ (which are opt-in at the app level; the shared SDK no longer manages them).
45
+
46
+ ---
47
+
48
+ ## 0.4.0 (2026-06-12)
49
+
50
+ ### Breaking changes
51
+
52
+ - **`SpaceVisibility` removed.** The type `'private' | 'public'` no longer exists; spaces
53
+ are neutral containers. Visibility/encryption move to the node level (see below).
54
+ - **Space-level keyring removed.** `keyringName`, `keyringPull`, `keyringPush` are gone.
55
+ There is no per-space CEK. Encryption is per-node.
56
+ - **`addDeviceToSpaceKeyring` removed.** Pairing no longer auto-grants a linked device
57
+ access to E2EE nodes — the owner must call `inviteToNode` per node after pairing.
58
+ - **`getSpaceAccess` / `buildSpaceAccess` / `clearSpaceAccessCache` / `SpaceAccessHandle`
59
+ removed.** Replaced by `getNodeAccess` / `buildNodeAccess` / `clearNodeAccessCache` /
60
+ `NodeAccessHandle`.
61
+ - **`spaceIndexName` / `spaceIndexPull` removed.** Replaced by `objectDirName` /
62
+ `objectDirPull` (target `_index/objects/{shard}`).
63
+ - **`createSpace(session, name, opts?)` — `opts` removed.** Spaces no longer have a
64
+ `visibility` or `type`/`subtype`; call is now `createSpace(session, name)`.
65
+ - **`Space.visibility`, `Space.ownerId`, `Space.write` removed.** `Space` interface now
66
+ carries only `{ id, name, short, image?, members, unread? }`.
67
+ - **`SpaceMeta.type` / `SpaceMeta.subtype` removed.**
68
+ - **`joinSpaceByLink` no longer sets `visibility`/`ownerId`/`write` on the returned Space.**
69
+ - **`acceptSpaceInvite` no longer requires `cap.iss`.** Keyring verification is gone.
70
+
71
+ ### Added
72
+
73
+ - **`NodeAccess = 'public' | 'space' | 'invite'`** — per-node access axis. Absent ⇒ `'space'`.
74
+ - **`ObjectNode.access?: NodeAccess`** and **`ObjectNode.enc?: boolean`** — two orthogonal
75
+ axes. The invalid combo `public+enc` is rejected at `createNode`/`setNodeAccess`.
76
+ - **Per-node keyrings**: `nodeKeyringName/Pull/Push(spaceId, nodeId)` at
77
+ `spaces/{spaceId}/objects/n/{nodeId}/_keyring` (collection `nodekeyring`).
78
+ - **Public node content**: `objPubName/Pull/Push(spaceId, nodeId)` at
79
+ `spaces/{spaceId}/objects/pub/{nodeId}` (collection `objpub`, `readRoles:['public']`).
80
+ - **Invite-only plaintext content**: `objInvName/Pull/Push(spaceId, nodeId)` at
81
+ `spaces/{spaceId}/objects/n/{nodeId}/content` (collection `objinv`, excluded from
82
+ `spaceMemberScope`).
83
+ - **Global object directory**: `objectDirName/Pull(shard?)` → `_index/objects/{shard}`.
84
+ - **`nodeMemberScope(spaceId, nodeId, canWrite)`** — narrow per-node cap covering
85
+ `['nodekeyring', 'objinv']`. Only this scope reaches invite-plaintext content.
86
+ - **`OBJECT_COLLECTIONS`** updated: `spacekeyring` → `nodekeyring`; `objpub` added;
87
+ `objinv` intentionally absent (excluded from broad scope by design).
88
+ - **`getSpaceClient(spaceId, session)`** — returns the member-gated client for index/access
89
+ docs; always plaintext.
90
+ - **`getNodeAccess(spaceId, nodeId, node, session, reg?)`** — resolves `{ encryptor, client,
91
+ isOwnerOpen }` for a specific node's content.
92
+ - **`buildNodeAccess(session, spaceId, nodeId, node)`** — soft variant (returns null instead
93
+ of throwing on missing access).
94
+ - **`clearNodeAccessCache()`** — drop cached handles on account switch.
95
+ - **`getNodeAccessEntry / saveNodeAccessEntry / removeNodeAccessEntry`** — per-node entries
96
+ in the unified space-access store (composite key `${spaceId}:${nodeId}`).
97
+ - **`readObjectTree(session, spaceId)`** — read-only pull of a space's node list.
98
+ - **`spaces/nodes.ts`** — new module:
99
+ - `createNode(session, spaceId, input, reg?)` — creates a node; mints per-node keyring
100
+ for `enc` nodes.
101
+ - `setNodeAccess(session, spaceId, nodeId, patch, reg?)` — flips `access`/`enc` flags.
102
+ - `inviteToNode(session, spaceId, nodeId, requestJson, node, nodeName?)` — owner-side
103
+ direct invite; adds to keyring (`enc`) or mints narrow cap (`invite+plaintext`).
104
+ - `acceptNodeInvite(session, bundleJson)` — invitee stores per-node access.
105
+ - `createNodeInviteLink(…)` — shareable link invite for a specific node.
106
+ - `joinNodeByLink(session, token)` — bearer stores per-node link entry.
107
+ - **`NewObjectInput.access?` / `NewObjectInput.enc?`** — `addObject` passes these through
108
+ to the node; `patchObject` now accepts them in its patch type.
109
+ - **`pushIndexSeed` API simplified**: `pushIndexSeed(client, spaceId, nodes?)` — no
110
+ encryptor argument (index is always plaintext).
111
+
112
+ ### Changed
113
+
114
+ - Object index is **always plaintext**. `invite` node entries have `title` / `emoji`
115
+ stripped before storage (non-invited members see a placeholder row only).
116
+ - **`inviteToSpace`** no longer adds the invitee to a space keyring (there is none).
117
+ - **`acceptSpaceInvite`** no longer verifies keyring access.
118
+ - **`startDevicePairing`** no longer auto-grants linked devices to space keyrings.
119
+
120
+ ---
121
+
122
+ ## 0.3.0 (2026-06-12)
123
+
124
+ ### Added
125
+
126
+ - **`Space.type` / `Space.subtype`** — optional opaque string fields on the `Space` interface.
127
+ App-owned; no builtins defined in the SDK (`'chat'`, `'vault'`, `'chat-only'`, etc. are yours
128
+ to declare).
129
+ - **`SpaceMeta.type` / `SpaceMeta.subtype`** — same fields added to the write-side meta struct.
130
+ - **`writeSpaceAccess`** now persists `type` / `subtype` when truthy; `readSpaceAccess` reads them
131
+ back (string | null). Both are threaded through `addSpaceMember` / `removeSpaceMember` so roster
132
+ edits no longer drop them.
133
+ - **`createSpace`** accepts `opts.type` / `opts.subtype`; both are stored in `_access` and
134
+ mirrored on the returned `Space` object.
135
+ - **`spaceIndexName` exported** from the barrel (`src/index.ts`). `spaceIndexPull` / `spaceIndexName`
136
+ signatures generalised from `(shard: 'public')` to `(shard?: string)` — default `'public'`
137
+ keeps existing call sites unchanged. Clients read a typed catalog via `spaceIndexPull('chat')`.
138
+
139
+ ### Notes
140
+
141
+ `type` / `subtype` may be set on private spaces (stored in the member-gated `_access` doc, not
142
+ publicly visible). Only public spaces reach the world-readable directory; the server projection
143
+ shards on `type`. Treat `type` as set-at-create — changing it after the fact leaves a stale row
144
+ in the old shard (same caveat as public → private flips today).
145
+
146
+ ---
147
+
148
+ ## 0.2.0 (2026-06-12)
149
+
150
+ ### Breaking changes
151
+
152
+ - **Domain object types removed.** `BuiltinObjectType`, `BUILTIN_OBJECT_TYPES`, `RoomKind`,
153
+ `RoomSubtype`, `AutomationMeta`, `AutomationSchedule`, and `Room` are no longer exported.
154
+ `ObjectType` is now `string`. Apps must declare their own type constants.
155
+ - **`ObjectNode` fields removed.** `subtype` and `automation` fields are gone; store
156
+ app-specific node config in the existing `meta?: Record<string, unknown>` field instead.
157
+ - **Room/category bridge functions removed.** `categoryId`, `DEFAULT_CATEGORY`,
158
+ `objectsToRoomCategories`, `excludeAutomatedRooms`, `roomKindToSubtype`, `subtypeToRoomKind`,
159
+ `AdaptedCategory`, `SeedRoom`, `seedIndexNodes`, `normalizeCategories`, `CategoryError`.
160
+ - **Room projection functions removed.** `readIndexRooms`, `readSpaceIndexRooms`,
161
+ `readSpaceRooms`. Use `updateObjectIndex(session, spaceId, nodes => nodes, reg)` as a
162
+ read-only alternative.
163
+ - **Access-record helpers renamed.** `roomsRegistryPull`/`roomsRegistryPush` →
164
+ `spaceAccessPull`/`spaceAccessPush`; `readRooms`/`writeRooms` →
165
+ `readSpaceAccess`/`writeSpaceAccess`.
166
+ - **Storage leaf renamed.** Access records move from `spaces/{id}/_rooms` to
167
+ `spaces/{id}/_access`. Apps that haven't adopted this migration continue to work via the
168
+ Infra enricher's default `registry_path` param.
169
+ - **Collection names updated.** `rooms` → `spaceregistry`; `chatkeyring` → `spacekeyring`.
170
+ `accountScope` and `linkedDeviceScope` updated accordingly.
171
+ - **`createSpace` no longer seeds a general channel.** The index is seeded empty; apps add
172
+ their own initial nodes after creation.
173
+
174
+ ### Migration
175
+
176
+ Adopting apps must declare their own type constants:
177
+
178
+ ```ts
179
+ // e.g. in your own SDK package
180
+ export const MY_TYPES = { page: 'page', folder: 'folder' } as const;
181
+ ```
182
+
183
+ Replace removed helpers:
184
+ - `readSpaceIndexRooms(session, spaceId, reg)` →
185
+ `updateObjectIndex(session, spaceId, nodes => nodes, reg)`
186
+ - `roomsRegistryPull/Push` → `spaceAccessPull`/`spaceAccessPush`
187
+ - `readRooms/writeRooms` → `readSpaceAccess`/`writeSpaceAccess`
188
+ - `ObjectNode.subtype` → `ObjectNode.meta.subtype` (or a first-class type string)
189
+ - `ObjectNode.automation` → `ObjectNode.meta.automation`
190
+
191
+ See `OCTOCHAT_MIGRATION.md` and `OCTOVAULT_MIGRATION.md` at the repo root for full
192
+ per-app migration guides.
193
+
194
+ ---
195
+
196
+ ## 0.1.0 (initial)
197
+
198
+ Initial release — unified public/private spaces on one `spaces/{spaceId}/**` path family,
199
+ E2EE object index, link-based joins, cross-app keyring, and the generic `ObjectNode` tree
200
+ engine.