@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 +144 -1
- package/dist/index.js +164 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/types.ts +3 -2
- package/src/index.ts +20 -0
- package/src/utils/invite-preview.test.ts +169 -0
- package/src/utils/invite-preview.ts +101 -0
- package/src/utils/live-sync-bus.test.ts +116 -0
- package/src/utils/live-sync-bus.ts +71 -0
- package/src/utils/search-match.test.ts +149 -0
- package/src/utils/search-match.ts +145 -0
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
|
-
|
|
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,
|