@tinycloudlabs/sdk-core 1.0.0
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/LICENSE.md +320 -0
- package/dist/TinyCloud.d.ts +206 -0
- package/dist/TinyCloud.d.ts.map +1 -0
- package/dist/TinyCloud.js +244 -0
- package/dist/TinyCloud.js.map +1 -0
- package/dist/TinyCloud.schema.d.ts +173 -0
- package/dist/TinyCloud.schema.d.ts.map +1 -0
- package/dist/TinyCloud.schema.js +136 -0
- package/dist/TinyCloud.schema.js.map +1 -0
- package/dist/TinyCloud.schema.test.d.ts +5 -0
- package/dist/TinyCloud.schema.test.d.ts.map +1 -0
- package/dist/TinyCloud.schema.test.js +286 -0
- package/dist/TinyCloud.schema.test.js.map +1 -0
- package/dist/authorization/CapabilityKeyRegistry.d.ts +317 -0
- package/dist/authorization/CapabilityKeyRegistry.d.ts.map +1 -0
- package/dist/authorization/CapabilityKeyRegistry.js +509 -0
- package/dist/authorization/CapabilityKeyRegistry.js.map +1 -0
- package/dist/authorization/authorization.schema.d.ts +233 -0
- package/dist/authorization/authorization.schema.d.ts.map +1 -0
- package/dist/authorization/authorization.schema.js +220 -0
- package/dist/authorization/authorization.schema.js.map +1 -0
- package/dist/authorization/authorization.schema.test.d.ts +5 -0
- package/dist/authorization/authorization.schema.test.d.ts.map +1 -0
- package/dist/authorization/authorization.schema.test.js +618 -0
- package/dist/authorization/authorization.schema.test.js.map +1 -0
- package/dist/authorization/index.d.ts +38 -0
- package/dist/authorization/index.d.ts.map +1 -0
- package/dist/authorization/index.js +52 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/spaceCreation.d.ts +96 -0
- package/dist/authorization/spaceCreation.d.ts.map +1 -0
- package/dist/authorization/spaceCreation.js +35 -0
- package/dist/authorization/spaceCreation.js.map +1 -0
- package/dist/authorization/spaceCreation.schema.d.ts +67 -0
- package/dist/authorization/spaceCreation.schema.d.ts.map +1 -0
- package/dist/authorization/spaceCreation.schema.js +95 -0
- package/dist/authorization/spaceCreation.schema.js.map +1 -0
- package/dist/authorization/spaceCreation.schema.test.d.ts +5 -0
- package/dist/authorization/spaceCreation.schema.test.d.ts.map +1 -0
- package/dist/authorization/spaceCreation.schema.test.js +168 -0
- package/dist/authorization/spaceCreation.schema.test.js.map +1 -0
- package/dist/authorization/strategies.d.ts +134 -0
- package/dist/authorization/strategies.d.ts.map +1 -0
- package/dist/authorization/strategies.js +15 -0
- package/dist/authorization/strategies.js.map +1 -0
- package/dist/authorization/strategies.schema.d.ts +185 -0
- package/dist/authorization/strategies.schema.d.ts.map +1 -0
- package/dist/authorization/strategies.schema.js +147 -0
- package/dist/authorization/strategies.schema.js.map +1 -0
- package/dist/authorization/strategies.schema.test.d.ts +5 -0
- package/dist/authorization/strategies.schema.test.d.ts.map +1 -0
- package/dist/authorization/strategies.schema.test.js +253 -0
- package/dist/authorization/strategies.schema.test.js.map +1 -0
- package/dist/delegations/DelegationManager.d.ts +164 -0
- package/dist/delegations/DelegationManager.d.ts.map +1 -0
- package/dist/delegations/DelegationManager.js +428 -0
- package/dist/delegations/DelegationManager.js.map +1 -0
- package/dist/delegations/SharingService.d.ts +279 -0
- package/dist/delegations/SharingService.d.ts.map +1 -0
- package/dist/delegations/SharingService.js +558 -0
- package/dist/delegations/SharingService.js.map +1 -0
- package/dist/delegations/SharingService.schema.d.ts +401 -0
- package/dist/delegations/SharingService.schema.d.ts.map +1 -0
- package/dist/delegations/SharingService.schema.js +211 -0
- package/dist/delegations/SharingService.schema.js.map +1 -0
- package/dist/delegations/index.d.ts +38 -0
- package/dist/delegations/index.d.ts.map +1 -0
- package/dist/delegations/index.js +42 -0
- package/dist/delegations/index.js.map +1 -0
- package/dist/delegations/types.d.ts +13 -0
- package/dist/delegations/types.d.ts.map +1 -0
- package/dist/delegations/types.js +42 -0
- package/dist/delegations/types.js.map +1 -0
- package/dist/delegations/types.schema.d.ts +1641 -0
- package/dist/delegations/types.schema.d.ts.map +1 -0
- package/dist/delegations/types.schema.js +535 -0
- package/dist/delegations/types.schema.js.map +1 -0
- package/dist/delegations/types.schema.test.d.ts +5 -0
- package/dist/delegations/types.schema.test.d.ts.map +1 -0
- package/dist/delegations/types.schema.test.js +627 -0
- package/dist/delegations/types.schema.test.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema.d.ts +327 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +703 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/json-schema.test.d.ts +7 -0
- package/dist/json-schema.test.d.ts.map +1 -0
- package/dist/json-schema.test.js +365 -0
- package/dist/json-schema.test.js.map +1 -0
- package/dist/signer.d.ts +28 -0
- package/dist/signer.d.ts.map +1 -0
- package/dist/signer.js +2 -0
- package/dist/signer.js.map +1 -0
- package/dist/space.d.ts +53 -0
- package/dist/space.d.ts.map +1 -0
- package/dist/space.js +67 -0
- package/dist/space.js.map +1 -0
- package/dist/space.schema.d.ts +65 -0
- package/dist/space.schema.d.ts.map +1 -0
- package/dist/space.schema.js +65 -0
- package/dist/space.schema.js.map +1 -0
- package/dist/space.schema.test.d.ts +5 -0
- package/dist/space.schema.test.d.ts.map +1 -0
- package/dist/space.schema.test.js +148 -0
- package/dist/space.schema.test.js.map +1 -0
- package/dist/spaces/Space.d.ts +175 -0
- package/dist/spaces/Space.d.ts.map +1 -0
- package/dist/spaces/Space.js +84 -0
- package/dist/spaces/Space.js.map +1 -0
- package/dist/spaces/SpaceService.d.ts +271 -0
- package/dist/spaces/SpaceService.d.ts.map +1 -0
- package/dist/spaces/SpaceService.js +715 -0
- package/dist/spaces/SpaceService.js.map +1 -0
- package/dist/spaces/index.d.ts +11 -0
- package/dist/spaces/index.d.ts.map +1 -0
- package/dist/spaces/index.js +20 -0
- package/dist/spaces/index.js.map +1 -0
- package/dist/spaces/spaces.schema.d.ts +421 -0
- package/dist/spaces/spaces.schema.d.ts.map +1 -0
- package/dist/spaces/spaces.schema.js +342 -0
- package/dist/spaces/spaces.schema.js.map +1 -0
- package/dist/spaces/spaces.schema.test.d.ts +5 -0
- package/dist/spaces/spaces.schema.test.d.ts.map +1 -0
- package/dist/spaces/spaces.schema.test.js +471 -0
- package/dist/spaces/spaces.schema.test.js.map +1 -0
- package/dist/storage.d.ts +47 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +14 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.schema.d.ts +277 -0
- package/dist/storage.schema.d.ts.map +1 -0
- package/dist/storage.schema.js +185 -0
- package/dist/storage.schema.js.map +1 -0
- package/dist/storage.schema.test.d.ts +5 -0
- package/dist/storage.schema.test.d.ts.map +1 -0
- package/dist/storage.schema.test.js +346 -0
- package/dist/storage.schema.test.js.map +1 -0
- package/dist/userAuthorization.d.ts +99 -0
- package/dist/userAuthorization.d.ts.map +1 -0
- package/dist/userAuthorization.js +3 -0
- package/dist/userAuthorization.js.map +1 -0
- package/dist/userAuthorization.schema.d.ts +259 -0
- package/dist/userAuthorization.schema.d.ts.map +1 -0
- package/dist/userAuthorization.schema.js +175 -0
- package/dist/userAuthorization.schema.js.map +1 -0
- package/dist/userAuthorization.schema.test.d.ts +5 -0
- package/dist/userAuthorization.schema.test.d.ts.map +1 -0
- package/dist/userAuthorization.schema.test.js +356 -0
- package/dist/userAuthorization.schema.test.js.map +1 -0
- package/dist/version.d.ts +30 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +54 -0
- package/dist/version.js.map +1 -0
- package/dist/wasm-validation.d.ts +287 -0
- package/dist/wasm-validation.d.ts.map +1 -0
- package/dist/wasm-validation.js +219 -0
- package/dist/wasm-validation.js.map +1 -0
- package/dist/wasm-validation.test.d.ts +5 -0
- package/dist/wasm-validation.test.d.ts.map +1 -0
- package/dist/wasm-validation.test.js +233 -0
- package/dist/wasm-validation.test.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpaceService - Global singleton for managing spaces (owned and delegated).
|
|
3
|
+
*
|
|
4
|
+
* SpaceService provides a unified interface for discovering, creating,
|
|
5
|
+
* and accessing spaces. It handles both owned spaces (created by the user)
|
|
6
|
+
* and delegated spaces (shared by other users).
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { ok, err, serviceError } from "@tinycloudlabs/sdk-services";
|
|
11
|
+
import { Space, } from "./Space";
|
|
12
|
+
import { validateServerDelegationsResponse, validateServerOwnedSpacesResponse, validateServerCreateSpaceResponse, validateServerSpaceInfoResponse, } from "./spaces.schema.js";
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Service Name and Error Codes
|
|
15
|
+
// =============================================================================
|
|
16
|
+
const SERVICE_NAME = "space";
|
|
17
|
+
/**
|
|
18
|
+
* Error codes for SpaceService operations.
|
|
19
|
+
*/
|
|
20
|
+
export const SpaceErrorCodes = {
|
|
21
|
+
/** Space not found */
|
|
22
|
+
NOT_FOUND: "SPACE_NOT_FOUND",
|
|
23
|
+
/** Space already exists */
|
|
24
|
+
ALREADY_EXISTS: "SPACE_ALREADY_EXISTS",
|
|
25
|
+
/** Creation failed */
|
|
26
|
+
CREATION_FAILED: "SPACE_CREATION_FAILED",
|
|
27
|
+
/** Authentication required */
|
|
28
|
+
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
29
|
+
/** Invalid space name or URI */
|
|
30
|
+
INVALID_NAME: "INVALID_SPACE_NAME",
|
|
31
|
+
/** Network error */
|
|
32
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
33
|
+
/** Not initialized */
|
|
34
|
+
NOT_INITIALIZED: "NOT_INITIALIZED",
|
|
35
|
+
};
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// Space URI Utilities
|
|
38
|
+
// =============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Parse a space URI to extract components.
|
|
41
|
+
*
|
|
42
|
+
* Full URI format: `tinycloud:pkh:eip155:{chainId}:{address}:{name}`
|
|
43
|
+
* Short name format: `{name}`
|
|
44
|
+
*
|
|
45
|
+
* @param uri - The space URI or short name
|
|
46
|
+
* @returns Parsed components or null if invalid
|
|
47
|
+
*/
|
|
48
|
+
export function parseSpaceUri(uri) {
|
|
49
|
+
// Full URI format: tinycloud:pkh:eip155:{chainId}:{address}:{name}
|
|
50
|
+
const fullUriMatch = uri.match(/^tinycloud:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40}):(.+)$/);
|
|
51
|
+
if (fullUriMatch) {
|
|
52
|
+
const [, chainId, address, name] = fullUriMatch;
|
|
53
|
+
return {
|
|
54
|
+
owner: `did:pkh:eip155:${chainId}:${address}`,
|
|
55
|
+
name,
|
|
56
|
+
chainId,
|
|
57
|
+
address,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Short name format - just return the name, owner will be inferred
|
|
61
|
+
if (/^[a-zA-Z0-9_-]+$/.test(uri)) {
|
|
62
|
+
return {
|
|
63
|
+
owner: "", // Will be filled in from session
|
|
64
|
+
name: uri,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a full space URI from components.
|
|
71
|
+
*
|
|
72
|
+
* @param owner - Owner DID (did:pkh:eip155:{chainId}:{address})
|
|
73
|
+
* @param name - Space name
|
|
74
|
+
* @returns Full space URI
|
|
75
|
+
*/
|
|
76
|
+
export function buildSpaceUri(owner, name) {
|
|
77
|
+
// Extract chain ID and address from PKH DID
|
|
78
|
+
const pkhMatch = owner.match(/^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/);
|
|
79
|
+
if (pkhMatch) {
|
|
80
|
+
const [, chainId, address] = pkhMatch;
|
|
81
|
+
return `tinycloud:pkh:eip155:${chainId}:${address}:${name}`;
|
|
82
|
+
}
|
|
83
|
+
// Fallback - shouldn't happen with valid PKH DIDs
|
|
84
|
+
return `tinycloud:${owner}:${name}`;
|
|
85
|
+
}
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Server Response Transformation
|
|
88
|
+
// =============================================================================
|
|
89
|
+
/**
|
|
90
|
+
* Transform validated server delegation response to SDK's Delegation[] format.
|
|
91
|
+
*
|
|
92
|
+
* Server returns { [cid: string]: DelegationInfo } where:
|
|
93
|
+
* - Key is the delegation CID
|
|
94
|
+
* - Value is DelegationInfo with delegator, delegate, capabilities, etc.
|
|
95
|
+
*
|
|
96
|
+
* SDK expects Delegation[] with cid field included.
|
|
97
|
+
*
|
|
98
|
+
* @param validatedData - Pre-validated server response from validateServerDelegationsResponse()
|
|
99
|
+
* @param defaultSpaceId - Default space ID to use if not extractable from resource
|
|
100
|
+
*/
|
|
101
|
+
function transformServerDelegations(validatedData, defaultSpaceId) {
|
|
102
|
+
const result = [];
|
|
103
|
+
for (const [cid, info] of Object.entries(validatedData)) {
|
|
104
|
+
// Extract path from capabilities (use first capability's resource path)
|
|
105
|
+
const capabilities = info.capabilities;
|
|
106
|
+
let path = "";
|
|
107
|
+
let spaceId = defaultSpaceId;
|
|
108
|
+
const actions = [];
|
|
109
|
+
for (const cap of capabilities) {
|
|
110
|
+
actions.push(cap.ability);
|
|
111
|
+
// Parse resource to extract space and path
|
|
112
|
+
// Resource format: tinycloud:pkh:eip155:{chainId}:{address}:{spaceName}/{service}/{path}
|
|
113
|
+
const resourceMatch = cap.resource.match(/^(tinycloud:pkh:eip155:\d+:0x[a-fA-F0-9]+:[^/]+)\/[^/]+\/(.*)$/);
|
|
114
|
+
if (resourceMatch) {
|
|
115
|
+
spaceId = resourceMatch[1];
|
|
116
|
+
path = resourceMatch[2] || "";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Extract first string parent CID (server may return byte arrays for some CIDs)
|
|
120
|
+
const firstStringParent = info.parents?.find((p) => typeof p === 'string');
|
|
121
|
+
result.push({
|
|
122
|
+
cid,
|
|
123
|
+
delegateDID: info.delegate,
|
|
124
|
+
delegatorDID: info.delegator,
|
|
125
|
+
spaceId,
|
|
126
|
+
path,
|
|
127
|
+
actions,
|
|
128
|
+
expiry: info.expiry ? new Date(info.expiry) : new Date(Date.now() + 24 * 60 * 60 * 1000),
|
|
129
|
+
isRevoked: false,
|
|
130
|
+
createdAt: info.issued_at ? new Date(info.issued_at) : undefined,
|
|
131
|
+
parentCid: firstStringParent,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
// =============================================================================
|
|
137
|
+
// Implementation
|
|
138
|
+
// =============================================================================
|
|
139
|
+
/**
|
|
140
|
+
* SpaceService - Global singleton for managing spaces.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const spaceService = new SpaceService({
|
|
145
|
+
* hosts: ['https://node.tinycloud.xyz'],
|
|
146
|
+
* session,
|
|
147
|
+
* invoke,
|
|
148
|
+
* });
|
|
149
|
+
*
|
|
150
|
+
* // List all accessible spaces
|
|
151
|
+
* const result = await spaceService.list();
|
|
152
|
+
* if (result.ok) {
|
|
153
|
+
* for (const space of result.data) {
|
|
154
|
+
* console.log(`${space.name} (${space.type})`);
|
|
155
|
+
* }
|
|
156
|
+
* }
|
|
157
|
+
*
|
|
158
|
+
* // Create a new space
|
|
159
|
+
* const createResult = await spaceService.create('photos');
|
|
160
|
+
*
|
|
161
|
+
* // Get a space object for operations
|
|
162
|
+
* const space = spaceService.get('photos');
|
|
163
|
+
* await space.kv.put('album/vacation', { photos: [...] });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export class SpaceService {
|
|
167
|
+
/**
|
|
168
|
+
* Create a new SpaceService instance.
|
|
169
|
+
*
|
|
170
|
+
* @param config - Service configuration
|
|
171
|
+
*/
|
|
172
|
+
constructor(config) {
|
|
173
|
+
/** Cache of created Space objects */
|
|
174
|
+
this.spaceCache = new Map();
|
|
175
|
+
/** Cache of space info */
|
|
176
|
+
this.infoCache = new Map();
|
|
177
|
+
/** Cache TTL in milliseconds (5 minutes) */
|
|
178
|
+
this.cacheTTL = 5 * 60 * 1000;
|
|
179
|
+
this.hosts = config.hosts;
|
|
180
|
+
this.session = config.session;
|
|
181
|
+
this.invoke = config.invoke;
|
|
182
|
+
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
183
|
+
this.capabilityRegistry = config.capabilityRegistry;
|
|
184
|
+
this.createKVServiceFn = config.createKVService;
|
|
185
|
+
this._userDid = config.userDid;
|
|
186
|
+
this.sharingService = config.sharingService;
|
|
187
|
+
this.createDelegationFn = config.createDelegation;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Update the service configuration.
|
|
191
|
+
*/
|
|
192
|
+
updateConfig(config) {
|
|
193
|
+
if (config.hosts)
|
|
194
|
+
this.hosts = config.hosts;
|
|
195
|
+
if (config.session)
|
|
196
|
+
this.session = config.session;
|
|
197
|
+
if (config.invoke)
|
|
198
|
+
this.invoke = config.invoke;
|
|
199
|
+
if (config.fetch)
|
|
200
|
+
this.fetchFn = config.fetch;
|
|
201
|
+
if (config.capabilityRegistry)
|
|
202
|
+
this.capabilityRegistry = config.capabilityRegistry;
|
|
203
|
+
if (config.createKVService)
|
|
204
|
+
this.createKVServiceFn = config.createKVService;
|
|
205
|
+
if (config.userDid !== undefined)
|
|
206
|
+
this._userDid = config.userDid;
|
|
207
|
+
if (config.sharingService)
|
|
208
|
+
this.sharingService = config.sharingService;
|
|
209
|
+
if (config.createDelegation)
|
|
210
|
+
this.createDelegationFn = config.createDelegation;
|
|
211
|
+
// Clear caches when config changes
|
|
212
|
+
this.spaceCache.clear();
|
|
213
|
+
this.infoCache.clear();
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get the current user's primary space ID.
|
|
217
|
+
*/
|
|
218
|
+
getCurrentSpaceId() {
|
|
219
|
+
return this.session?.spaceId;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get the primary host URL.
|
|
223
|
+
*/
|
|
224
|
+
get host() {
|
|
225
|
+
return this.hosts[0];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get the current user's PKH DID.
|
|
229
|
+
*/
|
|
230
|
+
get userDid() {
|
|
231
|
+
// Return explicitly set user DID, or try to derive from verificationMethod
|
|
232
|
+
if (this._userDid) {
|
|
233
|
+
return this._userDid;
|
|
234
|
+
}
|
|
235
|
+
// verificationMethod might be did:key format - cannot derive PKH from it
|
|
236
|
+
// The caller should provide userDid explicitly for full functionality
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
// ===========================================================================
|
|
240
|
+
// List Spaces
|
|
241
|
+
// ===========================================================================
|
|
242
|
+
/**
|
|
243
|
+
* List all spaces the user has access to.
|
|
244
|
+
*
|
|
245
|
+
* Combines owned spaces (from the server) with delegated spaces
|
|
246
|
+
* (from the capability registry).
|
|
247
|
+
*/
|
|
248
|
+
async list() {
|
|
249
|
+
if (!this.session) {
|
|
250
|
+
return err(serviceError(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME));
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
const spaces = [];
|
|
254
|
+
// 1. Get owned spaces from the server
|
|
255
|
+
const ownedResult = await this.listOwnedSpaces();
|
|
256
|
+
if (ownedResult.ok) {
|
|
257
|
+
spaces.push(...ownedResult.data);
|
|
258
|
+
}
|
|
259
|
+
// 2. Get delegated spaces from capability registry
|
|
260
|
+
if (this.capabilityRegistry) {
|
|
261
|
+
const delegatedSpaces = this.discoverDelegatedSpaces();
|
|
262
|
+
spaces.push(...delegatedSpaces);
|
|
263
|
+
}
|
|
264
|
+
// Remove duplicates (prefer owned over delegated)
|
|
265
|
+
const uniqueSpaces = this.deduplicateSpaces(spaces);
|
|
266
|
+
return ok(uniqueSpaces);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to list spaces: ${String(error)}`, SERVICE_NAME, { cause: error instanceof Error ? error : undefined }));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* List owned spaces from the server.
|
|
274
|
+
*/
|
|
275
|
+
async listOwnedSpaces() {
|
|
276
|
+
try {
|
|
277
|
+
const headers = this.invoke(this.session, "space", "", "tinycloud.space/list");
|
|
278
|
+
const response = await this.fetchFn(`${this.host}/invoke`, {
|
|
279
|
+
method: "POST",
|
|
280
|
+
headers,
|
|
281
|
+
});
|
|
282
|
+
if (!response.ok) {
|
|
283
|
+
const errorText = await response.text();
|
|
284
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to list owned spaces: ${response.status} - ${errorText}`, SERVICE_NAME, { meta: { status: response.status } }));
|
|
285
|
+
}
|
|
286
|
+
const rawData = await response.json();
|
|
287
|
+
// Validate server response
|
|
288
|
+
const validationResult = validateServerOwnedSpacesResponse(rawData);
|
|
289
|
+
if (!validationResult.ok) {
|
|
290
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, validationResult.error.message, SERVICE_NAME, { meta: validationResult.error.meta }));
|
|
291
|
+
}
|
|
292
|
+
const spaces = validationResult.data.map((item) => ({
|
|
293
|
+
id: item.id,
|
|
294
|
+
name: item.name ?? this.extractNameFromId(item.id),
|
|
295
|
+
owner: item.owner,
|
|
296
|
+
type: "owned",
|
|
297
|
+
permissions: ["*"], // Full permissions for owned spaces
|
|
298
|
+
}));
|
|
299
|
+
return ok(spaces);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error listing owned spaces: ${String(error)}`, SERVICE_NAME, { cause: error instanceof Error ? error : undefined }));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Discover delegated spaces from the capability registry.
|
|
307
|
+
*/
|
|
308
|
+
discoverDelegatedSpaces() {
|
|
309
|
+
if (!this.capabilityRegistry) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
const spaces = new Map();
|
|
313
|
+
// Get all capabilities and extract unique space IDs
|
|
314
|
+
const capabilities = this.capabilityRegistry.getAllCapabilities();
|
|
315
|
+
for (const capability of capabilities) {
|
|
316
|
+
const spaceId = capability.delegation.spaceId;
|
|
317
|
+
// Skip if we already have this space
|
|
318
|
+
if (spaces.has(spaceId)) {
|
|
319
|
+
const existing = spaces.get(spaceId);
|
|
320
|
+
// Merge permissions
|
|
321
|
+
if (existing.permissions) {
|
|
322
|
+
const actions = capability.delegation.actions;
|
|
323
|
+
for (const action of actions) {
|
|
324
|
+
if (!existing.permissions.includes(action)) {
|
|
325
|
+
existing.permissions.push(action);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
// Skip if this is the user's own space
|
|
332
|
+
if (spaceId === this.session?.spaceId) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const parsed = parseSpaceUri(spaceId);
|
|
336
|
+
spaces.set(spaceId, {
|
|
337
|
+
id: spaceId,
|
|
338
|
+
name: parsed?.name ?? this.extractNameFromId(spaceId),
|
|
339
|
+
owner: capability.delegation.delegatorDID ?? parsed?.owner ?? "",
|
|
340
|
+
type: "delegated",
|
|
341
|
+
permissions: [...capability.delegation.actions],
|
|
342
|
+
expiresAt: capability.expiresAt,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return Array.from(spaces.values());
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Extract space name from a full space ID.
|
|
349
|
+
*/
|
|
350
|
+
extractNameFromId(id) {
|
|
351
|
+
const parsed = parseSpaceUri(id);
|
|
352
|
+
if (parsed) {
|
|
353
|
+
return parsed.name;
|
|
354
|
+
}
|
|
355
|
+
// Fallback: take last segment
|
|
356
|
+
const parts = id.split(":");
|
|
357
|
+
return parts[parts.length - 1] || id;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Deduplicate spaces, preferring owned over delegated.
|
|
361
|
+
*/
|
|
362
|
+
deduplicateSpaces(spaces) {
|
|
363
|
+
const seen = new Map();
|
|
364
|
+
for (const space of spaces) {
|
|
365
|
+
const existing = seen.get(space.id);
|
|
366
|
+
if (!existing || (existing.type === "delegated" && space.type === "owned")) {
|
|
367
|
+
seen.set(space.id, space);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return Array.from(seen.values());
|
|
371
|
+
}
|
|
372
|
+
// ===========================================================================
|
|
373
|
+
// Create Space
|
|
374
|
+
// ===========================================================================
|
|
375
|
+
/**
|
|
376
|
+
* Create a new space.
|
|
377
|
+
*
|
|
378
|
+
* @param name - The name for the new space
|
|
379
|
+
*/
|
|
380
|
+
async create(name) {
|
|
381
|
+
if (!this.session) {
|
|
382
|
+
return err(serviceError(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME));
|
|
383
|
+
}
|
|
384
|
+
// Validate name
|
|
385
|
+
if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
386
|
+
return err(serviceError(SpaceErrorCodes.INVALID_NAME, "Space name must contain only alphanumeric characters, underscores, and hyphens", SERVICE_NAME));
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
const headers = this.invoke(this.session, "space", name, "tinycloud.space/create");
|
|
390
|
+
const response = await this.fetchFn(`${this.host}/invoke`, {
|
|
391
|
+
method: "POST",
|
|
392
|
+
headers,
|
|
393
|
+
body: JSON.stringify({ name }),
|
|
394
|
+
});
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
const errorText = await response.text();
|
|
397
|
+
if (response.status === 409) {
|
|
398
|
+
return err(serviceError(SpaceErrorCodes.ALREADY_EXISTS, `Space "${name}" already exists`, SERVICE_NAME));
|
|
399
|
+
}
|
|
400
|
+
return err(serviceError(SpaceErrorCodes.CREATION_FAILED, `Failed to create space: ${response.status} - ${errorText}`, SERVICE_NAME, { meta: { status: response.status } }));
|
|
401
|
+
}
|
|
402
|
+
const rawData = await response.json();
|
|
403
|
+
// Validate server response
|
|
404
|
+
const validationResult = validateServerCreateSpaceResponse(rawData);
|
|
405
|
+
if (!validationResult.ok) {
|
|
406
|
+
return err(serviceError(SpaceErrorCodes.CREATION_FAILED, validationResult.error.message, SERVICE_NAME, { meta: validationResult.error.meta }));
|
|
407
|
+
}
|
|
408
|
+
const spaceInfo = {
|
|
409
|
+
id: validationResult.data.id,
|
|
410
|
+
name: validationResult.data.name || name,
|
|
411
|
+
owner: validationResult.data.owner || this.userDid || "",
|
|
412
|
+
type: "owned",
|
|
413
|
+
permissions: ["*"],
|
|
414
|
+
};
|
|
415
|
+
// Cache the info
|
|
416
|
+
this.infoCache.set(spaceInfo.id, { info: spaceInfo, cachedAt: Date.now() });
|
|
417
|
+
return ok(spaceInfo);
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error creating space: ${String(error)}`, SERVICE_NAME, { cause: error instanceof Error ? error : undefined }));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// ===========================================================================
|
|
424
|
+
// Get Space
|
|
425
|
+
// ===========================================================================
|
|
426
|
+
/**
|
|
427
|
+
* Get a Space object by name or full URI.
|
|
428
|
+
*
|
|
429
|
+
* @param nameOrUri - Short name or full URI
|
|
430
|
+
*/
|
|
431
|
+
get(nameOrUri) {
|
|
432
|
+
// Resolve the full space ID
|
|
433
|
+
const spaceId = this.resolveSpaceId(nameOrUri);
|
|
434
|
+
// Check cache
|
|
435
|
+
const cached = this.spaceCache.get(spaceId);
|
|
436
|
+
if (cached) {
|
|
437
|
+
return cached;
|
|
438
|
+
}
|
|
439
|
+
// Create new Space object
|
|
440
|
+
const parsed = parseSpaceUri(spaceId);
|
|
441
|
+
const name = parsed?.name ?? this.extractNameFromId(spaceId);
|
|
442
|
+
const config = {
|
|
443
|
+
id: spaceId,
|
|
444
|
+
name,
|
|
445
|
+
createKV: this.createSpaceScopedKV.bind(this),
|
|
446
|
+
createDelegations: this.createSpaceScopedDelegations.bind(this),
|
|
447
|
+
createSharing: this.createSpaceScopedSharing.bind(this),
|
|
448
|
+
getInfo: this.getSpaceInfo.bind(this),
|
|
449
|
+
};
|
|
450
|
+
const space = new Space(config);
|
|
451
|
+
this.spaceCache.set(spaceId, space);
|
|
452
|
+
return space;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Resolve a name or URI to a full space ID.
|
|
456
|
+
*/
|
|
457
|
+
resolveSpaceId(nameOrUri) {
|
|
458
|
+
const parsed = parseSpaceUri(nameOrUri);
|
|
459
|
+
if (!parsed) {
|
|
460
|
+
// Invalid format, return as-is
|
|
461
|
+
return nameOrUri;
|
|
462
|
+
}
|
|
463
|
+
if (parsed.owner) {
|
|
464
|
+
// Full URI - return as-is
|
|
465
|
+
return nameOrUri;
|
|
466
|
+
}
|
|
467
|
+
// Short name - build full URI from user's DID
|
|
468
|
+
if (this.userDid) {
|
|
469
|
+
return buildSpaceUri(this.userDid, parsed.name);
|
|
470
|
+
}
|
|
471
|
+
// No user DID available, return as-is
|
|
472
|
+
return nameOrUri;
|
|
473
|
+
}
|
|
474
|
+
// ===========================================================================
|
|
475
|
+
// Exists Check
|
|
476
|
+
// ===========================================================================
|
|
477
|
+
/**
|
|
478
|
+
* Check if a space exists and the user has access.
|
|
479
|
+
*/
|
|
480
|
+
async exists(nameOrUri) {
|
|
481
|
+
const spaceId = this.resolveSpaceId(nameOrUri);
|
|
482
|
+
// Check info cache first
|
|
483
|
+
const cached = this.infoCache.get(spaceId);
|
|
484
|
+
if (cached && Date.now() - cached.cachedAt < this.cacheTTL) {
|
|
485
|
+
return ok(true);
|
|
486
|
+
}
|
|
487
|
+
// Query the server
|
|
488
|
+
const infoResult = await this.getSpaceInfo(spaceId);
|
|
489
|
+
return ok(infoResult.ok);
|
|
490
|
+
}
|
|
491
|
+
// ===========================================================================
|
|
492
|
+
// Space Info
|
|
493
|
+
// ===========================================================================
|
|
494
|
+
/**
|
|
495
|
+
* Get space info from server or cache.
|
|
496
|
+
*/
|
|
497
|
+
async getSpaceInfo(spaceId) {
|
|
498
|
+
// Check cache
|
|
499
|
+
const cached = this.infoCache.get(spaceId);
|
|
500
|
+
if (cached && Date.now() - cached.cachedAt < this.cacheTTL) {
|
|
501
|
+
return ok(cached.info);
|
|
502
|
+
}
|
|
503
|
+
if (!this.session) {
|
|
504
|
+
return err(serviceError(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME));
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
const headers = this.invoke(this.session, "space", spaceId, "tinycloud.space/info");
|
|
508
|
+
const response = await this.fetchFn(`${this.host}/invoke`, {
|
|
509
|
+
method: "POST",
|
|
510
|
+
headers,
|
|
511
|
+
body: JSON.stringify({ spaceId }),
|
|
512
|
+
});
|
|
513
|
+
if (!response.ok) {
|
|
514
|
+
if (response.status === 404) {
|
|
515
|
+
return err(serviceError(SpaceErrorCodes.NOT_FOUND, `Space not found: ${spaceId}`, SERVICE_NAME));
|
|
516
|
+
}
|
|
517
|
+
const errorText = await response.text();
|
|
518
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to get space info: ${response.status} - ${errorText}`, SERVICE_NAME));
|
|
519
|
+
}
|
|
520
|
+
const rawData = await response.json();
|
|
521
|
+
// Validate server response
|
|
522
|
+
const validationResult = validateServerSpaceInfoResponse(rawData);
|
|
523
|
+
if (!validationResult.ok) {
|
|
524
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, validationResult.error.message, SERVICE_NAME, { meta: validationResult.error.meta }));
|
|
525
|
+
}
|
|
526
|
+
const data = validationResult.data;
|
|
527
|
+
const spaceInfo = {
|
|
528
|
+
id: data.id,
|
|
529
|
+
name: data.name ?? this.extractNameFromId(data.id),
|
|
530
|
+
owner: data.owner,
|
|
531
|
+
type: data.type ?? (data.owner === this.userDid ? "owned" : "delegated"),
|
|
532
|
+
permissions: data.permissions,
|
|
533
|
+
expiresAt: data.expiresAt ? new Date(data.expiresAt) : undefined,
|
|
534
|
+
};
|
|
535
|
+
// Cache the info
|
|
536
|
+
this.infoCache.set(spaceId, { info: spaceInfo, cachedAt: Date.now() });
|
|
537
|
+
return ok(spaceInfo);
|
|
538
|
+
}
|
|
539
|
+
catch (error) {
|
|
540
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error getting space info: ${String(error)}`, SERVICE_NAME, { cause: error instanceof Error ? error : undefined }));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// ===========================================================================
|
|
544
|
+
// Space-Scoped Service Factories
|
|
545
|
+
// ===========================================================================
|
|
546
|
+
/**
|
|
547
|
+
* Create a space-scoped KV service.
|
|
548
|
+
*/
|
|
549
|
+
createSpaceScopedKV(spaceId) {
|
|
550
|
+
if (this.createKVServiceFn) {
|
|
551
|
+
return this.createKVServiceFn(spaceId);
|
|
552
|
+
}
|
|
553
|
+
// Return a proxy that throws a helpful error
|
|
554
|
+
return new Proxy({}, {
|
|
555
|
+
get: () => {
|
|
556
|
+
throw new Error("KV service factory not configured. Provide createKVService in SpaceServiceConfig.");
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Create space-scoped delegation operations.
|
|
562
|
+
*/
|
|
563
|
+
createSpaceScopedDelegations(spaceId) {
|
|
564
|
+
const self = this;
|
|
565
|
+
return {
|
|
566
|
+
async list() {
|
|
567
|
+
// List outgoing delegations (created by user) using tinycloud.capabilities/read
|
|
568
|
+
try {
|
|
569
|
+
// Facts contain the query params for the capabilities/read capability
|
|
570
|
+
const facts = [
|
|
571
|
+
{
|
|
572
|
+
capabilitiesReadParams: {
|
|
573
|
+
type: "list",
|
|
574
|
+
filters: { direction: "created" },
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
];
|
|
578
|
+
// The capabilities/read endpoint requires path="all" to match server routing
|
|
579
|
+
const headers = self.invoke(self.session, "capabilities", "all", "tinycloud.capabilities/read", facts);
|
|
580
|
+
const response = await self.fetchFn(`${self.host}/invoke`, {
|
|
581
|
+
method: "POST",
|
|
582
|
+
headers,
|
|
583
|
+
});
|
|
584
|
+
if (!response.ok) {
|
|
585
|
+
const errorText = await response.text();
|
|
586
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to list delegations: ${response.status} - ${errorText}`, SERVICE_NAME));
|
|
587
|
+
}
|
|
588
|
+
// Server returns { [cid: string]: DelegationInfo } - validate and transform to Delegation[]
|
|
589
|
+
const rawData = await response.json();
|
|
590
|
+
// Validate server response
|
|
591
|
+
const validationResult = validateServerDelegationsResponse(rawData);
|
|
592
|
+
if (!validationResult.ok) {
|
|
593
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, validationResult.error.message, SERVICE_NAME, { meta: validationResult.error.meta }));
|
|
594
|
+
}
|
|
595
|
+
const delegations = transformServerDelegations(validationResult.data, spaceId);
|
|
596
|
+
return ok(delegations);
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error listing delegations: ${String(error)}`, SERVICE_NAME));
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
async listReceived() {
|
|
603
|
+
// List incoming delegations (received by user) using tinycloud.capabilities/read
|
|
604
|
+
try {
|
|
605
|
+
// Facts contain the query params for the capabilities/read capability
|
|
606
|
+
const facts = [
|
|
607
|
+
{
|
|
608
|
+
capabilitiesReadParams: {
|
|
609
|
+
type: "list",
|
|
610
|
+
filters: { direction: "received" },
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
];
|
|
614
|
+
// The capabilities/read endpoint requires path="all" to match server routing
|
|
615
|
+
const headers = self.invoke(self.session, "capabilities", "all", "tinycloud.capabilities/read", facts);
|
|
616
|
+
const response = await self.fetchFn(`${self.host}/invoke`, {
|
|
617
|
+
method: "POST",
|
|
618
|
+
headers,
|
|
619
|
+
});
|
|
620
|
+
if (!response.ok) {
|
|
621
|
+
const errorText = await response.text();
|
|
622
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to list received delegations: ${response.status} - ${errorText}`, SERVICE_NAME));
|
|
623
|
+
}
|
|
624
|
+
// Server returns { [cid: string]: DelegationInfo } - validate and transform to Delegation[]
|
|
625
|
+
const rawData = await response.json();
|
|
626
|
+
// Validate server response
|
|
627
|
+
const validationResult = validateServerDelegationsResponse(rawData);
|
|
628
|
+
if (!validationResult.ok) {
|
|
629
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, validationResult.error.message, SERVICE_NAME, { meta: validationResult.error.meta }));
|
|
630
|
+
}
|
|
631
|
+
const delegations = transformServerDelegations(validationResult.data, spaceId);
|
|
632
|
+
return ok(delegations);
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error listing received delegations: ${String(error)}`, SERVICE_NAME));
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
async create(params) {
|
|
639
|
+
// Use the platform-provided createDelegation function (SIWE-based flow)
|
|
640
|
+
if (self.createDelegationFn) {
|
|
641
|
+
return self.createDelegationFn({ ...params, spaceId });
|
|
642
|
+
}
|
|
643
|
+
// Fallback: return error if no createDelegation function provided
|
|
644
|
+
// The old invoke-based approach doesn't work because /delegate expects
|
|
645
|
+
// SIWE delegation headers, not invocation headers
|
|
646
|
+
return err(serviceError(SpaceErrorCodes.NOT_INITIALIZED, "Delegation creation requires a createDelegation function. " +
|
|
647
|
+
"This should be provided by the platform SDK (web-sdk or node-sdk).", SERVICE_NAME));
|
|
648
|
+
},
|
|
649
|
+
async revoke(cid) {
|
|
650
|
+
try {
|
|
651
|
+
const headers = self.invoke(self.session, "delegation", cid, "tinycloud.delegation/revoke");
|
|
652
|
+
const response = await self.fetchFn(`${self.host}/revoke`, {
|
|
653
|
+
method: "POST",
|
|
654
|
+
headers,
|
|
655
|
+
body: JSON.stringify({ cid, spaceId }),
|
|
656
|
+
});
|
|
657
|
+
if (!response.ok) {
|
|
658
|
+
const errorText = await response.text();
|
|
659
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Failed to revoke delegation: ${response.status} - ${errorText}`, SERVICE_NAME));
|
|
660
|
+
}
|
|
661
|
+
return ok(undefined);
|
|
662
|
+
}
|
|
663
|
+
catch (error) {
|
|
664
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, `Network error revoking delegation: ${String(error)}`, SERVICE_NAME));
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Create space-scoped sharing operations.
|
|
671
|
+
*
|
|
672
|
+
* When a SharingService is configured, delegates to client-side v2 sharing.
|
|
673
|
+
* V2 sharing links are self-contained with embedded private keys - no server tracking.
|
|
674
|
+
*/
|
|
675
|
+
createSpaceScopedSharing(spaceId) {
|
|
676
|
+
const self = this;
|
|
677
|
+
return {
|
|
678
|
+
async generate(params) {
|
|
679
|
+
// Use v2 SharingService when available (client-side sharing links)
|
|
680
|
+
if (self.sharingService) {
|
|
681
|
+
// Note: SharingService uses session.spaceId for the space.
|
|
682
|
+
// For space-scoped sharing on delegated spaces, ensure the session
|
|
683
|
+
// is configured for the correct space before calling generate().
|
|
684
|
+
const result = await self.sharingService.generate(params);
|
|
685
|
+
if (!result.ok) {
|
|
686
|
+
return err(serviceError(SpaceErrorCodes.NETWORK_ERROR, result.error.message || "Failed to generate share link", SERVICE_NAME));
|
|
687
|
+
}
|
|
688
|
+
return ok(result.data);
|
|
689
|
+
}
|
|
690
|
+
// Fallback: return error since server endpoint doesn't exist
|
|
691
|
+
return err(serviceError(SpaceErrorCodes.NOT_INITIALIZED, "SharingService not configured. V2 sharing requires a SharingService instance.", SERVICE_NAME));
|
|
692
|
+
},
|
|
693
|
+
async list() {
|
|
694
|
+
// V2 sharing links are self-contained (not server-tracked)
|
|
695
|
+
// This operation is not supported in the v2 spec
|
|
696
|
+
return err(serviceError(SpaceErrorCodes.NOT_INITIALIZED, "Listing share links is not supported in v2. Share links are self-contained tokens that are not tracked on the server.", SERVICE_NAME));
|
|
697
|
+
},
|
|
698
|
+
async revoke(token) {
|
|
699
|
+
// V2 sharing links are revoked by revoking the underlying delegation
|
|
700
|
+
// This requires the delegation CID, not the share token
|
|
701
|
+
return err(serviceError(SpaceErrorCodes.NOT_INITIALIZED, "Revoking share links by token is not supported in v2. To revoke access, revoke the underlying delegation using space.delegations.revoke(cid).", SERVICE_NAME));
|
|
702
|
+
},
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Create a new SpaceService instance.
|
|
708
|
+
*
|
|
709
|
+
* @param config - Service configuration
|
|
710
|
+
* @returns A new SpaceService instance
|
|
711
|
+
*/
|
|
712
|
+
export function createSpaceService(config) {
|
|
713
|
+
return new SpaceService(config);
|
|
714
|
+
}
|
|
715
|
+
//# sourceMappingURL=SpaceService.js.map
|