@tinycloud/sdk-core 2.0.0 → 2.0.2-beta.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.
Files changed (188) hide show
  1. package/dist/index.cjs +3816 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +3867 -0
  4. package/dist/index.d.ts +3861 -21
  5. package/dist/index.js +3767 -61
  6. package/dist/index.js.map +1 -1
  7. package/package.json +6 -5
  8. package/dist/TinyCloud.d.ts +0 -271
  9. package/dist/TinyCloud.d.ts.map +0 -1
  10. package/dist/TinyCloud.js +0 -458
  11. package/dist/TinyCloud.js.map +0 -1
  12. package/dist/TinyCloud.schema.d.ts +0 -173
  13. package/dist/TinyCloud.schema.d.ts.map +0 -1
  14. package/dist/TinyCloud.schema.js +0 -136
  15. package/dist/TinyCloud.schema.js.map +0 -1
  16. package/dist/TinyCloud.schema.test.d.ts +0 -5
  17. package/dist/TinyCloud.schema.test.d.ts.map +0 -1
  18. package/dist/TinyCloud.schema.test.js +0 -286
  19. package/dist/TinyCloud.schema.test.js.map +0 -1
  20. package/dist/authorization/CapabilityKeyRegistry.d.ts +0 -317
  21. package/dist/authorization/CapabilityKeyRegistry.d.ts.map +0 -1
  22. package/dist/authorization/CapabilityKeyRegistry.js +0 -509
  23. package/dist/authorization/CapabilityKeyRegistry.js.map +0 -1
  24. package/dist/authorization/authorization.schema.d.ts +0 -233
  25. package/dist/authorization/authorization.schema.d.ts.map +0 -1
  26. package/dist/authorization/authorization.schema.js +0 -220
  27. package/dist/authorization/authorization.schema.js.map +0 -1
  28. package/dist/authorization/authorization.schema.test.d.ts +0 -5
  29. package/dist/authorization/authorization.schema.test.d.ts.map +0 -1
  30. package/dist/authorization/authorization.schema.test.js +0 -618
  31. package/dist/authorization/authorization.schema.test.js.map +0 -1
  32. package/dist/authorization/index.d.ts +0 -38
  33. package/dist/authorization/index.d.ts.map +0 -1
  34. package/dist/authorization/index.js +0 -52
  35. package/dist/authorization/index.js.map +0 -1
  36. package/dist/authorization/spaceCreation.d.ts +0 -96
  37. package/dist/authorization/spaceCreation.d.ts.map +0 -1
  38. package/dist/authorization/spaceCreation.js +0 -35
  39. package/dist/authorization/spaceCreation.js.map +0 -1
  40. package/dist/authorization/spaceCreation.schema.d.ts +0 -67
  41. package/dist/authorization/spaceCreation.schema.d.ts.map +0 -1
  42. package/dist/authorization/spaceCreation.schema.js +0 -95
  43. package/dist/authorization/spaceCreation.schema.js.map +0 -1
  44. package/dist/authorization/spaceCreation.schema.test.d.ts +0 -5
  45. package/dist/authorization/spaceCreation.schema.test.d.ts.map +0 -1
  46. package/dist/authorization/spaceCreation.schema.test.js +0 -168
  47. package/dist/authorization/spaceCreation.schema.test.js.map +0 -1
  48. package/dist/authorization/strategies.d.ts +0 -134
  49. package/dist/authorization/strategies.d.ts.map +0 -1
  50. package/dist/authorization/strategies.js +0 -15
  51. package/dist/authorization/strategies.js.map +0 -1
  52. package/dist/authorization/strategies.schema.d.ts +0 -185
  53. package/dist/authorization/strategies.schema.d.ts.map +0 -1
  54. package/dist/authorization/strategies.schema.js +0 -147
  55. package/dist/authorization/strategies.schema.js.map +0 -1
  56. package/dist/authorization/strategies.schema.test.d.ts +0 -5
  57. package/dist/authorization/strategies.schema.test.d.ts.map +0 -1
  58. package/dist/authorization/strategies.schema.test.js +0 -253
  59. package/dist/authorization/strategies.schema.test.js.map +0 -1
  60. package/dist/client-types.d.ts +0 -128
  61. package/dist/client-types.d.ts.map +0 -1
  62. package/dist/client-types.js +0 -40
  63. package/dist/client-types.js.map +0 -1
  64. package/dist/delegations/DelegationManager.d.ts +0 -164
  65. package/dist/delegations/DelegationManager.d.ts.map +0 -1
  66. package/dist/delegations/DelegationManager.js +0 -428
  67. package/dist/delegations/DelegationManager.js.map +0 -1
  68. package/dist/delegations/SharingService.d.ts +0 -341
  69. package/dist/delegations/SharingService.d.ts.map +0 -1
  70. package/dist/delegations/SharingService.js +0 -722
  71. package/dist/delegations/SharingService.js.map +0 -1
  72. package/dist/delegations/SharingService.schema.d.ts +0 -409
  73. package/dist/delegations/SharingService.schema.d.ts.map +0 -1
  74. package/dist/delegations/SharingService.schema.js +0 -222
  75. package/dist/delegations/SharingService.schema.js.map +0 -1
  76. package/dist/delegations/index.d.ts +0 -38
  77. package/dist/delegations/index.d.ts.map +0 -1
  78. package/dist/delegations/index.js +0 -42
  79. package/dist/delegations/index.js.map +0 -1
  80. package/dist/delegations/types.d.ts +0 -13
  81. package/dist/delegations/types.d.ts.map +0 -1
  82. package/dist/delegations/types.js +0 -42
  83. package/dist/delegations/types.js.map +0 -1
  84. package/dist/delegations/types.schema.d.ts +0 -1773
  85. package/dist/delegations/types.schema.d.ts.map +0 -1
  86. package/dist/delegations/types.schema.js +0 -535
  87. package/dist/delegations/types.schema.js.map +0 -1
  88. package/dist/delegations/types.schema.test.d.ts +0 -5
  89. package/dist/delegations/types.schema.test.d.ts.map +0 -1
  90. package/dist/delegations/types.schema.test.js +0 -627
  91. package/dist/delegations/types.schema.test.js.map +0 -1
  92. package/dist/ens.d.ts +0 -17
  93. package/dist/ens.d.ts.map +0 -1
  94. package/dist/ens.js +0 -10
  95. package/dist/ens.js.map +0 -1
  96. package/dist/index.d.ts.map +0 -1
  97. package/dist/json-schema.d.ts +0 -327
  98. package/dist/json-schema.d.ts.map +0 -1
  99. package/dist/json-schema.js +0 -703
  100. package/dist/json-schema.js.map +0 -1
  101. package/dist/json-schema.test.d.ts +0 -7
  102. package/dist/json-schema.test.d.ts.map +0 -1
  103. package/dist/json-schema.test.js +0 -365
  104. package/dist/json-schema.test.js.map +0 -1
  105. package/dist/notifications.d.ts +0 -33
  106. package/dist/notifications.d.ts.map +0 -1
  107. package/dist/notifications.js +0 -15
  108. package/dist/notifications.js.map +0 -1
  109. package/dist/signer.d.ts +0 -28
  110. package/dist/signer.d.ts.map +0 -1
  111. package/dist/signer.js +0 -2
  112. package/dist/signer.js.map +0 -1
  113. package/dist/space.d.ts +0 -57
  114. package/dist/space.d.ts.map +0 -1
  115. package/dist/space.js +0 -87
  116. package/dist/space.js.map +0 -1
  117. package/dist/space.schema.d.ts +0 -65
  118. package/dist/space.schema.d.ts.map +0 -1
  119. package/dist/space.schema.js +0 -65
  120. package/dist/space.schema.js.map +0 -1
  121. package/dist/space.schema.test.d.ts +0 -5
  122. package/dist/space.schema.test.d.ts.map +0 -1
  123. package/dist/space.schema.test.js +0 -148
  124. package/dist/space.schema.test.js.map +0 -1
  125. package/dist/space.test.d.ts +0 -5
  126. package/dist/space.test.d.ts.map +0 -1
  127. package/dist/space.test.js +0 -87
  128. package/dist/space.test.js.map +0 -1
  129. package/dist/spaces/Space.d.ts +0 -175
  130. package/dist/spaces/Space.d.ts.map +0 -1
  131. package/dist/spaces/Space.js +0 -84
  132. package/dist/spaces/Space.js.map +0 -1
  133. package/dist/spaces/SpaceService.d.ts +0 -291
  134. package/dist/spaces/SpaceService.d.ts.map +0 -1
  135. package/dist/spaces/SpaceService.js +0 -740
  136. package/dist/spaces/SpaceService.js.map +0 -1
  137. package/dist/spaces/index.d.ts +0 -11
  138. package/dist/spaces/index.d.ts.map +0 -1
  139. package/dist/spaces/index.js +0 -22
  140. package/dist/spaces/index.js.map +0 -1
  141. package/dist/spaces/spaces.schema.d.ts +0 -421
  142. package/dist/spaces/spaces.schema.d.ts.map +0 -1
  143. package/dist/spaces/spaces.schema.js +0 -342
  144. package/dist/spaces/spaces.schema.js.map +0 -1
  145. package/dist/spaces/spaces.schema.test.d.ts +0 -5
  146. package/dist/spaces/spaces.schema.test.d.ts.map +0 -1
  147. package/dist/spaces/spaces.schema.test.js +0 -471
  148. package/dist/spaces/spaces.schema.test.js.map +0 -1
  149. package/dist/storage.d.ts +0 -47
  150. package/dist/storage.d.ts.map +0 -1
  151. package/dist/storage.js +0 -14
  152. package/dist/storage.js.map +0 -1
  153. package/dist/storage.schema.d.ts +0 -291
  154. package/dist/storage.schema.d.ts.map +0 -1
  155. package/dist/storage.schema.js +0 -189
  156. package/dist/storage.schema.js.map +0 -1
  157. package/dist/storage.schema.test.d.ts +0 -5
  158. package/dist/storage.schema.test.d.ts.map +0 -1
  159. package/dist/storage.schema.test.js +0 -346
  160. package/dist/storage.schema.test.js.map +0 -1
  161. package/dist/userAuthorization.d.ts +0 -117
  162. package/dist/userAuthorization.d.ts.map +0 -1
  163. package/dist/userAuthorization.js +0 -3
  164. package/dist/userAuthorization.js.map +0 -1
  165. package/dist/userAuthorization.schema.d.ts +0 -260
  166. package/dist/userAuthorization.schema.d.ts.map +0 -1
  167. package/dist/userAuthorization.schema.js +0 -169
  168. package/dist/userAuthorization.schema.js.map +0 -1
  169. package/dist/userAuthorization.schema.test.d.ts +0 -5
  170. package/dist/userAuthorization.schema.test.d.ts.map +0 -1
  171. package/dist/userAuthorization.schema.test.js +0 -356
  172. package/dist/userAuthorization.schema.test.js.map +0 -1
  173. package/dist/version.d.ts +0 -32
  174. package/dist/version.d.ts.map +0 -1
  175. package/dist/version.js +0 -59
  176. package/dist/version.js.map +0 -1
  177. package/dist/wasm-validation.d.ts +0 -291
  178. package/dist/wasm-validation.d.ts.map +0 -1
  179. package/dist/wasm-validation.js +0 -221
  180. package/dist/wasm-validation.js.map +0 -1
  181. package/dist/wasm-validation.test.d.ts +0 -5
  182. package/dist/wasm-validation.test.d.ts.map +0 -1
  183. package/dist/wasm-validation.test.js +0 -233
  184. package/dist/wasm-validation.test.js.map +0 -1
  185. package/dist/wasm.d.ts +0 -66
  186. package/dist/wasm.d.ts.map +0 -1
  187. package/dist/wasm.js +0 -10
  188. package/dist/wasm.js.map +0 -1
package/dist/index.cjs ADDED
@@ -0,0 +1,3816 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AutoApproveSpaceCreationHandler: () => AutoApproveSpaceCreationHandler,
24
+ CapabilityKeyRegistry: () => CapabilityKeyRegistry,
25
+ CapabilityKeyRegistryErrorCodes: () => CapabilityKeyRegistryErrorCodes,
26
+ ClientSessionSchema: () => ClientSessionSchema,
27
+ DataVaultService: () => import_sdk_services4.DataVaultService,
28
+ DatabaseHandle: () => import_sdk_services4.DatabaseHandle,
29
+ DelegationErrorCodes: () => DelegationErrorCodes,
30
+ DelegationManager: () => DelegationManager,
31
+ DuckDbAction: () => import_sdk_services4.DuckDbAction,
32
+ DuckDbDatabaseHandle: () => import_sdk_services4.DuckDbDatabaseHandle,
33
+ DuckDbService: () => import_sdk_services4.DuckDbService,
34
+ EnsDataSchema: () => EnsDataSchema,
35
+ ErrorCodes: () => import_sdk_services4.ErrorCodes,
36
+ KVService: () => import_sdk_services4.KVService,
37
+ PrefixedKVService: () => import_sdk_services4.PrefixedKVService,
38
+ ProtocolMismatchError: () => ProtocolMismatchError,
39
+ SQLAction: () => import_sdk_services4.SQLAction,
40
+ SQLService: () => import_sdk_services4.SQLService,
41
+ ServiceContext: () => import_sdk_services4.ServiceContext,
42
+ SharingService: () => SharingService,
43
+ SilentNotificationHandler: () => SilentNotificationHandler,
44
+ SiweConfigSchema: () => SiweConfigSchema,
45
+ SiweMessage: () => import_siwe.SiweMessage,
46
+ Space: () => Space,
47
+ SpaceErrorCodes: () => SpaceErrorCodes,
48
+ SpaceService: () => SpaceService,
49
+ TinyCloud: () => TinyCloud,
50
+ UnsupportedFeatureError: () => UnsupportedFeatureError,
51
+ VaultHeaders: () => import_sdk_services4.VaultHeaders,
52
+ VaultPublicSpaceKVActions: () => import_sdk_services4.VaultPublicSpaceKVActions,
53
+ VersionCheckError: () => VersionCheckError,
54
+ activateSessionWithHost: () => activateSessionWithHost,
55
+ buildSpaceUri: () => buildSpaceUri,
56
+ checkNodeInfo: () => checkNodeInfo,
57
+ createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
58
+ createSharingService: () => createSharingService,
59
+ createSpaceService: () => createSpaceService,
60
+ createVaultCrypto: () => import_sdk_services4.createVaultCrypto,
61
+ defaultRetryPolicy: () => import_sdk_services4.defaultRetryPolicy,
62
+ defaultSignStrategy: () => defaultSignStrategy,
63
+ defaultSpaceCreationHandler: () => defaultSpaceCreationHandler,
64
+ err: () => import_sdk_services4.err,
65
+ fetchPeerId: () => fetchPeerId,
66
+ makePublicSpaceId: () => makePublicSpaceId,
67
+ ok: () => import_sdk_services4.ok,
68
+ parseSpaceUri: () => parseSpaceUri,
69
+ serviceError: () => import_sdk_services4.serviceError,
70
+ submitHostDelegation: () => submitHostDelegation,
71
+ validateClientSession: () => validateClientSession,
72
+ validatePersistedSessionData: () => validatePersistedSessionData
73
+ });
74
+ module.exports = __toCommonJS(index_exports);
75
+
76
+ // src/client-types.ts
77
+ var import_zod = require("zod");
78
+ var import_siwe = require("siwe");
79
+ var EnsDataSchema = import_zod.z.object({
80
+ domain: import_zod.z.string().nullable().optional(),
81
+ avatarUrl: import_zod.z.string().nullable().optional()
82
+ });
83
+ var SiweConfigSchema = import_zod.z.object({
84
+ domain: import_zod.z.string().optional(),
85
+ uri: import_zod.z.string().optional(),
86
+ chainId: import_zod.z.number().optional(),
87
+ statement: import_zod.z.string().optional(),
88
+ nonce: import_zod.z.string().optional(),
89
+ expirationTime: import_zod.z.string().optional(),
90
+ notBefore: import_zod.z.string().optional(),
91
+ requestId: import_zod.z.string().optional(),
92
+ resources: import_zod.z.array(import_zod.z.string()).optional()
93
+ }).passthrough();
94
+ var ClientSessionSchema = import_zod.z.object({
95
+ address: import_zod.z.string(),
96
+ walletAddress: import_zod.z.string(),
97
+ chainId: import_zod.z.number(),
98
+ sessionKey: import_zod.z.string(),
99
+ siwe: import_zod.z.string(),
100
+ signature: import_zod.z.string(),
101
+ ens: EnsDataSchema.optional()
102
+ });
103
+ function validateClientSession(data) {
104
+ const result = ClientSessionSchema.safeParse(data);
105
+ return result.success ? result.data : null;
106
+ }
107
+
108
+ // src/notifications.ts
109
+ var SilentNotificationHandler = class {
110
+ success() {
111
+ }
112
+ warning() {
113
+ }
114
+ error() {
115
+ }
116
+ };
117
+
118
+ // src/storage.schema.ts
119
+ var import_zod2 = require("zod");
120
+ var ethereumAddressPattern = /^0x[a-fA-F0-9]{40}$/;
121
+ var EnsDataSchema2 = import_zod2.z.object({
122
+ /** ENS name/domain. */
123
+ domain: import_zod2.z.string().nullable().optional(),
124
+ /** ENS avatar URL. */
125
+ avatarUrl: import_zod2.z.string().nullable().optional()
126
+ });
127
+ var PersistedTinyCloudSessionSchema = import_zod2.z.object({
128
+ /** The delegation header containing the UCAN */
129
+ delegationHeader: import_zod2.z.object({
130
+ Authorization: import_zod2.z.string()
131
+ }),
132
+ /** The delegation CID */
133
+ delegationCid: import_zod2.z.string(),
134
+ /** The space ID for this session */
135
+ spaceId: import_zod2.z.string(),
136
+ /** Additional spaces included in this session's capabilities. Key is logical name, value is full spaceId URI */
137
+ spaces: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
138
+ /** The verification method DID */
139
+ verificationMethod: import_zod2.z.string()
140
+ });
141
+ var PersistedSessionDataSchema = import_zod2.z.object({
142
+ /** User's Ethereum address */
143
+ address: import_zod2.z.string().regex(ethereumAddressPattern, "Invalid Ethereum address"),
144
+ /** EIP-155 Chain ID */
145
+ chainId: import_zod2.z.number().int().positive(),
146
+ /** Session key in JWK format (stringified) */
147
+ sessionKey: import_zod2.z.string(),
148
+ /** The signed SIWE message */
149
+ siwe: import_zod2.z.string(),
150
+ /** User's signature of the SIWE message */
151
+ signature: import_zod2.z.string(),
152
+ /** TinyCloud delegation data if available */
153
+ tinycloudSession: PersistedTinyCloudSessionSchema.optional(),
154
+ /** Session expiration timestamp (ISO 8601 with timezone offset) */
155
+ expiresAt: import_zod2.z.string().datetime({ offset: true }),
156
+ /** Session creation timestamp (ISO 8601 with timezone offset) */
157
+ createdAt: import_zod2.z.string().datetime({ offset: true }),
158
+ /** Schema version for migrations */
159
+ version: import_zod2.z.string(),
160
+ /** Optional ENS data */
161
+ ens: EnsDataSchema2.optional()
162
+ });
163
+ var TinyCloudSessionSchema = import_zod2.z.object({
164
+ /** User's Ethereum address */
165
+ address: import_zod2.z.string().regex(ethereumAddressPattern, "Invalid Ethereum address"),
166
+ /** EIP-155 Chain ID */
167
+ chainId: import_zod2.z.number().int().positive(),
168
+ /** Session key ID */
169
+ sessionKey: import_zod2.z.string(),
170
+ /** The space ID for this session */
171
+ spaceId: import_zod2.z.string(),
172
+ /** Additional spaces included in this session's capabilities. Key is logical name, value is full spaceId URI */
173
+ spaces: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
174
+ /** The delegation CID */
175
+ delegationCid: import_zod2.z.string(),
176
+ /** The delegation header for API calls */
177
+ delegationHeader: import_zod2.z.object({
178
+ Authorization: import_zod2.z.string()
179
+ }),
180
+ /** The verification method DID */
181
+ verificationMethod: import_zod2.z.string(),
182
+ /** The session key JWK (required for invoke operations) */
183
+ jwk: import_zod2.z.object({}).passthrough(),
184
+ /** The signed SIWE message */
185
+ siwe: import_zod2.z.string(),
186
+ /** User's signature of the SIWE message */
187
+ signature: import_zod2.z.string()
188
+ });
189
+ function validatePersistedSessionData(data) {
190
+ const result = PersistedSessionDataSchema.safeParse(data);
191
+ if (!result.success) {
192
+ return {
193
+ ok: false,
194
+ error: {
195
+ code: "VALIDATION_ERROR",
196
+ message: result.error.message,
197
+ service: "session",
198
+ meta: { issues: result.error.issues }
199
+ }
200
+ };
201
+ }
202
+ return { ok: true, data: result.data };
203
+ }
204
+
205
+ // src/TinyCloud.ts
206
+ var import_sdk_services2 = require("@tinycloud/sdk-services");
207
+
208
+ // src/spaces/SpaceService.ts
209
+ var import_sdk_services = require("@tinycloud/sdk-services");
210
+
211
+ // src/spaces/Space.ts
212
+ var Space = class {
213
+ /**
214
+ * Create a new Space instance.
215
+ *
216
+ * @param config - Space configuration
217
+ */
218
+ constructor(config) {
219
+ this._id = config.id;
220
+ this._name = config.name;
221
+ this._kv = config.createKV(config.id);
222
+ this._delegations = config.createDelegations(config.id);
223
+ this._sharing = config.createSharing(config.id);
224
+ this._getInfo = config.getInfo;
225
+ }
226
+ /**
227
+ * The space identifier (full URI).
228
+ */
229
+ get id() {
230
+ return this._id;
231
+ }
232
+ /**
233
+ * The short name of the space.
234
+ */
235
+ get name() {
236
+ return this._name;
237
+ }
238
+ /**
239
+ * KV operations scoped to this space.
240
+ */
241
+ get kv() {
242
+ return this._kv;
243
+ }
244
+ /**
245
+ * Delegation operations scoped to this space.
246
+ */
247
+ get delegations() {
248
+ return this._delegations;
249
+ }
250
+ /**
251
+ * Sharing operations scoped to this space.
252
+ */
253
+ get sharing() {
254
+ return this._sharing;
255
+ }
256
+ /**
257
+ * Get space metadata.
258
+ *
259
+ * @returns Result containing space information
260
+ */
261
+ async info() {
262
+ return this._getInfo(this._id);
263
+ }
264
+ };
265
+
266
+ // src/spaces/spaces.schema.ts
267
+ var import_zod4 = require("zod");
268
+
269
+ // src/delegations/types.schema.ts
270
+ var import_zod3 = require("zod");
271
+ var JWKSchema = import_zod3.z.object({
272
+ /** Key type (e.g., "EC", "RSA", "OKP") */
273
+ kty: import_zod3.z.string(),
274
+ /** Curve for EC/OKP keys (e.g., "P-256", "Ed25519") */
275
+ crv: import_zod3.z.string().optional(),
276
+ /** X coordinate for EC keys, public key for OKP */
277
+ x: import_zod3.z.string().optional(),
278
+ /** Y coordinate for EC keys */
279
+ y: import_zod3.z.string().optional(),
280
+ /** Private key value (d parameter) */
281
+ d: import_zod3.z.string().optional(),
282
+ /** Public exponent for RSA keys */
283
+ e: import_zod3.z.string().optional(),
284
+ /** Modulus for RSA keys */
285
+ n: import_zod3.z.string().optional(),
286
+ /** Key ID */
287
+ kid: import_zod3.z.string().optional(),
288
+ /** Algorithm */
289
+ alg: import_zod3.z.string().optional(),
290
+ /** Key use (e.g., "sig", "enc") */
291
+ use: import_zod3.z.string().optional(),
292
+ /** Key operations (e.g., ["sign", "verify"]) */
293
+ key_ops: import_zod3.z.array(import_zod3.z.string()).optional()
294
+ });
295
+ var KeyTypeSchema = import_zod3.z.enum(["main", "session", "ingested"]);
296
+ var KeyInfoSchema = import_zod3.z.object({
297
+ /** Unique identifier for this key */
298
+ id: import_zod3.z.string(),
299
+ /** DID associated with this key */
300
+ did: import_zod3.z.string(),
301
+ /** Type of key determining its authority level */
302
+ type: KeyTypeSchema,
303
+ /** Private key in JWK format */
304
+ jwk: JWKSchema.optional(),
305
+ /** Priority for key selection (lower = higher priority) */
306
+ priority: import_zod3.z.number()
307
+ });
308
+ var DelegationErrorSchema = import_zod3.z.object({
309
+ /** Error code for programmatic handling */
310
+ code: import_zod3.z.string(),
311
+ /** Human-readable error message */
312
+ message: import_zod3.z.string(),
313
+ /** The service that produced the error */
314
+ service: import_zod3.z.literal("delegation"),
315
+ /** Original error if wrapping another error */
316
+ cause: import_zod3.z.instanceof(Error).optional(),
317
+ /** Additional metadata about the error */
318
+ meta: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional()
319
+ });
320
+ var DelegationErrorCodes = {
321
+ AUTH_REQUIRED: "AUTH_REQUIRED",
322
+ AUTH_EXPIRED: "AUTH_EXPIRED",
323
+ NOT_INITIALIZED: "NOT_INITIALIZED",
324
+ NOT_FOUND: "NOT_FOUND",
325
+ REVOKED: "REVOKED",
326
+ NETWORK_ERROR: "NETWORK_ERROR",
327
+ TIMEOUT: "TIMEOUT",
328
+ ABORTED: "ABORTED",
329
+ INVALID_INPUT: "INVALID_INPUT",
330
+ PERMISSION_DENIED: "PERMISSION_DENIED",
331
+ CREATION_FAILED: "CREATION_FAILED",
332
+ REVOCATION_FAILED: "REVOCATION_FAILED",
333
+ INVALID_TOKEN: "INVALID_TOKEN",
334
+ KV_SERVICE_UNAVAILABLE: "KV_SERVICE_UNAVAILABLE",
335
+ DATA_FETCH_FAILED: "DATA_FETCH_FAILED",
336
+ VALIDATION_ERROR: "VALIDATION_ERROR"
337
+ };
338
+ var DelegationSchema = import_zod3.z.object({
339
+ /** Content identifier (CID) of the delegation */
340
+ cid: import_zod3.z.string(),
341
+ /** DID of the delegate (the party receiving the delegation) */
342
+ delegateDID: import_zod3.z.string(),
343
+ /** Space ID this delegation applies to */
344
+ spaceId: import_zod3.z.string(),
345
+ /** Resource path this delegation grants access to */
346
+ path: import_zod3.z.string(),
347
+ /** Actions this delegation authorizes */
348
+ actions: import_zod3.z.array(import_zod3.z.string()),
349
+ /** When this delegation expires (accepts Date or ISO string from JSON) */
350
+ expiry: import_zod3.z.coerce.date(),
351
+ /** Whether this delegation has been revoked */
352
+ isRevoked: import_zod3.z.boolean(),
353
+ /** DID of the delegator (the party granting the delegation) */
354
+ delegatorDID: import_zod3.z.string().optional(),
355
+ /** When this delegation was created (accepts Date or ISO string from JSON) */
356
+ createdAt: import_zod3.z.coerce.date().optional(),
357
+ /** Parent delegation CID if this is a sub-delegation */
358
+ parentCid: import_zod3.z.string().optional(),
359
+ /** Whether sub-delegation is allowed */
360
+ allowSubDelegation: import_zod3.z.boolean().optional(),
361
+ /** Authorization header (UCAN bearer token) */
362
+ authHeader: import_zod3.z.string().optional()
363
+ });
364
+ var CapabilityEntrySchema = import_zod3.z.object({
365
+ /** Resource URI this capability applies to */
366
+ resource: import_zod3.z.string(),
367
+ /** Action this capability authorizes */
368
+ action: import_zod3.z.string(),
369
+ /** Keys that can exercise this capability, ordered by priority */
370
+ keys: import_zod3.z.array(KeyInfoSchema),
371
+ /** The delegation that grants this capability */
372
+ delegation: DelegationSchema,
373
+ /** When this capability expires (accepts Date or ISO string from JSON) */
374
+ expiresAt: import_zod3.z.coerce.date().optional()
375
+ });
376
+ var DelegationRecordSchema = import_zod3.z.object({
377
+ /** Content identifier (CID) of the delegation */
378
+ cid: import_zod3.z.string(),
379
+ /** Space ID this delegation applies to */
380
+ spaceId: import_zod3.z.string(),
381
+ /** DID of the delegator (grantor) */
382
+ delegator: import_zod3.z.string(),
383
+ /** DID of the delegatee (recipient) */
384
+ delegatee: import_zod3.z.string(),
385
+ /** Key ID used to sign/exercise this delegation */
386
+ keyId: import_zod3.z.string().optional(),
387
+ /** Resource path pattern this delegation grants access to */
388
+ path: import_zod3.z.string(),
389
+ /** Actions this delegation authorizes */
390
+ actions: import_zod3.z.array(import_zod3.z.string()),
391
+ /** When this delegation expires (accepts Date or ISO string from JSON) */
392
+ expiry: import_zod3.z.coerce.date().optional(),
393
+ /** When this delegation becomes valid (not before) (accepts Date or ISO string) */
394
+ notBefore: import_zod3.z.coerce.date().optional(),
395
+ /** Whether this delegation has been revoked */
396
+ isRevoked: import_zod3.z.boolean(),
397
+ /** When this delegation was created (accepts Date or ISO string from JSON) */
398
+ createdAt: import_zod3.z.coerce.date(),
399
+ /** Parent delegation CID if this is a sub-delegation */
400
+ parentCid: import_zod3.z.string().optional()
401
+ });
402
+ var CreateDelegationParamsSchema = import_zod3.z.object({
403
+ /** DID of the delegate (the party receiving the delegation) */
404
+ delegateDID: import_zod3.z.string(),
405
+ /** Resource path this delegation grants access to */
406
+ path: import_zod3.z.string(),
407
+ /** Actions to authorize */
408
+ actions: import_zod3.z.array(import_zod3.z.string()),
409
+ /** When this delegation expires (accepts Date or ISO string) */
410
+ expiry: import_zod3.z.coerce.date().optional(),
411
+ /** Whether to disable sub-delegation */
412
+ disableSubDelegation: import_zod3.z.boolean().optional(),
413
+ /** Optional statement for the SIWE message */
414
+ statement: import_zod3.z.string().optional()
415
+ });
416
+ var DelegationChainSchema = import_zod3.z.array(DelegationSchema);
417
+ var DelegationChainV2Schema = import_zod3.z.object({
418
+ /** The root delegation from the original authority */
419
+ root: DelegationSchema,
420
+ /** Intermediate delegations in the chain (may be empty) */
421
+ chain: import_zod3.z.array(DelegationSchema),
422
+ /** The final delegation to the current user */
423
+ leaf: DelegationSchema
424
+ });
425
+ var DelegationDirectionSchema = import_zod3.z.enum(["granted", "received", "all"]);
426
+ var DelegationFiltersSchema = import_zod3.z.object({
427
+ /** Filter by delegation direction */
428
+ direction: DelegationDirectionSchema.optional(),
429
+ /** Filter by resource path pattern */
430
+ path: import_zod3.z.string().optional(),
431
+ /** Filter by required actions */
432
+ actions: import_zod3.z.array(import_zod3.z.string()).optional(),
433
+ /** Include revoked delegations */
434
+ includeRevoked: import_zod3.z.boolean().optional(),
435
+ /** Filter by delegator DID */
436
+ delegator: import_zod3.z.string().optional(),
437
+ /** Filter by delegatee DID */
438
+ delegatee: import_zod3.z.string().optional(),
439
+ /** Only include delegations valid at this time */
440
+ validAt: import_zod3.z.coerce.date().optional(),
441
+ /** Maximum number of results to return */
442
+ limit: import_zod3.z.number().optional(),
443
+ /** Cursor for pagination */
444
+ cursor: import_zod3.z.string().optional()
445
+ });
446
+ var SpaceOwnershipSchema = import_zod3.z.enum(["owned", "delegated"]);
447
+ var SpaceInfoSchema = import_zod3.z.object({
448
+ /** Space identifier */
449
+ id: import_zod3.z.string(),
450
+ /** Human-readable name for the space */
451
+ name: import_zod3.z.string().optional(),
452
+ /** DID of the space owner */
453
+ owner: import_zod3.z.string(),
454
+ /** Whether user owns or has delegated access */
455
+ type: SpaceOwnershipSchema,
456
+ /** Permissions the user has in this space */
457
+ permissions: import_zod3.z.array(import_zod3.z.string()).optional(),
458
+ /** When the access expires (for delegated spaces) */
459
+ expiresAt: import_zod3.z.coerce.date().optional()
460
+ });
461
+ var ShareSchemaSchema = import_zod3.z.enum(["base64", "compact", "ipfs"]);
462
+ var ShareLinkSchema = import_zod3.z.object({
463
+ /** Unique token identifying this share link */
464
+ token: import_zod3.z.string(),
465
+ /** Full URL for sharing */
466
+ url: import_zod3.z.string(),
467
+ /** The delegation this link grants access to */
468
+ delegation: DelegationSchema,
469
+ /** Encoding schema used for the link */
470
+ schema: ShareSchemaSchema,
471
+ /** When this share link expires */
472
+ expiresAt: import_zod3.z.coerce.date().optional(),
473
+ /** Human-readable description of what is being shared */
474
+ description: import_zod3.z.string().optional()
475
+ });
476
+ function createShareLinkDataSchema(dataSchema) {
477
+ return import_zod3.z.object({
478
+ /** The retrieved data */
479
+ data: dataSchema,
480
+ /** The delegation that authorized this access */
481
+ delegation: DelegationSchema,
482
+ /** The space the data belongs to */
483
+ spaceId: import_zod3.z.string(),
484
+ /** The resource path that was accessed */
485
+ path: import_zod3.z.string()
486
+ });
487
+ }
488
+ var ShareLinkDataSchema = createShareLinkDataSchema(import_zod3.z.unknown());
489
+ var IngestOptionsSchema = import_zod3.z.object({
490
+ /** Whether to persist the delegation to storage */
491
+ persist: import_zod3.z.boolean().optional(),
492
+ /** Whether to validate the full delegation chain */
493
+ validateChain: import_zod3.z.boolean().optional(),
494
+ /** Name for the ingested key */
495
+ keyName: import_zod3.z.string().optional(),
496
+ /** Whether to create a session key for this delegation */
497
+ createSessionKey: import_zod3.z.boolean().optional(),
498
+ /** Override the priority for the ingested key */
499
+ priority: import_zod3.z.number().optional()
500
+ });
501
+ var GenerateShareParamsSchema = import_zod3.z.object({
502
+ /** Resource path to share */
503
+ path: import_zod3.z.string(),
504
+ /** Actions to authorize */
505
+ actions: import_zod3.z.array(import_zod3.z.string()).optional(),
506
+ /** When the share link expires */
507
+ expiry: import_zod3.z.coerce.date().optional(),
508
+ /** Encoding schema for the link */
509
+ schema: ShareSchemaSchema.optional(),
510
+ /** Human-readable description */
511
+ description: import_zod3.z.string().optional(),
512
+ /** Base URL for the share link */
513
+ baseUrl: import_zod3.z.string().optional()
514
+ });
515
+ var DelegationManagerConfigSchema = import_zod3.z.object({
516
+ /** TinyCloud host URLs */
517
+ hosts: import_zod3.z.array(import_zod3.z.string()),
518
+ /** Active session for authentication */
519
+ session: import_zod3.z.unknown().refine(
520
+ (val) => val !== null && typeof val === "object",
521
+ { message: "Expected a ServiceSession object" }
522
+ ),
523
+ /** Platform-specific invoke function */
524
+ invoke: import_zod3.z.unknown().refine(
525
+ (val) => typeof val === "function",
526
+ { message: "Expected an invoke function" }
527
+ ),
528
+ /** Optional custom fetch implementation */
529
+ fetch: import_zod3.z.unknown().refine(
530
+ (val) => val === void 0 || typeof val === "function",
531
+ { message: "Expected a fetch function or undefined" }
532
+ ).optional()
533
+ });
534
+ var KeyProviderSchema = import_zod3.z.object({
535
+ /** Generate a new session key, returns key ID */
536
+ createSessionKey: import_zod3.z.unknown().refine(
537
+ (val) => typeof val === "function",
538
+ { message: "Expected a function" }
539
+ ),
540
+ /** Get JWK for a key */
541
+ getJWK: import_zod3.z.unknown().refine(
542
+ (val) => typeof val === "function",
543
+ { message: "Expected a function" }
544
+ ),
545
+ /** Get DID for a key */
546
+ getDID: import_zod3.z.unknown().refine(
547
+ (val) => typeof val === "function",
548
+ { message: "Expected a function" }
549
+ )
550
+ });
551
+ var DelegationApiResponseSchema = import_zod3.z.object({
552
+ /** SIWE message content */
553
+ siwe: import_zod3.z.string(),
554
+ /** Signature of the SIWE message */
555
+ signature: import_zod3.z.string(),
556
+ /** Delegation version */
557
+ version: import_zod3.z.number(),
558
+ /** CID of the created delegation */
559
+ cid: import_zod3.z.string().optional()
560
+ });
561
+ var CreateDelegationWasmParamsSchema = import_zod3.z.object({
562
+ /** The session containing delegation credentials */
563
+ session: import_zod3.z.unknown().refine(
564
+ (val) => val !== null && typeof val === "object",
565
+ { message: "Expected a ServiceSession object" }
566
+ ),
567
+ /** DID of the delegate */
568
+ delegateDID: import_zod3.z.string(),
569
+ /** Space ID this delegation applies to */
570
+ spaceId: import_zod3.z.string(),
571
+ /** Resource path this delegation grants access to */
572
+ path: import_zod3.z.string(),
573
+ /** Actions to authorize */
574
+ actions: import_zod3.z.array(import_zod3.z.string()),
575
+ /** Expiration time in seconds since Unix epoch */
576
+ expirationSecs: import_zod3.z.number(),
577
+ /** Optional not-before time in seconds since Unix epoch */
578
+ notBeforeSecs: import_zod3.z.number().optional()
579
+ });
580
+ var CreateDelegationWasmResultSchema = import_zod3.z.object({
581
+ /** Base64url-encoded UCAN delegation */
582
+ delegation: import_zod3.z.string(),
583
+ /** CID of the delegation */
584
+ cid: import_zod3.z.string(),
585
+ /** DID of the delegate */
586
+ delegateDID: import_zod3.z.string(),
587
+ /** Resource path the delegation grants access to */
588
+ path: import_zod3.z.string(),
589
+ /** Actions the delegation authorizes */
590
+ actions: import_zod3.z.array(import_zod3.z.string()),
591
+ /** Expiration time */
592
+ expiry: import_zod3.z.coerce.date()
593
+ });
594
+
595
+ // src/spaces/spaces.schema.ts
596
+ var SpaceConfigSchema = import_zod4.z.object({
597
+ /** The space identifier (full URI) */
598
+ id: import_zod4.z.string(),
599
+ /** The short name of the space */
600
+ name: import_zod4.z.string(),
601
+ /** Factory function to create a space-scoped KV service */
602
+ createKV: import_zod4.z.function(),
603
+ /** Factory function to create space-scoped delegations */
604
+ createDelegations: import_zod4.z.function(),
605
+ /** Factory function to create space-scoped sharing */
606
+ createSharing: import_zod4.z.function(),
607
+ /** Function to get space info */
608
+ getInfo: import_zod4.z.function()
609
+ });
610
+ var SpaceServiceConfigSchema = import_zod4.z.object({
611
+ /** TinyCloud host URLs */
612
+ hosts: import_zod4.z.array(import_zod4.z.string()),
613
+ /** Active session for authentication */
614
+ session: import_zod4.z.unknown(),
615
+ /** Platform-specific invoke function */
616
+ invoke: import_zod4.z.function(),
617
+ /** Optional custom fetch implementation */
618
+ fetch: import_zod4.z.function().optional(),
619
+ /** Optional capability key registry for delegated space discovery */
620
+ capabilityRegistry: import_zod4.z.unknown().optional(),
621
+ /** Factory function to create a space-scoped KV service */
622
+ createKVService: import_zod4.z.function().optional(),
623
+ /** User's PKH DID (derived from address or provided explicitly) */
624
+ userDid: import_zod4.z.string().optional(),
625
+ /** Optional SharingService for v2 sharing links (client-side) */
626
+ sharingService: import_zod4.z.unknown().optional(),
627
+ /** Factory function to create delegations using SIWE-based flow */
628
+ createDelegation: import_zod4.z.function().optional()
629
+ });
630
+ var SpaceDelegationParamsSchema = CreateDelegationParamsSchema.extend({
631
+ /** The space ID to create the delegation for */
632
+ spaceId: import_zod4.z.string()
633
+ });
634
+ var ServerDelegationInfoSchema = import_zod4.z.object({
635
+ /** DID of the delegator */
636
+ delegator: import_zod4.z.string(),
637
+ /** DID of the delegate */
638
+ delegate: import_zod4.z.string(),
639
+ /** Parent delegation CIDs - accepts string or byte array format from server */
640
+ parents: import_zod4.z.array(import_zod4.z.union([import_zod4.z.string(), import_zod4.z.array(import_zod4.z.number())])),
641
+ /** Expiration time (ISO8601 string) */
642
+ expiry: import_zod4.z.string().optional(),
643
+ /** Not-before time (ISO8601 string) */
644
+ not_before: import_zod4.z.string().optional(),
645
+ /** Issued-at time (ISO8601 string) */
646
+ issued_at: import_zod4.z.string().optional(),
647
+ /** Capabilities granted by this delegation */
648
+ capabilities: import_zod4.z.array(
649
+ import_zod4.z.object({
650
+ resource: import_zod4.z.string(),
651
+ ability: import_zod4.z.string()
652
+ })
653
+ )
654
+ });
655
+ var ServerDelegationsResponseSchema = import_zod4.z.record(
656
+ import_zod4.z.string(),
657
+ ServerDelegationInfoSchema
658
+ );
659
+ var ServerOwnedSpaceSchema = import_zod4.z.object({
660
+ /** Space identifier */
661
+ id: import_zod4.z.string(),
662
+ /** Space name (optional, can be derived from id) */
663
+ name: import_zod4.z.string().optional(),
664
+ /** Owner DID */
665
+ owner: import_zod4.z.string(),
666
+ /** Creation timestamp */
667
+ createdAt: import_zod4.z.string().optional()
668
+ });
669
+ var ServerOwnedSpacesResponseSchema = import_zod4.z.array(ServerOwnedSpaceSchema);
670
+ var ServerCreateSpaceResponseSchema = import_zod4.z.object({
671
+ /** Space identifier */
672
+ id: import_zod4.z.string(),
673
+ /** Space name */
674
+ name: import_zod4.z.string(),
675
+ /** Owner DID */
676
+ owner: import_zod4.z.string(),
677
+ /** Creation timestamp */
678
+ createdAt: import_zod4.z.string().optional()
679
+ });
680
+ var ServerSpaceInfoResponseSchema = import_zod4.z.object({
681
+ /** Space identifier */
682
+ id: import_zod4.z.string(),
683
+ /** Space name (optional) */
684
+ name: import_zod4.z.string().optional(),
685
+ /** Owner DID */
686
+ owner: import_zod4.z.string(),
687
+ /** Ownership type */
688
+ type: import_zod4.z.enum(["owned", "delegated"]).optional(),
689
+ /** Permissions the user has in this space */
690
+ permissions: import_zod4.z.array(import_zod4.z.string()).optional(),
691
+ /** Expiration for delegated access */
692
+ expiresAt: import_zod4.z.string().optional()
693
+ });
694
+ function validateServerDelegationsResponse(data) {
695
+ if (data === null || data === void 0) {
696
+ return { ok: true, data: {} };
697
+ }
698
+ if (Array.isArray(data)) {
699
+ return { ok: true, data: {} };
700
+ }
701
+ const result = ServerDelegationsResponseSchema.safeParse(data);
702
+ if (!result.success) {
703
+ return {
704
+ ok: false,
705
+ error: {
706
+ code: "VALIDATION_ERROR",
707
+ message: `Invalid server delegations response: ${result.error.message}`,
708
+ service: "space",
709
+ meta: { issues: result.error.issues }
710
+ }
711
+ };
712
+ }
713
+ return { ok: true, data: result.data };
714
+ }
715
+ function validateServerOwnedSpacesResponse(data) {
716
+ const result = ServerOwnedSpacesResponseSchema.safeParse(data);
717
+ if (!result.success) {
718
+ return {
719
+ ok: false,
720
+ error: {
721
+ code: "VALIDATION_ERROR",
722
+ message: `Invalid server owned spaces response: ${result.error.message}`,
723
+ service: "space",
724
+ meta: { issues: result.error.issues }
725
+ }
726
+ };
727
+ }
728
+ return { ok: true, data: result.data };
729
+ }
730
+ function validateServerCreateSpaceResponse(data) {
731
+ const result = ServerCreateSpaceResponseSchema.safeParse(data);
732
+ if (!result.success) {
733
+ return {
734
+ ok: false,
735
+ error: {
736
+ code: "VALIDATION_ERROR",
737
+ message: `Invalid server create space response: ${result.error.message}`,
738
+ service: "space",
739
+ meta: { issues: result.error.issues }
740
+ }
741
+ };
742
+ }
743
+ return { ok: true, data: result.data };
744
+ }
745
+ function validateServerSpaceInfoResponse(data) {
746
+ const result = ServerSpaceInfoResponseSchema.safeParse(data);
747
+ if (!result.success) {
748
+ return {
749
+ ok: false,
750
+ error: {
751
+ code: "VALIDATION_ERROR",
752
+ message: `Invalid server space info response: ${result.error.message}`,
753
+ service: "space",
754
+ meta: { issues: result.error.issues }
755
+ }
756
+ };
757
+ }
758
+ return { ok: true, data: result.data };
759
+ }
760
+
761
+ // src/spaces/SpaceService.ts
762
+ var SERVICE_NAME = "space";
763
+ var SpaceErrorCodes = {
764
+ /** Space not found */
765
+ NOT_FOUND: "SPACE_NOT_FOUND",
766
+ /** Space already exists */
767
+ ALREADY_EXISTS: "SPACE_ALREADY_EXISTS",
768
+ /** Creation failed */
769
+ CREATION_FAILED: "SPACE_CREATION_FAILED",
770
+ /** Authentication required */
771
+ AUTH_REQUIRED: "AUTH_REQUIRED",
772
+ /** Invalid space name or URI */
773
+ INVALID_NAME: "INVALID_SPACE_NAME",
774
+ /** Network error */
775
+ NETWORK_ERROR: "NETWORK_ERROR",
776
+ /** Not initialized */
777
+ NOT_INITIALIZED: "NOT_INITIALIZED"
778
+ };
779
+ function makePublicSpaceId(address, chainId) {
780
+ return `tinycloud:pkh:eip155:${chainId}:${address}:public`;
781
+ }
782
+ function parseSpaceUri(uri) {
783
+ const fullUriMatch = uri.match(
784
+ /^tinycloud:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40}):(.+)$/
785
+ );
786
+ if (fullUriMatch) {
787
+ const [, chainId, address, name] = fullUriMatch;
788
+ return {
789
+ owner: `did:pkh:eip155:${chainId}:${address}`,
790
+ name,
791
+ chainId,
792
+ address
793
+ };
794
+ }
795
+ if (/^[a-zA-Z0-9_-]+$/.test(uri)) {
796
+ return {
797
+ owner: "",
798
+ // Will be filled in from session
799
+ name: uri
800
+ };
801
+ }
802
+ return null;
803
+ }
804
+ function buildSpaceUri(owner, name) {
805
+ const pkhMatch = owner.match(/^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/);
806
+ if (pkhMatch) {
807
+ const [, chainId, address] = pkhMatch;
808
+ return `tinycloud:pkh:eip155:${chainId}:${address}:${name}`;
809
+ }
810
+ return `tinycloud:${owner}:${name}`;
811
+ }
812
+ function transformServerDelegations(validatedData, defaultSpaceId) {
813
+ const result = [];
814
+ for (const [cid, info] of Object.entries(validatedData)) {
815
+ const capabilities = info.capabilities;
816
+ let path = "";
817
+ let spaceId = defaultSpaceId;
818
+ const actions = [];
819
+ for (const cap of capabilities) {
820
+ actions.push(cap.ability);
821
+ const resourceMatch = cap.resource.match(
822
+ /^(tinycloud:pkh:eip155:\d+:0x[a-fA-F0-9]+:[^/]+)\/[^/]+\/(.*)$/
823
+ );
824
+ if (resourceMatch) {
825
+ spaceId = resourceMatch[1];
826
+ path = resourceMatch[2] || "";
827
+ }
828
+ }
829
+ const firstStringParent = info.parents?.find((p) => typeof p === "string");
830
+ result.push({
831
+ cid,
832
+ delegateDID: info.delegate,
833
+ delegatorDID: info.delegator,
834
+ spaceId,
835
+ path,
836
+ actions,
837
+ expiry: info.expiry ? new Date(info.expiry) : new Date(Date.now() + 24 * 60 * 60 * 1e3),
838
+ isRevoked: false,
839
+ createdAt: info.issued_at ? new Date(info.issued_at) : void 0,
840
+ parentCid: firstStringParent
841
+ });
842
+ }
843
+ return result;
844
+ }
845
+ var SpaceService = class {
846
+ /**
847
+ * Create a new SpaceService instance.
848
+ *
849
+ * @param config - Service configuration
850
+ */
851
+ constructor(config) {
852
+ /** Cache of created Space objects */
853
+ this.spaceCache = /* @__PURE__ */ new Map();
854
+ /** Cache of space info */
855
+ this.infoCache = /* @__PURE__ */ new Map();
856
+ /** Cache TTL in milliseconds (5 minutes) */
857
+ this.cacheTTL = 5 * 60 * 1e3;
858
+ this.hosts = config.hosts;
859
+ this.session = config.session;
860
+ this.invoke = config.invoke;
861
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
862
+ this.capabilityRegistry = config.capabilityRegistry;
863
+ this.createKVServiceFn = config.createKVService;
864
+ this._userDid = config.userDid;
865
+ this.sharingService = config.sharingService;
866
+ this.createDelegationFn = config.createDelegation;
867
+ }
868
+ /**
869
+ * Update the service configuration.
870
+ */
871
+ updateConfig(config) {
872
+ if (config.hosts) this.hosts = config.hosts;
873
+ if (config.session) this.session = config.session;
874
+ if (config.invoke) this.invoke = config.invoke;
875
+ if (config.fetch) this.fetchFn = config.fetch;
876
+ if (config.capabilityRegistry) this.capabilityRegistry = config.capabilityRegistry;
877
+ if (config.createKVService) this.createKVServiceFn = config.createKVService;
878
+ if (config.userDid !== void 0) this._userDid = config.userDid;
879
+ if (config.sharingService) this.sharingService = config.sharingService;
880
+ if (config.createDelegation) this.createDelegationFn = config.createDelegation;
881
+ this.spaceCache.clear();
882
+ this.infoCache.clear();
883
+ }
884
+ /**
885
+ * Get the current user's primary space ID.
886
+ */
887
+ getCurrentSpaceId() {
888
+ return this.session?.spaceId;
889
+ }
890
+ /**
891
+ * Get the primary host URL.
892
+ */
893
+ get host() {
894
+ return this.hosts[0];
895
+ }
896
+ /**
897
+ * Get the current user's PKH DID.
898
+ */
899
+ get userDid() {
900
+ if (this._userDid) {
901
+ return this._userDid;
902
+ }
903
+ return void 0;
904
+ }
905
+ // ===========================================================================
906
+ // List Spaces
907
+ // ===========================================================================
908
+ /**
909
+ * List all spaces the user has access to.
910
+ *
911
+ * Combines owned spaces (from the server) with delegated spaces
912
+ * (from the capability registry).
913
+ */
914
+ async list() {
915
+ if (!this.session) {
916
+ return (0, import_sdk_services.err)(
917
+ (0, import_sdk_services.serviceError)(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME)
918
+ );
919
+ }
920
+ try {
921
+ const spaces = [];
922
+ const ownedResult = await this.listOwnedSpaces();
923
+ if (ownedResult.ok) {
924
+ spaces.push(...ownedResult.data);
925
+ }
926
+ if (this.capabilityRegistry) {
927
+ const delegatedSpaces = this.discoverDelegatedSpaces();
928
+ spaces.push(...delegatedSpaces);
929
+ }
930
+ const uniqueSpaces = this.deduplicateSpaces(spaces);
931
+ return (0, import_sdk_services.ok)(uniqueSpaces);
932
+ } catch (error) {
933
+ return (0, import_sdk_services.err)(
934
+ (0, import_sdk_services.serviceError)(
935
+ SpaceErrorCodes.NETWORK_ERROR,
936
+ `Failed to list spaces: ${String(error)}`,
937
+ SERVICE_NAME,
938
+ { cause: error instanceof Error ? error : void 0 }
939
+ )
940
+ );
941
+ }
942
+ }
943
+ /**
944
+ * List owned spaces from the server.
945
+ */
946
+ async listOwnedSpaces() {
947
+ try {
948
+ const headers = this.invoke(this.session, "space", "", "tinycloud.space/list");
949
+ const response = await this.fetchFn(`${this.host}/invoke`, {
950
+ method: "POST",
951
+ headers
952
+ });
953
+ if (!response.ok) {
954
+ const errorText = await response.text();
955
+ return (0, import_sdk_services.err)(
956
+ (0, import_sdk_services.serviceError)(
957
+ SpaceErrorCodes.NETWORK_ERROR,
958
+ `Failed to list owned spaces: ${response.status} - ${errorText}`,
959
+ SERVICE_NAME,
960
+ { meta: { status: response.status } }
961
+ )
962
+ );
963
+ }
964
+ const rawData = await response.json();
965
+ const validationResult = validateServerOwnedSpacesResponse(rawData);
966
+ if (!validationResult.ok) {
967
+ return (0, import_sdk_services.err)(
968
+ (0, import_sdk_services.serviceError)(
969
+ SpaceErrorCodes.NETWORK_ERROR,
970
+ validationResult.error.message,
971
+ SERVICE_NAME,
972
+ { meta: validationResult.error.meta }
973
+ )
974
+ );
975
+ }
976
+ const spaces = validationResult.data.map((item) => ({
977
+ id: item.id,
978
+ name: item.name ?? this.extractNameFromId(item.id),
979
+ owner: item.owner,
980
+ type: "owned",
981
+ permissions: ["*"]
982
+ // Full permissions for owned spaces
983
+ }));
984
+ return (0, import_sdk_services.ok)(spaces);
985
+ } catch (error) {
986
+ return (0, import_sdk_services.err)(
987
+ (0, import_sdk_services.serviceError)(
988
+ SpaceErrorCodes.NETWORK_ERROR,
989
+ `Network error listing owned spaces: ${String(error)}`,
990
+ SERVICE_NAME,
991
+ { cause: error instanceof Error ? error : void 0 }
992
+ )
993
+ );
994
+ }
995
+ }
996
+ /**
997
+ * Discover delegated spaces from the capability registry.
998
+ */
999
+ discoverDelegatedSpaces() {
1000
+ if (!this.capabilityRegistry) {
1001
+ return [];
1002
+ }
1003
+ const spaces = /* @__PURE__ */ new Map();
1004
+ const capabilities = this.capabilityRegistry.getAllCapabilities();
1005
+ for (const capability of capabilities) {
1006
+ const spaceId = capability.delegation.spaceId;
1007
+ if (spaces.has(spaceId)) {
1008
+ const existing = spaces.get(spaceId);
1009
+ if (existing.permissions) {
1010
+ const actions = capability.delegation.actions;
1011
+ for (const action of actions) {
1012
+ if (!existing.permissions.includes(action)) {
1013
+ existing.permissions.push(action);
1014
+ }
1015
+ }
1016
+ }
1017
+ continue;
1018
+ }
1019
+ if (spaceId === this.session?.spaceId) {
1020
+ continue;
1021
+ }
1022
+ const parsed = parseSpaceUri(spaceId);
1023
+ spaces.set(spaceId, {
1024
+ id: spaceId,
1025
+ name: parsed?.name ?? this.extractNameFromId(spaceId),
1026
+ owner: capability.delegation.delegatorDID ?? parsed?.owner ?? "",
1027
+ type: "delegated",
1028
+ permissions: [...capability.delegation.actions],
1029
+ expiresAt: capability.expiresAt
1030
+ });
1031
+ }
1032
+ return Array.from(spaces.values());
1033
+ }
1034
+ /**
1035
+ * Extract space name from a full space ID.
1036
+ */
1037
+ extractNameFromId(id) {
1038
+ const parsed = parseSpaceUri(id);
1039
+ if (parsed) {
1040
+ return parsed.name;
1041
+ }
1042
+ const parts = id.split(":");
1043
+ return parts[parts.length - 1] || id;
1044
+ }
1045
+ /**
1046
+ * Deduplicate spaces, preferring owned over delegated.
1047
+ */
1048
+ deduplicateSpaces(spaces) {
1049
+ const seen = /* @__PURE__ */ new Map();
1050
+ for (const space of spaces) {
1051
+ const existing = seen.get(space.id);
1052
+ if (!existing || existing.type === "delegated" && space.type === "owned") {
1053
+ seen.set(space.id, space);
1054
+ }
1055
+ }
1056
+ return Array.from(seen.values());
1057
+ }
1058
+ // ===========================================================================
1059
+ // Create Space
1060
+ // ===========================================================================
1061
+ /**
1062
+ * Create a new space.
1063
+ *
1064
+ * @param name - The name for the new space
1065
+ */
1066
+ async create(name) {
1067
+ if (!this.session) {
1068
+ return (0, import_sdk_services.err)(
1069
+ (0, import_sdk_services.serviceError)(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME)
1070
+ );
1071
+ }
1072
+ if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
1073
+ return (0, import_sdk_services.err)(
1074
+ (0, import_sdk_services.serviceError)(
1075
+ SpaceErrorCodes.INVALID_NAME,
1076
+ "Space name must contain only alphanumeric characters, underscores, and hyphens",
1077
+ SERVICE_NAME
1078
+ )
1079
+ );
1080
+ }
1081
+ try {
1082
+ const headers = this.invoke(this.session, "space", name, "tinycloud.space/create");
1083
+ const response = await this.fetchFn(`${this.host}/invoke`, {
1084
+ method: "POST",
1085
+ headers,
1086
+ body: JSON.stringify({ name })
1087
+ });
1088
+ if (!response.ok) {
1089
+ const errorText = await response.text();
1090
+ if (response.status === 409) {
1091
+ return (0, import_sdk_services.err)(
1092
+ (0, import_sdk_services.serviceError)(
1093
+ SpaceErrorCodes.ALREADY_EXISTS,
1094
+ `Space "${name}" already exists`,
1095
+ SERVICE_NAME
1096
+ )
1097
+ );
1098
+ }
1099
+ return (0, import_sdk_services.err)(
1100
+ (0, import_sdk_services.serviceError)(
1101
+ SpaceErrorCodes.CREATION_FAILED,
1102
+ `Failed to create space: ${response.status} - ${errorText}`,
1103
+ SERVICE_NAME,
1104
+ { meta: { status: response.status } }
1105
+ )
1106
+ );
1107
+ }
1108
+ const rawData = await response.json();
1109
+ const validationResult = validateServerCreateSpaceResponse(rawData);
1110
+ if (!validationResult.ok) {
1111
+ return (0, import_sdk_services.err)(
1112
+ (0, import_sdk_services.serviceError)(
1113
+ SpaceErrorCodes.CREATION_FAILED,
1114
+ validationResult.error.message,
1115
+ SERVICE_NAME,
1116
+ { meta: validationResult.error.meta }
1117
+ )
1118
+ );
1119
+ }
1120
+ const spaceInfo = {
1121
+ id: validationResult.data.id,
1122
+ name: validationResult.data.name || name,
1123
+ owner: validationResult.data.owner || this.userDid || "",
1124
+ type: "owned",
1125
+ permissions: ["*"]
1126
+ };
1127
+ this.infoCache.set(spaceInfo.id, { info: spaceInfo, cachedAt: Date.now() });
1128
+ return (0, import_sdk_services.ok)(spaceInfo);
1129
+ } catch (error) {
1130
+ return (0, import_sdk_services.err)(
1131
+ (0, import_sdk_services.serviceError)(
1132
+ SpaceErrorCodes.NETWORK_ERROR,
1133
+ `Network error creating space: ${String(error)}`,
1134
+ SERVICE_NAME,
1135
+ { cause: error instanceof Error ? error : void 0 }
1136
+ )
1137
+ );
1138
+ }
1139
+ }
1140
+ // ===========================================================================
1141
+ // Get Space
1142
+ // ===========================================================================
1143
+ /**
1144
+ * Get a Space object by name or full URI.
1145
+ *
1146
+ * @param nameOrUri - Short name or full URI
1147
+ */
1148
+ get(nameOrUri) {
1149
+ const spaceId = this.resolveSpaceId(nameOrUri);
1150
+ const cached = this.spaceCache.get(spaceId);
1151
+ if (cached) {
1152
+ return cached;
1153
+ }
1154
+ const parsed = parseSpaceUri(spaceId);
1155
+ const name = parsed?.name ?? this.extractNameFromId(spaceId);
1156
+ const config = {
1157
+ id: spaceId,
1158
+ name,
1159
+ createKV: this.createSpaceScopedKV.bind(this),
1160
+ createDelegations: this.createSpaceScopedDelegations.bind(this),
1161
+ createSharing: this.createSpaceScopedSharing.bind(this),
1162
+ getInfo: this.getSpaceInfo.bind(this)
1163
+ };
1164
+ const space = new Space(config);
1165
+ this.spaceCache.set(spaceId, space);
1166
+ return space;
1167
+ }
1168
+ /**
1169
+ * Resolve a name or URI to a full space ID.
1170
+ */
1171
+ resolveSpaceId(nameOrUri) {
1172
+ const parsed = parseSpaceUri(nameOrUri);
1173
+ if (!parsed) {
1174
+ return nameOrUri;
1175
+ }
1176
+ if (parsed.owner) {
1177
+ return nameOrUri;
1178
+ }
1179
+ if (this.userDid) {
1180
+ return buildSpaceUri(this.userDid, parsed.name);
1181
+ }
1182
+ return nameOrUri;
1183
+ }
1184
+ // ===========================================================================
1185
+ // Exists Check
1186
+ // ===========================================================================
1187
+ /**
1188
+ * Check if a space exists and the user has access.
1189
+ */
1190
+ async exists(nameOrUri) {
1191
+ const spaceId = this.resolveSpaceId(nameOrUri);
1192
+ const cached = this.infoCache.get(spaceId);
1193
+ if (cached && Date.now() - cached.cachedAt < this.cacheTTL) {
1194
+ return (0, import_sdk_services.ok)(true);
1195
+ }
1196
+ const infoResult = await this.getSpaceInfo(spaceId);
1197
+ return (0, import_sdk_services.ok)(infoResult.ok);
1198
+ }
1199
+ // ===========================================================================
1200
+ // Space Info
1201
+ // ===========================================================================
1202
+ /**
1203
+ * Get space info from server or cache.
1204
+ */
1205
+ async getSpaceInfo(spaceId) {
1206
+ const cached = this.infoCache.get(spaceId);
1207
+ if (cached && Date.now() - cached.cachedAt < this.cacheTTL) {
1208
+ return (0, import_sdk_services.ok)(cached.info);
1209
+ }
1210
+ if (!this.session) {
1211
+ return (0, import_sdk_services.err)(
1212
+ (0, import_sdk_services.serviceError)(SpaceErrorCodes.AUTH_REQUIRED, "Authentication required", SERVICE_NAME)
1213
+ );
1214
+ }
1215
+ try {
1216
+ const headers = this.invoke(this.session, "space", spaceId, "tinycloud.space/info");
1217
+ const response = await this.fetchFn(`${this.host}/invoke`, {
1218
+ method: "POST",
1219
+ headers,
1220
+ body: JSON.stringify({ spaceId })
1221
+ });
1222
+ if (!response.ok) {
1223
+ if (response.status === 404) {
1224
+ return (0, import_sdk_services.err)(
1225
+ (0, import_sdk_services.serviceError)(SpaceErrorCodes.NOT_FOUND, `Space not found: ${spaceId}`, SERVICE_NAME)
1226
+ );
1227
+ }
1228
+ const errorText = await response.text();
1229
+ return (0, import_sdk_services.err)(
1230
+ (0, import_sdk_services.serviceError)(
1231
+ SpaceErrorCodes.NETWORK_ERROR,
1232
+ `Failed to get space info: ${response.status} - ${errorText}`,
1233
+ SERVICE_NAME
1234
+ )
1235
+ );
1236
+ }
1237
+ const rawData = await response.json();
1238
+ const validationResult = validateServerSpaceInfoResponse(rawData);
1239
+ if (!validationResult.ok) {
1240
+ return (0, import_sdk_services.err)(
1241
+ (0, import_sdk_services.serviceError)(
1242
+ SpaceErrorCodes.NETWORK_ERROR,
1243
+ validationResult.error.message,
1244
+ SERVICE_NAME,
1245
+ { meta: validationResult.error.meta }
1246
+ )
1247
+ );
1248
+ }
1249
+ const data = validationResult.data;
1250
+ const spaceInfo = {
1251
+ id: data.id,
1252
+ name: data.name ?? this.extractNameFromId(data.id),
1253
+ owner: data.owner,
1254
+ type: data.type ?? (data.owner === this.userDid ? "owned" : "delegated"),
1255
+ permissions: data.permissions,
1256
+ expiresAt: data.expiresAt ? new Date(data.expiresAt) : void 0
1257
+ };
1258
+ this.infoCache.set(spaceId, { info: spaceInfo, cachedAt: Date.now() });
1259
+ return (0, import_sdk_services.ok)(spaceInfo);
1260
+ } catch (error) {
1261
+ return (0, import_sdk_services.err)(
1262
+ (0, import_sdk_services.serviceError)(
1263
+ SpaceErrorCodes.NETWORK_ERROR,
1264
+ `Network error getting space info: ${String(error)}`,
1265
+ SERVICE_NAME,
1266
+ { cause: error instanceof Error ? error : void 0 }
1267
+ )
1268
+ );
1269
+ }
1270
+ }
1271
+ // ===========================================================================
1272
+ // Space-Scoped Service Factories
1273
+ // ===========================================================================
1274
+ /**
1275
+ * Create a space-scoped KV service.
1276
+ */
1277
+ createSpaceScopedKV(spaceId) {
1278
+ if (this.createKVServiceFn) {
1279
+ return this.createKVServiceFn(spaceId);
1280
+ }
1281
+ return new Proxy({}, {
1282
+ get: () => {
1283
+ throw new Error(
1284
+ "KV service factory not configured. Provide createKVService in SpaceServiceConfig."
1285
+ );
1286
+ }
1287
+ });
1288
+ }
1289
+ /**
1290
+ * Create space-scoped delegation operations.
1291
+ */
1292
+ createSpaceScopedDelegations(spaceId) {
1293
+ const self = this;
1294
+ return {
1295
+ async list() {
1296
+ try {
1297
+ const facts = [
1298
+ {
1299
+ capabilitiesReadParams: {
1300
+ type: "list",
1301
+ filters: { direction: "created" }
1302
+ }
1303
+ }
1304
+ ];
1305
+ const headers = self.invoke(
1306
+ self.session,
1307
+ "capabilities",
1308
+ "all",
1309
+ "tinycloud.capabilities/read",
1310
+ facts
1311
+ );
1312
+ const response = await self.fetchFn(`${self.host}/invoke`, {
1313
+ method: "POST",
1314
+ headers
1315
+ });
1316
+ if (!response.ok) {
1317
+ const errorText = await response.text();
1318
+ return (0, import_sdk_services.err)(
1319
+ (0, import_sdk_services.serviceError)(
1320
+ SpaceErrorCodes.NETWORK_ERROR,
1321
+ `Failed to list delegations: ${response.status} - ${errorText}`,
1322
+ SERVICE_NAME
1323
+ )
1324
+ );
1325
+ }
1326
+ const rawData = await response.json();
1327
+ const validationResult = validateServerDelegationsResponse(rawData);
1328
+ if (!validationResult.ok) {
1329
+ return (0, import_sdk_services.err)(
1330
+ (0, import_sdk_services.serviceError)(
1331
+ SpaceErrorCodes.NETWORK_ERROR,
1332
+ validationResult.error.message,
1333
+ SERVICE_NAME,
1334
+ { meta: validationResult.error.meta }
1335
+ )
1336
+ );
1337
+ }
1338
+ const delegations = transformServerDelegations(validationResult.data, spaceId);
1339
+ return (0, import_sdk_services.ok)(delegations);
1340
+ } catch (error) {
1341
+ return (0, import_sdk_services.err)(
1342
+ (0, import_sdk_services.serviceError)(
1343
+ SpaceErrorCodes.NETWORK_ERROR,
1344
+ `Network error listing delegations: ${String(error)}`,
1345
+ SERVICE_NAME
1346
+ )
1347
+ );
1348
+ }
1349
+ },
1350
+ async listReceived() {
1351
+ try {
1352
+ const facts = [
1353
+ {
1354
+ capabilitiesReadParams: {
1355
+ type: "list",
1356
+ filters: { direction: "received" }
1357
+ }
1358
+ }
1359
+ ];
1360
+ const headers = self.invoke(
1361
+ self.session,
1362
+ "capabilities",
1363
+ "all",
1364
+ "tinycloud.capabilities/read",
1365
+ facts
1366
+ );
1367
+ const response = await self.fetchFn(`${self.host}/invoke`, {
1368
+ method: "POST",
1369
+ headers
1370
+ });
1371
+ if (!response.ok) {
1372
+ const errorText = await response.text();
1373
+ return (0, import_sdk_services.err)(
1374
+ (0, import_sdk_services.serviceError)(
1375
+ SpaceErrorCodes.NETWORK_ERROR,
1376
+ `Failed to list received delegations: ${response.status} - ${errorText}`,
1377
+ SERVICE_NAME
1378
+ )
1379
+ );
1380
+ }
1381
+ const rawData = await response.json();
1382
+ const validationResult = validateServerDelegationsResponse(rawData);
1383
+ if (!validationResult.ok) {
1384
+ return (0, import_sdk_services.err)(
1385
+ (0, import_sdk_services.serviceError)(
1386
+ SpaceErrorCodes.NETWORK_ERROR,
1387
+ validationResult.error.message,
1388
+ SERVICE_NAME,
1389
+ { meta: validationResult.error.meta }
1390
+ )
1391
+ );
1392
+ }
1393
+ const delegations = transformServerDelegations(validationResult.data, spaceId);
1394
+ return (0, import_sdk_services.ok)(delegations);
1395
+ } catch (error) {
1396
+ return (0, import_sdk_services.err)(
1397
+ (0, import_sdk_services.serviceError)(
1398
+ SpaceErrorCodes.NETWORK_ERROR,
1399
+ `Network error listing received delegations: ${String(error)}`,
1400
+ SERVICE_NAME
1401
+ )
1402
+ );
1403
+ }
1404
+ },
1405
+ async create(params) {
1406
+ if (self.createDelegationFn) {
1407
+ return self.createDelegationFn({ ...params, spaceId });
1408
+ }
1409
+ return (0, import_sdk_services.err)(
1410
+ (0, import_sdk_services.serviceError)(
1411
+ SpaceErrorCodes.NOT_INITIALIZED,
1412
+ "Delegation creation requires a createDelegation function. This should be provided by the platform SDK (web-sdk or node-sdk).",
1413
+ SERVICE_NAME
1414
+ )
1415
+ );
1416
+ },
1417
+ async revoke(cid) {
1418
+ try {
1419
+ const headers = self.invoke(
1420
+ self.session,
1421
+ "delegation",
1422
+ cid,
1423
+ "tinycloud.delegation/revoke"
1424
+ );
1425
+ const response = await self.fetchFn(`${self.host}/revoke`, {
1426
+ method: "POST",
1427
+ headers,
1428
+ body: JSON.stringify({ cid, spaceId })
1429
+ });
1430
+ if (!response.ok) {
1431
+ const errorText = await response.text();
1432
+ return (0, import_sdk_services.err)(
1433
+ (0, import_sdk_services.serviceError)(
1434
+ SpaceErrorCodes.NETWORK_ERROR,
1435
+ `Failed to revoke delegation: ${response.status} - ${errorText}`,
1436
+ SERVICE_NAME
1437
+ )
1438
+ );
1439
+ }
1440
+ return (0, import_sdk_services.ok)(void 0);
1441
+ } catch (error) {
1442
+ return (0, import_sdk_services.err)(
1443
+ (0, import_sdk_services.serviceError)(
1444
+ SpaceErrorCodes.NETWORK_ERROR,
1445
+ `Network error revoking delegation: ${String(error)}`,
1446
+ SERVICE_NAME
1447
+ )
1448
+ );
1449
+ }
1450
+ }
1451
+ };
1452
+ }
1453
+ /**
1454
+ * Create space-scoped sharing operations.
1455
+ *
1456
+ * When a SharingService is configured, delegates to client-side v2 sharing.
1457
+ * V2 sharing links are self-contained with embedded private keys - no server tracking.
1458
+ */
1459
+ createSpaceScopedSharing(spaceId) {
1460
+ const self = this;
1461
+ return {
1462
+ async generate(params) {
1463
+ if (self.sharingService) {
1464
+ const result = await self.sharingService.generate(params);
1465
+ if (!result.ok) {
1466
+ return (0, import_sdk_services.err)(
1467
+ (0, import_sdk_services.serviceError)(
1468
+ SpaceErrorCodes.NETWORK_ERROR,
1469
+ result.error.message || "Failed to generate share link",
1470
+ SERVICE_NAME
1471
+ )
1472
+ );
1473
+ }
1474
+ return (0, import_sdk_services.ok)(result.data);
1475
+ }
1476
+ return (0, import_sdk_services.err)(
1477
+ (0, import_sdk_services.serviceError)(
1478
+ SpaceErrorCodes.NOT_INITIALIZED,
1479
+ "SharingService not configured. V2 sharing requires a SharingService instance.",
1480
+ SERVICE_NAME
1481
+ )
1482
+ );
1483
+ },
1484
+ async list() {
1485
+ return (0, import_sdk_services.err)(
1486
+ (0, import_sdk_services.serviceError)(
1487
+ SpaceErrorCodes.NOT_INITIALIZED,
1488
+ "Listing share links is not supported in v2. Share links are self-contained tokens that are not tracked on the server.",
1489
+ SERVICE_NAME
1490
+ )
1491
+ );
1492
+ },
1493
+ async revoke(token) {
1494
+ return (0, import_sdk_services.err)(
1495
+ (0, import_sdk_services.serviceError)(
1496
+ SpaceErrorCodes.NOT_INITIALIZED,
1497
+ "Revoking share links by token is not supported in v2. To revoke access, revoke the underlying delegation using space.delegations.revoke(cid).",
1498
+ SERVICE_NAME
1499
+ )
1500
+ );
1501
+ }
1502
+ };
1503
+ }
1504
+ };
1505
+ function createSpaceService(config) {
1506
+ return new SpaceService(config);
1507
+ }
1508
+
1509
+ // src/TinyCloud.ts
1510
+ var TinyCloud = class _TinyCloud {
1511
+ /**
1512
+ * Create a new TinyCloud SDK instance.
1513
+ *
1514
+ * @param userAuthorization - Platform-specific authorization implementation
1515
+ * @param config - Optional SDK configuration
1516
+ */
1517
+ constructor(userAuthorization, config) {
1518
+ /**
1519
+ * Registered extensions.
1520
+ */
1521
+ this.extensions = [];
1522
+ /**
1523
+ * Registered services by name.
1524
+ */
1525
+ this._services = /* @__PURE__ */ new Map();
1526
+ /**
1527
+ * Whether services have been initialized.
1528
+ */
1529
+ this._servicesInitialized = false;
1530
+ this.userAuthorization = userAuthorization;
1531
+ this.config = config || {};
1532
+ }
1533
+ // === Service Management ===
1534
+ /**
1535
+ * Initialize services with platform dependencies.
1536
+ * Must be called before using services.
1537
+ *
1538
+ * @param invoke - Platform-specific invoke function from WASM binding
1539
+ * @param hosts - TinyCloud host URLs (optional, uses config.hosts)
1540
+ * @param fetchFn - Custom fetch implementation (optional)
1541
+ */
1542
+ initializeServices(invoke, hosts, fetchFn) {
1543
+ const effectiveInvoke = invoke ?? this.config.invoke;
1544
+ const effectiveHosts = hosts ?? this.config.hosts;
1545
+ if (!effectiveInvoke) {
1546
+ throw new Error(
1547
+ "invoke function is required to initialize services. Provide it via config.invoke or initializeServices()."
1548
+ );
1549
+ }
1550
+ if (!effectiveHosts || effectiveHosts.length === 0) {
1551
+ throw new Error(
1552
+ "hosts are required to initialize services. Provide them via config.hosts or initializeServices()."
1553
+ );
1554
+ }
1555
+ this._serviceContext = new import_sdk_services2.ServiceContext({
1556
+ invoke: effectiveInvoke,
1557
+ fetch: fetchFn ?? this.config.fetch ?? globalThis.fetch.bind(globalThis),
1558
+ hosts: effectiveHosts,
1559
+ retryPolicy: this.config.retryPolicy
1560
+ });
1561
+ const serviceConstructors = {
1562
+ kv: import_sdk_services2.KVService,
1563
+ sql: import_sdk_services2.SQLService,
1564
+ duckdb: import_sdk_services2.DuckDbService,
1565
+ ...this.config.services
1566
+ };
1567
+ for (const [name, ServiceClass] of Object.entries(serviceConstructors)) {
1568
+ const serviceConfig = this.config.serviceConfigs?.[name] ?? {};
1569
+ const service = new ServiceClass(serviceConfig);
1570
+ service.initialize(this._serviceContext);
1571
+ this._serviceContext.registerService(name, service);
1572
+ this._services.set(name, service);
1573
+ }
1574
+ this._servicesInitialized = true;
1575
+ }
1576
+ /**
1577
+ * Get the service context.
1578
+ * @throws Error if services are not initialized
1579
+ */
1580
+ get serviceContext() {
1581
+ if (!this._serviceContext) {
1582
+ throw new Error(
1583
+ "Services not initialized. Call initializeServices() first."
1584
+ );
1585
+ }
1586
+ return this._serviceContext;
1587
+ }
1588
+ /**
1589
+ * Get a registered service by name.
1590
+ *
1591
+ * @param name - Service name (e.g., 'kv')
1592
+ * @returns The service instance or undefined
1593
+ */
1594
+ getService(name) {
1595
+ return this._services.get(name);
1596
+ }
1597
+ /**
1598
+ * Get the KV service.
1599
+ * @throws Error if services are not initialized
1600
+ */
1601
+ get kv() {
1602
+ if (!this._servicesInitialized) {
1603
+ throw new Error(
1604
+ "Services not initialized. Call initializeServices() first, or use TinyCloudWeb/TinyCloudNode which handles this automatically."
1605
+ );
1606
+ }
1607
+ const service = this._services.get("kv");
1608
+ if (!service) {
1609
+ throw new Error("KV service is not registered.");
1610
+ }
1611
+ return service;
1612
+ }
1613
+ /**
1614
+ * Get the SQL service.
1615
+ * @throws Error if services are not initialized
1616
+ */
1617
+ get sql() {
1618
+ if (!this._servicesInitialized) {
1619
+ throw new Error(
1620
+ "Services not initialized. Call initializeServices() first, or use TinyCloudWeb/TinyCloudNode which handles this automatically."
1621
+ );
1622
+ }
1623
+ const service = this._services.get("sql");
1624
+ if (!service) {
1625
+ throw new Error("SQL service is not registered.");
1626
+ }
1627
+ return service;
1628
+ }
1629
+ /**
1630
+ * Get the DuckDB service.
1631
+ * @throws Error if services are not initialized
1632
+ */
1633
+ get duckdb() {
1634
+ if (!this._servicesInitialized) {
1635
+ throw new Error(
1636
+ "Services not initialized. Call initializeServices() first, or use TinyCloudWeb/TinyCloudNode which handles this automatically."
1637
+ );
1638
+ }
1639
+ const service = this._services.get("duckdb");
1640
+ if (!service) {
1641
+ throw new Error("DuckDB service is not registered.");
1642
+ }
1643
+ return service;
1644
+ }
1645
+ /**
1646
+ * Get the Data Vault service.
1647
+ * @throws Error if services are not initialized or vault service is not registered
1648
+ */
1649
+ get vault() {
1650
+ if (!this._servicesInitialized) {
1651
+ throw new Error(
1652
+ "Services not initialized. Call initializeServices() first, or use TinyCloudWeb/TinyCloudNode which handles this automatically."
1653
+ );
1654
+ }
1655
+ const service = this._services.get("vault");
1656
+ if (!service) {
1657
+ throw new Error("Vault service is not registered.");
1658
+ }
1659
+ return service;
1660
+ }
1661
+ /**
1662
+ * Notify services of session change.
1663
+ * Called internally after sign-in and sign-out.
1664
+ *
1665
+ * @param session - The new session, or null if signed out
1666
+ */
1667
+ notifyServicesOfSessionChange(session) {
1668
+ if (this._serviceContext) {
1669
+ this._serviceContext.setSession(session);
1670
+ }
1671
+ }
1672
+ /**
1673
+ * Abort all pending service operations.
1674
+ * Called internally before sign-out.
1675
+ */
1676
+ abortServiceOperations() {
1677
+ if (this._serviceContext) {
1678
+ this._serviceContext.abort();
1679
+ }
1680
+ }
1681
+ /**
1682
+ * Convert ClientSession to ServiceSession.
1683
+ * Returns null if session lacks required fields.
1684
+ */
1685
+ toServiceSession(clientSession) {
1686
+ if (!clientSession) return null;
1687
+ const tcSession = clientSession.tinycloudSession;
1688
+ if (!tcSession) return null;
1689
+ return {
1690
+ delegationHeader: tcSession.delegationHeader,
1691
+ delegationCid: tcSession.delegationCid,
1692
+ spaceId: tcSession.spaceId,
1693
+ verificationMethod: tcSession.verificationMethod,
1694
+ jwk: tcSession.jwk
1695
+ };
1696
+ }
1697
+ /**
1698
+ * Add an extension to the SDK.
1699
+ * Extensions can add capabilities and lifecycle hooks.
1700
+ */
1701
+ extend(extension) {
1702
+ this.extensions.push(extension);
1703
+ this.userAuthorization.extend(extension);
1704
+ }
1705
+ /**
1706
+ * Check if an extension is enabled.
1707
+ * @param namespace - The extension namespace to check
1708
+ */
1709
+ isExtensionEnabled(namespace) {
1710
+ return this.extensions.some((ext) => ext.namespace === namespace);
1711
+ }
1712
+ // === Authentication Methods (delegate to userAuthorization) ===
1713
+ /**
1714
+ * Get the current session, if signed in.
1715
+ */
1716
+ get session() {
1717
+ return this.userAuthorization.session;
1718
+ }
1719
+ /**
1720
+ * Check if the user is signed in.
1721
+ */
1722
+ get isSignedIn() {
1723
+ return !!this.userAuthorization.session;
1724
+ }
1725
+ /**
1726
+ * Sign in and create a new session.
1727
+ * Notifies services of the new session after successful sign-in.
1728
+ * @returns The new session
1729
+ */
1730
+ async signIn() {
1731
+ const session = await this.userAuthorization.signIn();
1732
+ const serviceSession = this.toServiceSession(session);
1733
+ this.notifyServicesOfSessionChange(serviceSession);
1734
+ return session;
1735
+ }
1736
+ /**
1737
+ * Sign out and clear the current session.
1738
+ * Aborts pending service operations and notifies services.
1739
+ */
1740
+ async signOut() {
1741
+ this.abortServiceOperations();
1742
+ await this.userAuthorization.signOut();
1743
+ this._publicKV = void 0;
1744
+ this.notifyServicesOfSessionChange(null);
1745
+ }
1746
+ /**
1747
+ * Get the current wallet address.
1748
+ */
1749
+ address() {
1750
+ return this.userAuthorization.address();
1751
+ }
1752
+ /**
1753
+ * Get the current chain ID.
1754
+ */
1755
+ chainId() {
1756
+ return this.userAuthorization.chainId();
1757
+ }
1758
+ /**
1759
+ * Sign a message with the connected wallet.
1760
+ * @param message - Message to sign
1761
+ */
1762
+ async signMessage(message) {
1763
+ return this.userAuthorization.signMessage(message);
1764
+ }
1765
+ /**
1766
+ * Construct the deterministic public space ID for a given address and chain ID.
1767
+ *
1768
+ * @param address - Ethereum address (0x-prefixed)
1769
+ * @param chainId - Chain ID (e.g., 1 for mainnet)
1770
+ * @returns The public space ID
1771
+ */
1772
+ static makePublicSpaceId(address, chainId) {
1773
+ return makePublicSpaceId(address, chainId);
1774
+ }
1775
+ /**
1776
+ * Ensure the user's public space exists.
1777
+ * Creates it via spaces.create('public') if it doesn't.
1778
+ * Called automatically by modules that need to publish data.
1779
+ *
1780
+ * Requires the user to be signed in and services to be initialized.
1781
+ */
1782
+ async ensurePublicSpace() {
1783
+ const address = this.address();
1784
+ const chainId = this.chainId();
1785
+ if (!address || !chainId) {
1786
+ return (0, import_sdk_services2.err)(
1787
+ (0, import_sdk_services2.serviceError)(
1788
+ import_sdk_services2.ErrorCodes.AUTH_REQUIRED,
1789
+ "Must be signed in to ensure public space",
1790
+ "public-space"
1791
+ )
1792
+ );
1793
+ }
1794
+ if (!this._serviceContext) {
1795
+ return (0, import_sdk_services2.err)(
1796
+ (0, import_sdk_services2.serviceError)(
1797
+ import_sdk_services2.ErrorCodes.AUTH_REQUIRED,
1798
+ "Services not initialized. Call initializeServices() or signIn() first.",
1799
+ "public-space"
1800
+ )
1801
+ );
1802
+ }
1803
+ const spaceId = makePublicSpaceId(address, chainId);
1804
+ try {
1805
+ const session = this._serviceContext.session;
1806
+ if (!session) {
1807
+ return (0, import_sdk_services2.err)(
1808
+ (0, import_sdk_services2.serviceError)(
1809
+ import_sdk_services2.ErrorCodes.AUTH_REQUIRED,
1810
+ "No active session",
1811
+ "public-space"
1812
+ )
1813
+ );
1814
+ }
1815
+ const headers = this._serviceContext.invoke(
1816
+ session,
1817
+ "space",
1818
+ spaceId,
1819
+ "tinycloud.space/info"
1820
+ );
1821
+ const response = await this._serviceContext.fetch(
1822
+ `${this._serviceContext.hosts[0]}/invoke`,
1823
+ { method: "POST", headers, body: JSON.stringify({ spaceId }) }
1824
+ );
1825
+ if (response.ok) {
1826
+ return (0, import_sdk_services2.ok)(void 0);
1827
+ }
1828
+ if (response.status === 404) {
1829
+ const createHeaders = this._serviceContext.invoke(
1830
+ session,
1831
+ "space",
1832
+ "public",
1833
+ "tinycloud.space/create"
1834
+ );
1835
+ const createResponse = await this._serviceContext.fetch(
1836
+ `${this._serviceContext.hosts[0]}/invoke`,
1837
+ {
1838
+ method: "POST",
1839
+ headers: createHeaders,
1840
+ body: JSON.stringify({ name: "public" })
1841
+ }
1842
+ );
1843
+ if (!createResponse.ok) {
1844
+ if (createResponse.status === 409) {
1845
+ return (0, import_sdk_services2.ok)(void 0);
1846
+ }
1847
+ const errorText2 = await createResponse.text();
1848
+ return (0, import_sdk_services2.err)(
1849
+ (0, import_sdk_services2.serviceError)(
1850
+ import_sdk_services2.ErrorCodes.NETWORK_ERROR,
1851
+ `Failed to create public space: ${createResponse.status} - ${errorText2}`,
1852
+ "public-space"
1853
+ )
1854
+ );
1855
+ }
1856
+ return (0, import_sdk_services2.ok)(void 0);
1857
+ }
1858
+ const errorText = await response.text();
1859
+ return (0, import_sdk_services2.err)(
1860
+ (0, import_sdk_services2.serviceError)(
1861
+ import_sdk_services2.ErrorCodes.NETWORK_ERROR,
1862
+ `Failed to check public space: ${response.status} - ${errorText}`,
1863
+ "public-space"
1864
+ )
1865
+ );
1866
+ } catch (error) {
1867
+ return (0, import_sdk_services2.err)(
1868
+ (0, import_sdk_services2.serviceError)(
1869
+ import_sdk_services2.ErrorCodes.NETWORK_ERROR,
1870
+ `Network error ensuring public space: ${String(error)}`,
1871
+ "public-space",
1872
+ { cause: error instanceof Error ? error : void 0 }
1873
+ )
1874
+ );
1875
+ }
1876
+ }
1877
+ /**
1878
+ * Get a KVService scoped to the user's own public space.
1879
+ * Writes require authentication (owner/delegate).
1880
+ *
1881
+ * @throws Error if not signed in or services not initialized
1882
+ */
1883
+ get publicKV() {
1884
+ if (!this._servicesInitialized || !this._serviceContext) {
1885
+ throw new Error(
1886
+ "Services not initialized. Call initializeServices() first, or use TinyCloudWeb/TinyCloudNode which handles this automatically."
1887
+ );
1888
+ }
1889
+ const address = this.address();
1890
+ const chainId = this.chainId();
1891
+ if (!address || !chainId) {
1892
+ throw new Error("Must be signed in to access publicKV.");
1893
+ }
1894
+ if (this._publicKV) {
1895
+ return this._publicKV;
1896
+ }
1897
+ const publicSpaceId = makePublicSpaceId(address, chainId);
1898
+ const session = this._serviceContext.session;
1899
+ if (!session) {
1900
+ throw new Error("No active session. Sign in first.");
1901
+ }
1902
+ const publicKV = new import_sdk_services2.KVService({ prefix: "" });
1903
+ const publicContext = new import_sdk_services2.ServiceContext({
1904
+ invoke: this._serviceContext.invoke,
1905
+ fetch: this._serviceContext.fetch,
1906
+ hosts: this._serviceContext.hosts,
1907
+ retryPolicy: this.config.retryPolicy
1908
+ });
1909
+ publicContext.setSession({
1910
+ ...session,
1911
+ spaceId: publicSpaceId
1912
+ });
1913
+ publicKV.initialize(publicContext);
1914
+ this._publicKV = publicKV;
1915
+ return this._publicKV;
1916
+ }
1917
+ /**
1918
+ * Read from any user's public space (unauthenticated).
1919
+ * Uses the public REST endpoint — no session needed.
1920
+ *
1921
+ * @param host - TinyCloud server URL (e.g., "https://node.tinycloud.xyz")
1922
+ * @param spaceId - Full public space ID
1923
+ * @param key - Key to read
1924
+ * @param fetchFn - Optional custom fetch function
1925
+ * @returns The data at the key
1926
+ */
1927
+ static async readPublicSpace(host, spaceId, key, fetchFn) {
1928
+ const doFetch = fetchFn ?? globalThis.fetch.bind(globalThis);
1929
+ const encodedKey = key.split("/").map(encodeURIComponent).join("/");
1930
+ const url = `${host}/public/${encodeURIComponent(spaceId)}/kv/${encodedKey}`;
1931
+ try {
1932
+ const response = await doFetch(url, { method: "GET" });
1933
+ if (!response.ok) {
1934
+ if (response.status === 404) {
1935
+ return (0, import_sdk_services2.err)(
1936
+ (0, import_sdk_services2.serviceError)(
1937
+ import_sdk_services2.ErrorCodes.NOT_FOUND,
1938
+ `Key not found: ${key} in space ${spaceId}`,
1939
+ "public-space"
1940
+ )
1941
+ );
1942
+ }
1943
+ const errorText = await response.text();
1944
+ return (0, import_sdk_services2.err)(
1945
+ (0, import_sdk_services2.serviceError)(
1946
+ import_sdk_services2.ErrorCodes.NETWORK_ERROR,
1947
+ `Failed to read public space: ${response.status} - ${errorText}`,
1948
+ "public-space",
1949
+ { meta: { status: response.status } }
1950
+ )
1951
+ );
1952
+ }
1953
+ const contentType = response.headers.get("content-type");
1954
+ let data;
1955
+ if (contentType?.includes("application/json")) {
1956
+ data = await response.json();
1957
+ } else {
1958
+ const text = await response.text();
1959
+ try {
1960
+ data = JSON.parse(text);
1961
+ } catch {
1962
+ data = text;
1963
+ }
1964
+ }
1965
+ return (0, import_sdk_services2.ok)(data);
1966
+ } catch (error) {
1967
+ return (0, import_sdk_services2.err)(
1968
+ (0, import_sdk_services2.serviceError)(
1969
+ import_sdk_services2.ErrorCodes.NETWORK_ERROR,
1970
+ `Network error reading public space: ${String(error)}`,
1971
+ "public-space",
1972
+ { cause: error instanceof Error ? error : void 0 }
1973
+ )
1974
+ );
1975
+ }
1976
+ }
1977
+ /**
1978
+ * Read from any user's public space by address (unauthenticated).
1979
+ * Convenience method that constructs the space ID from address and chain ID.
1980
+ *
1981
+ * @param host - TinyCloud server URL
1982
+ * @param address - Ethereum address (0x-prefixed)
1983
+ * @param chainId - Chain ID (e.g., 1 for mainnet)
1984
+ * @param key - Key to read
1985
+ * @param fetchFn - Optional custom fetch function
1986
+ * @returns The data at the key
1987
+ */
1988
+ static async readPublicKey(host, address, chainId, key, fetchFn) {
1989
+ const spaceId = makePublicSpaceId(address, chainId);
1990
+ return _TinyCloud.readPublicSpace(host, spaceId, key, fetchFn);
1991
+ }
1992
+ };
1993
+
1994
+ // src/index.ts
1995
+ var import_sdk_services4 = require("@tinycloud/sdk-services");
1996
+
1997
+ // src/space.ts
1998
+ async function fetchPeerId(host, spaceId) {
1999
+ const res = await fetch(
2000
+ `${host}/peer/generate/${encodeURIComponent(spaceId)}`
2001
+ );
2002
+ if (!res.ok) {
2003
+ const error = await res.text().catch(() => res.statusText);
2004
+ throw new Error(`Failed to get peer ID: ${res.status} - ${error}`);
2005
+ }
2006
+ return res.text();
2007
+ }
2008
+ async function submitHostDelegation(host, headers) {
2009
+ const res = await fetch(`${host}/delegate`, {
2010
+ method: "POST",
2011
+ headers
2012
+ });
2013
+ return {
2014
+ success: res.ok,
2015
+ status: res.status,
2016
+ error: res.ok ? void 0 : await res.text().catch(() => res.statusText)
2017
+ };
2018
+ }
2019
+ async function activateSessionWithHost(host, delegationHeader) {
2020
+ const res = await fetch(`${host}/delegate`, {
2021
+ method: "POST",
2022
+ headers: delegationHeader
2023
+ });
2024
+ if (res.ok) {
2025
+ try {
2026
+ const body = await res.json();
2027
+ return {
2028
+ success: true,
2029
+ status: res.status,
2030
+ activated: body.activated ?? [],
2031
+ skipped: body.skipped ?? []
2032
+ };
2033
+ } catch {
2034
+ return {
2035
+ success: true,
2036
+ status: res.status,
2037
+ activated: [],
2038
+ skipped: []
2039
+ };
2040
+ }
2041
+ }
2042
+ return {
2043
+ success: false,
2044
+ status: res.status,
2045
+ error: await res.text().catch(() => res.statusText)
2046
+ };
2047
+ }
2048
+
2049
+ // src/delegations/DelegationManager.ts
2050
+ var DelegationAction = {
2051
+ CREATE: "tinycloud.delegation/create",
2052
+ REVOKE: "tinycloud.delegation/revoke",
2053
+ LIST: "tinycloud.delegation/list",
2054
+ GET: "tinycloud.delegation/get",
2055
+ CHECK: "tinycloud.delegation/check"
2056
+ };
2057
+ function createError(code, message, cause, meta) {
2058
+ return {
2059
+ code,
2060
+ message,
2061
+ service: "delegation",
2062
+ cause,
2063
+ meta
2064
+ };
2065
+ }
2066
+ var DelegationManager = class {
2067
+ /**
2068
+ * Creates a new DelegationManager instance.
2069
+ *
2070
+ * @param config - Configuration including hosts, session, and invoke function
2071
+ */
2072
+ constructor(config) {
2073
+ this.hosts = config.hosts;
2074
+ this.session = config.session;
2075
+ this.invoke = config.invoke;
2076
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
2077
+ }
2078
+ /**
2079
+ * Updates the session (e.g., after re-authentication).
2080
+ *
2081
+ * @param session - New session to use for operations
2082
+ */
2083
+ updateSession(session) {
2084
+ this.session = session;
2085
+ }
2086
+ /**
2087
+ * Gets the primary host URL.
2088
+ */
2089
+ get host() {
2090
+ return this.hosts[0];
2091
+ }
2092
+ /**
2093
+ * Executes an invoke operation against the delegation API.
2094
+ */
2095
+ async invokeOperation(path, action, body) {
2096
+ const headers = this.invoke(this.session, "delegation", path, action);
2097
+ return this.fetchFn(`${this.host}/invoke`, {
2098
+ method: "POST",
2099
+ headers,
2100
+ body
2101
+ });
2102
+ }
2103
+ /**
2104
+ * Creates a new delegation.
2105
+ *
2106
+ * Delegates specific permissions to another DID for a given path.
2107
+ * The delegatee can then use these permissions to access resources
2108
+ * within the specified scope.
2109
+ *
2110
+ * @param params - Parameters for the delegation
2111
+ * @returns Result containing the created Delegation or an error
2112
+ *
2113
+ * @example
2114
+ * ```typescript
2115
+ * const result = await manager.create({
2116
+ * delegateDID: bob.did,
2117
+ * path: "documents/shared/",
2118
+ * actions: ["tinycloud.kv/get", "tinycloud.kv/put"],
2119
+ * expiry: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
2120
+ * });
2121
+ * ```
2122
+ */
2123
+ async create(params) {
2124
+ if (!params.delegateDID) {
2125
+ return {
2126
+ ok: false,
2127
+ error: createError(
2128
+ DelegationErrorCodes.INVALID_INPUT,
2129
+ "delegateDID is required"
2130
+ )
2131
+ };
2132
+ }
2133
+ if (!params.path) {
2134
+ return {
2135
+ ok: false,
2136
+ error: createError(
2137
+ DelegationErrorCodes.INVALID_INPUT,
2138
+ "path is required"
2139
+ )
2140
+ };
2141
+ }
2142
+ if (!params.actions || params.actions.length === 0) {
2143
+ return {
2144
+ ok: false,
2145
+ error: createError(
2146
+ DelegationErrorCodes.INVALID_INPUT,
2147
+ "at least one action is required"
2148
+ )
2149
+ };
2150
+ }
2151
+ try {
2152
+ const body = JSON.stringify({
2153
+ delegateDID: params.delegateDID,
2154
+ path: params.path,
2155
+ actions: params.actions,
2156
+ expiry: params.expiry?.toISOString(),
2157
+ disableSubDelegation: params.disableSubDelegation ?? false,
2158
+ statement: params.statement
2159
+ });
2160
+ const response = await this.invokeOperation(
2161
+ params.path,
2162
+ DelegationAction.CREATE,
2163
+ body
2164
+ );
2165
+ if (!response.ok) {
2166
+ const errorText = await response.text();
2167
+ return {
2168
+ ok: false,
2169
+ error: createError(
2170
+ DelegationErrorCodes.CREATION_FAILED,
2171
+ `Failed to create delegation: ${response.status} - ${errorText}`,
2172
+ void 0,
2173
+ { status: response.status, path: params.path }
2174
+ )
2175
+ };
2176
+ }
2177
+ const apiResponse = await response.json();
2178
+ const delegation = {
2179
+ cid: apiResponse.cid ?? "",
2180
+ delegateDID: params.delegateDID,
2181
+ spaceId: this.session.spaceId,
2182
+ path: params.path,
2183
+ actions: params.actions,
2184
+ expiry: params.expiry ?? new Date(Date.now() + 24 * 60 * 60 * 1e3),
2185
+ isRevoked: false,
2186
+ allowSubDelegation: !(params.disableSubDelegation ?? false),
2187
+ createdAt: /* @__PURE__ */ new Date()
2188
+ };
2189
+ return { ok: true, data: delegation };
2190
+ } catch (error) {
2191
+ if (error instanceof Error && error.name === "AbortError") {
2192
+ return {
2193
+ ok: false,
2194
+ error: createError(
2195
+ DelegationErrorCodes.ABORTED,
2196
+ "Request aborted",
2197
+ error
2198
+ )
2199
+ };
2200
+ }
2201
+ return {
2202
+ ok: false,
2203
+ error: createError(
2204
+ DelegationErrorCodes.NETWORK_ERROR,
2205
+ `Network error during delegation creation: ${String(error)}`,
2206
+ error instanceof Error ? error : void 0
2207
+ )
2208
+ };
2209
+ }
2210
+ }
2211
+ /**
2212
+ * Revokes an existing delegation.
2213
+ *
2214
+ * Once revoked, the delegation can no longer be used to access resources.
2215
+ * This also invalidates any sub-delegations derived from this delegation.
2216
+ *
2217
+ * @param cid - The CID of the delegation to revoke
2218
+ * @returns Result indicating success or an error
2219
+ *
2220
+ * @example
2221
+ * ```typescript
2222
+ * const result = await manager.revoke("bafy...");
2223
+ * if (result.ok) {
2224
+ * console.log("Delegation revoked successfully");
2225
+ * }
2226
+ * ```
2227
+ */
2228
+ async revoke(cid) {
2229
+ if (!cid) {
2230
+ return {
2231
+ ok: false,
2232
+ error: createError(
2233
+ DelegationErrorCodes.INVALID_INPUT,
2234
+ "cid is required"
2235
+ )
2236
+ };
2237
+ }
2238
+ try {
2239
+ const body = JSON.stringify({ cid });
2240
+ const response = await this.invokeOperation(
2241
+ cid,
2242
+ DelegationAction.REVOKE,
2243
+ body
2244
+ );
2245
+ if (!response.ok) {
2246
+ const errorText = await response.text();
2247
+ if (response.status === 404) {
2248
+ return {
2249
+ ok: false,
2250
+ error: createError(
2251
+ DelegationErrorCodes.NOT_FOUND,
2252
+ `Delegation not found: ${cid}`
2253
+ )
2254
+ };
2255
+ }
2256
+ return {
2257
+ ok: false,
2258
+ error: createError(
2259
+ DelegationErrorCodes.REVOCATION_FAILED,
2260
+ `Failed to revoke delegation: ${response.status} - ${errorText}`,
2261
+ void 0,
2262
+ { status: response.status, cid }
2263
+ )
2264
+ };
2265
+ }
2266
+ return { ok: true, data: void 0 };
2267
+ } catch (error) {
2268
+ if (error instanceof Error && error.name === "AbortError") {
2269
+ return {
2270
+ ok: false,
2271
+ error: createError(
2272
+ DelegationErrorCodes.ABORTED,
2273
+ "Request aborted",
2274
+ error
2275
+ )
2276
+ };
2277
+ }
2278
+ return {
2279
+ ok: false,
2280
+ error: createError(
2281
+ DelegationErrorCodes.NETWORK_ERROR,
2282
+ `Network error during delegation revocation: ${String(error)}`,
2283
+ error instanceof Error ? error : void 0
2284
+ )
2285
+ };
2286
+ }
2287
+ }
2288
+ /**
2289
+ * Lists all delegations for the current session's space.
2290
+ *
2291
+ * Returns both delegations created by the current user (as delegator)
2292
+ * and delegations granted to the current user (as delegatee).
2293
+ *
2294
+ * @returns Result containing an array of Delegations or an error
2295
+ *
2296
+ * @example
2297
+ * ```typescript
2298
+ * const result = await manager.list();
2299
+ * if (result.ok) {
2300
+ * for (const delegation of result.data) {
2301
+ * console.log(`${delegation.cid}: ${delegation.path} -> ${delegation.delegateDID}`);
2302
+ * }
2303
+ * }
2304
+ * ```
2305
+ */
2306
+ async list() {
2307
+ try {
2308
+ const response = await this.invokeOperation("", DelegationAction.LIST);
2309
+ if (!response.ok) {
2310
+ const errorText = await response.text();
2311
+ return {
2312
+ ok: false,
2313
+ error: createError(
2314
+ DelegationErrorCodes.NETWORK_ERROR,
2315
+ `Failed to list delegations: ${response.status} - ${errorText}`,
2316
+ void 0,
2317
+ { status: response.status }
2318
+ )
2319
+ };
2320
+ }
2321
+ const data = await response.json();
2322
+ const delegations = data.map((item) => ({
2323
+ cid: item.cid,
2324
+ delegateDID: item.delegateDID,
2325
+ delegatorDID: item.delegatorDID,
2326
+ spaceId: item.spaceId,
2327
+ path: item.path,
2328
+ actions: item.actions,
2329
+ expiry: new Date(item.expiry),
2330
+ isRevoked: item.isRevoked,
2331
+ createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
2332
+ parentCid: item.parentCid,
2333
+ allowSubDelegation: item.allowSubDelegation
2334
+ }));
2335
+ return { ok: true, data: delegations };
2336
+ } catch (error) {
2337
+ if (error instanceof Error && error.name === "AbortError") {
2338
+ return {
2339
+ ok: false,
2340
+ error: createError(
2341
+ DelegationErrorCodes.ABORTED,
2342
+ "Request aborted",
2343
+ error
2344
+ )
2345
+ };
2346
+ }
2347
+ return {
2348
+ ok: false,
2349
+ error: createError(
2350
+ DelegationErrorCodes.NETWORK_ERROR,
2351
+ `Network error during delegation list: ${String(error)}`,
2352
+ error instanceof Error ? error : void 0
2353
+ )
2354
+ };
2355
+ }
2356
+ }
2357
+ /**
2358
+ * Gets the full delegation chain for a given delegation.
2359
+ *
2360
+ * Returns the chain of delegations from the root (original delegator)
2361
+ * to the specified delegation, including all intermediate sub-delegations.
2362
+ *
2363
+ * @param cid - The CID of the delegation to get the chain for
2364
+ * @returns Result containing the DelegationChain or an error
2365
+ *
2366
+ * @example
2367
+ * ```typescript
2368
+ * const result = await manager.getChain("bafy...");
2369
+ * if (result.ok) {
2370
+ * console.log("Chain length:", result.data.length);
2371
+ * for (const delegation of result.data) {
2372
+ * console.log(`- ${delegation.delegatorDID} -> ${delegation.delegateDID}`);
2373
+ * }
2374
+ * }
2375
+ * ```
2376
+ */
2377
+ async getChain(cid) {
2378
+ if (!cid) {
2379
+ return {
2380
+ ok: false,
2381
+ error: createError(
2382
+ DelegationErrorCodes.INVALID_INPUT,
2383
+ "cid is required"
2384
+ )
2385
+ };
2386
+ }
2387
+ try {
2388
+ const body = JSON.stringify({ cid, includeChain: true });
2389
+ const response = await this.invokeOperation(
2390
+ cid,
2391
+ DelegationAction.GET,
2392
+ body
2393
+ );
2394
+ if (!response.ok) {
2395
+ const errorText = await response.text();
2396
+ if (response.status === 404) {
2397
+ return {
2398
+ ok: false,
2399
+ error: createError(
2400
+ DelegationErrorCodes.NOT_FOUND,
2401
+ `Delegation not found: ${cid}`
2402
+ )
2403
+ };
2404
+ }
2405
+ return {
2406
+ ok: false,
2407
+ error: createError(
2408
+ DelegationErrorCodes.NETWORK_ERROR,
2409
+ `Failed to get delegation chain: ${response.status} - ${errorText}`,
2410
+ void 0,
2411
+ { status: response.status, cid }
2412
+ )
2413
+ };
2414
+ }
2415
+ const data = await response.json();
2416
+ const chain = data.chain.map((item) => ({
2417
+ cid: item.cid,
2418
+ delegateDID: item.delegateDID,
2419
+ delegatorDID: item.delegatorDID,
2420
+ spaceId: item.spaceId,
2421
+ path: item.path,
2422
+ actions: item.actions,
2423
+ expiry: new Date(item.expiry),
2424
+ isRevoked: item.isRevoked,
2425
+ createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
2426
+ parentCid: item.parentCid,
2427
+ allowSubDelegation: item.allowSubDelegation
2428
+ }));
2429
+ return { ok: true, data: chain };
2430
+ } catch (error) {
2431
+ if (error instanceof Error && error.name === "AbortError") {
2432
+ return {
2433
+ ok: false,
2434
+ error: createError(
2435
+ DelegationErrorCodes.ABORTED,
2436
+ "Request aborted",
2437
+ error
2438
+ )
2439
+ };
2440
+ }
2441
+ return {
2442
+ ok: false,
2443
+ error: createError(
2444
+ DelegationErrorCodes.NETWORK_ERROR,
2445
+ `Network error during chain retrieval: ${String(error)}`,
2446
+ error instanceof Error ? error : void 0
2447
+ )
2448
+ };
2449
+ }
2450
+ }
2451
+ /**
2452
+ * Checks if the current session has permission for a given path and action.
2453
+ *
2454
+ * This can be used to verify permissions before attempting an operation,
2455
+ * or to implement custom access control logic.
2456
+ *
2457
+ * @param path - The resource path to check
2458
+ * @param action - The action to check (e.g., "tinycloud.kv/get")
2459
+ * @returns Result containing a boolean indicating permission or an error
2460
+ *
2461
+ * @example
2462
+ * ```typescript
2463
+ * const result = await manager.checkPermission("documents/private/", "tinycloud.kv/put");
2464
+ * if (result.ok && result.data) {
2465
+ * console.log("Permission granted");
2466
+ * } else {
2467
+ * console.log("Permission denied");
2468
+ * }
2469
+ * ```
2470
+ */
2471
+ async checkPermission(path, action) {
2472
+ if (!path) {
2473
+ return {
2474
+ ok: false,
2475
+ error: createError(
2476
+ DelegationErrorCodes.INVALID_INPUT,
2477
+ "path is required"
2478
+ )
2479
+ };
2480
+ }
2481
+ if (!action) {
2482
+ return {
2483
+ ok: false,
2484
+ error: createError(
2485
+ DelegationErrorCodes.INVALID_INPUT,
2486
+ "action is required"
2487
+ )
2488
+ };
2489
+ }
2490
+ try {
2491
+ const body = JSON.stringify({ path, action });
2492
+ const response = await this.invokeOperation(
2493
+ path,
2494
+ DelegationAction.CHECK,
2495
+ body
2496
+ );
2497
+ if (!response.ok) {
2498
+ if (response.status === 403) {
2499
+ return { ok: true, data: false };
2500
+ }
2501
+ const errorText = await response.text();
2502
+ return {
2503
+ ok: false,
2504
+ error: createError(
2505
+ DelegationErrorCodes.NETWORK_ERROR,
2506
+ `Failed to check permission: ${response.status} - ${errorText}`,
2507
+ void 0,
2508
+ { status: response.status, path, action }
2509
+ )
2510
+ };
2511
+ }
2512
+ const data = await response.json();
2513
+ return { ok: true, data: data.allowed };
2514
+ } catch (error) {
2515
+ if (error instanceof Error && error.name === "AbortError") {
2516
+ return {
2517
+ ok: false,
2518
+ error: createError(
2519
+ DelegationErrorCodes.ABORTED,
2520
+ "Request aborted",
2521
+ error
2522
+ )
2523
+ };
2524
+ }
2525
+ return {
2526
+ ok: false,
2527
+ error: createError(
2528
+ DelegationErrorCodes.NETWORK_ERROR,
2529
+ `Network error during permission check: ${String(error)}`,
2530
+ error instanceof Error ? error : void 0
2531
+ )
2532
+ };
2533
+ }
2534
+ }
2535
+ };
2536
+
2537
+ // src/delegations/SharingService.schema.ts
2538
+ var import_zod5 = require("zod");
2539
+ var EncodedShareDataSchema = import_zod5.z.object({
2540
+ /** Private key in JWK format (must include d parameter) */
2541
+ key: JWKSchema.refine(
2542
+ (jwk) => typeof jwk.d === "string" && jwk.d.length > 0,
2543
+ { message: "JWK must include private key (d parameter)" }
2544
+ ),
2545
+ /** DID of the key */
2546
+ keyDid: import_zod5.z.string().min(1, "keyDid is required"),
2547
+ /** The delegation granting access */
2548
+ delegation: DelegationSchema,
2549
+ /** Resource path this link grants access to */
2550
+ path: import_zod5.z.string().min(1, "path is required"),
2551
+ /** TinyCloud host URL */
2552
+ host: import_zod5.z.string().url("host must be a valid URL"),
2553
+ /** Space ID */
2554
+ spaceId: import_zod5.z.string().min(1, "spaceId is required"),
2555
+ /** Schema version (must be 1) */
2556
+ version: import_zod5.z.literal(1)
2557
+ });
2558
+ var ReceiveOptionsSchema = import_zod5.z.object({
2559
+ /**
2560
+ * Whether to automatically create a sub-delegation to the current session key.
2561
+ * Default: true
2562
+ */
2563
+ autoSubdelegate: import_zod5.z.boolean().optional(),
2564
+ /**
2565
+ * Whether to use the current session key for operations (requires autoSubdelegate).
2566
+ * Default: true
2567
+ */
2568
+ useSessionKey: import_zod5.z.boolean().optional(),
2569
+ /**
2570
+ * Ingestion options passed to CapabilityKeyRegistry.
2571
+ */
2572
+ ingestOptions: IngestOptionsSchema.optional()
2573
+ });
2574
+ var SharingServiceConfigSchema = import_zod5.z.object({
2575
+ /** TinyCloud host URLs */
2576
+ hosts: import_zod5.z.array(import_zod5.z.string().url()).min(1, "At least one host URL is required"),
2577
+ /**
2578
+ * Active session for authentication.
2579
+ * Required for generate(), optional for receive().
2580
+ */
2581
+ session: import_zod5.z.unknown().refine(
2582
+ (val) => val === void 0 || val !== null && typeof val === "object",
2583
+ { message: "Expected a ServiceSession object or undefined" }
2584
+ ).optional(),
2585
+ /** Platform-specific invoke function */
2586
+ invoke: import_zod5.z.unknown().refine((val) => typeof val === "function", {
2587
+ message: "Expected an invoke function"
2588
+ }),
2589
+ /** Optional custom fetch implementation */
2590
+ fetch: import_zod5.z.unknown().refine(
2591
+ (val) => val === void 0 || typeof val === "function",
2592
+ { message: "Expected a fetch function or undefined" }
2593
+ ).optional(),
2594
+ /** Key provider for cryptographic operations */
2595
+ keyProvider: KeyProviderSchema,
2596
+ /** Capability key registry for key/delegation management */
2597
+ registry: import_zod5.z.unknown().refine(
2598
+ (val) => val !== null && typeof val === "object",
2599
+ { message: "Expected an ICapabilityKeyRegistry object" }
2600
+ ),
2601
+ /**
2602
+ * Delegation manager for creating delegations.
2603
+ * Required for generate(), optional for receive().
2604
+ */
2605
+ delegationManager: import_zod5.z.unknown().refine(
2606
+ (val) => val === void 0 || val !== null && typeof val === "object",
2607
+ { message: "Expected a DelegationManager object or undefined" }
2608
+ ).optional(),
2609
+ /** Factory for creating KV service instances */
2610
+ createKVService: import_zod5.z.unknown().refine(
2611
+ (val) => typeof val === "function",
2612
+ { message: "Expected a createKVService factory function" }
2613
+ ),
2614
+ /** Base URL for sharing links (e.g., "https://share.myapp.com") */
2615
+ baseUrl: import_zod5.z.string().optional(),
2616
+ /**
2617
+ * Custom delegation creation function.
2618
+ */
2619
+ createDelegation: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
2620
+ message: "Expected a createDelegation function or undefined"
2621
+ }).optional(),
2622
+ /**
2623
+ * WASM function for client-side delegation creation.
2624
+ */
2625
+ createDelegationWasm: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
2626
+ message: "Expected a createDelegationWasm function or undefined"
2627
+ }).optional(),
2628
+ /**
2629
+ * Path prefix for KV operations.
2630
+ */
2631
+ pathPrefix: import_zod5.z.string().optional(),
2632
+ /**
2633
+ * Session expiry time.
2634
+ */
2635
+ sessionExpiry: import_zod5.z.date().optional(),
2636
+ /**
2637
+ * Callback to create a DIRECT delegation from wallet to share key.
2638
+ * This is the preferred method for long-lived share links because it
2639
+ * bypasses the session delegation chain entirely.
2640
+ */
2641
+ onRootDelegationNeeded: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
2642
+ message: "Expected an onRootDelegationNeeded function or undefined"
2643
+ }).optional()
2644
+ });
2645
+ function validateEncodedShareData(data) {
2646
+ const result = EncodedShareDataSchema.safeParse(data);
2647
+ if (!result.success) {
2648
+ return {
2649
+ ok: false,
2650
+ error: {
2651
+ code: DelegationErrorCodes.VALIDATION_ERROR,
2652
+ message: `Invalid share data: ${result.error.message}`,
2653
+ service: "delegation",
2654
+ meta: { issues: result.error.issues }
2655
+ }
2656
+ };
2657
+ }
2658
+ return { ok: true, data: result.data };
2659
+ }
2660
+
2661
+ // src/delegations/SharingService.ts
2662
+ var DEFAULT_READ_ACTIONS = ["tinycloud.kv/get", "tinycloud.kv/metadata"];
2663
+ var DEFAULT_EXPIRY_MS = 24 * 60 * 60 * 1e3;
2664
+ var BASE64_PREFIX = "tc1:";
2665
+ function createError2(code, message, cause, meta) {
2666
+ return {
2667
+ code,
2668
+ message,
2669
+ service: "delegation",
2670
+ cause,
2671
+ meta
2672
+ };
2673
+ }
2674
+ function base64UrlEncode(data) {
2675
+ let base64;
2676
+ if (typeof btoa !== "undefined") {
2677
+ base64 = btoa(unescape(encodeURIComponent(data)));
2678
+ } else if (typeof Buffer !== "undefined") {
2679
+ base64 = Buffer.from(data, "utf-8").toString("base64");
2680
+ } else {
2681
+ throw new Error("No base64 encoding available");
2682
+ }
2683
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2684
+ }
2685
+ function base64UrlDecode(encoded) {
2686
+ let base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
2687
+ while (base64.length % 4) {
2688
+ base64 += "=";
2689
+ }
2690
+ if (typeof atob !== "undefined") {
2691
+ return decodeURIComponent(escape(atob(base64)));
2692
+ } else if (typeof Buffer !== "undefined") {
2693
+ return Buffer.from(base64, "base64").toString("utf-8");
2694
+ } else {
2695
+ throw new Error("No base64 decoding available");
2696
+ }
2697
+ }
2698
+ var SharingService = class {
2699
+ /**
2700
+ * Creates a new SharingService instance.
2701
+ */
2702
+ constructor(config) {
2703
+ this.hosts = config.hosts;
2704
+ this.session = config.session;
2705
+ this.invoke = config.invoke;
2706
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
2707
+ this.keyProvider = config.keyProvider;
2708
+ this.registry = config.registry;
2709
+ this.delegationManager = config.delegationManager;
2710
+ this.createKVService = config.createKVService;
2711
+ this.baseUrl = (config.baseUrl ?? "").replace(/\/$/, "");
2712
+ this.createDelegationFn = config.createDelegation;
2713
+ this.createDelegationWasmFn = config.createDelegationWasm;
2714
+ this.pathPrefix = config.pathPrefix ?? "";
2715
+ this.sessionExpiry = config.sessionExpiry;
2716
+ this.onRootDelegationNeeded = config.onRootDelegationNeeded;
2717
+ }
2718
+ /**
2719
+ * Gets the primary host URL.
2720
+ */
2721
+ get host() {
2722
+ return this.hosts[0];
2723
+ }
2724
+ /**
2725
+ * Updates the session (e.g., after re-authentication).
2726
+ */
2727
+ updateSession(session) {
2728
+ this.session = session;
2729
+ }
2730
+ /**
2731
+ * Updates the service configuration.
2732
+ * Used to add full capabilities (session, delegationManager, createDelegation, createDelegationWasm) after signIn.
2733
+ */
2734
+ updateConfig(config) {
2735
+ if (config.session !== void 0) {
2736
+ this.session = config.session;
2737
+ }
2738
+ if (config.delegationManager !== void 0) {
2739
+ this.delegationManager = config.delegationManager;
2740
+ }
2741
+ if (config.createDelegation !== void 0) {
2742
+ this.createDelegationFn = config.createDelegation;
2743
+ }
2744
+ if (config.createDelegationWasm !== void 0) {
2745
+ this.createDelegationWasmFn = config.createDelegationWasm;
2746
+ }
2747
+ if (config.sessionExpiry !== void 0) {
2748
+ this.sessionExpiry = config.sessionExpiry;
2749
+ }
2750
+ if (config.onRootDelegationNeeded !== void 0) {
2751
+ this.onRootDelegationNeeded = config.onRootDelegationNeeded;
2752
+ }
2753
+ }
2754
+ /**
2755
+ * Generate a sharing link with an embedded private key.
2756
+ *
2757
+ * Flow:
2758
+ * 1. Spawn new session key (unique per share)
2759
+ * 2. Create delegation from current session to spawned key
2760
+ * 3. Package: { key (with private!), delegation, path, host }
2761
+ * 4. Encode based on schema (base64 for now)
2762
+ * 5. Return link string
2763
+ */
2764
+ async generate(params) {
2765
+ if (!this.session) {
2766
+ return {
2767
+ ok: false,
2768
+ error: createError2(
2769
+ DelegationErrorCodes.NOT_INITIALIZED,
2770
+ "Session required for generating sharing links. Call signIn() first."
2771
+ )
2772
+ };
2773
+ }
2774
+ if (!this.createDelegationWasmFn && !this.createDelegationFn && !this.delegationManager) {
2775
+ return {
2776
+ ok: false,
2777
+ error: createError2(
2778
+ DelegationErrorCodes.NOT_INITIALIZED,
2779
+ "DelegationManager, createDelegation, or createDelegationWasm function required for generating sharing links."
2780
+ )
2781
+ };
2782
+ }
2783
+ if (!params.path) {
2784
+ return {
2785
+ ok: false,
2786
+ error: createError2(
2787
+ DelegationErrorCodes.INVALID_INPUT,
2788
+ "path is required"
2789
+ )
2790
+ };
2791
+ }
2792
+ const actions = params.actions ?? DEFAULT_READ_ACTIONS;
2793
+ const requestedExpiry = params.expiry ?? new Date(Date.now() + DEFAULT_EXPIRY_MS);
2794
+ let expiry = requestedExpiry;
2795
+ const schema = params.schema ?? "base64";
2796
+ const fullPath = this.pathPrefix ? `${this.pathPrefix}/${params.path}`.replace(/\/+/g, "/") : params.path;
2797
+ if (schema !== "base64") {
2798
+ return {
2799
+ ok: false,
2800
+ error: createError2(
2801
+ DelegationErrorCodes.INVALID_INPUT,
2802
+ `Schema '${schema}' not implemented. Only 'base64' is supported.`
2803
+ )
2804
+ };
2805
+ }
2806
+ let keyId;
2807
+ let keyDid;
2808
+ let keyJwk;
2809
+ try {
2810
+ const shareKeyName = `share:${Date.now()}:${Math.random().toString(36).substring(2, 10)}`;
2811
+ keyId = await this.keyProvider.createSessionKey(shareKeyName);
2812
+ keyDid = await this.keyProvider.getDID(keyId);
2813
+ keyJwk = this.keyProvider.getJWK(keyId);
2814
+ if (!keyJwk.d) {
2815
+ return {
2816
+ ok: false,
2817
+ error: createError2(
2818
+ DelegationErrorCodes.CREATION_FAILED,
2819
+ "KeyProvider did not return private key (d parameter) in JWK"
2820
+ )
2821
+ };
2822
+ }
2823
+ } catch (err5) {
2824
+ return {
2825
+ ok: false,
2826
+ error: createError2(
2827
+ DelegationErrorCodes.CREATION_FAILED,
2828
+ `Failed to generate session key for share: ${err5 instanceof Error ? err5.message : String(err5)}`,
2829
+ err5 instanceof Error ? err5 : void 0
2830
+ )
2831
+ };
2832
+ }
2833
+ let delegation;
2834
+ const plainDID = keyDid.split("#")[0];
2835
+ const handleDelegationResult = (result) => {
2836
+ if (result && typeof result === "object" && "ok" in result) {
2837
+ return result;
2838
+ }
2839
+ return result;
2840
+ };
2841
+ const canSatisfyFromRegistry = this.findSuitableKeyForDelegation(
2842
+ fullPath,
2843
+ actions,
2844
+ requestedExpiry
2845
+ );
2846
+ if (canSatisfyFromRegistry) {
2847
+ const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
2848
+ const parsed = handleDelegationResult(delegationResult);
2849
+ if ("ok" in parsed && parsed.ok === false) {
2850
+ return parsed;
2851
+ }
2852
+ delegation = parsed;
2853
+ } else if (this.onRootDelegationNeeded) {
2854
+ try {
2855
+ const rootDelegation = await this.onRootDelegationNeeded({
2856
+ shareKeyDID: plainDID,
2857
+ spaceId: this.session.spaceId,
2858
+ path: fullPath,
2859
+ actions,
2860
+ requestedExpiry
2861
+ });
2862
+ if (rootDelegation) {
2863
+ delegation = rootDelegation;
2864
+ expiry = requestedExpiry;
2865
+ } else {
2866
+ const fallbackResult = await this.handleSessionExtensionFallback(requestedExpiry);
2867
+ expiry = fallbackResult.expiry;
2868
+ const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
2869
+ const parsed = handleDelegationResult(delegationResult);
2870
+ if ("ok" in parsed && parsed.ok === false) {
2871
+ return parsed;
2872
+ }
2873
+ delegation = parsed;
2874
+ }
2875
+ } catch (err5) {
2876
+ const fallbackResult = await this.handleSessionExtensionFallback(requestedExpiry);
2877
+ expiry = fallbackResult.expiry;
2878
+ const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
2879
+ const parsed = handleDelegationResult(delegationResult);
2880
+ if ("ok" in parsed && parsed.ok === false) {
2881
+ return parsed;
2882
+ }
2883
+ delegation = parsed;
2884
+ }
2885
+ } else {
2886
+ const fallbackResult = await this.handleSessionExtensionFallback(requestedExpiry);
2887
+ expiry = fallbackResult.expiry;
2888
+ const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
2889
+ const parsed = handleDelegationResult(delegationResult);
2890
+ if ("ok" in parsed && parsed.ok === false) {
2891
+ return parsed;
2892
+ }
2893
+ delegation = parsed;
2894
+ }
2895
+ const shareData = {
2896
+ key: keyJwk,
2897
+ keyDid,
2898
+ delegation,
2899
+ path: fullPath,
2900
+ host: this.host,
2901
+ spaceId: this.session.spaceId,
2902
+ version: 1
2903
+ };
2904
+ const encodedData = this.encodeLink(shareData, schema);
2905
+ const baseUrl = params.baseUrl ?? this.baseUrl;
2906
+ const url = baseUrl ? `${baseUrl}/share/${encodedData}` : encodedData;
2907
+ const shareLink = {
2908
+ token: encodedData,
2909
+ url,
2910
+ delegation,
2911
+ schema,
2912
+ expiresAt: expiry,
2913
+ description: params.description
2914
+ };
2915
+ return { ok: true, data: shareLink };
2916
+ }
2917
+ /**
2918
+ * Check if any key in the registry can satisfy the delegation request.
2919
+ * A key can satisfy if it has a delegation that:
2920
+ * 1. Covers the required path (exact match or parent path)
2921
+ * 2. Has all required actions
2922
+ * 3. Has sufficient expiry (delegation.expiry >= requestedExpiry)
2923
+ * 4. Allows sub-delegation
2924
+ * @internal
2925
+ */
2926
+ findSuitableKeyForDelegation(path, actions, requestedExpiry) {
2927
+ if (this.sessionExpiry && requestedExpiry <= this.sessionExpiry) {
2928
+ return true;
2929
+ }
2930
+ const allKeys = this.registry.getAllKeys();
2931
+ for (const key of allKeys) {
2932
+ const delegations = this.registry.getDelegationsForKey(key.id);
2933
+ for (const delegation of delegations) {
2934
+ if (!this.registry.isDelegationValid(delegation)) {
2935
+ continue;
2936
+ }
2937
+ if (delegation.expiry < requestedExpiry) {
2938
+ continue;
2939
+ }
2940
+ if (delegation.allowSubDelegation === false) {
2941
+ continue;
2942
+ }
2943
+ const delegationPath = delegation.path || "";
2944
+ if (!this.pathMatches(delegationPath, path)) {
2945
+ continue;
2946
+ }
2947
+ const delegationActions = delegation.actions || [];
2948
+ const hasAllActions = actions.every(
2949
+ (action) => delegationActions.includes(action) || delegationActions.includes("*")
2950
+ );
2951
+ if (!hasAllActions) {
2952
+ continue;
2953
+ }
2954
+ return true;
2955
+ }
2956
+ }
2957
+ return false;
2958
+ }
2959
+ /**
2960
+ * Check if a delegation path matches/covers the requested path.
2961
+ * A delegation path covers the request if:
2962
+ * - It's an exact match
2963
+ * - It's a parent path (e.g., delegation for "" covers "foo/bar")
2964
+ * - It uses wildcards that match
2965
+ * @internal
2966
+ */
2967
+ pathMatches(delegationPath, requestedPath) {
2968
+ if (delegationPath === "" || delegationPath === "*") {
2969
+ return true;
2970
+ }
2971
+ if (delegationPath === requestedPath) {
2972
+ return true;
2973
+ }
2974
+ const normalizedDelegation = delegationPath.replace(/\/$/, "");
2975
+ const normalizedRequest = requestedPath.replace(/\/$/, "");
2976
+ if (normalizedRequest.startsWith(normalizedDelegation + "/")) {
2977
+ return true;
2978
+ }
2979
+ return false;
2980
+ }
2981
+ /**
2982
+ * Handle fallback to session extension when root delegation is not available.
2983
+ * @internal
2984
+ */
2985
+ async handleSessionExtensionFallback(requestedExpiry) {
2986
+ return { expiry: this.sessionExpiry ?? requestedExpiry };
2987
+ }
2988
+ /**
2989
+ * Create a delegation from the current session to a share key.
2990
+ * This is the fallback path when root delegation is not available.
2991
+ * @internal
2992
+ */
2993
+ async createSessionDelegation(delegateDID, path, actions, expiry) {
2994
+ if (!this.session) {
2995
+ return {
2996
+ ok: false,
2997
+ error: createError2(
2998
+ DelegationErrorCodes.NOT_INITIALIZED,
2999
+ "Session required for creating delegation"
3000
+ )
3001
+ };
3002
+ }
3003
+ if (this.createDelegationWasmFn) {
3004
+ try {
3005
+ const wasmResult = this.createDelegationWasmFn({
3006
+ session: this.session,
3007
+ delegateDID,
3008
+ spaceId: this.session.spaceId,
3009
+ path,
3010
+ actions,
3011
+ expirationSecs: Math.floor(expiry.getTime() / 1e3)
3012
+ });
3013
+ const registerRes = await this.fetchFn(`${this.host}/delegate`, {
3014
+ method: "POST",
3015
+ headers: {
3016
+ Authorization: wasmResult.delegation
3017
+ }
3018
+ });
3019
+ if (!registerRes.ok) {
3020
+ const errorText = await registerRes.text();
3021
+ return {
3022
+ ok: false,
3023
+ error: createError2(
3024
+ DelegationErrorCodes.CREATION_FAILED,
3025
+ `Failed to register delegation with server: ${registerRes.status} ${errorText}`
3026
+ )
3027
+ };
3028
+ }
3029
+ return {
3030
+ cid: wasmResult.cid,
3031
+ delegateDID: wasmResult.delegateDID,
3032
+ spaceId: this.session.spaceId,
3033
+ path: wasmResult.path,
3034
+ actions: wasmResult.actions,
3035
+ expiry: wasmResult.expiry,
3036
+ isRevoked: false,
3037
+ authHeader: wasmResult.delegation,
3038
+ allowSubDelegation: true,
3039
+ createdAt: /* @__PURE__ */ new Date()
3040
+ };
3041
+ } catch (err5) {
3042
+ return {
3043
+ ok: false,
3044
+ error: createError2(
3045
+ DelegationErrorCodes.CREATION_FAILED,
3046
+ `Failed to create delegation via WASM: ${err5 instanceof Error ? err5.message : String(err5)}`,
3047
+ err5 instanceof Error ? err5 : void 0
3048
+ )
3049
+ };
3050
+ }
3051
+ } else {
3052
+ const delegationParams = {
3053
+ delegateDID,
3054
+ path,
3055
+ actions,
3056
+ expiry,
3057
+ disableSubDelegation: false
3058
+ };
3059
+ const delegationResult = this.createDelegationFn ? await this.createDelegationFn(delegationParams) : await this.delegationManager.create(delegationParams);
3060
+ if (!delegationResult.ok) {
3061
+ return {
3062
+ ok: false,
3063
+ error: createError2(
3064
+ DelegationErrorCodes.CREATION_FAILED,
3065
+ `Failed to create delegation for share: ${delegationResult.error.message}`,
3066
+ delegationResult.error.cause,
3067
+ delegationResult.error.meta
3068
+ )
3069
+ };
3070
+ }
3071
+ return delegationResult.data;
3072
+ }
3073
+ }
3074
+ /**
3075
+ * Receive and activate a sharing link.
3076
+ *
3077
+ * Flow:
3078
+ * 1. Decode link -> extract { key, delegation, path, host }
3079
+ * 2. Ingest key into CapabilityKeyRegistry
3080
+ * 3. If autoSubdelegate (default true) + useSessionKey:
3081
+ * - Create sub-delegation from ingested key -> current session
3082
+ * - Register sub-delegation capabilities
3083
+ * 4. Return ShareAccess with pre-configured KV service
3084
+ */
3085
+ async receive(link, options = {}) {
3086
+ const {
3087
+ autoSubdelegate = true,
3088
+ useSessionKey = true,
3089
+ ingestOptions
3090
+ } = options;
3091
+ const decodeResult = this.decodeLinkWithValidation(link);
3092
+ if (!decodeResult.ok) {
3093
+ return decodeResult;
3094
+ }
3095
+ const shareData = decodeResult.data;
3096
+ const delegationExpiry = new Date(shareData.delegation.expiry);
3097
+ if (delegationExpiry < /* @__PURE__ */ new Date()) {
3098
+ return {
3099
+ ok: false,
3100
+ error: createError2(
3101
+ DelegationErrorCodes.AUTH_EXPIRED,
3102
+ "Sharing link has expired"
3103
+ )
3104
+ };
3105
+ }
3106
+ if (shareData.delegation.isRevoked) {
3107
+ return {
3108
+ ok: false,
3109
+ error: createError2(
3110
+ DelegationErrorCodes.REVOKED,
3111
+ "Sharing link has been revoked"
3112
+ )
3113
+ };
3114
+ }
3115
+ const keyInfo = {
3116
+ id: `ingested:${shareData.keyDid}`,
3117
+ did: shareData.keyDid,
3118
+ type: "ingested",
3119
+ jwk: shareData.key,
3120
+ priority: 2
3121
+ // Ingested keys have lowest priority
3122
+ };
3123
+ this.registry.ingestKey(keyInfo, shareData.delegation, ingestOptions);
3124
+ let activeDelegation = shareData.delegation;
3125
+ let activeKey = keyInfo;
3126
+ if (autoSubdelegate && useSessionKey && this.session) {
3127
+ try {
3128
+ } catch (err5) {
3129
+ console.warn("Auto-subdelegation failed, using ingested key directly:", err5);
3130
+ }
3131
+ }
3132
+ const authHeader = shareData.delegation.authHeader ?? `Bearer ${shareData.delegation.cid}`;
3133
+ const shareSession = {
3134
+ delegationHeader: { Authorization: authHeader },
3135
+ delegationCid: shareData.delegation.cid,
3136
+ spaceId: shareData.spaceId,
3137
+ verificationMethod: shareData.keyDid,
3138
+ jwk: shareData.key
3139
+ };
3140
+ const kvService = this.createKVService({
3141
+ hosts: [shareData.host],
3142
+ session: shareSession,
3143
+ invoke: this.invoke,
3144
+ fetch: this.fetchFn,
3145
+ pathPrefix: shareData.path
3146
+ });
3147
+ const shareAccess = {
3148
+ delegation: activeDelegation,
3149
+ key: activeKey,
3150
+ kv: kvService,
3151
+ spaceId: shareData.spaceId,
3152
+ path: shareData.path
3153
+ };
3154
+ return { ok: true, data: shareAccess };
3155
+ }
3156
+ /**
3157
+ * Encode sharing data into a link string.
3158
+ *
3159
+ * @param data - The share data to encode
3160
+ * @param schema - The encoding schema (default: "base64")
3161
+ * @returns Encoded link string
3162
+ */
3163
+ encodeLink(data, schema = "base64") {
3164
+ if (schema !== "base64") {
3165
+ throw new Error(`Schema '${schema}' not implemented. Only 'base64' is supported.`);
3166
+ }
3167
+ const jsonString = JSON.stringify(data);
3168
+ const encoded = base64UrlEncode(jsonString);
3169
+ return `${BASE64_PREFIX}${encoded}`;
3170
+ }
3171
+ /**
3172
+ * Decode a link string into sharing data.
3173
+ *
3174
+ * @param link - The encoded link string (may include URL prefix)
3175
+ * @returns Decoded share data
3176
+ * @throws Error if link format is invalid or data fails validation
3177
+ */
3178
+ decodeLink(link) {
3179
+ const result = this.decodeLinkWithValidation(link);
3180
+ if (!result.ok) {
3181
+ throw new Error(result.error.message);
3182
+ }
3183
+ return result.data;
3184
+ }
3185
+ /**
3186
+ * Decode and validate a link string into sharing data.
3187
+ *
3188
+ * Internal method that returns a Result instead of throwing.
3189
+ * Used by receive() for proper error handling.
3190
+ *
3191
+ * @param link - The encoded link string (may include URL prefix)
3192
+ * @returns Result with decoded share data or validation error
3193
+ */
3194
+ decodeLinkWithValidation(link) {
3195
+ let encoded = link;
3196
+ if (link.includes("/share/")) {
3197
+ const parts = link.split("/share/");
3198
+ encoded = parts[parts.length - 1];
3199
+ }
3200
+ if (link.includes("?share=")) {
3201
+ try {
3202
+ const url = new URL(link);
3203
+ encoded = url.searchParams.get("share") ?? encoded;
3204
+ } catch {
3205
+ return {
3206
+ ok: false,
3207
+ error: createError2(
3208
+ DelegationErrorCodes.INVALID_TOKEN,
3209
+ "Invalid URL format in sharing link"
3210
+ )
3211
+ };
3212
+ }
3213
+ }
3214
+ if (!encoded.startsWith(BASE64_PREFIX)) {
3215
+ return {
3216
+ ok: false,
3217
+ error: createError2(
3218
+ DelegationErrorCodes.INVALID_TOKEN,
3219
+ `Invalid sharing link format. Expected prefix '${BASE64_PREFIX}'`
3220
+ )
3221
+ };
3222
+ }
3223
+ const base64Data = encoded.slice(BASE64_PREFIX.length);
3224
+ let jsonString;
3225
+ try {
3226
+ jsonString = base64UrlDecode(base64Data);
3227
+ } catch (err5) {
3228
+ return {
3229
+ ok: false,
3230
+ error: createError2(
3231
+ DelegationErrorCodes.INVALID_TOKEN,
3232
+ `Failed to decode base64 data: ${err5 instanceof Error ? err5.message : String(err5)}`,
3233
+ err5 instanceof Error ? err5 : void 0
3234
+ )
3235
+ };
3236
+ }
3237
+ let parsed;
3238
+ try {
3239
+ parsed = JSON.parse(jsonString);
3240
+ } catch (err5) {
3241
+ return {
3242
+ ok: false,
3243
+ error: createError2(
3244
+ DelegationErrorCodes.INVALID_TOKEN,
3245
+ `Failed to parse share data JSON: ${err5 instanceof Error ? err5.message : String(err5)}`,
3246
+ err5 instanceof Error ? err5 : void 0
3247
+ )
3248
+ };
3249
+ }
3250
+ if (parsed && typeof parsed === "object" && "delegation" in parsed && parsed.delegation && typeof parsed.delegation === "object" && "expiry" in parsed.delegation && typeof parsed.delegation.expiry === "string") {
3251
+ parsed.delegation.expiry = new Date(parsed.delegation.expiry);
3252
+ }
3253
+ const validationResult = validateEncodedShareData(parsed);
3254
+ if (!validationResult.ok) {
3255
+ return {
3256
+ ok: false,
3257
+ error: createError2(
3258
+ DelegationErrorCodes.INVALID_TOKEN,
3259
+ validationResult.error.message,
3260
+ void 0,
3261
+ validationResult.error.meta
3262
+ )
3263
+ };
3264
+ }
3265
+ return { ok: true, data: validationResult.data };
3266
+ }
3267
+ };
3268
+ function createSharingService(config) {
3269
+ return new SharingService(config);
3270
+ }
3271
+
3272
+ // src/authorization/CapabilityKeyRegistry.ts
3273
+ var import_sdk_services3 = require("@tinycloud/sdk-services");
3274
+ var SERVICE_NAME2 = "capability-key-registry";
3275
+ var CapabilityKeyRegistryErrorCodes = {
3276
+ /** Key not found in registry */
3277
+ KEY_NOT_FOUND: "KEY_NOT_FOUND",
3278
+ /** No key available for the requested capability */
3279
+ NO_CAPABLE_KEY: "NO_CAPABLE_KEY",
3280
+ /** Delegation has expired */
3281
+ DELEGATION_EXPIRED: "DELEGATION_EXPIRED",
3282
+ /** Delegation has been revoked */
3283
+ DELEGATION_REVOKED: "DELEGATION_REVOKED",
3284
+ /** Invalid delegation data */
3285
+ INVALID_DELEGATION: "INVALID_DELEGATION",
3286
+ /** Key already registered */
3287
+ KEY_EXISTS: "KEY_EXISTS"
3288
+ };
3289
+ var CapabilityKeyRegistry = class {
3290
+ constructor() {
3291
+ /**
3292
+ * Registry of all keys indexed by ID.
3293
+ */
3294
+ this.keys = /* @__PURE__ */ new Map();
3295
+ /**
3296
+ * Delegation storage.
3297
+ */
3298
+ this.store = {
3299
+ byKey: /* @__PURE__ */ new Map(),
3300
+ byCid: /* @__PURE__ */ new Map(),
3301
+ byCapability: /* @__PURE__ */ new Map()
3302
+ };
3303
+ }
3304
+ // ===========================================================================
3305
+ // Key Management
3306
+ // ===========================================================================
3307
+ /**
3308
+ * Register a key with its associated delegations.
3309
+ *
3310
+ * @param key - Key information
3311
+ * @param delegations - Delegations granted to this key
3312
+ */
3313
+ registerKey(key, delegations) {
3314
+ this.keys.set(key.id, key);
3315
+ if (!this.store.byKey.has(key.id)) {
3316
+ this.store.byKey.set(key.id, []);
3317
+ }
3318
+ for (const delegation of delegations) {
3319
+ this.addDelegation(key, delegation);
3320
+ }
3321
+ }
3322
+ /**
3323
+ * Remove a key and all its associated delegations.
3324
+ *
3325
+ * @param keyId - The key ID to remove
3326
+ */
3327
+ removeKey(keyId) {
3328
+ const delegations = this.store.byKey.get(keyId) || [];
3329
+ for (const delegation of delegations) {
3330
+ this.store.byCid.delete(delegation.cid);
3331
+ }
3332
+ for (const [capKey, entries] of this.store.byCapability) {
3333
+ const filtered = entries.filter(
3334
+ (entry) => !entry.keys.some((k) => k.id === keyId)
3335
+ );
3336
+ if (filtered.length === 0) {
3337
+ this.store.byCapability.delete(capKey);
3338
+ } else {
3339
+ for (const entry of filtered) {
3340
+ entry.keys = entry.keys.filter((k) => k.id !== keyId);
3341
+ }
3342
+ this.store.byCapability.set(capKey, filtered.filter((e) => e.keys.length > 0));
3343
+ }
3344
+ }
3345
+ this.store.byKey.delete(keyId);
3346
+ this.keys.delete(keyId);
3347
+ }
3348
+ // ===========================================================================
3349
+ // Capability Lookup
3350
+ // ===========================================================================
3351
+ /**
3352
+ * Get a key that can exercise the specified capability.
3353
+ *
3354
+ * Key selection algorithm:
3355
+ * 1. Filter keys that have the required capability
3356
+ * 2. Check delegation validity (not expired, not revoked)
3357
+ * 3. Sort by priority (session=0, main=1, ingested=2)
3358
+ * 4. Return highest priority valid key
3359
+ *
3360
+ * @param resource - Resource URI
3361
+ * @param action - Action to perform
3362
+ * @returns The best matching key, or null if none available
3363
+ */
3364
+ getKeyForCapability(resource, action) {
3365
+ const matchingEntries = this.findMatchingEntries(resource, action);
3366
+ if (matchingEntries.length === 0) {
3367
+ return null;
3368
+ }
3369
+ const validKeys = [];
3370
+ for (const entry of matchingEntries) {
3371
+ if (!this.isDelegationValid(entry.delegation)) {
3372
+ continue;
3373
+ }
3374
+ for (const key of entry.keys) {
3375
+ if (!validKeys.some((k) => k.id === key.id)) {
3376
+ validKeys.push(key);
3377
+ }
3378
+ }
3379
+ }
3380
+ if (validKeys.length === 0) {
3381
+ return null;
3382
+ }
3383
+ validKeys.sort((a, b) => a.priority - b.priority);
3384
+ return validKeys[0];
3385
+ }
3386
+ /**
3387
+ * Get all registered capabilities.
3388
+ *
3389
+ * @returns All capability entries in the registry
3390
+ */
3391
+ getAllCapabilities() {
3392
+ const all = [];
3393
+ for (const entries of this.store.byCapability.values()) {
3394
+ all.push(...entries);
3395
+ }
3396
+ return all;
3397
+ }
3398
+ // ===========================================================================
3399
+ // Delegation Tracking
3400
+ // ===========================================================================
3401
+ /**
3402
+ * Get all delegations for a specific key.
3403
+ *
3404
+ * @param keyId - The key ID
3405
+ * @returns Array of delegations for this key
3406
+ */
3407
+ getDelegationsForKey(keyId) {
3408
+ return this.store.byKey.get(keyId) || [];
3409
+ }
3410
+ // ===========================================================================
3411
+ // Ingestion
3412
+ // ===========================================================================
3413
+ /**
3414
+ * Ingest a key and delegation from an external source.
3415
+ *
3416
+ * @param key - Key information to ingest
3417
+ * @param delegation - Delegation to associate with the key
3418
+ * @param options - Ingestion options
3419
+ */
3420
+ ingestKey(key, delegation, options) {
3421
+ const keyToStore = options?.priority !== void 0 ? { ...key, priority: options.priority } : key;
3422
+ this.keys.set(keyToStore.id, keyToStore);
3423
+ if (!this.store.byKey.has(keyToStore.id)) {
3424
+ this.store.byKey.set(keyToStore.id, []);
3425
+ }
3426
+ this.addDelegation(keyToStore, delegation);
3427
+ }
3428
+ // ===========================================================================
3429
+ // Validation
3430
+ // ===========================================================================
3431
+ /**
3432
+ * Check if a delegation is currently valid.
3433
+ *
3434
+ * @param delegation - The delegation to check
3435
+ * @returns true if valid, false if expired or revoked
3436
+ */
3437
+ isDelegationValid(delegation) {
3438
+ if (delegation.isRevoked) {
3439
+ return false;
3440
+ }
3441
+ const now = /* @__PURE__ */ new Date();
3442
+ if (delegation.expiry && delegation.expiry < now) {
3443
+ return false;
3444
+ }
3445
+ return true;
3446
+ }
3447
+ // ===========================================================================
3448
+ // Key Access
3449
+ // ===========================================================================
3450
+ /**
3451
+ * Get a key by its ID.
3452
+ *
3453
+ * @param keyId - The key ID
3454
+ * @returns The key info, or undefined if not found
3455
+ */
3456
+ getKey(keyId) {
3457
+ return this.keys.get(keyId);
3458
+ }
3459
+ /**
3460
+ * Get all registered keys.
3461
+ *
3462
+ * @returns Array of all registered keys
3463
+ */
3464
+ getAllKeys() {
3465
+ return Array.from(this.keys.values());
3466
+ }
3467
+ // ===========================================================================
3468
+ // Clear
3469
+ // ===========================================================================
3470
+ /**
3471
+ * Clear all registered keys and delegations.
3472
+ */
3473
+ clear() {
3474
+ this.keys.clear();
3475
+ this.store.byKey.clear();
3476
+ this.store.byCid.clear();
3477
+ this.store.byCapability.clear();
3478
+ }
3479
+ // ===========================================================================
3480
+ // Revocation
3481
+ // ===========================================================================
3482
+ /**
3483
+ * Revoke a delegation by CID.
3484
+ *
3485
+ * @param cid - The delegation CID to revoke
3486
+ * @returns Result indicating success or failure
3487
+ */
3488
+ revokeDelegation(cid) {
3489
+ const stored = this.store.byCid.get(cid);
3490
+ if (!stored) {
3491
+ return (0, import_sdk_services3.err)(
3492
+ (0, import_sdk_services3.serviceError)(
3493
+ CapabilityKeyRegistryErrorCodes.KEY_NOT_FOUND,
3494
+ `Delegation not found: ${cid}`,
3495
+ SERVICE_NAME2
3496
+ )
3497
+ );
3498
+ }
3499
+ stored.delegation.isRevoked = true;
3500
+ const keyDelegations = this.store.byKey.get(stored.keyId);
3501
+ if (keyDelegations) {
3502
+ const delegation = keyDelegations.find((d) => d.cid === cid);
3503
+ if (delegation) {
3504
+ delegation.isRevoked = true;
3505
+ }
3506
+ }
3507
+ for (const entries of this.store.byCapability.values()) {
3508
+ for (const entry of entries) {
3509
+ if (entry.delegation.cid === cid) {
3510
+ entry.delegation.isRevoked = true;
3511
+ }
3512
+ }
3513
+ }
3514
+ return (0, import_sdk_services3.ok)(void 0);
3515
+ }
3516
+ // ===========================================================================
3517
+ // Search
3518
+ // ===========================================================================
3519
+ /**
3520
+ * Find capabilities that match a resource path pattern.
3521
+ *
3522
+ * @param resourcePattern - Resource pattern (supports wildcards)
3523
+ * @param action - Optional action filter
3524
+ * @returns Matching capability entries
3525
+ */
3526
+ findCapabilities(resourcePattern, action) {
3527
+ const results = [];
3528
+ for (const entries of this.store.byCapability.values()) {
3529
+ for (const entry of entries) {
3530
+ if (action && entry.action !== action) {
3531
+ continue;
3532
+ }
3533
+ if (this.matchesResourcePattern(entry.resource, resourcePattern)) {
3534
+ results.push(entry);
3535
+ }
3536
+ }
3537
+ }
3538
+ return results;
3539
+ }
3540
+ // ===========================================================================
3541
+ // Private Methods
3542
+ // ===========================================================================
3543
+ /**
3544
+ * Add a delegation to the store.
3545
+ *
3546
+ * @param key - The key associated with this delegation
3547
+ * @param delegation - The delegation to add
3548
+ */
3549
+ addDelegation(key, delegation) {
3550
+ const keyDelegations = this.store.byKey.get(key.id) || [];
3551
+ if (!keyDelegations.some((d) => d.cid === delegation.cid)) {
3552
+ keyDelegations.push(delegation);
3553
+ this.store.byKey.set(key.id, keyDelegations);
3554
+ }
3555
+ if (!this.store.byCid.has(delegation.cid)) {
3556
+ this.store.byCid.set(delegation.cid, {
3557
+ delegation,
3558
+ parentCid: delegation.parentCid,
3559
+ keyId: key.id,
3560
+ storedAt: /* @__PURE__ */ new Date()
3561
+ });
3562
+ }
3563
+ for (const action of delegation.actions) {
3564
+ const capKey = this.makeCapabilityKey(delegation.path, action);
3565
+ const entries = this.store.byCapability.get(capKey) || [];
3566
+ const existingEntry = entries.find((e) => e.delegation.cid === delegation.cid);
3567
+ if (existingEntry) {
3568
+ if (!existingEntry.keys.some((k) => k.id === key.id)) {
3569
+ existingEntry.keys.push(key);
3570
+ existingEntry.keys.sort((a, b) => a.priority - b.priority);
3571
+ }
3572
+ } else {
3573
+ const entry = {
3574
+ resource: delegation.path,
3575
+ action,
3576
+ keys: [key],
3577
+ delegation,
3578
+ expiresAt: delegation.expiry
3579
+ };
3580
+ entries.push(entry);
3581
+ this.store.byCapability.set(capKey, entries);
3582
+ }
3583
+ }
3584
+ }
3585
+ /**
3586
+ * Create a capability key for indexing.
3587
+ *
3588
+ * @param resource - Resource path
3589
+ * @param action - Action
3590
+ * @returns Combined key string
3591
+ */
3592
+ makeCapabilityKey(resource, action) {
3593
+ return `${resource}|${action}`;
3594
+ }
3595
+ /**
3596
+ * Find capability entries that match a resource and action.
3597
+ *
3598
+ * @param resource - Resource to match
3599
+ * @param action - Action to match
3600
+ * @returns Matching entries
3601
+ */
3602
+ findMatchingEntries(resource, action) {
3603
+ const results = [];
3604
+ const exactKey = this.makeCapabilityKey(resource, action);
3605
+ const exactEntries = this.store.byCapability.get(exactKey);
3606
+ if (exactEntries) {
3607
+ results.push(...exactEntries);
3608
+ }
3609
+ for (const [capKey, entries] of this.store.byCapability) {
3610
+ if (capKey === exactKey) continue;
3611
+ for (const entry of entries) {
3612
+ if (!this.actionMatches(entry.action, action)) {
3613
+ continue;
3614
+ }
3615
+ if (this.resourceMatchesPattern(resource, entry.resource)) {
3616
+ if (!results.some((r) => r.delegation.cid === entry.delegation.cid)) {
3617
+ results.push(entry);
3618
+ }
3619
+ }
3620
+ }
3621
+ }
3622
+ return results;
3623
+ }
3624
+ /**
3625
+ * Check if an action pattern matches a specific action.
3626
+ *
3627
+ * @param pattern - Action pattern (may include wildcard like "tinycloud.kv/*")
3628
+ * @param action - Specific action to check
3629
+ * @returns true if pattern matches action
3630
+ */
3631
+ actionMatches(pattern, action) {
3632
+ if (pattern === action) {
3633
+ return true;
3634
+ }
3635
+ if (pattern.endsWith("/*")) {
3636
+ const prefix = pattern.slice(0, -2);
3637
+ return action.startsWith(prefix + "/") || action === prefix;
3638
+ }
3639
+ return false;
3640
+ }
3641
+ /**
3642
+ * Check if a resource matches a pattern.
3643
+ *
3644
+ * Patterns support:
3645
+ * - Exact match: "/kv/data" matches "/kv/data"
3646
+ * - Wildcard suffix: "/kv/*" matches "/kv/anything"
3647
+ * - Double wildcard: "/kv/**" matches "/kv/any/nested/path"
3648
+ *
3649
+ * @param resource - The specific resource being accessed
3650
+ * @param pattern - The pattern from the delegation
3651
+ * @returns true if resource matches pattern
3652
+ */
3653
+ resourceMatchesPattern(resource, pattern) {
3654
+ if (pattern === resource) {
3655
+ return true;
3656
+ }
3657
+ if (pattern.endsWith("/**")) {
3658
+ const prefix = pattern.slice(0, -3);
3659
+ return resource.startsWith(prefix);
3660
+ }
3661
+ if (pattern.endsWith("/*")) {
3662
+ const prefix = pattern.slice(0, -2);
3663
+ if (!resource.startsWith(prefix)) {
3664
+ return false;
3665
+ }
3666
+ const remainder = resource.slice(prefix.length);
3667
+ return !remainder.includes("/") || remainder === "/";
3668
+ }
3669
+ if (pattern.endsWith("/") && resource.startsWith(pattern)) {
3670
+ return true;
3671
+ }
3672
+ return false;
3673
+ }
3674
+ /**
3675
+ * Check if a specific resource matches a resource pattern for searching.
3676
+ *
3677
+ * @param entryResource - The resource from a capability entry
3678
+ * @param searchPattern - The pattern to search for
3679
+ * @returns true if entry resource matches search pattern
3680
+ */
3681
+ matchesResourcePattern(entryResource, searchPattern) {
3682
+ return this.resourceMatchesPattern(entryResource, searchPattern) || this.resourceMatchesPattern(searchPattern, entryResource);
3683
+ }
3684
+ };
3685
+ function createCapabilityKeyRegistry() {
3686
+ return new CapabilityKeyRegistry();
3687
+ }
3688
+
3689
+ // src/authorization/strategies.ts
3690
+ var defaultSignStrategy = { type: "auto-sign" };
3691
+
3692
+ // src/authorization/spaceCreation.ts
3693
+ var AutoApproveSpaceCreationHandler = class {
3694
+ /**
3695
+ * Always returns true to auto-approve space creation.
3696
+ */
3697
+ async confirmSpaceCreation() {
3698
+ return true;
3699
+ }
3700
+ };
3701
+ var defaultSpaceCreationHandler = new AutoApproveSpaceCreationHandler();
3702
+
3703
+ // src/version.ts
3704
+ var ProtocolMismatchError = class extends Error {
3705
+ constructor(sdkProtocol, nodeProtocol, nodeVersion, host) {
3706
+ super(
3707
+ `SDK protocol version ${sdkProtocol} is incompatible with node protocol version ${nodeProtocol} (node v${nodeVersion}) at ${host}. ` + (sdkProtocol < nodeProtocol ? "Please update your SDK." : "Please update the TinyCloud node.")
3708
+ );
3709
+ this.sdkProtocol = sdkProtocol;
3710
+ this.nodeProtocol = nodeProtocol;
3711
+ this.nodeVersion = nodeVersion;
3712
+ this.host = host;
3713
+ this.name = "ProtocolMismatchError";
3714
+ }
3715
+ };
3716
+ var VersionCheckError = class extends Error {
3717
+ constructor(host, cause) {
3718
+ super(
3719
+ `Failed to fetch node info at ${host}. Ensure the node is running and the /info endpoint is accessible.`
3720
+ );
3721
+ this.host = host;
3722
+ this.cause = cause;
3723
+ this.name = "VersionCheckError";
3724
+ }
3725
+ };
3726
+ var UnsupportedFeatureError = class extends Error {
3727
+ constructor(feature, host, availableFeatures) {
3728
+ super(
3729
+ `Feature "${feature}" is not supported by the node at ${host}. Available features: ${availableFeatures.join(", ") || "none"}.`
3730
+ );
3731
+ this.feature = feature;
3732
+ this.host = host;
3733
+ this.availableFeatures = availableFeatures;
3734
+ this.name = "UnsupportedFeatureError";
3735
+ }
3736
+ };
3737
+ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(globalThis)) {
3738
+ let response;
3739
+ try {
3740
+ response = await fetchFn(`${host}/info`, {
3741
+ signal: AbortSignal.timeout(5e3)
3742
+ });
3743
+ } catch (err5) {
3744
+ throw new VersionCheckError(host, err5);
3745
+ }
3746
+ if (!response.ok) {
3747
+ throw new VersionCheckError(host);
3748
+ }
3749
+ const data = await response.json();
3750
+ if (sdkProtocol !== data.protocol) {
3751
+ throw new ProtocolMismatchError(
3752
+ sdkProtocol,
3753
+ data.protocol,
3754
+ data.version,
3755
+ host
3756
+ );
3757
+ }
3758
+ return {
3759
+ features: data.features ?? [],
3760
+ quotaUrl: data.quota_url
3761
+ };
3762
+ }
3763
+ // Annotate the CommonJS export names for ESM import in node:
3764
+ 0 && (module.exports = {
3765
+ AutoApproveSpaceCreationHandler,
3766
+ CapabilityKeyRegistry,
3767
+ CapabilityKeyRegistryErrorCodes,
3768
+ ClientSessionSchema,
3769
+ DataVaultService,
3770
+ DatabaseHandle,
3771
+ DelegationErrorCodes,
3772
+ DelegationManager,
3773
+ DuckDbAction,
3774
+ DuckDbDatabaseHandle,
3775
+ DuckDbService,
3776
+ EnsDataSchema,
3777
+ ErrorCodes,
3778
+ KVService,
3779
+ PrefixedKVService,
3780
+ ProtocolMismatchError,
3781
+ SQLAction,
3782
+ SQLService,
3783
+ ServiceContext,
3784
+ SharingService,
3785
+ SilentNotificationHandler,
3786
+ SiweConfigSchema,
3787
+ SiweMessage,
3788
+ Space,
3789
+ SpaceErrorCodes,
3790
+ SpaceService,
3791
+ TinyCloud,
3792
+ UnsupportedFeatureError,
3793
+ VaultHeaders,
3794
+ VaultPublicSpaceKVActions,
3795
+ VersionCheckError,
3796
+ activateSessionWithHost,
3797
+ buildSpaceUri,
3798
+ checkNodeInfo,
3799
+ createCapabilityKeyRegistry,
3800
+ createSharingService,
3801
+ createSpaceService,
3802
+ createVaultCrypto,
3803
+ defaultRetryPolicy,
3804
+ defaultSignStrategy,
3805
+ defaultSpaceCreationHandler,
3806
+ err,
3807
+ fetchPeerId,
3808
+ makePublicSpaceId,
3809
+ ok,
3810
+ parseSpaceUri,
3811
+ serviceError,
3812
+ submitHostDelegation,
3813
+ validateClientSession,
3814
+ validatePersistedSessionData
3815
+ });
3816
+ //# sourceMappingURL=index.cjs.map