@drakkar.software/octospaces-sdk 0.4.1 → 0.4.3

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/dist/index.d.ts CHANGED
@@ -302,6 +302,11 @@ declare function sealToRecipient(session: Session, recipientKemPub: string, plai
302
302
  declare function unsealFromRecipient(session: Session, blob: SealedBlob): Promise<string>;
303
303
 
304
304
  type ID = string;
305
+ /** A user's presence indicator. The theme maps each to a color (app-side). */
306
+ type PresenceStatus = 'online' | 'away' | 'dnd' | 'offline';
307
+ /** A security item's verification state. The theme maps each to a color (app-side).
308
+ * `none` = unknown / not yet verified; maps to a neutral/muted color in the theme. */
309
+ type VerificationLevel = 'verified' | 'pending' | 'unverified' | 'none';
305
310
  /** Maps a joined space's id → its owner-issued member cap-cert (serialized JSON).
306
311
  * Persisted both in device-local kv and, for durability, in the user's own synced
307
312
  * `_spaces` doc so a fresh device re-hydrates it. */
@@ -422,11 +427,15 @@ declare function roomSlug(name: string): string;
422
427
  * OBJECT_COLLECTIONS / spaceMemberScope — only a per-node cap can reach it.
423
428
  */
424
429
 
430
+ /** A room id is `sp-<rand>-<name>`; the space is its first two `-` segments. */
431
+ declare const spaceIdFromRoomId: (roomId: string) => string;
425
432
  /** Base name used as the `collectionName` arg to `addCollectionRecipient`.
426
433
  * Appending `/_keyring` gives the full storage path. */
427
434
  declare const keyringName: (spaceId: string) => string;
428
435
  declare const keyringPull: (spaceId: string) => string;
429
436
  declare const keyringPush: (spaceId: string) => string;
437
+ /** Storage path of one attachment blob — also the AAD bound into its seal. */
438
+ declare const attachmentName: (roomId: string, blobId: string) => string;
430
439
  declare const attachmentPull: (roomId: string, blobId: string) => string;
431
440
  declare const attachmentPush: (roomId: string, blobId: string) => string;
432
441
  declare const profilePull: (userId: string) => string;
@@ -435,12 +444,17 @@ declare const spacesPull: (userId: string) => string;
435
444
  declare const spacesPush: (userId: string) => string;
436
445
  declare const spaceAccessPull: (spaceId: string) => string;
437
446
  declare const spaceAccessPush: (spaceId: string) => string;
447
+ declare const objIndexName: (spaceId: string) => string;
438
448
  declare const objIndexPull: (spaceId: string) => string;
439
449
  declare const objIndexPush: (spaceId: string) => string;
450
+ declare const objLogName: (spaceId: string, objectId: string) => string;
440
451
  declare const objLogPull: (spaceId: string, objectId: string) => string;
441
452
  declare const objLogPush: (spaceId: string, objectId: string) => string;
453
+ declare const objDocName: (spaceId: string, objectId: string) => string;
442
454
  declare const objDocPull: (spaceId: string, objectId: string) => string;
443
455
  declare const objDocPush: (spaceId: string, objectId: string) => string;
456
+ /** Storage path of one sealed object blob — also the AAD bound into its seal. */
457
+ declare const objectBlobName: (spaceId: string, blobId: string) => string;
444
458
  declare const objectBlobPull: (spaceId: string, blobId: string) => string;
445
459
  declare const objectBlobPush: (spaceId: string, blobId: string) => string;
446
460
  declare const objPubName: (spaceId: string, nodeId: string) => string;
@@ -449,6 +463,7 @@ declare const objPubPush: (spaceId: string, nodeId: string) => string;
449
463
  declare const objInvName: (spaceId: string, nodeId: string) => string;
450
464
  declare const objInvPull: (spaceId: string, nodeId: string) => string;
451
465
  declare const objInvPush: (spaceId: string, nodeId: string) => string;
466
+ declare const typesIndexName: (spaceId: string) => string;
452
467
  declare const typesIndexPull: (spaceId: string) => string;
453
468
  declare const typesIndexPush: (spaceId: string) => string;
454
469
  declare const objectDirName: (shard?: string) => string;
@@ -1033,4 +1048,132 @@ declare const starfishBase64: Base64Provider;
1033
1048
  declare function toBase64Url(json: string): string;
1034
1049
  declare function fromBase64Url(b64url: string): string;
1035
1050
 
1036
- export { type ArchivedDms, CONNECT_TIMEOUT_MS, type CapMap, type CreateNodeInput, type DerivedIdentity, type DeviceKeys, type DmMap, type ID, type JoinRequest, type KvAdapter, type LinkedIdentity, type MutePrefs, type NewObjectInput, type NodeAccess, type NodeAccessHandle, type NodeInviteBundle, type NodeInviteLinkToken, OBJECT_COLLECTIONS, type ObjectContentKind, type ObjectNode, type ObjectTreeNode, type ObjectType, type ObjectsIndex, type OctoSpacesConfig, PAIR_PREFIX, PULL_CACHE_MAX_AGE_MS, type PairResult, type PasskeyEnrollment, type PersistedSession, type PubAccessMap, type PublicProfile, type ReadPrefs, type SealedBlob, type SeedLock, type Session, type Space, type SpaceAccessEntry, SpaceAccessError, type SpaceAccessMap, type SpaceInviteLinkToken, type SpaceMeta, type SpaceMetaUpdate, type UnlockMethod, type Vault, type VaultLoad, acceptNodeInvite, acceptSpaceInvite, accountScope, addDeviceToSpaceKeyring, addJoinedSpace, addJoinedSpaceWithCap, addJoinedSpaceWithLinkAccess, addObject, addSpaceMember, ancestors, archiveObject, attachmentPull, attachmentPush, breadcrumbs, broadcastSpaceMeta, buildAuthHeaders, buildEncryptor, buildLinkedSession, buildNodeAccess, buildSession, buildTree, bytesToHex, cacheProfile, capProviderFor, clearNodeAccessCache, clearSpaceAccessStore, completeDevicePairing, configureKv, configureOctoSpaces, createNode, createNodeInviteLink, createSpace, createSpaceInviteLink, decodeNodeInviteLink, decodeSpaceInviteLink, deriveSession, encodeNodeInviteLink, encodeSpaceInviteLink, ensureProfileKeys, ensurePseudo, fetchWithTimeout, fingerprintFromUserId, fromBase64Url, generateSeedWords, getNodeAccess, getNodeAccessEntry, getSharedSpacesNamespace, getSpaceAccessEntry, getSpaceClient, getSyncBase, getSyncNamespace, getSyncPrefix, hydrateSpaceAccessStore, inviteToNode, inviteToSpace, isValidSeed, joinNodeByLink, joinSpaceByLink, keyringName, keyringPull, keyringPush, kvGet, kvRemove, kvSet, linkAccessFromStore, linkedDeviceScope, loadCachedProfile, localSpaceAccessEntries, makeClient, makeJoinRequest, memberCapsFromStore, nextOrder, nodeMemberScope, objDocPull, objDocPush, objIndexPull, objIndexPush, objInvName, objInvPull, objInvPush, objLogPull, objLogPush, objPubName, objPubPull, objPubPush, objectBlobPull, objectBlobPush, objectDirName, objectDirPull, onSpaceMeta, openEncryptor, ownerEnsureKeyring, ownerScope, ownerTrustedAdders, patchObject, profilePull, profilePush, pullCache, pushIndexSeed, randomId, readObjectTree, readProfile, readProfiles, readPseudo, readSpaceAccess, readSpaces, reconcileSpaceMeta, recoverSpaceAccess, removeNodeAccessEntry, removeSpaceAccessEntry, removeSpaceMember, reorderObjects, reorderSpaces, reparentObject, roomSlug, rootIdentityOf, saveNodeAccessEntry, saveSpaceAccessEntry, sealToRecipient, sealToSelf, seedSpaceObjectIndex, setDmMapping, setNodeAccess, spaceAccessPull, spaceAccessPush, spaceMemberScope, spacesPull, spacesPush, starfishBase64, startDevicePairing, subtreeIds, toBase64Url, typesIndexPull, typesIndexPush, unsealFromRecipient, unsealFromSelf, updateArchivedDmsDoc, updateDmsDoc, updateMutesDoc, updateObjectIndex, updateQuickReactionsDoc, updateReadsDoc, updateSpacesDoc, userIdFromEdPub, writeProfile, writePseudo, writeSpaceAccess, writeSpaces };
1051
+ /**
1052
+ * Pure title matcher + ranker for Quick Find / Search. No React, no I/O.
1053
+ *
1054
+ * Relevance is tiered the way a human reads a match, strongest first:
1055
+ *
1056
+ * 1. PREFIX — the title starts with the query ("not" → "Notes").
1057
+ * 2. WORD boundary — some word starts with the query ("pa" → "New page").
1058
+ * 3. SUBSTRING — the query appears mid-word ("page" → "Homepage").
1059
+ * 4. FUZZY — the query is a subsequence ("rdm" → "Roadmap").
1060
+ *
1061
+ * Within a tier, earlier and tighter matches in shorter titles score higher;
1062
+ * tier gaps are wider than any intra-tier penalty, so a fuzzy hit can never
1063
+ * outrank a real substring. Ties (same score) fall back to `updatedAt` DESC in
1064
+ * {@link rankResults} — between two objects named "Notes", the one touched last
1065
+ * is almost always the one wanted.
1066
+ *
1067
+ * Matching is case- and diacritic-insensitive via a per-UTF-16-unit fold that
1068
+ * PRESERVES STRING LENGTH, so the returned ranges index straight into the
1069
+ * ORIGINAL title for highlight rendering.
1070
+ */
1071
+ /** Half-open [start, end) span into the original title. */
1072
+ interface MatchRange {
1073
+ start: number;
1074
+ end: number;
1075
+ }
1076
+ interface TitleMatch {
1077
+ score: number;
1078
+ ranges: MatchRange[];
1079
+ }
1080
+ /**
1081
+ * Lowercase + strip diacritics WITHOUT changing length: each UTF-16 unit maps
1082
+ * to exactly one folded unit (NFD base char, first lowercase unit). Surrogate
1083
+ * halves pass through unchanged — they can't match an ASCII query, which is
1084
+ * exactly right for emoji-bearing titles.
1085
+ */
1086
+ declare function fold(s: string): string;
1087
+ /** A word starts where the previous folded char is not alphanumeric. */
1088
+ declare function isWordStart(folded: string, i: number): boolean;
1089
+ /**
1090
+ * Match one title against a query. Returns `null` for an empty query or a miss.
1091
+ * Ranges cover every highlighted span (one for contiguous tiers, several merged
1092
+ * runs for fuzzy).
1093
+ */
1094
+ declare function matchTitle(query: string, title: string): TitleMatch | null;
1095
+ interface RankedResult<T> {
1096
+ item: T;
1097
+ score: number;
1098
+ ranges: MatchRange[];
1099
+ }
1100
+ /**
1101
+ * Rank a candidate list against a query: score every title, drop misses, sort
1102
+ * by score DESC then `updatedAt` DESC (recency breaks ties), cap at `limit`.
1103
+ */
1104
+ declare function rankResults<T extends {
1105
+ title: string;
1106
+ updatedAt: number;
1107
+ }>(query: string, items: readonly T[], limit?: number): RankedResult<T>[];
1108
+
1109
+ /**
1110
+ * Single dispatch point for live-sync events from a global SSE connection.
1111
+ *
1112
+ * When a server-sent event arrives, the unread/notification layer calls
1113
+ * `dispatchDocChange(docPath)`:
1114
+ * - if a hook has registered a pull for that path → call it (the user is
1115
+ * actively viewing that doc) and return `true` — the caller skips the
1116
+ * unread bump.
1117
+ * - otherwise return `false` → the caller bumps unread.
1118
+ *
1119
+ * Hooks register/unregister via `registerPull`. SSE connection health is
1120
+ * broadcast via `emitSseStatus` so hooks can gate their fallback polling.
1121
+ *
1122
+ * Call `clearLiveSyncBus()` on account switch to flush all registrations.
1123
+ */
1124
+ type PullFn = () => void;
1125
+ type StatusListener = (up: boolean) => void;
1126
+ /**
1127
+ * Register a pull function keyed by `docPath`. Returns an unsubscribe
1128
+ * function — call it when the hook unmounts.
1129
+ */
1130
+ declare function registerPull(docPath: string, fn: PullFn): () => void;
1131
+ /**
1132
+ * Dispatch a doc-change event. If a pull is registered for `docPath`, calls
1133
+ * it and returns `true`. Returns `false` if no listener is registered
1134
+ * (the caller should bump unread).
1135
+ */
1136
+ declare function dispatchDocChange(docPath: string): boolean;
1137
+ /** Broadcast the current SSE health to all subscribers. */
1138
+ declare function emitSseStatus(up: boolean): void;
1139
+ /**
1140
+ * Subscribe to SSE health changes. Fires immediately with the current state.
1141
+ * Returns an unsubscribe function.
1142
+ */
1143
+ declare function onSseStatus(cb: StatusListener): () => void;
1144
+ /**
1145
+ * Flush all registered doc pulls and reset SSE health. Call on account
1146
+ * switch. `statusListeners` are React subscriptions that self-unsubscribe on
1147
+ * unmount and are intentionally left intact.
1148
+ */
1149
+ declare function clearLiveSyncBus(): void;
1150
+
1151
+ type InvitePreview = {
1152
+ kind: 'space-link';
1153
+ spaceName: string;
1154
+ /** True if the link grants write access, false for read-only. */
1155
+ write: boolean;
1156
+ token: SpaceInviteLinkToken;
1157
+ } | {
1158
+ kind: 'node-link';
1159
+ spaceName: string;
1160
+ /** The node's display name, absent for legacy tokens that omit it. */
1161
+ nodeTitle?: string;
1162
+ token: NodeInviteLinkToken;
1163
+ } | {
1164
+ kind: 'member-bundle';
1165
+ spaceName: string;
1166
+ spaceId: string;
1167
+ /** Short hex fingerprint of the issuing owner's signing key, or null if absent. */
1168
+ issuerKey: string | null;
1169
+ /** The raw cap-bundle JSON — pass verbatim to `acceptSpaceInvite` on consent. */
1170
+ inviteJson: string;
1171
+ };
1172
+ /**
1173
+ * Classify and decode an invite string into a typed {@link InvitePreview}.
1174
+ * Throws a human-readable `Error` on invalid input (safe to surface verbatim
1175
+ * in a toast or inline error message).
1176
+ */
1177
+ declare function previewInvite(raw: string): InvitePreview;
1178
+
1179
+ export { type ArchivedDms, CONNECT_TIMEOUT_MS, type CapMap, type CreateNodeInput, type DerivedIdentity, type DeviceKeys, type DmMap, type ID, type InvitePreview, type JoinRequest, type KvAdapter, type LinkedIdentity, type MatchRange, type MutePrefs, type MuteValue, type NewObjectInput, type NodeAccess, type NodeAccessHandle, type NodeInviteBundle, type NodeInviteLinkToken, OBJECT_COLLECTIONS, type ObjectContentKind, type ObjectNode, type ObjectTreeNode, type ObjectType, type ObjectsIndex, type OctoSpacesConfig, PAIR_PREFIX, PULL_CACHE_MAX_AGE_MS, type PairResult, type PasskeyEnrollment, type PersistedSession, type PresenceStatus, type PubAccessMap, type PublicProfile, type RankedResult, type ReadPrefs, type ReadValue, type SealedBlob, type SeedLock, type Session, type Space, type SpaceAccessEntry, SpaceAccessError, type SpaceAccessMap, type SpaceInviteLinkToken, type SpaceMeta, type SpaceMetaUpdate, type TitleMatch, type UnlockMethod, type Vault, type VaultLoad, type VerificationLevel, acceptNodeInvite, acceptSpaceInvite, accountScope, addDeviceToSpaceKeyring, addJoinedSpace, addJoinedSpaceWithCap, addJoinedSpaceWithLinkAccess, addObject, addSpaceMember, ancestors, archiveObject, attachmentName, attachmentPull, attachmentPush, breadcrumbs, broadcastSpaceMeta, buildAuthHeaders, buildEncryptor, buildLinkedSession, buildNodeAccess, buildSession, buildTree, bytesToHex, cacheProfile, capProviderFor, clearLiveSyncBus, clearNodeAccessCache, clearSpaceAccessStore, completeDevicePairing, configureKv, configureOctoSpaces, createNode, createNodeInviteLink, createSpace, createSpaceInviteLink, decodeNodeInviteLink, decodeSpaceInviteLink, deriveSession, dispatchDocChange, emitSseStatus, encodeNodeInviteLink, encodeSpaceInviteLink, ensureProfileKeys, ensurePseudo, fetchWithTimeout, fingerprintFromUserId, fold, fromBase64Url, generateSeedWords, getNodeAccess, getNodeAccessEntry, getSharedSpacesNamespace, getSpaceAccessEntry, getSpaceClient, getSyncBase, getSyncNamespace, getSyncPrefix, hydrateSpaceAccessStore, inviteToNode, inviteToSpace, isValidSeed, isWordStart, joinNodeByLink, joinSpaceByLink, keyringName, keyringPull, keyringPush, kvGet, kvRemove, kvSet, linkAccessFromStore, linkedDeviceScope, loadCachedProfile, localSpaceAccessEntries, makeClient, makeJoinRequest, matchTitle, memberCapsFromStore, nextOrder, nodeMemberScope, objDocName, objDocPull, objDocPush, objIndexName, objIndexPull, objIndexPush, objInvName, objInvPull, objInvPush, objLogName, objLogPull, objLogPush, objPubName, objPubPull, objPubPush, objectBlobName, objectBlobPull, objectBlobPush, objectDirName, objectDirPull, onSpaceMeta, onSseStatus, openEncryptor, ownerEnsureKeyring, ownerScope, ownerTrustedAdders, patchObject, previewInvite, profilePull, profilePush, pullCache, pushIndexSeed, randomId, rankResults, readObjectTree, readProfile, readProfiles, readPseudo, readSpaceAccess, readSpaces, reconcileSpaceMeta, recoverSpaceAccess, registerPull, removeNodeAccessEntry, removeSpaceAccessEntry, removeSpaceMember, reorderObjects, reorderSpaces, reparentObject, roomSlug, rootIdentityOf, saveNodeAccessEntry, saveSpaceAccessEntry, sealToRecipient, sealToSelf, seedSpaceObjectIndex, setDmMapping, setNodeAccess, spaceAccessPull, spaceAccessPush, spaceIdFromRoomId, spaceMemberScope, spacesPull, spacesPush, starfishBase64, startDevicePairing, subtreeIds, toBase64Url, typesIndexName, typesIndexPull, typesIndexPush, unsealFromRecipient, unsealFromSelf, updateArchivedDmsDoc, updateDmsDoc, updateMutesDoc, updateObjectIndex, updateQuickReactionsDoc, updateReadsDoc, updateSpacesDoc, userIdFromEdPub, writeProfile, writePseudo, writeSpaceAccess, writeSpaces };
package/dist/index.js CHANGED
@@ -1841,6 +1841,153 @@ function decodePure(encoded) {
1841
1841
  return o === out.length ? out : out.subarray(0, o);
1842
1842
  }
1843
1843
  var starfishBase64 = nativeCodec ? { encode: encodeViaBtoa, decode: decodeViaAtob } : { encode: encodePure, decode: decodePure };
1844
+
1845
+ // src/utils/search-match.ts
1846
+ var TIER_PREFIX = 4e3;
1847
+ var TIER_WORD = 3e3;
1848
+ var TIER_SUBSTRING = 2e3;
1849
+ var TIER_FUZZY = 1e3;
1850
+ function fold(s) {
1851
+ let out = "";
1852
+ for (let i = 0; i < s.length; i++) {
1853
+ const base = s[i].normalize("NFD")[0];
1854
+ const lower = base.toLowerCase();
1855
+ out += lower.length === 1 ? lower : lower[0];
1856
+ }
1857
+ return out;
1858
+ }
1859
+ function isWordStart(folded, i) {
1860
+ if (i === 0) return true;
1861
+ return !/[a-z0-9]/.test(folded[i - 1]);
1862
+ }
1863
+ var startPenalty = (i) => Math.min(i * 8, 600);
1864
+ var lengthPenalty = (titleLen, queryLen) => Math.min(Math.max(titleLen - queryLen, 0), 100);
1865
+ function matchTitle(query, title) {
1866
+ const q = fold(query.trim());
1867
+ if (!q) return null;
1868
+ const t = fold(title);
1869
+ let first = -1;
1870
+ let wordAt = -1;
1871
+ for (let i = t.indexOf(q); i !== -1; i = t.indexOf(q, i + 1)) {
1872
+ if (first === -1) first = i;
1873
+ if (isWordStart(t, i)) {
1874
+ wordAt = i;
1875
+ break;
1876
+ }
1877
+ }
1878
+ if (first === 0) {
1879
+ return { score: TIER_PREFIX - lengthPenalty(t.length, q.length), ranges: [{ start: 0, end: q.length }] };
1880
+ }
1881
+ if (wordAt !== -1) {
1882
+ return {
1883
+ score: TIER_WORD - startPenalty(wordAt) - lengthPenalty(t.length, q.length),
1884
+ ranges: [{ start: wordAt, end: wordAt + q.length }]
1885
+ };
1886
+ }
1887
+ if (first !== -1) {
1888
+ return {
1889
+ score: TIER_SUBSTRING - startPenalty(first) - lengthPenalty(t.length, q.length),
1890
+ ranges: [{ start: first, end: first + q.length }]
1891
+ };
1892
+ }
1893
+ const chars = q.replace(/\s+/g, "");
1894
+ if (!chars) return null;
1895
+ const ranges = [];
1896
+ let from = 0;
1897
+ for (let ci = 0; ci < chars.length; ci++) {
1898
+ const at = t.indexOf(chars[ci], from);
1899
+ if (at === -1) return null;
1900
+ const last = ranges[ranges.length - 1];
1901
+ if (last && last.end === at) last.end = at + 1;
1902
+ else ranges.push({ start: at, end: at + 1 });
1903
+ from = at + 1;
1904
+ }
1905
+ const firstHit = ranges[0].start;
1906
+ const spread = ranges[ranges.length - 1].end - firstHit - chars.length;
1907
+ const score = TIER_FUZZY - Math.min(spread * 8, 600) - Math.min(firstHit * 2, 200) - lengthPenalty(t.length, chars.length);
1908
+ return { score, ranges };
1909
+ }
1910
+ function rankResults(query, items, limit = 50) {
1911
+ const out = [];
1912
+ for (const item of items) {
1913
+ const m = matchTitle(query, item.title);
1914
+ if (m) out.push({ item, score: m.score, ranges: m.ranges });
1915
+ }
1916
+ out.sort((a, b) => b.score - a.score || b.item.updatedAt - a.item.updatedAt);
1917
+ return out.slice(0, limit);
1918
+ }
1919
+
1920
+ // src/utils/live-sync-bus.ts
1921
+ var pullRegistry = /* @__PURE__ */ new Map();
1922
+ var statusListeners = /* @__PURE__ */ new Set();
1923
+ var sseUp = false;
1924
+ function registerPull(docPath, fn) {
1925
+ pullRegistry.set(docPath, fn);
1926
+ return () => {
1927
+ if (pullRegistry.get(docPath) === fn) pullRegistry.delete(docPath);
1928
+ };
1929
+ }
1930
+ function dispatchDocChange(docPath) {
1931
+ const pull2 = pullRegistry.get(docPath);
1932
+ if (!pull2) return false;
1933
+ pull2();
1934
+ return true;
1935
+ }
1936
+ function emitSseStatus(up) {
1937
+ sseUp = up;
1938
+ for (const l of statusListeners) l(up);
1939
+ }
1940
+ function onSseStatus(cb) {
1941
+ statusListeners.add(cb);
1942
+ cb(sseUp);
1943
+ return () => statusListeners.delete(cb);
1944
+ }
1945
+ function clearLiveSyncBus() {
1946
+ pullRegistry.clear();
1947
+ sseUp = false;
1948
+ }
1949
+
1950
+ // src/utils/invite-preview.ts
1951
+ function previewInvite(raw) {
1952
+ const text = raw.trim();
1953
+ if (!text) throw new Error("Paste an invite link or code first.");
1954
+ if (text.includes("#")) {
1955
+ const fragment = text.slice(text.indexOf("#"));
1956
+ try {
1957
+ const token = decodeNodeInviteLink(fragment);
1958
+ return {
1959
+ kind: "node-link",
1960
+ spaceName: `space-${token.spaceId.slice(-6)}`,
1961
+ nodeTitle: token.nodeName,
1962
+ token
1963
+ };
1964
+ } catch {
1965
+ }
1966
+ try {
1967
+ const token = decodeSpaceInviteLink(fragment);
1968
+ return { kind: "space-link", spaceName: token.spaceName, write: token.write, token };
1969
+ } catch {
1970
+ throw new Error("That invite link appears to be invalid or expired.");
1971
+ }
1972
+ }
1973
+ let parsed;
1974
+ try {
1975
+ parsed = JSON.parse(text);
1976
+ } catch {
1977
+ throw new Error("That doesn't look like an invite. Paste the full invite code or link.");
1978
+ }
1979
+ if (!parsed?.spaceId || parsed.cap?.kind !== "member") {
1980
+ throw new Error("That is not a valid space invite.");
1981
+ }
1982
+ const iss = parsed.cap?.iss;
1983
+ return {
1984
+ kind: "member-bundle",
1985
+ spaceName: parsed.spaceName?.trim() || `space-${parsed.spaceId.slice(-6)}`,
1986
+ spaceId: parsed.spaceId,
1987
+ issuerKey: typeof iss === "string" && iss.length >= 8 ? `${iss.slice(0, 8)}\u2026${iss.slice(-8)}` : null,
1988
+ inviteJson: text
1989
+ };
1990
+ }
1844
1991
  export {
1845
1992
  CONNECT_TIMEOUT_MS,
1846
1993
  OBJECT_COLLECTIONS,
@@ -1858,6 +2005,7 @@ export {
1858
2005
  addSpaceMember,
1859
2006
  ancestors,
1860
2007
  archiveObject,
2008
+ attachmentName,
1861
2009
  attachmentPull,
1862
2010
  attachmentPush,
1863
2011
  breadcrumbs,
@@ -1871,6 +2019,7 @@ export {
1871
2019
  bytesToHex,
1872
2020
  cacheProfile,
1873
2021
  capProviderFor,
2022
+ clearLiveSyncBus,
1874
2023
  clearNodeAccessCache,
1875
2024
  clearSpaceAccessStore,
1876
2025
  completeDevicePairing,
@@ -1883,12 +2032,15 @@ export {
1883
2032
  decodeNodeInviteLink,
1884
2033
  decodeSpaceInviteLink,
1885
2034
  deriveSession,
2035
+ dispatchDocChange,
2036
+ emitSseStatus,
1886
2037
  encodeNodeInviteLink,
1887
2038
  encodeSpaceInviteLink,
1888
2039
  ensureProfileKeys,
1889
2040
  ensurePseudo,
1890
2041
  fetchWithTimeout,
1891
2042
  fingerprintFromUserId,
2043
+ fold,
1892
2044
  fromBase64Url,
1893
2045
  generateSeedWords,
1894
2046
  getNodeAccess,
@@ -1903,6 +2055,7 @@ export {
1903
2055
  inviteToNode,
1904
2056
  inviteToSpace,
1905
2057
  isValidSeed,
2058
+ isWordStart,
1906
2059
  joinNodeByLink,
1907
2060
  joinSpaceByLink,
1908
2061
  keyringName,
@@ -1917,36 +2070,44 @@ export {
1917
2070
  localSpaceAccessEntries,
1918
2071
  makeClient,
1919
2072
  makeJoinRequest,
2073
+ matchTitle,
1920
2074
  memberCapsFromStore,
1921
2075
  nextOrder,
1922
2076
  nodeMemberScope,
2077
+ objDocName,
1923
2078
  objDocPull,
1924
2079
  objDocPush,
2080
+ objIndexName,
1925
2081
  objIndexPull,
1926
2082
  objIndexPush,
1927
2083
  objInvName,
1928
2084
  objInvPull,
1929
2085
  objInvPush,
2086
+ objLogName,
1930
2087
  objLogPull,
1931
2088
  objLogPush,
1932
2089
  objPubName,
1933
2090
  objPubPull,
1934
2091
  objPubPush,
2092
+ objectBlobName,
1935
2093
  objectBlobPull,
1936
2094
  objectBlobPush,
1937
2095
  objectDirName,
1938
2096
  objectDirPull,
1939
2097
  onSpaceMeta,
2098
+ onSseStatus,
1940
2099
  openEncryptor,
1941
2100
  ownerEnsureKeyring,
1942
2101
  ownerScope,
1943
2102
  ownerTrustedAdders,
1944
2103
  patchObject,
2104
+ previewInvite,
1945
2105
  profilePull,
1946
2106
  profilePush,
1947
2107
  pullCache,
1948
2108
  pushIndexSeed,
1949
2109
  randomId,
2110
+ rankResults,
1950
2111
  readObjectTree,
1951
2112
  readProfile,
1952
2113
  readProfiles,
@@ -1955,6 +2116,7 @@ export {
1955
2116
  readSpaces,
1956
2117
  reconcileSpaceMeta,
1957
2118
  recoverSpaceAccess,
2119
+ registerPull,
1958
2120
  removeNodeAccessEntry,
1959
2121
  removeSpaceAccessEntry,
1960
2122
  removeSpaceMember,
@@ -1972,6 +2134,7 @@ export {
1972
2134
  setNodeAccess,
1973
2135
  spaceAccessPull,
1974
2136
  spaceAccessPush,
2137
+ spaceIdFromRoomId,
1975
2138
  spaceMemberScope,
1976
2139
  spacesPull,
1977
2140
  spacesPush,
@@ -1979,6 +2142,7 @@ export {
1979
2142
  startDevicePairing,
1980
2143
  subtreeIds,
1981
2144
  toBase64Url,
2145
+ typesIndexName,
1982
2146
  typesIndexPull,
1983
2147
  typesIndexPush,
1984
2148
  unsealFromRecipient,