@tinycloud/sdk-core 2.4.0-beta.2 → 2.4.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1947 -1256
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +183 -59
- package/dist/index.d.ts +183 -59
- package/dist/index.js +2047 -1353
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,57 +32,58 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ACCOUNT_REGISTRY_PATH: () => ACCOUNT_REGISTRY_PATH,
|
|
34
34
|
ACCOUNT_REGISTRY_SPACE: () => ACCOUNT_REGISTRY_SPACE,
|
|
35
|
+
AccountService: () => AccountService,
|
|
35
36
|
AutoApproveSpaceCreationHandler: () => AutoApproveSpaceCreationHandler,
|
|
36
37
|
CapabilityKeyRegistry: () => CapabilityKeyRegistry,
|
|
37
38
|
CapabilityKeyRegistryErrorCodes: () => CapabilityKeyRegistryErrorCodes,
|
|
38
39
|
ClientSessionSchema: () => ClientSessionSchema,
|
|
39
40
|
CloudLocationResolutionError: () => CloudLocationResolutionError,
|
|
40
|
-
DECRYPT_ACTION: () =>
|
|
41
|
-
DECRYPT_FACT_TYPE: () =>
|
|
42
|
-
DECRYPT_RESULT_TYPE: () =>
|
|
41
|
+
DECRYPT_ACTION: () => import_sdk_services7.DECRYPT_ACTION,
|
|
42
|
+
DECRYPT_FACT_TYPE: () => import_sdk_services7.DECRYPT_FACT_TYPE,
|
|
43
|
+
DECRYPT_RESULT_TYPE: () => import_sdk_services7.DECRYPT_RESULT_TYPE,
|
|
43
44
|
DEFAULT_DEFAULTS: () => DEFAULT_DEFAULTS,
|
|
44
|
-
DEFAULT_ENCRYPTION_ALG: () =>
|
|
45
|
+
DEFAULT_ENCRYPTION_ALG: () => import_sdk_services7.DEFAULT_ENCRYPTION_ALG,
|
|
45
46
|
DEFAULT_EXPIRY: () => DEFAULT_EXPIRY,
|
|
46
|
-
DEFAULT_KEY_VERSION: () =>
|
|
47
|
+
DEFAULT_KEY_VERSION: () => import_sdk_services7.DEFAULT_KEY_VERSION,
|
|
47
48
|
DEFAULT_MANIFEST_SPACE: () => DEFAULT_MANIFEST_SPACE,
|
|
48
49
|
DEFAULT_MANIFEST_VERSION: () => DEFAULT_MANIFEST_VERSION,
|
|
49
50
|
DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
50
51
|
DEFAULT_TINYCLOUD_FALLBACK_HOST: () => DEFAULT_TINYCLOUD_FALLBACK_HOST,
|
|
51
52
|
DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL: () => DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
|
|
52
|
-
DataVaultService: () =>
|
|
53
|
-
DatabaseHandle: () =>
|
|
53
|
+
DataVaultService: () => import_sdk_services7.DataVaultService,
|
|
54
|
+
DatabaseHandle: () => import_sdk_services7.DatabaseHandle,
|
|
54
55
|
DelegationErrorCodes: () => DelegationErrorCodes,
|
|
55
56
|
DelegationManager: () => DelegationManager,
|
|
56
|
-
DuckDbAction: () =>
|
|
57
|
-
DuckDbDatabaseHandle: () =>
|
|
58
|
-
DuckDbService: () =>
|
|
57
|
+
DuckDbAction: () => import_sdk_services7.DuckDbAction,
|
|
58
|
+
DuckDbDatabaseHandle: () => import_sdk_services7.DuckDbDatabaseHandle,
|
|
59
|
+
DuckDbService: () => import_sdk_services7.DuckDbService,
|
|
59
60
|
ENCRYPTION_MANIFEST_SPACE: () => ENCRYPTION_MANIFEST_SPACE,
|
|
60
|
-
ENCRYPTION_NETWORK_URN_PREFIX: () =>
|
|
61
|
+
ENCRYPTION_NETWORK_URN_PREFIX: () => import_sdk_services7.ENCRYPTION_NETWORK_URN_PREFIX,
|
|
61
62
|
ENCRYPTION_PERMISSION_SERVICE: () => ENCRYPTION_PERMISSION_SERVICE,
|
|
62
|
-
ENCRYPTION_SERVICE: () =>
|
|
63
|
-
ENCRYPTION_SERVICE_SHORT: () =>
|
|
64
|
-
ENVELOPE_VERSION: () =>
|
|
63
|
+
ENCRYPTION_SERVICE: () => import_sdk_services7.ENCRYPTION_SERVICE,
|
|
64
|
+
ENCRYPTION_SERVICE_SHORT: () => import_sdk_services7.ENCRYPTION_SERVICE_SHORT,
|
|
65
|
+
ENVELOPE_VERSION: () => import_sdk_services7.ENVELOPE_VERSION,
|
|
65
66
|
EXPIRY: () => EXPIRY,
|
|
66
|
-
EncryptionService: () =>
|
|
67
|
+
EncryptionService: () => import_sdk_services7.EncryptionService,
|
|
67
68
|
EnsDataSchema: () => EnsDataSchema,
|
|
68
|
-
ErrorCodes: () =>
|
|
69
|
-
HooksService: () =>
|
|
69
|
+
ErrorCodes: () => import_sdk_services7.ErrorCodes,
|
|
70
|
+
HooksService: () => import_sdk_services7.HooksService,
|
|
70
71
|
IdentityParseError: () => IdentityParseError,
|
|
71
|
-
KVService: () =>
|
|
72
|
+
KVService: () => import_sdk_services7.KVService,
|
|
72
73
|
LocationRecordValidationError: () => LocationRecordValidationError,
|
|
73
74
|
ManifestValidationError: () => ManifestValidationError,
|
|
74
|
-
NETWORK_NAME_PATTERN: () =>
|
|
75
|
-
NetworkIdError: () =>
|
|
75
|
+
NETWORK_NAME_PATTERN: () => import_sdk_services7.NETWORK_NAME_PATTERN,
|
|
76
|
+
NetworkIdError: () => import_sdk_services7.NetworkIdError,
|
|
76
77
|
PermissionNotInManifestError: () => PermissionNotInManifestError,
|
|
77
|
-
PrefixedKVService: () =>
|
|
78
|
+
PrefixedKVService: () => import_sdk_services7.PrefixedKVService,
|
|
78
79
|
ProtocolMismatchError: () => ProtocolMismatchError,
|
|
79
|
-
SECRET_NAME_RE: () =>
|
|
80
|
+
SECRET_NAME_RE: () => import_sdk_services7.SECRET_NAME_RE,
|
|
80
81
|
SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
|
|
81
82
|
SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
|
|
82
|
-
SQLAction: () =>
|
|
83
|
-
SQLService: () =>
|
|
84
|
-
SecretsService: () =>
|
|
85
|
-
ServiceContext: () =>
|
|
83
|
+
SQLAction: () => import_sdk_services7.SQLAction,
|
|
84
|
+
SQLService: () => import_sdk_services7.SQLService,
|
|
85
|
+
SecretsService: () => import_sdk_services7.SecretsService,
|
|
86
|
+
ServiceContext: () => import_sdk_services7.ServiceContext,
|
|
86
87
|
SessionExpiredError: () => SessionExpiredError,
|
|
87
88
|
SharingService: () => SharingService,
|
|
88
89
|
SilentNotificationHandler: () => SilentNotificationHandler,
|
|
@@ -94,75 +95,75 @@ __export(index_exports, {
|
|
|
94
95
|
TinyCloud: () => TinyCloud,
|
|
95
96
|
UnsupportedFeatureError: () => UnsupportedFeatureError,
|
|
96
97
|
VAULT_PERMISSION_SERVICE: () => VAULT_PERMISSION_SERVICE,
|
|
97
|
-
VaultHeaders: () =>
|
|
98
|
-
VaultPublicSpaceKVActions: () =>
|
|
98
|
+
VaultHeaders: () => import_sdk_services7.VaultHeaders,
|
|
99
|
+
VaultPublicSpaceKVActions: () => import_sdk_services7.VaultPublicSpaceKVActions,
|
|
99
100
|
VersionCheckError: () => VersionCheckError,
|
|
100
101
|
activateSessionWithHost: () => activateSessionWithHost,
|
|
101
102
|
addressStorageKey: () => addressStorageKey,
|
|
102
103
|
applyPrefix: () => applyPrefix,
|
|
103
|
-
buildCanonicalDecryptRequest: () =>
|
|
104
|
-
buildDecryptAttenuation: () =>
|
|
105
|
-
buildDecryptFacts: () =>
|
|
106
|
-
buildDecryptInvocation: () =>
|
|
107
|
-
buildNetworkId: () =>
|
|
104
|
+
buildCanonicalDecryptRequest: () => import_sdk_services7.buildCanonicalDecryptRequest,
|
|
105
|
+
buildDecryptAttenuation: () => import_sdk_services7.buildDecryptAttenuation,
|
|
106
|
+
buildDecryptFacts: () => import_sdk_services7.buildDecryptFacts,
|
|
107
|
+
buildDecryptInvocation: () => import_sdk_services7.buildDecryptInvocation,
|
|
108
|
+
buildNetworkId: () => import_sdk_services7.buildNetworkId,
|
|
108
109
|
buildSpaceUri: () => buildSpaceUri,
|
|
109
|
-
canonicalHashHex: () =>
|
|
110
|
+
canonicalHashHex: () => import_sdk_services7.canonicalHashHex,
|
|
110
111
|
canonicalLocationPayload: () => canonicalLocationPayload,
|
|
111
|
-
canonicalSignedResponse: () =>
|
|
112
|
+
canonicalSignedResponse: () => import_sdk_services7.canonicalSignedResponse,
|
|
112
113
|
canonicalizeAddress: () => canonicalizeAddress,
|
|
113
114
|
canonicalizeDid: () => canonicalizeDid,
|
|
114
115
|
canonicalizeDidUrl: () => canonicalizeDidUrl,
|
|
115
|
-
canonicalizeEncryptionJson: () =>
|
|
116
|
+
canonicalizeEncryptionJson: () => import_sdk_services7.canonicalizeEncryptionJson,
|
|
116
117
|
canonicalizeNetworkId: () => canonicalizeNetworkId,
|
|
117
|
-
canonicalizeSecretScope: () =>
|
|
118
|
-
checkDecryptInvocationInput: () =>
|
|
118
|
+
canonicalizeSecretScope: () => import_sdk_services7.canonicalizeSecretScope,
|
|
119
|
+
checkDecryptInvocationInput: () => import_sdk_services7.checkDecryptInvocationInput,
|
|
119
120
|
checkNodeInfo: () => checkNodeInfo,
|
|
120
121
|
composeManifestRequest: () => composeManifestRequest,
|
|
121
122
|
createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
|
|
122
123
|
createSharingService: () => createSharingService,
|
|
123
124
|
createSpaceService: () => createSpaceService,
|
|
124
|
-
createVaultCrypto: () =>
|
|
125
|
-
decryptEnvelopeWithKey: () =>
|
|
126
|
-
defaultRetryPolicy: () =>
|
|
125
|
+
createVaultCrypto: () => import_sdk_services7.createVaultCrypto,
|
|
126
|
+
decryptEnvelopeWithKey: () => import_sdk_services7.decryptEnvelopeWithKey,
|
|
127
|
+
defaultRetryPolicy: () => import_sdk_services7.defaultRetryPolicy,
|
|
127
128
|
defaultSignStrategy: () => defaultSignStrategy,
|
|
128
129
|
defaultSpaceCreationHandler: () => defaultSpaceCreationHandler,
|
|
129
|
-
deriveSignedReceiverKey: () =>
|
|
130
|
+
deriveSignedReceiverKey: () => import_sdk_services7.deriveSignedReceiverKey,
|
|
130
131
|
didCacheKey: () => didCacheKey,
|
|
131
132
|
didEquals: () => didEquals,
|
|
132
|
-
discoverNetwork: () =>
|
|
133
|
-
encryptToNetwork: () =>
|
|
134
|
-
encryptionBase64Decode: () =>
|
|
135
|
-
encryptionBase64Encode: () =>
|
|
136
|
-
encryptionError: () =>
|
|
137
|
-
encryptionUtf8Decode: () =>
|
|
138
|
-
encryptionUtf8Encode: () =>
|
|
139
|
-
ensureNetworkUsableForDecrypt: () =>
|
|
140
|
-
err: () =>
|
|
133
|
+
discoverNetwork: () => import_sdk_services7.discoverNetwork,
|
|
134
|
+
encryptToNetwork: () => import_sdk_services7.encryptToNetwork,
|
|
135
|
+
encryptionBase64Decode: () => import_sdk_services7.base64Decode,
|
|
136
|
+
encryptionBase64Encode: () => import_sdk_services7.base64Encode,
|
|
137
|
+
encryptionError: () => import_sdk_services7.encryptionError,
|
|
138
|
+
encryptionUtf8Decode: () => import_sdk_services7.utf8Decode,
|
|
139
|
+
encryptionUtf8Encode: () => import_sdk_services7.utf8Encode,
|
|
140
|
+
ensureNetworkUsableForDecrypt: () => import_sdk_services7.ensureNetworkUsableForDecrypt,
|
|
141
|
+
err: () => import_sdk_services7.err,
|
|
141
142
|
expandActionShortNames: () => expandActionShortNames,
|
|
142
143
|
expandPermissionEntries: () => expandPermissionEntries,
|
|
143
144
|
expandPermissionEntry: () => expandPermissionEntry,
|
|
144
145
|
fetchLocationRecord: () => fetchLocationRecord,
|
|
145
146
|
fetchPeerId: () => fetchPeerId,
|
|
146
|
-
generateRandomReceiverKey: () =>
|
|
147
|
-
hexDecode: () =>
|
|
148
|
-
hexEncode: () =>
|
|
147
|
+
generateRandomReceiverKey: () => import_sdk_services7.generateRandomReceiverKey,
|
|
148
|
+
hexDecode: () => import_sdk_services7.hexDecode,
|
|
149
|
+
hexEncode: () => import_sdk_services7.hexEncode,
|
|
149
150
|
httpUrlToMultiaddr: () => httpUrlToMultiaddr,
|
|
150
151
|
isCapabilitySubset: () => isCapabilitySubset,
|
|
151
152
|
isEvmAddress: () => isEvmAddress,
|
|
152
|
-
isNetworkId: () =>
|
|
153
|
+
isNetworkId: () => import_sdk_services7.isNetworkId,
|
|
153
154
|
loadManifest: () => loadManifest,
|
|
154
155
|
locationPayloadForRecord: () => locationPayloadForRecord,
|
|
155
156
|
makePkhSpaceId: () => makePkhSpaceId,
|
|
156
157
|
makePublicSpaceId: () => makePublicSpaceId,
|
|
157
158
|
manifestAbilitiesUnion: () => manifestAbilitiesUnion,
|
|
158
159
|
multiaddrToHttpUrl: () => multiaddrToHttpUrl,
|
|
159
|
-
networkDiscoveryKey: () =>
|
|
160
|
+
networkDiscoveryKey: () => import_sdk_services7.networkDiscoveryKey,
|
|
160
161
|
normalizeDefaults: () => normalizeDefaults,
|
|
161
|
-
ok: () =>
|
|
162
|
-
openWrappedKey: () =>
|
|
162
|
+
ok: () => import_sdk_services7.ok,
|
|
163
|
+
openWrappedKey: () => import_sdk_services7.openWrappedKey,
|
|
163
164
|
parseCanonicalNetworkId: () => parseCanonicalNetworkId,
|
|
164
165
|
parseExpiry: () => parseExpiry,
|
|
165
|
-
parseNetworkId: () =>
|
|
166
|
+
parseNetworkId: () => import_sdk_services7.parseNetworkId,
|
|
166
167
|
parsePkhDid: () => parsePkhDid,
|
|
167
168
|
parseRecapCapabilities: () => parseRecapCapabilities,
|
|
168
169
|
parseSpaceUri: () => parseSpaceUri,
|
|
@@ -171,21 +172,21 @@ __export(index_exports, {
|
|
|
171
172
|
principalDidEquals: () => principalDidEquals,
|
|
172
173
|
resolveCloudLocation: () => resolveCloudLocation,
|
|
173
174
|
resolveManifest: () => resolveManifest,
|
|
174
|
-
resolveSecretListPrefix: () =>
|
|
175
|
-
resolveSecretPath: () =>
|
|
175
|
+
resolveSecretListPrefix: () => import_sdk_services7.resolveSecretListPrefix,
|
|
176
|
+
resolveSecretPath: () => import_sdk_services7.resolveSecretPath,
|
|
176
177
|
resolveTinyCloudHosts: () => resolveTinyCloudHosts,
|
|
177
178
|
resourceCapabilitiesToAbilitiesMap: () => resourceCapabilitiesToAbilitiesMap,
|
|
178
179
|
resourceCapabilitiesToSpaceAbilitiesMap: () => resourceCapabilitiesToSpaceAbilitiesMap,
|
|
179
|
-
serviceError: () =>
|
|
180
|
+
serviceError: () => import_sdk_services7.serviceError,
|
|
180
181
|
signLocationRecord: () => signLocationRecord,
|
|
181
182
|
submitHostDelegation: () => submitHostDelegation,
|
|
182
183
|
validateClientSession: () => validateClientSession,
|
|
183
|
-
validateEnvelope: () =>
|
|
184
|
+
validateEnvelope: () => import_sdk_services7.validateEnvelope,
|
|
184
185
|
validateLocationRecord: () => validateLocationRecord,
|
|
185
186
|
validateLocationRecordPayload: () => validateLocationRecordPayload,
|
|
186
187
|
validateManifest: () => validateManifest,
|
|
187
188
|
validatePersistedSessionData: () => validatePersistedSessionData,
|
|
188
|
-
verifyDecryptResponse: () =>
|
|
189
|
+
verifyDecryptResponse: () => import_sdk_services7.verifyDecryptResponse,
|
|
189
190
|
verifyDidKeyEd25519Signature: () => verifyDidKeyEd25519Signature,
|
|
190
191
|
verifyLocationRecord: () => verifyLocationRecord
|
|
191
192
|
});
|
|
@@ -1150,6 +1151,7 @@ var SpaceService = class {
|
|
|
1150
1151
|
this._userDid = config.userDid;
|
|
1151
1152
|
this.sharingService = config.sharingService;
|
|
1152
1153
|
this.createDelegationFn = config.createDelegation;
|
|
1154
|
+
this.onSpaceRegisteredFn = config.onSpaceRegistered;
|
|
1153
1155
|
}
|
|
1154
1156
|
/**
|
|
1155
1157
|
* Update the service configuration.
|
|
@@ -1165,6 +1167,7 @@ var SpaceService = class {
|
|
|
1165
1167
|
if (config.userDid !== void 0) this._userDid = config.userDid;
|
|
1166
1168
|
if (config.sharingService) this.sharingService = config.sharingService;
|
|
1167
1169
|
if (config.createDelegation) this.createDelegationFn = config.createDelegation;
|
|
1170
|
+
if (config.onSpaceRegistered) this.onSpaceRegisteredFn = config.onSpaceRegistered;
|
|
1168
1171
|
this.spaceCache.clear();
|
|
1169
1172
|
this.infoCache.clear();
|
|
1170
1173
|
}
|
|
@@ -1215,6 +1218,9 @@ var SpaceService = class {
|
|
|
1215
1218
|
spaces.push(...delegatedSpaces);
|
|
1216
1219
|
}
|
|
1217
1220
|
const uniqueSpaces = this.deduplicateSpaces(spaces);
|
|
1221
|
+
for (const space of uniqueSpaces) {
|
|
1222
|
+
this.notifySpaceRegistered(space);
|
|
1223
|
+
}
|
|
1218
1224
|
return (0, import_sdk_services2.ok)(uniqueSpaces);
|
|
1219
1225
|
} catch (error) {
|
|
1220
1226
|
return (0, import_sdk_services2.err)(
|
|
@@ -1412,6 +1418,7 @@ var SpaceService = class {
|
|
|
1412
1418
|
permissions: ["*"]
|
|
1413
1419
|
};
|
|
1414
1420
|
this.infoCache.set(spaceInfo.id, { info: spaceInfo, cachedAt: Date.now() });
|
|
1421
|
+
this.notifySpaceRegistered(spaceInfo);
|
|
1415
1422
|
return (0, import_sdk_services2.ok)(spaceInfo);
|
|
1416
1423
|
} catch (error) {
|
|
1417
1424
|
return (0, import_sdk_services2.err)(
|
|
@@ -1424,6 +1431,11 @@ var SpaceService = class {
|
|
|
1424
1431
|
);
|
|
1425
1432
|
}
|
|
1426
1433
|
}
|
|
1434
|
+
notifySpaceRegistered(space) {
|
|
1435
|
+
if (!this.onSpaceRegisteredFn) return;
|
|
1436
|
+
void Promise.resolve(this.onSpaceRegisteredFn(space)).catch(() => {
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1427
1439
|
// ===========================================================================
|
|
1428
1440
|
// Get Space
|
|
1429
1441
|
// ===========================================================================
|
|
@@ -2331,952 +2343,288 @@ var TinyCloud = class _TinyCloud {
|
|
|
2331
2343
|
}
|
|
2332
2344
|
};
|
|
2333
2345
|
|
|
2334
|
-
// src/
|
|
2335
|
-
var
|
|
2346
|
+
// src/account/AccountService.ts
|
|
2347
|
+
var import_sdk_services5 = require("@tinycloud/sdk-services");
|
|
2336
2348
|
|
|
2337
|
-
// src/
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
)
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
throw new Error(`Failed to get peer ID: ${res.status} - ${error}`);
|
|
2349
|
+
// src/manifest.ts
|
|
2350
|
+
var import_ms = __toESM(require("ms"), 1);
|
|
2351
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
2352
|
+
var ManifestValidationError = class extends Error {
|
|
2353
|
+
constructor(message) {
|
|
2354
|
+
super(`Manifest validation failed: ${message}`);
|
|
2355
|
+
this.name = "ManifestValidationError";
|
|
2345
2356
|
}
|
|
2346
|
-
|
|
2357
|
+
};
|
|
2358
|
+
var DEFAULT_EXPIRY = "30d";
|
|
2359
|
+
var DEFAULT_DEFAULTS = true;
|
|
2360
|
+
var DEFAULT_MANIFEST_VERSION = 1;
|
|
2361
|
+
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
2362
|
+
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
2363
|
+
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
2364
|
+
var SECRETS_SPACE = "secrets";
|
|
2365
|
+
var VAULT_PERMISSION_SERVICE = "tinycloud.vault";
|
|
2366
|
+
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
2367
|
+
kv: "tinycloud.kv",
|
|
2368
|
+
sql: "tinycloud.sql",
|
|
2369
|
+
duckdb: "tinycloud.duckdb",
|
|
2370
|
+
capabilities: "tinycloud.capabilities",
|
|
2371
|
+
hooks: "tinycloud.hooks",
|
|
2372
|
+
encryption: "tinycloud.encryption"
|
|
2373
|
+
});
|
|
2374
|
+
var ENCRYPTION_PERMISSION_SERVICE = "tinycloud.encryption";
|
|
2375
|
+
var ENCRYPTION_MANIFEST_SPACE = "encryption";
|
|
2376
|
+
var SERVICE_LONG_TO_SHORT = Object.freeze(
|
|
2377
|
+
Object.fromEntries(
|
|
2378
|
+
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
2379
|
+
)
|
|
2380
|
+
);
|
|
2381
|
+
var DEFAULT_STANDARD_ENTRIES = [
|
|
2382
|
+
{
|
|
2383
|
+
service: "tinycloud.kv",
|
|
2384
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2385
|
+
path: "/",
|
|
2386
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2387
|
+
},
|
|
2388
|
+
{
|
|
2389
|
+
service: "tinycloud.sql",
|
|
2390
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2391
|
+
path: "/",
|
|
2392
|
+
actions: ["read", "write"]
|
|
2393
|
+
}
|
|
2394
|
+
];
|
|
2395
|
+
var DEFAULT_ADMIN_ENTRIES = [
|
|
2396
|
+
{
|
|
2397
|
+
service: "tinycloud.kv",
|
|
2398
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2399
|
+
path: "/",
|
|
2400
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
service: "tinycloud.sql",
|
|
2404
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2405
|
+
path: "/",
|
|
2406
|
+
actions: ["read", "write", "ddl"]
|
|
2407
|
+
}
|
|
2408
|
+
];
|
|
2409
|
+
var DEFAULT_ALL_ENTRIES = [
|
|
2410
|
+
{
|
|
2411
|
+
service: "tinycloud.kv",
|
|
2412
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2413
|
+
path: "/",
|
|
2414
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
service: "tinycloud.sql",
|
|
2418
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2419
|
+
path: "/",
|
|
2420
|
+
actions: ["read", "write", "ddl"]
|
|
2421
|
+
},
|
|
2422
|
+
{
|
|
2423
|
+
service: "tinycloud.duckdb",
|
|
2424
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2425
|
+
path: "/",
|
|
2426
|
+
actions: ["read", "write"]
|
|
2427
|
+
}
|
|
2428
|
+
];
|
|
2429
|
+
function parseExpiry(duration) {
|
|
2430
|
+
if (typeof duration !== "string" || duration.length === 0) {
|
|
2431
|
+
throw new ManifestValidationError(
|
|
2432
|
+
`expiry must be a non-empty duration string (got ${JSON.stringify(duration)})`
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
const parsed = (0, import_ms.default)(duration);
|
|
2436
|
+
if (typeof parsed !== "number" || !Number.isFinite(parsed) || parsed <= 0) {
|
|
2437
|
+
throw new ManifestValidationError(
|
|
2438
|
+
`invalid expiry duration: ${JSON.stringify(duration)}`
|
|
2439
|
+
);
|
|
2440
|
+
}
|
|
2441
|
+
return parsed;
|
|
2347
2442
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2443
|
+
function expandActionShortNames(service, actions) {
|
|
2444
|
+
return actions.map((a) => {
|
|
2445
|
+
if (a.includes("/")) {
|
|
2446
|
+
return a;
|
|
2447
|
+
}
|
|
2448
|
+
return `${service}/${a}`;
|
|
2352
2449
|
});
|
|
2353
|
-
return {
|
|
2354
|
-
success: res.ok,
|
|
2355
|
-
status: res.status,
|
|
2356
|
-
error: res.ok ? void 0 : await res.text().catch(() => res.statusText)
|
|
2357
|
-
};
|
|
2358
2450
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2451
|
+
function expandPermissionEntry(entry) {
|
|
2452
|
+
if (entry.service === ENCRYPTION_PERMISSION_SERVICE) {
|
|
2453
|
+
return expandEncryptionPermissionEntry(entry);
|
|
2454
|
+
}
|
|
2455
|
+
if (entry.service !== VAULT_PERMISSION_SERVICE) {
|
|
2456
|
+
return [
|
|
2457
|
+
{
|
|
2458
|
+
...entry,
|
|
2459
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2460
|
+
}
|
|
2461
|
+
];
|
|
2462
|
+
}
|
|
2463
|
+
return expandVaultPermissionEntry(entry);
|
|
2464
|
+
}
|
|
2465
|
+
function expandEncryptionPermissionEntry(entry) {
|
|
2466
|
+
if (typeof entry.path !== "string" || !entry.path.startsWith("urn:tinycloud:encryption:")) {
|
|
2467
|
+
throw new ManifestValidationError(
|
|
2468
|
+
`tinycloud.encryption entries require path to be a networkId URN (got ${JSON.stringify(entry.path)})`
|
|
2469
|
+
);
|
|
2470
|
+
}
|
|
2471
|
+
const normalizedActions = [];
|
|
2472
|
+
for (const action of entry.actions) {
|
|
2473
|
+
if (action === "decrypt" || action === "tinycloud.encryption/decrypt") {
|
|
2474
|
+
normalizedActions.push("tinycloud.encryption/decrypt");
|
|
2475
|
+
continue;
|
|
2476
|
+
}
|
|
2477
|
+
if (action === "network.create" || action === "tinycloud.encryption/network.create") {
|
|
2478
|
+
normalizedActions.push("tinycloud.encryption/network.create");
|
|
2479
|
+
continue;
|
|
2480
|
+
}
|
|
2481
|
+
if (action === "network.revoke" || action === "tinycloud.encryption/network.revoke") {
|
|
2482
|
+
normalizedActions.push("tinycloud.encryption/network.revoke");
|
|
2483
|
+
continue;
|
|
2380
2484
|
}
|
|
2485
|
+
if (action.includes("/")) {
|
|
2486
|
+
throw new ManifestValidationError(
|
|
2487
|
+
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
throw new ManifestValidationError(
|
|
2491
|
+
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
2492
|
+
);
|
|
2381
2493
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2494
|
+
const dedupedActions = [];
|
|
2495
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2496
|
+
for (const a of normalizedActions) {
|
|
2497
|
+
if (!seen.has(a)) {
|
|
2498
|
+
dedupedActions.push(a);
|
|
2499
|
+
seen.add(a);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
return [
|
|
2503
|
+
{
|
|
2504
|
+
service: ENCRYPTION_PERMISSION_SERVICE,
|
|
2505
|
+
space: ENCRYPTION_MANIFEST_SPACE,
|
|
2506
|
+
path: entry.path,
|
|
2507
|
+
actions: dedupedActions,
|
|
2508
|
+
skipPrefix: true,
|
|
2509
|
+
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
2510
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2511
|
+
}
|
|
2512
|
+
];
|
|
2387
2513
|
}
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
var DelegationAction = {
|
|
2391
|
-
CREATE: "tinycloud.delegation/create",
|
|
2392
|
-
REVOKE: "tinycloud.delegation/revoke",
|
|
2393
|
-
LIST: "tinycloud.delegation/list",
|
|
2394
|
-
GET: "tinycloud.delegation/get",
|
|
2395
|
-
CHECK: "tinycloud.delegation/check"
|
|
2396
|
-
};
|
|
2397
|
-
function createError(code, message, cause, meta) {
|
|
2398
|
-
return {
|
|
2399
|
-
code,
|
|
2400
|
-
message,
|
|
2401
|
-
service: "delegation",
|
|
2402
|
-
cause,
|
|
2403
|
-
meta
|
|
2404
|
-
};
|
|
2514
|
+
function expandPermissionEntries(entries) {
|
|
2515
|
+
return entries.flatMap(expandPermissionEntry);
|
|
2405
2516
|
}
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
*
|
|
2410
|
-
* @param config - Configuration including hosts, session, and invoke function
|
|
2411
|
-
*/
|
|
2412
|
-
constructor(config) {
|
|
2413
|
-
this.hosts = config.hosts;
|
|
2414
|
-
this.session = config.session;
|
|
2415
|
-
this.invoke = config.invoke;
|
|
2416
|
-
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
2417
|
-
}
|
|
2418
|
-
/**
|
|
2419
|
-
* Updates the session (e.g., after re-authentication).
|
|
2420
|
-
*
|
|
2421
|
-
* @param session - New session to use for operations
|
|
2422
|
-
*/
|
|
2423
|
-
updateSession(session) {
|
|
2424
|
-
this.session = session;
|
|
2517
|
+
function applyPrefix(prefix, path, skipPrefix) {
|
|
2518
|
+
if (skipPrefix) {
|
|
2519
|
+
return path;
|
|
2425
2520
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
*/
|
|
2429
|
-
get host() {
|
|
2430
|
-
return this.hosts[0];
|
|
2521
|
+
if (prefix === "") {
|
|
2522
|
+
return path;
|
|
2431
2523
|
}
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
*/
|
|
2435
|
-
async invokeOperation(path, action, body) {
|
|
2436
|
-
const headers = this.invoke(this.session, "delegation", path, action);
|
|
2437
|
-
return this.fetchFn(`${this.host}/invoke`, {
|
|
2438
|
-
method: "POST",
|
|
2439
|
-
headers,
|
|
2440
|
-
body
|
|
2441
|
-
});
|
|
2524
|
+
if (path.startsWith("/")) {
|
|
2525
|
+
return `${prefix}${path}`;
|
|
2442
2526
|
}
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2527
|
+
return `${prefix}/${path}`;
|
|
2528
|
+
}
|
|
2529
|
+
async function loadManifest(url) {
|
|
2530
|
+
const fetchFn = globalThis.fetch;
|
|
2531
|
+
if (typeof fetchFn !== "function") {
|
|
2532
|
+
throw new ManifestValidationError(
|
|
2533
|
+
"loadManifest requires a global fetch; pass the manifest object directly on runtimes without fetch"
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
const res = await fetchFn(url);
|
|
2537
|
+
if (!res.ok) {
|
|
2538
|
+
throw new ManifestValidationError(
|
|
2539
|
+
`failed to fetch manifest from ${url}: HTTP ${res.status}`
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
const json = await res.json();
|
|
2543
|
+
return validateManifest(json);
|
|
2544
|
+
}
|
|
2545
|
+
function validateManifest(input) {
|
|
2546
|
+
if (input === null || typeof input !== "object") {
|
|
2547
|
+
throw new ManifestValidationError("manifest must be an object");
|
|
2548
|
+
}
|
|
2549
|
+
const m = input;
|
|
2550
|
+
if (m.manifest_version !== void 0 && m.manifest_version !== DEFAULT_MANIFEST_VERSION) {
|
|
2551
|
+
throw new ManifestValidationError(
|
|
2552
|
+
`manifest.manifest_version must be ${DEFAULT_MANIFEST_VERSION}`
|
|
2553
|
+
);
|
|
2554
|
+
}
|
|
2555
|
+
if (typeof m.app_id !== "string" || m.app_id.length === 0) {
|
|
2556
|
+
throw new ManifestValidationError(
|
|
2557
|
+
"manifest.app_id is required and must be a non-empty string"
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
if (typeof m.name !== "string" || m.name.length === 0) {
|
|
2561
|
+
throw new ManifestValidationError(
|
|
2562
|
+
"manifest.name is required and must be a non-empty string"
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
if (m.did !== void 0 && (typeof m.did !== "string" || m.did.length === 0)) {
|
|
2566
|
+
throw new ManifestValidationError(
|
|
2567
|
+
"manifest.did must be a non-empty DID string"
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
if (m.space !== void 0 && (typeof m.space !== "string" || m.space.length === 0)) {
|
|
2571
|
+
throw new ManifestValidationError(
|
|
2572
|
+
"manifest.space must be a non-empty string"
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
if (m.expiry !== void 0) {
|
|
2576
|
+
parseExpiry(m.expiry);
|
|
2577
|
+
}
|
|
2578
|
+
if (m.permissions !== void 0) {
|
|
2579
|
+
if (!Array.isArray(m.permissions)) {
|
|
2580
|
+
throw new ManifestValidationError(
|
|
2581
|
+
"manifest.permissions must be an array"
|
|
2582
|
+
);
|
|
2481
2583
|
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2584
|
+
m.permissions.forEach(
|
|
2585
|
+
(p, i) => validatePermissionEntry(p, `permissions[${i}]`)
|
|
2586
|
+
);
|
|
2587
|
+
}
|
|
2588
|
+
if (m.secrets !== void 0) {
|
|
2589
|
+
validateManifestSecrets(m.secrets);
|
|
2590
|
+
}
|
|
2591
|
+
return m;
|
|
2592
|
+
}
|
|
2593
|
+
function validateManifestSecrets(secrets) {
|
|
2594
|
+
if (secrets === null || typeof secrets !== "object" || Array.isArray(secrets)) {
|
|
2595
|
+
throw new ManifestValidationError("manifest.secrets must be an object");
|
|
2596
|
+
}
|
|
2597
|
+
for (const [name, spec] of Object.entries(secrets)) {
|
|
2598
|
+
if (!import_sdk_services4.SECRET_NAME_RE.test(name)) {
|
|
2599
|
+
throw new ManifestValidationError(
|
|
2600
|
+
`manifest.secrets.${name} must match ${import_sdk_services4.SECRET_NAME_RE.source}`
|
|
2601
|
+
);
|
|
2490
2602
|
}
|
|
2491
2603
|
try {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
actions: params.actions,
|
|
2496
|
-
expiry: params.expiry?.toISOString(),
|
|
2497
|
-
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
2498
|
-
statement: params.statement
|
|
2499
|
-
});
|
|
2500
|
-
const response = await this.invokeOperation(
|
|
2501
|
-
params.path,
|
|
2502
|
-
DelegationAction.CREATE,
|
|
2503
|
-
body
|
|
2604
|
+
(0, import_sdk_services4.resolveSecretPath)(
|
|
2605
|
+
secretNameFromSpec(name, spec),
|
|
2606
|
+
{ scope: secretScopeFromSpec(spec) }
|
|
2504
2607
|
);
|
|
2505
|
-
if (!response.ok) {
|
|
2506
|
-
const errorText = await response.text();
|
|
2507
|
-
return {
|
|
2508
|
-
ok: false,
|
|
2509
|
-
error: createError(
|
|
2510
|
-
DelegationErrorCodes.CREATION_FAILED,
|
|
2511
|
-
`Failed to create delegation: ${response.status} - ${errorText}`,
|
|
2512
|
-
void 0,
|
|
2513
|
-
{ status: response.status, path: params.path }
|
|
2514
|
-
)
|
|
2515
|
-
};
|
|
2516
|
-
}
|
|
2517
|
-
const apiResponse = await response.json();
|
|
2518
|
-
const delegation = {
|
|
2519
|
-
cid: apiResponse.cid ?? "",
|
|
2520
|
-
delegateDID: params.delegateDID,
|
|
2521
|
-
spaceId: this.session.spaceId,
|
|
2522
|
-
path: params.path,
|
|
2523
|
-
actions: params.actions,
|
|
2524
|
-
expiry: params.expiry ?? new Date(Date.now() + EXPIRY.SHARE_MS),
|
|
2525
|
-
isRevoked: false,
|
|
2526
|
-
allowSubDelegation: !(params.disableSubDelegation ?? false),
|
|
2527
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
2528
|
-
};
|
|
2529
|
-
return { ok: true, data: delegation };
|
|
2530
2608
|
} catch (error) {
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2609
|
+
throw new ManifestValidationError(
|
|
2610
|
+
`manifest.secrets.${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
const actions = secretActionsFromSpec(name, spec);
|
|
2614
|
+
if (actions.length === 0) {
|
|
2615
|
+
throw new ManifestValidationError(
|
|
2616
|
+
`manifest.secrets.${name} actions must be non-empty`
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
for (const action of actions) {
|
|
2620
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
2621
|
+
throw new ManifestValidationError(
|
|
2622
|
+
`manifest.secrets.${name} actions must be non-empty strings`
|
|
2623
|
+
);
|
|
2540
2624
|
}
|
|
2541
|
-
return {
|
|
2542
|
-
ok: false,
|
|
2543
|
-
error: createError(
|
|
2544
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2545
|
-
`Network error during delegation creation: ${String(error)}`,
|
|
2546
|
-
error instanceof Error ? error : void 0
|
|
2547
|
-
)
|
|
2548
|
-
};
|
|
2549
2625
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
* Revokes an existing delegation.
|
|
2553
|
-
*
|
|
2554
|
-
* Once revoked, the delegation can no longer be used to access resources.
|
|
2555
|
-
* This also invalidates any sub-delegations derived from this delegation.
|
|
2556
|
-
*
|
|
2557
|
-
* @param cid - The CID of the delegation to revoke
|
|
2558
|
-
* @returns Result indicating success or an error
|
|
2559
|
-
*
|
|
2560
|
-
* @example
|
|
2561
|
-
* ```typescript
|
|
2562
|
-
* const result = await manager.revoke("bafy...");
|
|
2563
|
-
* if (result.ok) {
|
|
2564
|
-
* console.log("Delegation revoked successfully");
|
|
2565
|
-
* }
|
|
2566
|
-
* ```
|
|
2567
|
-
*/
|
|
2568
|
-
async revoke(cid) {
|
|
2569
|
-
if (!cid) {
|
|
2570
|
-
return {
|
|
2571
|
-
ok: false,
|
|
2572
|
-
error: createError(
|
|
2573
|
-
DelegationErrorCodes.INVALID_INPUT,
|
|
2574
|
-
"cid is required"
|
|
2575
|
-
)
|
|
2576
|
-
};
|
|
2577
|
-
}
|
|
2578
|
-
try {
|
|
2579
|
-
const body = JSON.stringify({ cid });
|
|
2580
|
-
const response = await this.invokeOperation(
|
|
2581
|
-
cid,
|
|
2582
|
-
DelegationAction.REVOKE,
|
|
2583
|
-
body
|
|
2584
|
-
);
|
|
2585
|
-
if (!response.ok) {
|
|
2586
|
-
const errorText = await response.text();
|
|
2587
|
-
if (response.status === 404) {
|
|
2588
|
-
return {
|
|
2589
|
-
ok: false,
|
|
2590
|
-
error: createError(
|
|
2591
|
-
DelegationErrorCodes.NOT_FOUND,
|
|
2592
|
-
`Delegation not found: ${cid}`
|
|
2593
|
-
)
|
|
2594
|
-
};
|
|
2595
|
-
}
|
|
2596
|
-
return {
|
|
2597
|
-
ok: false,
|
|
2598
|
-
error: createError(
|
|
2599
|
-
DelegationErrorCodes.REVOCATION_FAILED,
|
|
2600
|
-
`Failed to revoke delegation: ${response.status} - ${errorText}`,
|
|
2601
|
-
void 0,
|
|
2602
|
-
{ status: response.status, cid }
|
|
2603
|
-
)
|
|
2604
|
-
};
|
|
2605
|
-
}
|
|
2606
|
-
return { ok: true, data: void 0 };
|
|
2607
|
-
} catch (error) {
|
|
2608
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
2609
|
-
return {
|
|
2610
|
-
ok: false,
|
|
2611
|
-
error: createError(
|
|
2612
|
-
DelegationErrorCodes.ABORTED,
|
|
2613
|
-
"Request aborted",
|
|
2614
|
-
error
|
|
2615
|
-
)
|
|
2616
|
-
};
|
|
2617
|
-
}
|
|
2618
|
-
return {
|
|
2619
|
-
ok: false,
|
|
2620
|
-
error: createError(
|
|
2621
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2622
|
-
`Network error during delegation revocation: ${String(error)}`,
|
|
2623
|
-
error instanceof Error ? error : void 0
|
|
2624
|
-
)
|
|
2625
|
-
};
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
/**
|
|
2629
|
-
* Lists all delegations for the current session's space.
|
|
2630
|
-
*
|
|
2631
|
-
* Returns both delegations created by the current user (as delegator)
|
|
2632
|
-
* and delegations granted to the current user (as delegatee).
|
|
2633
|
-
*
|
|
2634
|
-
* @returns Result containing an array of Delegations or an error
|
|
2635
|
-
*
|
|
2636
|
-
* @example
|
|
2637
|
-
* ```typescript
|
|
2638
|
-
* const result = await manager.list();
|
|
2639
|
-
* if (result.ok) {
|
|
2640
|
-
* for (const delegation of result.data) {
|
|
2641
|
-
* console.log(`${delegation.cid}: ${delegation.path} -> ${delegation.delegateDID}`);
|
|
2642
|
-
* }
|
|
2643
|
-
* }
|
|
2644
|
-
* ```
|
|
2645
|
-
*/
|
|
2646
|
-
async list() {
|
|
2647
|
-
try {
|
|
2648
|
-
const response = await this.invokeOperation("", DelegationAction.LIST);
|
|
2649
|
-
if (!response.ok) {
|
|
2650
|
-
const errorText = await response.text();
|
|
2651
|
-
return {
|
|
2652
|
-
ok: false,
|
|
2653
|
-
error: createError(
|
|
2654
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2655
|
-
`Failed to list delegations: ${response.status} - ${errorText}`,
|
|
2656
|
-
void 0,
|
|
2657
|
-
{ status: response.status }
|
|
2658
|
-
)
|
|
2659
|
-
};
|
|
2660
|
-
}
|
|
2661
|
-
const data = await response.json();
|
|
2662
|
-
const delegations = data.map((item) => ({
|
|
2663
|
-
cid: item.cid,
|
|
2664
|
-
delegateDID: item.delegateDID,
|
|
2665
|
-
delegatorDID: item.delegatorDID,
|
|
2666
|
-
spaceId: item.spaceId,
|
|
2667
|
-
path: item.path,
|
|
2668
|
-
actions: item.actions,
|
|
2669
|
-
expiry: new Date(item.expiry),
|
|
2670
|
-
isRevoked: item.isRevoked,
|
|
2671
|
-
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
2672
|
-
parentCid: item.parentCid,
|
|
2673
|
-
allowSubDelegation: item.allowSubDelegation
|
|
2674
|
-
}));
|
|
2675
|
-
return { ok: true, data: delegations };
|
|
2676
|
-
} catch (error) {
|
|
2677
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
2678
|
-
return {
|
|
2679
|
-
ok: false,
|
|
2680
|
-
error: createError(
|
|
2681
|
-
DelegationErrorCodes.ABORTED,
|
|
2682
|
-
"Request aborted",
|
|
2683
|
-
error
|
|
2684
|
-
)
|
|
2685
|
-
};
|
|
2686
|
-
}
|
|
2687
|
-
return {
|
|
2688
|
-
ok: false,
|
|
2689
|
-
error: createError(
|
|
2690
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2691
|
-
`Network error during delegation list: ${String(error)}`,
|
|
2692
|
-
error instanceof Error ? error : void 0
|
|
2693
|
-
)
|
|
2694
|
-
};
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
/**
|
|
2698
|
-
* Gets the full delegation chain for a given delegation.
|
|
2699
|
-
*
|
|
2700
|
-
* Returns the chain of delegations from the root (original delegator)
|
|
2701
|
-
* to the specified delegation, including all intermediate sub-delegations.
|
|
2702
|
-
*
|
|
2703
|
-
* @param cid - The CID of the delegation to get the chain for
|
|
2704
|
-
* @returns Result containing the DelegationChain or an error
|
|
2705
|
-
*
|
|
2706
|
-
* @example
|
|
2707
|
-
* ```typescript
|
|
2708
|
-
* const result = await manager.getChain("bafy...");
|
|
2709
|
-
* if (result.ok) {
|
|
2710
|
-
* console.log("Chain length:", result.data.length);
|
|
2711
|
-
* for (const delegation of result.data) {
|
|
2712
|
-
* console.log(`- ${delegation.delegatorDID} -> ${delegation.delegateDID}`);
|
|
2713
|
-
* }
|
|
2714
|
-
* }
|
|
2715
|
-
* ```
|
|
2716
|
-
*/
|
|
2717
|
-
async getChain(cid) {
|
|
2718
|
-
if (!cid) {
|
|
2719
|
-
return {
|
|
2720
|
-
ok: false,
|
|
2721
|
-
error: createError(
|
|
2722
|
-
DelegationErrorCodes.INVALID_INPUT,
|
|
2723
|
-
"cid is required"
|
|
2724
|
-
)
|
|
2725
|
-
};
|
|
2726
|
-
}
|
|
2727
|
-
try {
|
|
2728
|
-
const body = JSON.stringify({ cid, includeChain: true });
|
|
2729
|
-
const response = await this.invokeOperation(
|
|
2730
|
-
cid,
|
|
2731
|
-
DelegationAction.GET,
|
|
2732
|
-
body
|
|
2733
|
-
);
|
|
2734
|
-
if (!response.ok) {
|
|
2735
|
-
const errorText = await response.text();
|
|
2736
|
-
if (response.status === 404) {
|
|
2737
|
-
return {
|
|
2738
|
-
ok: false,
|
|
2739
|
-
error: createError(
|
|
2740
|
-
DelegationErrorCodes.NOT_FOUND,
|
|
2741
|
-
`Delegation not found: ${cid}`
|
|
2742
|
-
)
|
|
2743
|
-
};
|
|
2744
|
-
}
|
|
2745
|
-
return {
|
|
2746
|
-
ok: false,
|
|
2747
|
-
error: createError(
|
|
2748
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2749
|
-
`Failed to get delegation chain: ${response.status} - ${errorText}`,
|
|
2750
|
-
void 0,
|
|
2751
|
-
{ status: response.status, cid }
|
|
2752
|
-
)
|
|
2753
|
-
};
|
|
2754
|
-
}
|
|
2755
|
-
const data = await response.json();
|
|
2756
|
-
const chain = data.chain.map((item) => ({
|
|
2757
|
-
cid: item.cid,
|
|
2758
|
-
delegateDID: item.delegateDID,
|
|
2759
|
-
delegatorDID: item.delegatorDID,
|
|
2760
|
-
spaceId: item.spaceId,
|
|
2761
|
-
path: item.path,
|
|
2762
|
-
actions: item.actions,
|
|
2763
|
-
expiry: new Date(item.expiry),
|
|
2764
|
-
isRevoked: item.isRevoked,
|
|
2765
|
-
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
2766
|
-
parentCid: item.parentCid,
|
|
2767
|
-
allowSubDelegation: item.allowSubDelegation
|
|
2768
|
-
}));
|
|
2769
|
-
return { ok: true, data: chain };
|
|
2770
|
-
} catch (error) {
|
|
2771
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
2772
|
-
return {
|
|
2773
|
-
ok: false,
|
|
2774
|
-
error: createError(
|
|
2775
|
-
DelegationErrorCodes.ABORTED,
|
|
2776
|
-
"Request aborted",
|
|
2777
|
-
error
|
|
2778
|
-
)
|
|
2779
|
-
};
|
|
2780
|
-
}
|
|
2781
|
-
return {
|
|
2782
|
-
ok: false,
|
|
2783
|
-
error: createError(
|
|
2784
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2785
|
-
`Network error during chain retrieval: ${String(error)}`,
|
|
2786
|
-
error instanceof Error ? error : void 0
|
|
2787
|
-
)
|
|
2788
|
-
};
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
/**
|
|
2792
|
-
* Checks if the current session has permission for a given path and action.
|
|
2793
|
-
*
|
|
2794
|
-
* This can be used to verify permissions before attempting an operation,
|
|
2795
|
-
* or to implement custom access control logic.
|
|
2796
|
-
*
|
|
2797
|
-
* @param path - The resource path to check
|
|
2798
|
-
* @param action - The action to check (e.g., "tinycloud.kv/get")
|
|
2799
|
-
* @returns Result containing a boolean indicating permission or an error
|
|
2800
|
-
*
|
|
2801
|
-
* @example
|
|
2802
|
-
* ```typescript
|
|
2803
|
-
* const result = await manager.checkPermission("documents/private/", "tinycloud.kv/put");
|
|
2804
|
-
* if (result.ok && result.data) {
|
|
2805
|
-
* console.log("Permission granted");
|
|
2806
|
-
* } else {
|
|
2807
|
-
* console.log("Permission denied");
|
|
2808
|
-
* }
|
|
2809
|
-
* ```
|
|
2810
|
-
*/
|
|
2811
|
-
async checkPermission(path, action) {
|
|
2812
|
-
if (!path) {
|
|
2813
|
-
return {
|
|
2814
|
-
ok: false,
|
|
2815
|
-
error: createError(
|
|
2816
|
-
DelegationErrorCodes.INVALID_INPUT,
|
|
2817
|
-
"path is required"
|
|
2818
|
-
)
|
|
2819
|
-
};
|
|
2820
|
-
}
|
|
2821
|
-
if (!action) {
|
|
2822
|
-
return {
|
|
2823
|
-
ok: false,
|
|
2824
|
-
error: createError(
|
|
2825
|
-
DelegationErrorCodes.INVALID_INPUT,
|
|
2826
|
-
"action is required"
|
|
2827
|
-
)
|
|
2828
|
-
};
|
|
2829
|
-
}
|
|
2830
|
-
try {
|
|
2831
|
-
const body = JSON.stringify({ path, action });
|
|
2832
|
-
const response = await this.invokeOperation(
|
|
2833
|
-
path,
|
|
2834
|
-
DelegationAction.CHECK,
|
|
2835
|
-
body
|
|
2836
|
-
);
|
|
2837
|
-
if (!response.ok) {
|
|
2838
|
-
if (response.status === 403) {
|
|
2839
|
-
return { ok: true, data: false };
|
|
2840
|
-
}
|
|
2841
|
-
const errorText = await response.text();
|
|
2842
|
-
return {
|
|
2843
|
-
ok: false,
|
|
2844
|
-
error: createError(
|
|
2845
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2846
|
-
`Failed to check permission: ${response.status} - ${errorText}`,
|
|
2847
|
-
void 0,
|
|
2848
|
-
{ status: response.status, path, action }
|
|
2849
|
-
)
|
|
2850
|
-
};
|
|
2851
|
-
}
|
|
2852
|
-
const data = await response.json();
|
|
2853
|
-
return { ok: true, data: data.allowed };
|
|
2854
|
-
} catch (error) {
|
|
2855
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
2856
|
-
return {
|
|
2857
|
-
ok: false,
|
|
2858
|
-
error: createError(
|
|
2859
|
-
DelegationErrorCodes.ABORTED,
|
|
2860
|
-
"Request aborted",
|
|
2861
|
-
error
|
|
2862
|
-
)
|
|
2863
|
-
};
|
|
2864
|
-
}
|
|
2865
|
-
return {
|
|
2866
|
-
ok: false,
|
|
2867
|
-
error: createError(
|
|
2868
|
-
DelegationErrorCodes.NETWORK_ERROR,
|
|
2869
|
-
`Network error during permission check: ${String(error)}`,
|
|
2870
|
-
error instanceof Error ? error : void 0
|
|
2871
|
-
)
|
|
2872
|
-
};
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
};
|
|
2876
|
-
|
|
2877
|
-
// src/delegations/SharingService.schema.ts
|
|
2878
|
-
var import_zod5 = require("zod");
|
|
2879
|
-
var EncodedShareDataSchema = import_zod5.z.object({
|
|
2880
|
-
/** Private key in JWK format (must include d parameter) */
|
|
2881
|
-
key: JWKSchema.refine(
|
|
2882
|
-
(jwk) => typeof jwk.d === "string" && jwk.d.length > 0,
|
|
2883
|
-
{ message: "JWK must include private key (d parameter)" }
|
|
2884
|
-
),
|
|
2885
|
-
/** DID of the key */
|
|
2886
|
-
keyDid: import_zod5.z.string().min(1, "keyDid is required"),
|
|
2887
|
-
/** The delegation granting access */
|
|
2888
|
-
delegation: DelegationSchema,
|
|
2889
|
-
/** Resource path this link grants access to */
|
|
2890
|
-
path: import_zod5.z.string().min(1, "path is required"),
|
|
2891
|
-
/** TinyCloud host URL */
|
|
2892
|
-
host: import_zod5.z.string().url("host must be a valid URL"),
|
|
2893
|
-
/** Space ID */
|
|
2894
|
-
spaceId: import_zod5.z.string().min(1, "spaceId is required"),
|
|
2895
|
-
/** Schema version (must be 1) */
|
|
2896
|
-
version: import_zod5.z.literal(1)
|
|
2897
|
-
});
|
|
2898
|
-
var ReceiveOptionsSchema = import_zod5.z.object({
|
|
2899
|
-
/**
|
|
2900
|
-
* Whether to automatically create a sub-delegation to the current session key.
|
|
2901
|
-
* Default: true
|
|
2902
|
-
*/
|
|
2903
|
-
autoSubdelegate: import_zod5.z.boolean().optional(),
|
|
2904
|
-
/**
|
|
2905
|
-
* Whether to use the current session key for operations (requires autoSubdelegate).
|
|
2906
|
-
* Default: true
|
|
2907
|
-
*/
|
|
2908
|
-
useSessionKey: import_zod5.z.boolean().optional(),
|
|
2909
|
-
/**
|
|
2910
|
-
* Ingestion options passed to CapabilityKeyRegistry.
|
|
2911
|
-
*/
|
|
2912
|
-
ingestOptions: IngestOptionsSchema.optional()
|
|
2913
|
-
});
|
|
2914
|
-
var SharingServiceConfigSchema = import_zod5.z.object({
|
|
2915
|
-
/** TinyCloud host URLs */
|
|
2916
|
-
hosts: import_zod5.z.array(import_zod5.z.string().url()).min(1, "At least one host URL is required"),
|
|
2917
|
-
/**
|
|
2918
|
-
* Active session for authentication.
|
|
2919
|
-
* Required for generate(), optional for receive().
|
|
2920
|
-
*/
|
|
2921
|
-
session: import_zod5.z.unknown().refine(
|
|
2922
|
-
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
2923
|
-
{ message: "Expected a ServiceSession object or undefined" }
|
|
2924
|
-
).optional(),
|
|
2925
|
-
/** Platform-specific invoke function */
|
|
2926
|
-
invoke: import_zod5.z.unknown().refine((val) => typeof val === "function", {
|
|
2927
|
-
message: "Expected an invoke function"
|
|
2928
|
-
}),
|
|
2929
|
-
/** Optional custom fetch implementation */
|
|
2930
|
-
fetch: import_zod5.z.unknown().refine(
|
|
2931
|
-
(val) => val === void 0 || typeof val === "function",
|
|
2932
|
-
{ message: "Expected a fetch function or undefined" }
|
|
2933
|
-
).optional(),
|
|
2934
|
-
/** Key provider for cryptographic operations */
|
|
2935
|
-
keyProvider: KeyProviderSchema,
|
|
2936
|
-
/** Capability key registry for key/delegation management */
|
|
2937
|
-
registry: import_zod5.z.unknown().refine(
|
|
2938
|
-
(val) => val !== null && typeof val === "object",
|
|
2939
|
-
{ message: "Expected an ICapabilityKeyRegistry object" }
|
|
2940
|
-
),
|
|
2941
|
-
/**
|
|
2942
|
-
* Delegation manager for creating delegations.
|
|
2943
|
-
* Required for generate(), optional for receive().
|
|
2944
|
-
*/
|
|
2945
|
-
delegationManager: import_zod5.z.unknown().refine(
|
|
2946
|
-
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
2947
|
-
{ message: "Expected a DelegationManager object or undefined" }
|
|
2948
|
-
).optional(),
|
|
2949
|
-
/** Factory for creating KV service instances */
|
|
2950
|
-
createKVService: import_zod5.z.unknown().refine(
|
|
2951
|
-
(val) => typeof val === "function",
|
|
2952
|
-
{ message: "Expected a createKVService factory function" }
|
|
2953
|
-
),
|
|
2954
|
-
/** Base URL for sharing links (e.g., "https://share.myapp.com") */
|
|
2955
|
-
baseUrl: import_zod5.z.string().optional(),
|
|
2956
|
-
/**
|
|
2957
|
-
* Custom delegation creation function.
|
|
2958
|
-
*/
|
|
2959
|
-
createDelegation: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
2960
|
-
message: "Expected a createDelegation function or undefined"
|
|
2961
|
-
}).optional(),
|
|
2962
|
-
/**
|
|
2963
|
-
* WASM function for client-side delegation creation.
|
|
2964
|
-
*/
|
|
2965
|
-
createDelegationWasm: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
2966
|
-
message: "Expected a createDelegationWasm function or undefined"
|
|
2967
|
-
}).optional(),
|
|
2968
|
-
/**
|
|
2969
|
-
* Path prefix for KV operations.
|
|
2970
|
-
*/
|
|
2971
|
-
pathPrefix: import_zod5.z.string().optional(),
|
|
2972
|
-
/**
|
|
2973
|
-
* Session expiry time.
|
|
2974
|
-
*/
|
|
2975
|
-
sessionExpiry: import_zod5.z.date().optional(),
|
|
2976
|
-
/**
|
|
2977
|
-
* Callback to create a DIRECT delegation from wallet to share key.
|
|
2978
|
-
* This is the preferred method for long-lived share links because it
|
|
2979
|
-
* bypasses the session delegation chain entirely.
|
|
2980
|
-
*/
|
|
2981
|
-
onRootDelegationNeeded: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
2982
|
-
message: "Expected an onRootDelegationNeeded function or undefined"
|
|
2983
|
-
}).optional()
|
|
2984
|
-
});
|
|
2985
|
-
function validateEncodedShareData(data) {
|
|
2986
|
-
const result = EncodedShareDataSchema.safeParse(data);
|
|
2987
|
-
if (!result.success) {
|
|
2988
|
-
return {
|
|
2989
|
-
ok: false,
|
|
2990
|
-
error: {
|
|
2991
|
-
code: DelegationErrorCodes.VALIDATION_ERROR,
|
|
2992
|
-
message: `Invalid share data: ${result.error.message}`,
|
|
2993
|
-
service: "delegation",
|
|
2994
|
-
meta: { issues: result.error.issues }
|
|
2995
|
-
}
|
|
2996
|
-
};
|
|
2997
|
-
}
|
|
2998
|
-
return { ok: true, data: result.data };
|
|
2999
|
-
}
|
|
3000
|
-
|
|
3001
|
-
// src/manifest.ts
|
|
3002
|
-
var import_ms = __toESM(require("ms"), 1);
|
|
3003
|
-
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
3004
|
-
var ManifestValidationError = class extends Error {
|
|
3005
|
-
constructor(message) {
|
|
3006
|
-
super(`Manifest validation failed: ${message}`);
|
|
3007
|
-
this.name = "ManifestValidationError";
|
|
3008
|
-
}
|
|
3009
|
-
};
|
|
3010
|
-
var DEFAULT_EXPIRY = "30d";
|
|
3011
|
-
var DEFAULT_DEFAULTS = true;
|
|
3012
|
-
var DEFAULT_MANIFEST_VERSION = 1;
|
|
3013
|
-
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
3014
|
-
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
3015
|
-
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
3016
|
-
var SECRETS_SPACE = "secrets";
|
|
3017
|
-
var VAULT_PERMISSION_SERVICE = "tinycloud.vault";
|
|
3018
|
-
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
3019
|
-
kv: "tinycloud.kv",
|
|
3020
|
-
sql: "tinycloud.sql",
|
|
3021
|
-
duckdb: "tinycloud.duckdb",
|
|
3022
|
-
capabilities: "tinycloud.capabilities",
|
|
3023
|
-
hooks: "tinycloud.hooks",
|
|
3024
|
-
encryption: "tinycloud.encryption"
|
|
3025
|
-
});
|
|
3026
|
-
var ENCRYPTION_PERMISSION_SERVICE = "tinycloud.encryption";
|
|
3027
|
-
var ENCRYPTION_MANIFEST_SPACE = "encryption";
|
|
3028
|
-
var SERVICE_LONG_TO_SHORT = Object.freeze(
|
|
3029
|
-
Object.fromEntries(
|
|
3030
|
-
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
3031
|
-
)
|
|
3032
|
-
);
|
|
3033
|
-
var DEFAULT_STANDARD_ENTRIES = [
|
|
3034
|
-
{
|
|
3035
|
-
service: "tinycloud.kv",
|
|
3036
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3037
|
-
path: "/",
|
|
3038
|
-
actions: ["get", "put", "del", "list", "metadata"]
|
|
3039
|
-
},
|
|
3040
|
-
{
|
|
3041
|
-
service: "tinycloud.sql",
|
|
3042
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3043
|
-
path: "/",
|
|
3044
|
-
actions: ["read", "write"]
|
|
3045
|
-
}
|
|
3046
|
-
];
|
|
3047
|
-
var DEFAULT_ADMIN_ENTRIES = [
|
|
3048
|
-
{
|
|
3049
|
-
service: "tinycloud.kv",
|
|
3050
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3051
|
-
path: "/",
|
|
3052
|
-
actions: ["get", "put", "del", "list", "metadata"]
|
|
3053
|
-
},
|
|
3054
|
-
{
|
|
3055
|
-
service: "tinycloud.sql",
|
|
3056
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3057
|
-
path: "/",
|
|
3058
|
-
actions: ["read", "write", "ddl"]
|
|
3059
|
-
}
|
|
3060
|
-
];
|
|
3061
|
-
var DEFAULT_ALL_ENTRIES = [
|
|
3062
|
-
{
|
|
3063
|
-
service: "tinycloud.kv",
|
|
3064
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3065
|
-
path: "/",
|
|
3066
|
-
actions: ["get", "put", "del", "list", "metadata"]
|
|
3067
|
-
},
|
|
3068
|
-
{
|
|
3069
|
-
service: "tinycloud.sql",
|
|
3070
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3071
|
-
path: "/",
|
|
3072
|
-
actions: ["read", "write", "ddl"]
|
|
3073
|
-
},
|
|
3074
|
-
{
|
|
3075
|
-
service: "tinycloud.duckdb",
|
|
3076
|
-
space: DEFAULT_MANIFEST_SPACE,
|
|
3077
|
-
path: "/",
|
|
3078
|
-
actions: ["read", "write"]
|
|
3079
|
-
}
|
|
3080
|
-
];
|
|
3081
|
-
function parseExpiry(duration) {
|
|
3082
|
-
if (typeof duration !== "string" || duration.length === 0) {
|
|
3083
|
-
throw new ManifestValidationError(
|
|
3084
|
-
`expiry must be a non-empty duration string (got ${JSON.stringify(duration)})`
|
|
3085
|
-
);
|
|
3086
|
-
}
|
|
3087
|
-
const parsed = (0, import_ms.default)(duration);
|
|
3088
|
-
if (typeof parsed !== "number" || !Number.isFinite(parsed) || parsed <= 0) {
|
|
3089
|
-
throw new ManifestValidationError(
|
|
3090
|
-
`invalid expiry duration: ${JSON.stringify(duration)}`
|
|
3091
|
-
);
|
|
3092
|
-
}
|
|
3093
|
-
return parsed;
|
|
3094
|
-
}
|
|
3095
|
-
function expandActionShortNames(service, actions) {
|
|
3096
|
-
return actions.map((a) => {
|
|
3097
|
-
if (a.includes("/")) {
|
|
3098
|
-
return a;
|
|
3099
|
-
}
|
|
3100
|
-
return `${service}/${a}`;
|
|
3101
|
-
});
|
|
3102
|
-
}
|
|
3103
|
-
function expandPermissionEntry(entry) {
|
|
3104
|
-
if (entry.service === ENCRYPTION_PERMISSION_SERVICE) {
|
|
3105
|
-
return expandEncryptionPermissionEntry(entry);
|
|
3106
|
-
}
|
|
3107
|
-
if (entry.service !== VAULT_PERMISSION_SERVICE) {
|
|
3108
|
-
return [
|
|
3109
|
-
{
|
|
3110
|
-
...entry,
|
|
3111
|
-
actions: expandActionShortNames(entry.service, entry.actions)
|
|
3112
|
-
}
|
|
3113
|
-
];
|
|
3114
|
-
}
|
|
3115
|
-
return expandVaultPermissionEntry(entry);
|
|
3116
|
-
}
|
|
3117
|
-
function expandEncryptionPermissionEntry(entry) {
|
|
3118
|
-
if (typeof entry.path !== "string" || !entry.path.startsWith("urn:tinycloud:encryption:")) {
|
|
3119
|
-
throw new ManifestValidationError(
|
|
3120
|
-
`tinycloud.encryption entries require path to be a networkId URN (got ${JSON.stringify(entry.path)})`
|
|
3121
|
-
);
|
|
3122
|
-
}
|
|
3123
|
-
const normalizedActions = [];
|
|
3124
|
-
for (const action of entry.actions) {
|
|
3125
|
-
if (action === "decrypt" || action === "tinycloud.encryption/decrypt") {
|
|
3126
|
-
normalizedActions.push("tinycloud.encryption/decrypt");
|
|
3127
|
-
continue;
|
|
3128
|
-
}
|
|
3129
|
-
if (action === "network.create" || action === "tinycloud.encryption/network.create") {
|
|
3130
|
-
normalizedActions.push("tinycloud.encryption/network.create");
|
|
3131
|
-
continue;
|
|
3132
|
-
}
|
|
3133
|
-
if (action === "network.revoke" || action === "tinycloud.encryption/network.revoke") {
|
|
3134
|
-
normalizedActions.push("tinycloud.encryption/network.revoke");
|
|
3135
|
-
continue;
|
|
3136
|
-
}
|
|
3137
|
-
if (action.includes("/")) {
|
|
3138
|
-
throw new ManifestValidationError(
|
|
3139
|
-
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
3140
|
-
);
|
|
3141
|
-
}
|
|
3142
|
-
throw new ManifestValidationError(
|
|
3143
|
-
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
3144
|
-
);
|
|
3145
|
-
}
|
|
3146
|
-
const dedupedActions = [];
|
|
3147
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3148
|
-
for (const a of normalizedActions) {
|
|
3149
|
-
if (!seen.has(a)) {
|
|
3150
|
-
dedupedActions.push(a);
|
|
3151
|
-
seen.add(a);
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
return [
|
|
3155
|
-
{
|
|
3156
|
-
service: ENCRYPTION_PERMISSION_SERVICE,
|
|
3157
|
-
space: ENCRYPTION_MANIFEST_SPACE,
|
|
3158
|
-
path: entry.path,
|
|
3159
|
-
actions: dedupedActions,
|
|
3160
|
-
skipPrefix: true,
|
|
3161
|
-
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
3162
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3163
|
-
}
|
|
3164
|
-
];
|
|
3165
|
-
}
|
|
3166
|
-
function expandPermissionEntries(entries) {
|
|
3167
|
-
return entries.flatMap(expandPermissionEntry);
|
|
3168
|
-
}
|
|
3169
|
-
function applyPrefix(prefix, path, skipPrefix) {
|
|
3170
|
-
if (skipPrefix) {
|
|
3171
|
-
return path;
|
|
3172
|
-
}
|
|
3173
|
-
if (prefix === "") {
|
|
3174
|
-
return path;
|
|
3175
|
-
}
|
|
3176
|
-
if (path.startsWith("/")) {
|
|
3177
|
-
return `${prefix}${path}`;
|
|
3178
|
-
}
|
|
3179
|
-
return `${prefix}/${path}`;
|
|
3180
|
-
}
|
|
3181
|
-
async function loadManifest(url) {
|
|
3182
|
-
const fetchFn = globalThis.fetch;
|
|
3183
|
-
if (typeof fetchFn !== "function") {
|
|
3184
|
-
throw new ManifestValidationError(
|
|
3185
|
-
"loadManifest requires a global fetch; pass the manifest object directly on runtimes without fetch"
|
|
3186
|
-
);
|
|
3187
|
-
}
|
|
3188
|
-
const res = await fetchFn(url);
|
|
3189
|
-
if (!res.ok) {
|
|
3190
|
-
throw new ManifestValidationError(
|
|
3191
|
-
`failed to fetch manifest from ${url}: HTTP ${res.status}`
|
|
3192
|
-
);
|
|
3193
|
-
}
|
|
3194
|
-
const json = await res.json();
|
|
3195
|
-
return validateManifest(json);
|
|
3196
|
-
}
|
|
3197
|
-
function validateManifest(input) {
|
|
3198
|
-
if (input === null || typeof input !== "object") {
|
|
3199
|
-
throw new ManifestValidationError("manifest must be an object");
|
|
3200
|
-
}
|
|
3201
|
-
const m = input;
|
|
3202
|
-
if (m.manifest_version !== void 0 && m.manifest_version !== DEFAULT_MANIFEST_VERSION) {
|
|
3203
|
-
throw new ManifestValidationError(
|
|
3204
|
-
`manifest.manifest_version must be ${DEFAULT_MANIFEST_VERSION}`
|
|
3205
|
-
);
|
|
3206
|
-
}
|
|
3207
|
-
if (typeof m.app_id !== "string" || m.app_id.length === 0) {
|
|
3208
|
-
throw new ManifestValidationError(
|
|
3209
|
-
"manifest.app_id is required and must be a non-empty string"
|
|
3210
|
-
);
|
|
3211
|
-
}
|
|
3212
|
-
if (typeof m.name !== "string" || m.name.length === 0) {
|
|
3213
|
-
throw new ManifestValidationError(
|
|
3214
|
-
"manifest.name is required and must be a non-empty string"
|
|
3215
|
-
);
|
|
3216
|
-
}
|
|
3217
|
-
if (m.did !== void 0 && (typeof m.did !== "string" || m.did.length === 0)) {
|
|
3218
|
-
throw new ManifestValidationError(
|
|
3219
|
-
"manifest.did must be a non-empty DID string"
|
|
3220
|
-
);
|
|
3221
|
-
}
|
|
3222
|
-
if (m.space !== void 0 && (typeof m.space !== "string" || m.space.length === 0)) {
|
|
3223
|
-
throw new ManifestValidationError(
|
|
3224
|
-
"manifest.space must be a non-empty string"
|
|
3225
|
-
);
|
|
3226
|
-
}
|
|
3227
|
-
if (m.expiry !== void 0) {
|
|
3228
|
-
parseExpiry(m.expiry);
|
|
3229
|
-
}
|
|
3230
|
-
if (m.permissions !== void 0) {
|
|
3231
|
-
if (!Array.isArray(m.permissions)) {
|
|
3232
|
-
throw new ManifestValidationError(
|
|
3233
|
-
"manifest.permissions must be an array"
|
|
3234
|
-
);
|
|
3235
|
-
}
|
|
3236
|
-
m.permissions.forEach(
|
|
3237
|
-
(p, i) => validatePermissionEntry(p, `permissions[${i}]`)
|
|
3238
|
-
);
|
|
3239
|
-
}
|
|
3240
|
-
if (m.secrets !== void 0) {
|
|
3241
|
-
validateManifestSecrets(m.secrets);
|
|
3242
|
-
}
|
|
3243
|
-
return m;
|
|
3244
|
-
}
|
|
3245
|
-
function validateManifestSecrets(secrets) {
|
|
3246
|
-
if (secrets === null || typeof secrets !== "object" || Array.isArray(secrets)) {
|
|
3247
|
-
throw new ManifestValidationError("manifest.secrets must be an object");
|
|
3248
|
-
}
|
|
3249
|
-
for (const [name, spec] of Object.entries(secrets)) {
|
|
3250
|
-
if (!import_sdk_services4.SECRET_NAME_RE.test(name)) {
|
|
3251
|
-
throw new ManifestValidationError(
|
|
3252
|
-
`manifest.secrets.${name} must match ${import_sdk_services4.SECRET_NAME_RE.source}`
|
|
3253
|
-
);
|
|
3254
|
-
}
|
|
3255
|
-
try {
|
|
3256
|
-
(0, import_sdk_services4.resolveSecretPath)(
|
|
3257
|
-
secretNameFromSpec(name, spec),
|
|
3258
|
-
{ scope: secretScopeFromSpec(spec) }
|
|
3259
|
-
);
|
|
3260
|
-
} catch (error) {
|
|
3261
|
-
throw new ManifestValidationError(
|
|
3262
|
-
`manifest.secrets.${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
3263
|
-
);
|
|
3264
|
-
}
|
|
3265
|
-
const actions = secretActionsFromSpec(name, spec);
|
|
3266
|
-
if (actions.length === 0) {
|
|
3267
|
-
throw new ManifestValidationError(
|
|
3268
|
-
`manifest.secrets.${name} actions must be non-empty`
|
|
3269
|
-
);
|
|
3270
|
-
}
|
|
3271
|
-
for (const action of actions) {
|
|
3272
|
-
if (typeof action !== "string" || action.length === 0) {
|
|
3273
|
-
throw new ManifestValidationError(
|
|
3274
|
-
`manifest.secrets.${name} actions must be non-empty strings`
|
|
3275
|
-
);
|
|
3276
|
-
}
|
|
3277
|
-
}
|
|
3278
|
-
if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
|
|
3279
|
-
parseExpiry(spec.expiry);
|
|
2626
|
+
if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
|
|
2627
|
+
parseExpiry(spec.expiry);
|
|
3280
2628
|
}
|
|
3281
2629
|
}
|
|
3282
2630
|
}
|
|
@@ -3454,286 +2802,1628 @@ function secretActionsFromSpec(name, spec) {
|
|
|
3454
2802
|
if (Array.isArray(spec.actions)) {
|
|
3455
2803
|
return spec.actions;
|
|
3456
2804
|
}
|
|
3457
|
-
throw new ManifestValidationError(
|
|
3458
|
-
`manifest.secrets.${name}.actions must be a string or array`
|
|
3459
|
-
);
|
|
2805
|
+
throw new ManifestValidationError(
|
|
2806
|
+
`manifest.secrets.${name}.actions must be a string or array`
|
|
2807
|
+
);
|
|
2808
|
+
}
|
|
2809
|
+
function secretEntriesForManifest(secrets) {
|
|
2810
|
+
if (secrets === void 0) {
|
|
2811
|
+
return [];
|
|
2812
|
+
}
|
|
2813
|
+
const entries = [];
|
|
2814
|
+
for (const [name, spec] of Object.entries(secrets)) {
|
|
2815
|
+
const actions = secretActionsFromSpec(name, spec);
|
|
2816
|
+
const secretPath = (0, import_sdk_services4.resolveSecretPath)(
|
|
2817
|
+
secretNameFromSpec(name, spec),
|
|
2818
|
+
{ scope: secretScopeFromSpec(spec) }
|
|
2819
|
+
);
|
|
2820
|
+
const extra = spec !== true && typeof spec === "object" && !Array.isArray(spec) ? spec : {};
|
|
2821
|
+
entries.push({
|
|
2822
|
+
service: VAULT_PERMISSION_SERVICE,
|
|
2823
|
+
space: SECRETS_SPACE,
|
|
2824
|
+
path: secretPath.vaultKey,
|
|
2825
|
+
actions: normalizeSecretActions(actions),
|
|
2826
|
+
skipPrefix: true,
|
|
2827
|
+
...extra.expiry !== void 0 ? { expiry: extra.expiry } : {},
|
|
2828
|
+
...extra.description !== void 0 ? { description: extra.description } : {}
|
|
2829
|
+
});
|
|
2830
|
+
}
|
|
2831
|
+
return entries;
|
|
2832
|
+
}
|
|
2833
|
+
function resolveEntry(entry, prefix, _inheritedExpiryMs, inheritedSpace) {
|
|
2834
|
+
const skipPrefixForEntry = entry.skipPrefix === true || entry.service === ENCRYPTION_PERMISSION_SERVICE;
|
|
2835
|
+
const resolvedPath = applyPrefix(prefix, entry.path, skipPrefixForEntry);
|
|
2836
|
+
const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
|
|
2837
|
+
return expandPermissionEntry({
|
|
2838
|
+
...entry,
|
|
2839
|
+
space: entry.space ?? inheritedSpace,
|
|
2840
|
+
path: resolvedPath,
|
|
2841
|
+
skipPrefix: true
|
|
2842
|
+
}).map((expanded) => ({
|
|
2843
|
+
service: expanded.service,
|
|
2844
|
+
space: expanded.space ?? inheritedSpace,
|
|
2845
|
+
path: expanded.path,
|
|
2846
|
+
actions: expanded.actions,
|
|
2847
|
+
// Only populate `expiryMs` when the entry had its own expiry override.
|
|
2848
|
+
// When absent, callers use the parent (delegation or manifest) expiry
|
|
2849
|
+
// which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
|
|
2850
|
+
...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {},
|
|
2851
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2852
|
+
}));
|
|
2853
|
+
}
|
|
2854
|
+
function expandVaultPermissionEntry(entry) {
|
|
2855
|
+
const byBase = /* @__PURE__ */ new Map();
|
|
2856
|
+
for (const action of entry.actions) {
|
|
2857
|
+
const expansion = vaultActionExpansion(action);
|
|
2858
|
+
for (const base of expansion.bases) {
|
|
2859
|
+
const actions = byBase.get(base) ?? [];
|
|
2860
|
+
if (!actions.includes(expansion.action)) {
|
|
2861
|
+
actions.push(expansion.action);
|
|
2862
|
+
}
|
|
2863
|
+
byBase.set(base, actions);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return [...byBase.entries()].map(([base, actions]) => ({
|
|
2867
|
+
...entry,
|
|
2868
|
+
service: "tinycloud.kv",
|
|
2869
|
+
path: vaultKVPath(base, entry.path),
|
|
2870
|
+
actions,
|
|
2871
|
+
skipPrefix: true
|
|
2872
|
+
}));
|
|
2873
|
+
}
|
|
2874
|
+
function vaultActionExpansion(action) {
|
|
2875
|
+
const normalized = normalizeVaultAction(action);
|
|
2876
|
+
if (normalized === "read" || normalized === "get") {
|
|
2877
|
+
return { bases: ["vault"], action: "tinycloud.kv/get" };
|
|
2878
|
+
}
|
|
2879
|
+
if (normalized === "write" || normalized === "put") {
|
|
2880
|
+
return { bases: ["vault"], action: "tinycloud.kv/put" };
|
|
2881
|
+
}
|
|
2882
|
+
if (normalized === "delete" || normalized === "del") {
|
|
2883
|
+
return { bases: ["vault"], action: "tinycloud.kv/del" };
|
|
2884
|
+
}
|
|
2885
|
+
if (normalized === "list") {
|
|
2886
|
+
return { bases: ["vault"], action: "tinycloud.kv/list" };
|
|
2887
|
+
}
|
|
2888
|
+
if (normalized === "head") {
|
|
2889
|
+
return { bases: ["vault"], action: "tinycloud.kv/get" };
|
|
2890
|
+
}
|
|
2891
|
+
if (normalized === "metadata") {
|
|
2892
|
+
return { bases: ["vault"], action: "tinycloud.kv/metadata" };
|
|
2893
|
+
}
|
|
2894
|
+
throw new ManifestValidationError(
|
|
2895
|
+
`unknown vault action ${JSON.stringify(action)}; expected read, write, delete, get, put, del, list, head, or metadata`
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
function normalizeVaultAction(action) {
|
|
2899
|
+
if (action.startsWith(`${VAULT_PERMISSION_SERVICE}/`)) {
|
|
2900
|
+
return action.slice(`${VAULT_PERMISSION_SERVICE}/`.length);
|
|
2901
|
+
}
|
|
2902
|
+
if (action.startsWith("tinycloud.kv/")) {
|
|
2903
|
+
return action.slice("tinycloud.kv/".length);
|
|
2904
|
+
}
|
|
2905
|
+
if (action.includes("/")) {
|
|
2906
|
+
throw new ManifestValidationError(
|
|
2907
|
+
`unknown vault action ${JSON.stringify(action)}; expected a tinycloud.vault or tinycloud.kv action`
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
return action;
|
|
2911
|
+
}
|
|
2912
|
+
function vaultKVPath(base, path) {
|
|
2913
|
+
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
2914
|
+
return `${base}/${normalized}`;
|
|
2915
|
+
}
|
|
2916
|
+
function cloneResourceCapability(entry) {
|
|
2917
|
+
return {
|
|
2918
|
+
service: entry.service,
|
|
2919
|
+
space: entry.space,
|
|
2920
|
+
path: entry.path,
|
|
2921
|
+
actions: [...entry.actions],
|
|
2922
|
+
...entry.expiryMs !== void 0 ? { expiryMs: entry.expiryMs } : {},
|
|
2923
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
function clonePermissionEntry(entry) {
|
|
2927
|
+
return {
|
|
2928
|
+
service: entry.service,
|
|
2929
|
+
...entry.space !== void 0 ? { space: entry.space } : {},
|
|
2930
|
+
path: entry.path,
|
|
2931
|
+
actions: [...entry.actions],
|
|
2932
|
+
...entry.skipPrefix !== void 0 ? { skipPrefix: entry.skipPrefix } : {},
|
|
2933
|
+
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
2934
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2937
|
+
function dedupeResources(resources) {
|
|
2938
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2939
|
+
for (const resource of resources) {
|
|
2940
|
+
const key = `${resource.service}\0${resource.space}\0${resource.path}\0${resource.expiryMs ?? ""}`;
|
|
2941
|
+
const existing = byKey.get(key);
|
|
2942
|
+
if (existing === void 0) {
|
|
2943
|
+
byKey.set(key, cloneResourceCapability(resource));
|
|
2944
|
+
continue;
|
|
2945
|
+
}
|
|
2946
|
+
const seen = new Set(existing.actions);
|
|
2947
|
+
for (const action of resource.actions) {
|
|
2948
|
+
if (!seen.has(action)) {
|
|
2949
|
+
existing.actions.push(action);
|
|
2950
|
+
seen.add(action);
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
if (existing.description === void 0 && resource.description !== void 0) {
|
|
2954
|
+
existing.description = resource.description;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
return [...byKey.values()];
|
|
2958
|
+
}
|
|
2959
|
+
function capabilitiesReadPermission(space) {
|
|
2960
|
+
return {
|
|
2961
|
+
service: "tinycloud.capabilities",
|
|
2962
|
+
space,
|
|
2963
|
+
path: "",
|
|
2964
|
+
actions: ["tinycloud.capabilities/read"]
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
function withCapabilitiesReadForSpaces(resources) {
|
|
2968
|
+
if (resources.length === 0) {
|
|
2969
|
+
return [];
|
|
2970
|
+
}
|
|
2971
|
+
const spaces = new Set(
|
|
2972
|
+
resources.filter((resource) => resource.service !== ENCRYPTION_PERMISSION_SERVICE).map((resource) => resource.space)
|
|
2973
|
+
);
|
|
2974
|
+
return dedupeResources([
|
|
2975
|
+
...resources,
|
|
2976
|
+
...[...spaces].map(capabilitiesReadPermission)
|
|
2977
|
+
]);
|
|
2978
|
+
}
|
|
2979
|
+
function accountRegistryPermissions() {
|
|
2980
|
+
return [ACCOUNT_REGISTRY_PATH, "spaces/"].map((path) => ({
|
|
2981
|
+
service: "tinycloud.kv",
|
|
2982
|
+
space: ACCOUNT_REGISTRY_SPACE,
|
|
2983
|
+
path,
|
|
2984
|
+
actions: ["tinycloud.kv/get", "tinycloud.kv/put", "tinycloud.kv/list"]
|
|
2985
|
+
}));
|
|
2986
|
+
}
|
|
2987
|
+
function accountRegistryIndexPermission() {
|
|
2988
|
+
return {
|
|
2989
|
+
service: "tinycloud.sql",
|
|
2990
|
+
space: ACCOUNT_REGISTRY_SPACE,
|
|
2991
|
+
path: "account",
|
|
2992
|
+
actions: ["tinycloud.sql/read", "tinycloud.sql/write"]
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
function composeManifestRequest(inputs, options = {}) {
|
|
2996
|
+
if (!Array.isArray(inputs) || inputs.length === 0) {
|
|
2997
|
+
throw new ManifestValidationError(
|
|
2998
|
+
"composeManifestRequest requires at least one manifest"
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
const includeAccountRegistryPermissions = options.includeAccountRegistryPermissions ?? true;
|
|
3002
|
+
const manifests = inputs.map(validateManifest);
|
|
3003
|
+
const resolved = manifests.map(resolveManifest);
|
|
3004
|
+
const resources = resolved.flatMap((entry) => entry.resources);
|
|
3005
|
+
const delegationTargets = resolved.flatMap(
|
|
3006
|
+
(entry) => entry.additionalDelegates.map((delegate) => ({
|
|
3007
|
+
...delegate,
|
|
3008
|
+
permissions: dedupeResources(delegate.permissions)
|
|
3009
|
+
}))
|
|
3010
|
+
);
|
|
3011
|
+
if (includeAccountRegistryPermissions) {
|
|
3012
|
+
resources.push(...accountRegistryPermissions());
|
|
3013
|
+
resources.push(accountRegistryIndexPermission());
|
|
3014
|
+
}
|
|
3015
|
+
const resourcesWithImplicitCapabilities = withCapabilitiesReadForSpaces(resources);
|
|
3016
|
+
const manifestsByAppId = /* @__PURE__ */ new Map();
|
|
3017
|
+
for (const manifest of manifests) {
|
|
3018
|
+
const current = manifestsByAppId.get(manifest.app_id);
|
|
3019
|
+
if (current === void 0) {
|
|
3020
|
+
manifestsByAppId.set(manifest.app_id, [manifest]);
|
|
3021
|
+
} else {
|
|
3022
|
+
current.push(manifest);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
const registryRecords = includeAccountRegistryPermissions ? [...manifestsByAppId.entries()].map(([app_id, appManifests]) => ({
|
|
3026
|
+
key: `${ACCOUNT_REGISTRY_PATH}${app_id}`,
|
|
3027
|
+
app_id,
|
|
3028
|
+
manifests: appManifests.map((manifest) => ({
|
|
3029
|
+
...manifest,
|
|
3030
|
+
permissions: manifest.permissions?.map(clonePermissionEntry)
|
|
3031
|
+
}))
|
|
3032
|
+
})) : [];
|
|
3033
|
+
return {
|
|
3034
|
+
manifests,
|
|
3035
|
+
resources: resourcesWithImplicitCapabilities,
|
|
3036
|
+
delegationTargets,
|
|
3037
|
+
registryRecords,
|
|
3038
|
+
expiryMs: Math.max(...resolved.map((entry) => entry.expiryMs)),
|
|
3039
|
+
includePublicSpace: resolved.some((entry) => entry.includePublicSpace)
|
|
3040
|
+
};
|
|
3041
|
+
}
|
|
3042
|
+
function resourceCapabilitiesToAbilitiesMap(resources) {
|
|
3043
|
+
const out = {};
|
|
3044
|
+
for (const r of resources) {
|
|
3045
|
+
const shortService = SERVICE_LONG_TO_SHORT[r.service];
|
|
3046
|
+
if (shortService === void 0) {
|
|
3047
|
+
throw new ManifestValidationError(
|
|
3048
|
+
`unknown service '${r.service}' \u2014 no short-form mapping. Known services: ${Object.keys(SERVICE_LONG_TO_SHORT).join(", ")}`
|
|
3049
|
+
);
|
|
3050
|
+
}
|
|
3051
|
+
if (out[shortService] === void 0) {
|
|
3052
|
+
out[shortService] = {};
|
|
3053
|
+
}
|
|
3054
|
+
const pathsMap = out[shortService];
|
|
3055
|
+
const existing = pathsMap[r.path];
|
|
3056
|
+
if (existing === void 0) {
|
|
3057
|
+
pathsMap[r.path] = [...r.actions];
|
|
3058
|
+
} else {
|
|
3059
|
+
const seen = new Set(existing);
|
|
3060
|
+
for (const action of r.actions) {
|
|
3061
|
+
if (!seen.has(action)) {
|
|
3062
|
+
existing.push(action);
|
|
3063
|
+
seen.add(action);
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
return out;
|
|
3460
3069
|
}
|
|
3461
|
-
function
|
|
3462
|
-
|
|
3463
|
-
|
|
3070
|
+
function resourceCapabilitiesToSpaceAbilitiesMap(resources) {
|
|
3071
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
3072
|
+
for (const resource of resources) {
|
|
3073
|
+
const entries = grouped.get(resource.space);
|
|
3074
|
+
if (entries === void 0) {
|
|
3075
|
+
grouped.set(resource.space, [resource]);
|
|
3076
|
+
} else {
|
|
3077
|
+
entries.push(resource);
|
|
3078
|
+
}
|
|
3464
3079
|
}
|
|
3465
|
-
const
|
|
3466
|
-
for (const [
|
|
3467
|
-
|
|
3468
|
-
const secretPath = (0, import_sdk_services4.resolveSecretPath)(
|
|
3469
|
-
secretNameFromSpec(name, spec),
|
|
3470
|
-
{ scope: secretScopeFromSpec(spec) }
|
|
3471
|
-
);
|
|
3472
|
-
const extra = spec !== true && typeof spec === "object" && !Array.isArray(spec) ? spec : {};
|
|
3473
|
-
entries.push({
|
|
3474
|
-
service: VAULT_PERMISSION_SERVICE,
|
|
3475
|
-
space: SECRETS_SPACE,
|
|
3476
|
-
path: secretPath.vaultKey,
|
|
3477
|
-
actions: normalizeSecretActions(actions),
|
|
3478
|
-
skipPrefix: true,
|
|
3479
|
-
...extra.expiry !== void 0 ? { expiry: extra.expiry } : {},
|
|
3480
|
-
...extra.description !== void 0 ? { description: extra.description } : {}
|
|
3481
|
-
});
|
|
3080
|
+
const out = {};
|
|
3081
|
+
for (const [space, entries] of grouped.entries()) {
|
|
3082
|
+
out[space] = resourceCapabilitiesToAbilitiesMap(entries);
|
|
3482
3083
|
}
|
|
3483
|
-
return
|
|
3084
|
+
return out;
|
|
3484
3085
|
}
|
|
3485
|
-
function
|
|
3486
|
-
const
|
|
3487
|
-
const
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
skipPrefix: true
|
|
3494
|
-
}).map((expanded) => ({
|
|
3495
|
-
service: expanded.service,
|
|
3496
|
-
space: expanded.space ?? inheritedSpace,
|
|
3497
|
-
path: expanded.path,
|
|
3498
|
-
actions: expanded.actions,
|
|
3499
|
-
// Only populate `expiryMs` when the entry had its own expiry override.
|
|
3500
|
-
// When absent, callers use the parent (delegation or manifest) expiry
|
|
3501
|
-
// which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
|
|
3502
|
-
...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {},
|
|
3503
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3504
|
-
}));
|
|
3086
|
+
function manifestAbilitiesUnion(resolved) {
|
|
3087
|
+
const all = [...resolved.resources];
|
|
3088
|
+
for (const delegate of resolved.additionalDelegates) {
|
|
3089
|
+
for (const perm of delegate.permissions) {
|
|
3090
|
+
all.push(perm);
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
return resourceCapabilitiesToAbilitiesMap(all);
|
|
3505
3094
|
}
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3095
|
+
|
|
3096
|
+
// src/account/AccountService.ts
|
|
3097
|
+
var SERVICE_NAME2 = "account";
|
|
3098
|
+
var ACCOUNT_INDEX_DB = "account";
|
|
3099
|
+
var ACCOUNT_SPACES_PATH = "spaces/";
|
|
3100
|
+
var AccountService = class {
|
|
3101
|
+
constructor(config) {
|
|
3102
|
+
this.config = config;
|
|
3103
|
+
this.applications = {
|
|
3104
|
+
list: async () => {
|
|
3105
|
+
const kvResult = this.accountKV();
|
|
3106
|
+
if (!kvResult.ok) return kvResult;
|
|
3107
|
+
const listed = await kvResult.data.list({ prefix: ACCOUNT_REGISTRY_PATH });
|
|
3108
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3109
|
+
const applications = [];
|
|
3110
|
+
for (const key of listed.data.keys) {
|
|
3111
|
+
const loaded = await kvResult.data.get(key);
|
|
3112
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3113
|
+
applications.push(applicationFromRecord(key, loaded.data.data));
|
|
3114
|
+
}
|
|
3115
|
+
applications.sort((a, b) => a.appId.localeCompare(b.appId));
|
|
3116
|
+
return (0, import_sdk_services5.ok)(applications);
|
|
3117
|
+
},
|
|
3118
|
+
get: async (appId) => {
|
|
3119
|
+
const kvResult = this.accountKV();
|
|
3120
|
+
if (!kvResult.ok) return kvResult;
|
|
3121
|
+
const key = applicationKey(appId);
|
|
3122
|
+
const loaded = await kvResult.data.get(key);
|
|
3123
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3124
|
+
return (0, import_sdk_services5.ok)(applicationFromRecord(key, loaded.data.data));
|
|
3125
|
+
},
|
|
3126
|
+
register: async (manifest) => {
|
|
3127
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
3128
|
+
const request = composeManifestRequest(manifests);
|
|
3129
|
+
if (request.registryRecords.length === 0) {
|
|
3130
|
+
return (0, import_sdk_services5.err)(
|
|
3131
|
+
(0, import_sdk_services5.serviceError)(
|
|
3132
|
+
"INVALID_MANIFEST",
|
|
3133
|
+
"Manifest did not produce an account application registry record",
|
|
3134
|
+
SERVICE_NAME2
|
|
3135
|
+
)
|
|
3136
|
+
);
|
|
3137
|
+
}
|
|
3138
|
+
await this.config.ensureAccountSpaceHosted?.();
|
|
3139
|
+
const kvResult = this.accountKV();
|
|
3140
|
+
if (!kvResult.ok) return kvResult;
|
|
3141
|
+
let registered;
|
|
3142
|
+
for (const record of request.registryRecords) {
|
|
3143
|
+
const manifestHash = hashJson(record.manifests);
|
|
3144
|
+
if (await this.indexHasApplicationHash(record.app_id, manifestHash)) {
|
|
3145
|
+
registered = {
|
|
3146
|
+
appId: record.app_id,
|
|
3147
|
+
manifests: record.manifests,
|
|
3148
|
+
manifestHash,
|
|
3149
|
+
name: record.manifests[0]?.name,
|
|
3150
|
+
description: record.manifests[0]?.description
|
|
3151
|
+
};
|
|
3152
|
+
continue;
|
|
3153
|
+
}
|
|
3154
|
+
const stored = {
|
|
3155
|
+
app_id: record.app_id,
|
|
3156
|
+
manifests: record.manifests,
|
|
3157
|
+
manifest_hash: manifestHash,
|
|
3158
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3159
|
+
};
|
|
3160
|
+
const written = await kvResult.data.put(record.key, stored);
|
|
3161
|
+
if (!written.ok) return accountErr(written.error);
|
|
3162
|
+
registered = applicationFromRecord(record.key, stored);
|
|
3163
|
+
const indexed = await this.upsertApplicationIndex(registered);
|
|
3164
|
+
if (!indexed.ok) return indexed;
|
|
3165
|
+
}
|
|
3166
|
+
return (0, import_sdk_services5.ok)(registered);
|
|
3167
|
+
},
|
|
3168
|
+
remove: async (appId) => {
|
|
3169
|
+
const kvResult = this.accountKV();
|
|
3170
|
+
if (!kvResult.ok) return kvResult;
|
|
3171
|
+
const removed = await kvResult.data.delete(applicationKey(appId));
|
|
3172
|
+
if (!removed.ok) return accountErr(removed.error);
|
|
3173
|
+
const indexed = await this.deleteApplicationIndex(appId);
|
|
3174
|
+
if (!indexed.ok) return indexed;
|
|
3175
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3514
3176
|
}
|
|
3515
|
-
|
|
3177
|
+
};
|
|
3178
|
+
this.spaces = {
|
|
3179
|
+
list: async () => {
|
|
3180
|
+
const kvResult = this.accountKV();
|
|
3181
|
+
if (!kvResult.ok) return kvResult;
|
|
3182
|
+
const listed = await kvResult.data.list({ prefix: ACCOUNT_SPACES_PATH });
|
|
3183
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3184
|
+
const spaces = [];
|
|
3185
|
+
for (const key of listed.data.keys) {
|
|
3186
|
+
const loaded = await kvResult.data.get(key);
|
|
3187
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3188
|
+
spaces.push(spaceFromRecord(key, loaded.data.data));
|
|
3189
|
+
}
|
|
3190
|
+
spaces.sort((a, b) => a.name.localeCompare(b.name) || a.spaceId.localeCompare(b.spaceId));
|
|
3191
|
+
return (0, import_sdk_services5.ok)(spaces);
|
|
3192
|
+
},
|
|
3193
|
+
get: async (spaceId) => {
|
|
3194
|
+
const kvResult = this.accountKV();
|
|
3195
|
+
if (!kvResult.ok) return kvResult;
|
|
3196
|
+
const loaded = await kvResult.data.get(spaceKey(spaceId));
|
|
3197
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3198
|
+
return (0, import_sdk_services5.ok)(spaceFromRecord(spaceKey(spaceId), loaded.data.data));
|
|
3199
|
+
},
|
|
3200
|
+
register: async (space) => {
|
|
3201
|
+
await this.config.ensureAccountSpaceHosted?.();
|
|
3202
|
+
const kvResult = this.accountKV();
|
|
3203
|
+
if (!kvResult.ok) return kvResult;
|
|
3204
|
+
const stored = spaceRecordFromInput(space);
|
|
3205
|
+
const written = await kvResult.data.put(spaceKey(stored.space_id), stored);
|
|
3206
|
+
if (!written.ok) return accountErr(written.error);
|
|
3207
|
+
const registered = spaceFromRecord(spaceKey(stored.space_id), stored);
|
|
3208
|
+
const indexed = await this.upsertSpaceIndex(registered);
|
|
3209
|
+
if (!indexed.ok) return indexed;
|
|
3210
|
+
return (0, import_sdk_services5.ok)(registered);
|
|
3211
|
+
},
|
|
3212
|
+
syncAccessible: async () => {
|
|
3213
|
+
const listed = await this.config.getSpaces().list();
|
|
3214
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3215
|
+
const registered = [];
|
|
3216
|
+
for (const space of listed.data) {
|
|
3217
|
+
const result = await this.spaces.register(space);
|
|
3218
|
+
if (!result.ok) return result;
|
|
3219
|
+
registered.push(result.data);
|
|
3220
|
+
}
|
|
3221
|
+
return (0, import_sdk_services5.ok)(registered);
|
|
3222
|
+
},
|
|
3223
|
+
remove: async (spaceId) => {
|
|
3224
|
+
const kvResult = this.accountKV();
|
|
3225
|
+
if (!kvResult.ok) return kvResult;
|
|
3226
|
+
const removed = await kvResult.data.delete(spaceKey(spaceId));
|
|
3227
|
+
if (!removed.ok) return accountErr(removed.error);
|
|
3228
|
+
const indexed = await this.deleteSpaceIndex(spaceId);
|
|
3229
|
+
if (!indexed.ok) return indexed;
|
|
3230
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3231
|
+
}
|
|
3232
|
+
};
|
|
3233
|
+
this.delegations = {
|
|
3234
|
+
list: async (options = {}) => {
|
|
3235
|
+
const spaces = await this.config.getSpaces().list();
|
|
3236
|
+
if (!spaces.ok) return accountErr(spaces.error);
|
|
3237
|
+
const targetSpaces = options.space ? spaces.data.filter((space) => space.id === options.space || space.name === options.space) : spaces.data;
|
|
3238
|
+
const delegations = [];
|
|
3239
|
+
for (const space of targetSpaces) {
|
|
3240
|
+
const scoped = this.config.getSpaces().get(space.id).delegations;
|
|
3241
|
+
if (options.direction !== "received") {
|
|
3242
|
+
const granted = await scoped.list();
|
|
3243
|
+
if (!granted.ok) return accountErr(granted.error);
|
|
3244
|
+
delegations.push(...granted.data.map((d) => mapDelegation(d, space, "granted")));
|
|
3245
|
+
}
|
|
3246
|
+
if (options.direction !== "granted") {
|
|
3247
|
+
const received = await scoped.listReceived();
|
|
3248
|
+
if (!received.ok) return accountErr(received.error);
|
|
3249
|
+
delegations.push(...received.data.map((d) => mapDelegation(d, space, "received")));
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
delegations.sort((a, b) => a.spaceId.localeCompare(b.spaceId) || a.cid.localeCompare(b.cid));
|
|
3253
|
+
return (0, import_sdk_services5.ok)(delegations);
|
|
3254
|
+
},
|
|
3255
|
+
revoke: async (options) => {
|
|
3256
|
+
const space = await this.resolveSpace(options.space);
|
|
3257
|
+
if (!space.ok) return space;
|
|
3258
|
+
const revoked = await this.config.getSpaces().get(space.data.id).delegations.revoke(options.cid);
|
|
3259
|
+
if (!revoked.ok) return accountErr(revoked.error);
|
|
3260
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3261
|
+
}
|
|
3262
|
+
};
|
|
3263
|
+
this.index = {
|
|
3264
|
+
rebuild: async () => {
|
|
3265
|
+
const dbResult = this.accountDb();
|
|
3266
|
+
if (!dbResult.ok) return dbResult;
|
|
3267
|
+
const applications = await this.applications.list();
|
|
3268
|
+
if (!applications.ok) return applications;
|
|
3269
|
+
const spaces = await this.spaces.list();
|
|
3270
|
+
if (!spaces.ok) return spaces;
|
|
3271
|
+
const delegations = await this.delegations.list();
|
|
3272
|
+
if (!delegations.ok) return delegations;
|
|
3273
|
+
const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3274
|
+
const statements = [
|
|
3275
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3276
|
+
{ sql: "DELETE FROM applications" },
|
|
3277
|
+
{ sql: "DELETE FROM application_state" },
|
|
3278
|
+
{ sql: "DELETE FROM spaces" },
|
|
3279
|
+
{ sql: "DELETE FROM delegations" },
|
|
3280
|
+
{ sql: "DELETE FROM sync_state" },
|
|
3281
|
+
...applications.data.map((app) => ({
|
|
3282
|
+
sql: "INSERT INTO applications (app_id, name, description, updated_at, manifest_json) VALUES (?, ?, ?, ?, ?)",
|
|
3283
|
+
params: [
|
|
3284
|
+
app.appId,
|
|
3285
|
+
app.name ?? null,
|
|
3286
|
+
app.description ?? null,
|
|
3287
|
+
app.updatedAt ?? syncedAt,
|
|
3288
|
+
JSON.stringify(app.manifests)
|
|
3289
|
+
]
|
|
3290
|
+
})),
|
|
3291
|
+
...applications.data.map((app) => ({
|
|
3292
|
+
sql: "INSERT OR REPLACE INTO application_state (app_id, manifest_hash, indexed_at) VALUES (?, ?, ?)",
|
|
3293
|
+
params: [app.appId, app.manifestHash ?? hashJson(app.manifests), syncedAt]
|
|
3294
|
+
})),
|
|
3295
|
+
...spaces.data.map((space) => ({
|
|
3296
|
+
sql: "INSERT OR REPLACE INTO spaces (space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
3297
|
+
params: [
|
|
3298
|
+
space.spaceId,
|
|
3299
|
+
space.name,
|
|
3300
|
+
space.ownerDid,
|
|
3301
|
+
space.type,
|
|
3302
|
+
JSON.stringify(space.permissions),
|
|
3303
|
+
space.status,
|
|
3304
|
+
space.registeredAt ?? syncedAt,
|
|
3305
|
+
space.updatedAt ?? syncedAt,
|
|
3306
|
+
space.expiresAt?.toISOString() ?? null
|
|
3307
|
+
]
|
|
3308
|
+
})),
|
|
3309
|
+
...delegations.data.map((delegation) => ({
|
|
3310
|
+
sql: "INSERT INTO delegations (cid, direction, space_id, space_name, counterparty_did, delegate_did, delegator_did, path, actions_json, expiry, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
3311
|
+
params: [
|
|
3312
|
+
delegation.cid,
|
|
3313
|
+
delegation.direction,
|
|
3314
|
+
delegation.spaceId,
|
|
3315
|
+
delegation.spaceName ?? null,
|
|
3316
|
+
delegation.counterpartyDid,
|
|
3317
|
+
delegation.delegateDid,
|
|
3318
|
+
delegation.delegatorDid ?? null,
|
|
3319
|
+
delegation.path,
|
|
3320
|
+
JSON.stringify(delegation.actions),
|
|
3321
|
+
delegation.expiry.toISOString(),
|
|
3322
|
+
delegation.status,
|
|
3323
|
+
delegation.createdAt?.toISOString() ?? null,
|
|
3324
|
+
syncedAt
|
|
3325
|
+
]
|
|
3326
|
+
})),
|
|
3327
|
+
{
|
|
3328
|
+
sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
|
|
3329
|
+
params: ["applications", syncedAt, applications.data.length]
|
|
3330
|
+
},
|
|
3331
|
+
{
|
|
3332
|
+
sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
|
|
3333
|
+
params: ["spaces", syncedAt, spaces.data.length]
|
|
3334
|
+
},
|
|
3335
|
+
{
|
|
3336
|
+
sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
|
|
3337
|
+
params: ["delegations", syncedAt, delegations.data.length]
|
|
3338
|
+
}
|
|
3339
|
+
];
|
|
3340
|
+
const rebuilt = await dbResult.data.batch(statements);
|
|
3341
|
+
if (!rebuilt.ok) return accountErr(rebuilt.error);
|
|
3342
|
+
return (0, import_sdk_services5.ok)({
|
|
3343
|
+
database: ACCOUNT_INDEX_DB,
|
|
3344
|
+
applications: applications.data.length,
|
|
3345
|
+
spaces: spaces.data.length,
|
|
3346
|
+
delegations: delegations.data.length,
|
|
3347
|
+
syncedAt
|
|
3348
|
+
});
|
|
3349
|
+
},
|
|
3350
|
+
applications: {
|
|
3351
|
+
list: async () => {
|
|
3352
|
+
const dbResult = this.accountDb();
|
|
3353
|
+
if (!dbResult.ok) return dbResult;
|
|
3354
|
+
const queried = await dbResult.data.query(
|
|
3355
|
+
"SELECT applications.app_id, name, description, updated_at, manifest_json, application_state.manifest_hash FROM applications LEFT JOIN application_state ON applications.app_id = application_state.app_id ORDER BY applications.app_id"
|
|
3356
|
+
);
|
|
3357
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3358
|
+
return (0, import_sdk_services5.ok)(queried.data.rows.map(indexedApplicationFromRow));
|
|
3359
|
+
}
|
|
3360
|
+
},
|
|
3361
|
+
spaces: {
|
|
3362
|
+
list: async () => {
|
|
3363
|
+
const dbResult = this.accountDb();
|
|
3364
|
+
if (!dbResult.ok) return dbResult;
|
|
3365
|
+
const queried = await dbResult.data.query(
|
|
3366
|
+
"SELECT space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at FROM spaces ORDER BY name, space_id"
|
|
3367
|
+
);
|
|
3368
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3369
|
+
return (0, import_sdk_services5.ok)(queried.data.rows.map(indexedSpaceFromRow));
|
|
3370
|
+
}
|
|
3371
|
+
},
|
|
3372
|
+
delegations: {
|
|
3373
|
+
list: async (options = {}) => {
|
|
3374
|
+
const dbResult = this.accountDb();
|
|
3375
|
+
if (!dbResult.ok) return dbResult;
|
|
3376
|
+
const where = [];
|
|
3377
|
+
const params = [];
|
|
3378
|
+
if (options.direction && options.direction !== "all") {
|
|
3379
|
+
where.push("direction = ?");
|
|
3380
|
+
params.push(options.direction);
|
|
3381
|
+
}
|
|
3382
|
+
if (options.space) {
|
|
3383
|
+
where.push("(space_id = ? OR space_name = ?)");
|
|
3384
|
+
params.push(options.space, options.space);
|
|
3385
|
+
}
|
|
3386
|
+
const queried = await dbResult.data.query(
|
|
3387
|
+
`SELECT cid, direction, space_id, space_name, counterparty_did, delegate_did, delegator_did, path, actions_json, expiry, status, created_at FROM delegations${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""} ORDER BY space_id, cid`,
|
|
3388
|
+
params
|
|
3389
|
+
);
|
|
3390
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3391
|
+
return (0, import_sdk_services5.ok)(queried.data.rows.map(indexedDelegationFromRow));
|
|
3392
|
+
}
|
|
3393
|
+
},
|
|
3394
|
+
query: async (sql, params) => {
|
|
3395
|
+
const dbResult = this.accountDb();
|
|
3396
|
+
if (!dbResult.ok) return dbResult;
|
|
3397
|
+
const queried = await dbResult.data.query(sql, params);
|
|
3398
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3399
|
+
return (0, import_sdk_services5.ok)(queried.data);
|
|
3400
|
+
},
|
|
3401
|
+
status: async () => {
|
|
3402
|
+
const dbResult = this.accountDb();
|
|
3403
|
+
if (!dbResult.ok) return dbResult;
|
|
3404
|
+
const queried = await dbResult.data.query(
|
|
3405
|
+
"SELECT source, synced_at, count FROM sync_state ORDER BY source"
|
|
3406
|
+
);
|
|
3407
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3408
|
+
return (0, import_sdk_services5.ok)({
|
|
3409
|
+
database: ACCOUNT_INDEX_DB,
|
|
3410
|
+
sources: queried.data.rows.map(([source, syncedAt, count]) => ({
|
|
3411
|
+
source,
|
|
3412
|
+
syncedAt,
|
|
3413
|
+
count
|
|
3414
|
+
}))
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
};
|
|
3418
|
+
}
|
|
3419
|
+
async status() {
|
|
3420
|
+
const apps = await this.applications.list();
|
|
3421
|
+
if (!apps.ok) return apps;
|
|
3422
|
+
const delegations = await this.delegations.list();
|
|
3423
|
+
if (!delegations.ok) return delegations;
|
|
3424
|
+
const spaces = await this.spaces.list();
|
|
3425
|
+
if (!spaces.ok) return spaces;
|
|
3426
|
+
return (0, import_sdk_services5.ok)({
|
|
3427
|
+
did: this.config.getDid(),
|
|
3428
|
+
host: this.config.getHost(),
|
|
3429
|
+
primarySpaceId: this.config.getPrimarySpaceId(),
|
|
3430
|
+
accountSpaceId: this.config.getAccountSpaceId(),
|
|
3431
|
+
applications: apps.data.length,
|
|
3432
|
+
spaces: spaces.data.length,
|
|
3433
|
+
grantedDelegations: delegations.data.filter((d) => d.direction === "granted").length,
|
|
3434
|
+
receivedDelegations: delegations.data.filter((d) => d.direction === "received").length
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
accountKV() {
|
|
3438
|
+
const accountSpaceId = this.config.getAccountSpaceId();
|
|
3439
|
+
if (!accountSpaceId) {
|
|
3440
|
+
return (0, import_sdk_services5.err)(
|
|
3441
|
+
(0, import_sdk_services5.serviceError)(
|
|
3442
|
+
"ACCOUNT_SPACE_UNAVAILABLE",
|
|
3443
|
+
"Account space is unavailable. Sign in with a wallet-backed profile first.",
|
|
3444
|
+
SERVICE_NAME2
|
|
3445
|
+
)
|
|
3446
|
+
);
|
|
3516
3447
|
}
|
|
3448
|
+
return (0, import_sdk_services5.ok)(this.config.getSpaces().get(accountSpaceId).kv);
|
|
3517
3449
|
}
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
return
|
|
3450
|
+
accountDb() {
|
|
3451
|
+
const db = this.config.getAccountDb?.();
|
|
3452
|
+
if (!db) {
|
|
3453
|
+
return (0, import_sdk_services5.err)(
|
|
3454
|
+
(0, import_sdk_services5.serviceError)(
|
|
3455
|
+
"ACCOUNT_INDEX_UNAVAILABLE",
|
|
3456
|
+
"Account index database is unavailable. Sign in with a wallet-backed profile first.",
|
|
3457
|
+
SERVICE_NAME2
|
|
3458
|
+
)
|
|
3459
|
+
);
|
|
3460
|
+
}
|
|
3461
|
+
return (0, import_sdk_services5.ok)(db);
|
|
3530
3462
|
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3463
|
+
async indexHasApplicationHash(appId, manifestHash) {
|
|
3464
|
+
const dbResult = this.accountDb();
|
|
3465
|
+
if (!dbResult.ok) return false;
|
|
3466
|
+
const schema = await dbResult.data.batch(ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })));
|
|
3467
|
+
if (!schema.ok) return false;
|
|
3468
|
+
const queried = await dbResult.data.query(
|
|
3469
|
+
"SELECT 1 FROM application_state WHERE app_id = ? AND manifest_hash = ? LIMIT 1",
|
|
3470
|
+
[appId, manifestHash]
|
|
3471
|
+
);
|
|
3472
|
+
return queried.ok && queried.data.rows.length > 0;
|
|
3473
|
+
}
|
|
3474
|
+
async upsertApplicationIndex(app) {
|
|
3475
|
+
const dbResult = this.accountDb();
|
|
3476
|
+
if (!dbResult.ok) return (0, import_sdk_services5.ok)(void 0);
|
|
3477
|
+
const updatedAt = app.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3478
|
+
const manifestHash = app.manifestHash ?? hashJson(app.manifests);
|
|
3479
|
+
const written = await dbResult.data.batch([
|
|
3480
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3481
|
+
{
|
|
3482
|
+
sql: "INSERT OR REPLACE INTO applications (app_id, name, description, updated_at, manifest_json) VALUES (?, ?, ?, ?, ?)",
|
|
3483
|
+
params: [
|
|
3484
|
+
app.appId,
|
|
3485
|
+
app.name ?? null,
|
|
3486
|
+
app.description ?? null,
|
|
3487
|
+
updatedAt,
|
|
3488
|
+
JSON.stringify(app.manifests)
|
|
3489
|
+
]
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
sql: "INSERT OR REPLACE INTO application_state (app_id, manifest_hash, indexed_at) VALUES (?, ?, ?)",
|
|
3493
|
+
params: [app.appId, manifestHash, updatedAt]
|
|
3494
|
+
}
|
|
3495
|
+
]);
|
|
3496
|
+
if (!written.ok) return accountErr(written.error);
|
|
3497
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3533
3498
|
}
|
|
3534
|
-
|
|
3535
|
-
|
|
3499
|
+
async deleteApplicationIndex(appId) {
|
|
3500
|
+
const dbResult = this.accountDb();
|
|
3501
|
+
if (!dbResult.ok) return (0, import_sdk_services5.ok)(void 0);
|
|
3502
|
+
const deleted = await dbResult.data.batch([
|
|
3503
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3504
|
+
{ sql: "DELETE FROM applications WHERE app_id = ?", params: [appId] },
|
|
3505
|
+
{ sql: "DELETE FROM application_state WHERE app_id = ?", params: [appId] }
|
|
3506
|
+
]);
|
|
3507
|
+
if (!deleted.ok) return accountErr(deleted.error);
|
|
3508
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3536
3509
|
}
|
|
3537
|
-
|
|
3538
|
-
|
|
3510
|
+
async upsertSpaceIndex(space) {
|
|
3511
|
+
const dbResult = this.accountDb();
|
|
3512
|
+
if (!dbResult.ok) return (0, import_sdk_services5.ok)(void 0);
|
|
3513
|
+
const updatedAt = space.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3514
|
+
const written = await dbResult.data.batch([
|
|
3515
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3516
|
+
{
|
|
3517
|
+
sql: "INSERT OR REPLACE INTO spaces (space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
3518
|
+
params: [
|
|
3519
|
+
space.spaceId,
|
|
3520
|
+
space.name,
|
|
3521
|
+
space.ownerDid,
|
|
3522
|
+
space.type,
|
|
3523
|
+
JSON.stringify(space.permissions),
|
|
3524
|
+
space.status,
|
|
3525
|
+
space.registeredAt ?? updatedAt,
|
|
3526
|
+
updatedAt,
|
|
3527
|
+
space.expiresAt?.toISOString() ?? null
|
|
3528
|
+
]
|
|
3529
|
+
}
|
|
3530
|
+
]);
|
|
3531
|
+
if (!written.ok) return accountErr(written.error);
|
|
3532
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3539
3533
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3534
|
+
async deleteSpaceIndex(spaceId) {
|
|
3535
|
+
const dbResult = this.accountDb();
|
|
3536
|
+
if (!dbResult.ok) return (0, import_sdk_services5.ok)(void 0);
|
|
3537
|
+
const deleted = await dbResult.data.batch([
|
|
3538
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3539
|
+
{ sql: "DELETE FROM spaces WHERE space_id = ?", params: [spaceId] }
|
|
3540
|
+
]);
|
|
3541
|
+
if (!deleted.ok) return accountErr(deleted.error);
|
|
3542
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3542
3543
|
}
|
|
3543
|
-
|
|
3544
|
-
|
|
3544
|
+
async resolveSpace(space) {
|
|
3545
|
+
const listed = await this.config.getSpaces().list();
|
|
3546
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3547
|
+
const found = listed.data.find((candidate) => candidate.id === space || candidate.name === space);
|
|
3548
|
+
if (!found) {
|
|
3549
|
+
return (0, import_sdk_services5.err)(
|
|
3550
|
+
(0, import_sdk_services5.serviceError)("SPACE_NOT_FOUND", `No account space found for ${JSON.stringify(space)}`, SERVICE_NAME2)
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
return (0, import_sdk_services5.ok)(found);
|
|
3545
3554
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3555
|
+
};
|
|
3556
|
+
var ACCOUNT_INDEX_SCHEMA = [
|
|
3557
|
+
`CREATE TABLE IF NOT EXISTS applications (
|
|
3558
|
+
app_id TEXT PRIMARY KEY,
|
|
3559
|
+
name TEXT,
|
|
3560
|
+
description TEXT,
|
|
3561
|
+
updated_at TEXT,
|
|
3562
|
+
manifest_json TEXT NOT NULL
|
|
3563
|
+
)`,
|
|
3564
|
+
`CREATE TABLE IF NOT EXISTS application_state (
|
|
3565
|
+
app_id TEXT PRIMARY KEY,
|
|
3566
|
+
manifest_hash TEXT NOT NULL,
|
|
3567
|
+
indexed_at TEXT NOT NULL
|
|
3568
|
+
)`,
|
|
3569
|
+
`CREATE TABLE IF NOT EXISTS spaces (
|
|
3570
|
+
space_id TEXT PRIMARY KEY,
|
|
3571
|
+
name TEXT NOT NULL,
|
|
3572
|
+
owner_did TEXT NOT NULL,
|
|
3573
|
+
type TEXT NOT NULL,
|
|
3574
|
+
permissions_json TEXT NOT NULL,
|
|
3575
|
+
status TEXT NOT NULL,
|
|
3576
|
+
registered_at TEXT,
|
|
3577
|
+
updated_at TEXT NOT NULL,
|
|
3578
|
+
expires_at TEXT
|
|
3579
|
+
)`,
|
|
3580
|
+
`CREATE TABLE IF NOT EXISTS delegations (
|
|
3581
|
+
cid TEXT PRIMARY KEY,
|
|
3582
|
+
direction TEXT NOT NULL,
|
|
3583
|
+
space_id TEXT NOT NULL,
|
|
3584
|
+
space_name TEXT,
|
|
3585
|
+
counterparty_did TEXT NOT NULL,
|
|
3586
|
+
delegate_did TEXT NOT NULL,
|
|
3587
|
+
delegator_did TEXT,
|
|
3588
|
+
path TEXT NOT NULL,
|
|
3589
|
+
actions_json TEXT NOT NULL,
|
|
3590
|
+
expiry TEXT NOT NULL,
|
|
3591
|
+
status TEXT NOT NULL,
|
|
3592
|
+
created_at TEXT,
|
|
3593
|
+
updated_at TEXT NOT NULL
|
|
3594
|
+
)`,
|
|
3595
|
+
`CREATE TABLE IF NOT EXISTS sync_state (
|
|
3596
|
+
source TEXT PRIMARY KEY,
|
|
3597
|
+
synced_at TEXT NOT NULL,
|
|
3598
|
+
count INTEGER NOT NULL
|
|
3599
|
+
)`,
|
|
3600
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_direction ON delegations(direction)",
|
|
3601
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_space ON delegations(space_id)",
|
|
3602
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_counterparty ON delegations(counterparty_did)",
|
|
3603
|
+
"CREATE INDEX IF NOT EXISTS idx_spaces_owner ON spaces(owner_did)",
|
|
3604
|
+
"CREATE INDEX IF NOT EXISTS idx_spaces_type ON spaces(type)"
|
|
3605
|
+
];
|
|
3606
|
+
function applicationKey(appId) {
|
|
3607
|
+
return `${ACCOUNT_REGISTRY_PATH}${appId}`;
|
|
3549
3608
|
}
|
|
3550
|
-
function
|
|
3551
|
-
|
|
3552
|
-
|
|
3609
|
+
function appIdFromKey(key) {
|
|
3610
|
+
return key.startsWith(ACCOUNT_REGISTRY_PATH) ? key.slice(ACCOUNT_REGISTRY_PATH.length) : key;
|
|
3611
|
+
}
|
|
3612
|
+
function applicationFromRecord(key, record) {
|
|
3613
|
+
const manifests = Array.isArray(record.manifests) ? record.manifests : [];
|
|
3614
|
+
const first = manifests[0];
|
|
3615
|
+
return {
|
|
3616
|
+
appId: record.app_id ?? record.appId ?? first?.app_id ?? appIdFromKey(key),
|
|
3617
|
+
manifests,
|
|
3618
|
+
updatedAt: record.updated_at ?? record.updatedAt,
|
|
3619
|
+
name: first?.name,
|
|
3620
|
+
description: first?.description,
|
|
3621
|
+
manifestHash: record.manifest_hash ?? record.manifestHash ?? hashJson(manifests)
|
|
3622
|
+
};
|
|
3623
|
+
}
|
|
3624
|
+
function indexedApplicationFromRow(row) {
|
|
3625
|
+
const [appId, name, description, updatedAt, manifestJson, manifestHash] = row;
|
|
3626
|
+
return {
|
|
3627
|
+
appId,
|
|
3628
|
+
name: name ?? void 0,
|
|
3629
|
+
description: description ?? void 0,
|
|
3630
|
+
updatedAt: updatedAt ?? void 0,
|
|
3631
|
+
manifests: JSON.parse(manifestJson),
|
|
3632
|
+
manifestHash: manifestHash ?? void 0
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
function spaceKey(spaceId) {
|
|
3636
|
+
return `${ACCOUNT_SPACES_PATH}${spaceId}`;
|
|
3637
|
+
}
|
|
3638
|
+
function spaceIdFromKey(key) {
|
|
3639
|
+
return key.startsWith(ACCOUNT_SPACES_PATH) ? key.slice(ACCOUNT_SPACES_PATH.length) : key;
|
|
3640
|
+
}
|
|
3641
|
+
function spaceRecordFromInput(space) {
|
|
3642
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3643
|
+
const accountSpace = "spaceId" in space ? space : {
|
|
3644
|
+
spaceId: space.id,
|
|
3645
|
+
name: space.name ?? space.id.split(":").pop() ?? space.id,
|
|
3646
|
+
ownerDid: space.owner ?? "",
|
|
3647
|
+
type: space.type ?? "discovered",
|
|
3648
|
+
permissions: space.permissions ?? [],
|
|
3649
|
+
status: "active",
|
|
3650
|
+
expiresAt: space.expiresAt
|
|
3651
|
+
};
|
|
3652
|
+
return {
|
|
3653
|
+
space_id: accountSpace.spaceId,
|
|
3654
|
+
name: accountSpace.name,
|
|
3655
|
+
owner_did: accountSpace.ownerDid,
|
|
3656
|
+
type: accountSpace.type,
|
|
3657
|
+
permissions: accountSpace.permissions,
|
|
3658
|
+
status: accountSpace.status,
|
|
3659
|
+
registered_at: accountSpace.registeredAt ?? now,
|
|
3660
|
+
updated_at: now,
|
|
3661
|
+
expires_at: accountSpace.expiresAt instanceof Date ? accountSpace.expiresAt.toISOString() : accountSpace.expiresAt
|
|
3662
|
+
};
|
|
3663
|
+
}
|
|
3664
|
+
function spaceFromRecord(key, record) {
|
|
3665
|
+
const expiresAt = record.expires_at ?? record.expiresAt;
|
|
3666
|
+
return {
|
|
3667
|
+
spaceId: record.space_id ?? record.spaceId ?? spaceIdFromKey(key),
|
|
3668
|
+
name: record.name ?? spaceIdFromKey(key).split(":").pop() ?? spaceIdFromKey(key),
|
|
3669
|
+
ownerDid: record.owner_did ?? record.ownerDid ?? record.owner ?? "",
|
|
3670
|
+
type: record.type ?? "discovered",
|
|
3671
|
+
permissions: Array.isArray(record.permissions) ? record.permissions : [],
|
|
3672
|
+
status: record.status ?? "active",
|
|
3673
|
+
registeredAt: record.registered_at ?? record.registeredAt,
|
|
3674
|
+
updatedAt: record.updated_at ?? record.updatedAt,
|
|
3675
|
+
expiresAt: expiresAt ? new Date(expiresAt) : void 0
|
|
3676
|
+
};
|
|
3677
|
+
}
|
|
3678
|
+
function indexedSpaceFromRow(row) {
|
|
3679
|
+
const [spaceId, name, ownerDid, type, permissionsJson, status, registeredAt, updatedAt, expiresAt] = row;
|
|
3680
|
+
return {
|
|
3681
|
+
spaceId,
|
|
3682
|
+
name,
|
|
3683
|
+
ownerDid,
|
|
3684
|
+
type,
|
|
3685
|
+
permissions: JSON.parse(permissionsJson),
|
|
3686
|
+
status,
|
|
3687
|
+
registeredAt: registeredAt ?? void 0,
|
|
3688
|
+
updatedAt,
|
|
3689
|
+
expiresAt: expiresAt ? new Date(expiresAt) : void 0
|
|
3690
|
+
};
|
|
3691
|
+
}
|
|
3692
|
+
function hashJson(value) {
|
|
3693
|
+
const input = stableJson(value);
|
|
3694
|
+
let hash = 0xcbf29ce484222325n;
|
|
3695
|
+
const prime = 0x100000001b3n;
|
|
3696
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
3697
|
+
hash ^= BigInt(input.charCodeAt(index));
|
|
3698
|
+
hash = BigInt.asUintN(64, hash * prime);
|
|
3699
|
+
}
|
|
3700
|
+
return hash.toString(16).padStart(16, "0");
|
|
3701
|
+
}
|
|
3702
|
+
function stableJson(value) {
|
|
3703
|
+
if (value === null || typeof value !== "object") {
|
|
3704
|
+
return JSON.stringify(value);
|
|
3553
3705
|
}
|
|
3554
|
-
if (
|
|
3555
|
-
return
|
|
3706
|
+
if (Array.isArray(value)) {
|
|
3707
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
3556
3708
|
}
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3709
|
+
const object = value;
|
|
3710
|
+
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
|
|
3711
|
+
}
|
|
3712
|
+
function indexedDelegationFromRow(row) {
|
|
3713
|
+
const [
|
|
3714
|
+
cid,
|
|
3715
|
+
direction,
|
|
3716
|
+
spaceId,
|
|
3717
|
+
spaceName,
|
|
3718
|
+
counterpartyDid,
|
|
3719
|
+
delegateDid,
|
|
3720
|
+
delegatorDid,
|
|
3721
|
+
path,
|
|
3722
|
+
actionsJson,
|
|
3723
|
+
expiry,
|
|
3724
|
+
status,
|
|
3725
|
+
createdAt
|
|
3726
|
+
] = row;
|
|
3727
|
+
return {
|
|
3728
|
+
cid,
|
|
3729
|
+
direction,
|
|
3730
|
+
spaceId,
|
|
3731
|
+
spaceName: spaceName ?? void 0,
|
|
3732
|
+
counterpartyDid,
|
|
3733
|
+
delegateDid,
|
|
3734
|
+
delegatorDid: delegatorDid ?? void 0,
|
|
3735
|
+
path,
|
|
3736
|
+
actions: JSON.parse(actionsJson),
|
|
3737
|
+
expiry: new Date(expiry),
|
|
3738
|
+
status,
|
|
3739
|
+
createdAt: createdAt ? new Date(createdAt) : void 0
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3742
|
+
function mapDelegation(delegation, space, direction) {
|
|
3743
|
+
return {
|
|
3744
|
+
cid: delegation.cid,
|
|
3745
|
+
direction,
|
|
3746
|
+
spaceId: delegation.spaceId || space.id,
|
|
3747
|
+
spaceName: space.name,
|
|
3748
|
+
counterpartyDid: direction === "granted" ? delegation.delegateDID : delegation.delegatorDID ?? delegation.delegateDID,
|
|
3749
|
+
delegateDid: delegation.delegateDID,
|
|
3750
|
+
delegatorDid: delegation.delegatorDID,
|
|
3751
|
+
path: delegation.path,
|
|
3752
|
+
actions: delegation.actions,
|
|
3753
|
+
expiry: delegation.expiry,
|
|
3754
|
+
status: delegation.isRevoked ? "revoked" : delegation.expiry.getTime() <= Date.now() ? "expired" : "active",
|
|
3755
|
+
createdAt: delegation.createdAt
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3758
|
+
function accountErr(error) {
|
|
3759
|
+
return (0, import_sdk_services5.err)((0, import_sdk_services5.serviceError)(error.code, error.message, SERVICE_NAME2, { cause: error.cause, meta: error.meta }));
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
// src/index.ts
|
|
3763
|
+
var import_sdk_services7 = require("@tinycloud/sdk-services");
|
|
3764
|
+
|
|
3765
|
+
// src/space.ts
|
|
3766
|
+
async function fetchPeerId(host, spaceId) {
|
|
3767
|
+
const res = await fetch(
|
|
3768
|
+
`${host}/peer/generate/${encodeURIComponent(spaceId)}`
|
|
3769
|
+
);
|
|
3770
|
+
if (!res.ok) {
|
|
3771
|
+
const error = await res.text().catch(() => res.statusText);
|
|
3772
|
+
throw new Error(`Failed to get peer ID: ${res.status} - ${error}`);
|
|
3773
|
+
}
|
|
3774
|
+
return res.text();
|
|
3775
|
+
}
|
|
3776
|
+
async function submitHostDelegation(host, headers) {
|
|
3777
|
+
const res = await fetch(`${host}/delegate`, {
|
|
3778
|
+
method: "POST",
|
|
3779
|
+
headers
|
|
3780
|
+
});
|
|
3781
|
+
return {
|
|
3782
|
+
success: res.ok,
|
|
3783
|
+
status: res.status,
|
|
3784
|
+
error: res.ok ? void 0 : await res.text().catch(() => res.statusText)
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
async function activateSessionWithHost(host, delegationHeader) {
|
|
3788
|
+
const res = await fetch(`${host}/delegate`, {
|
|
3789
|
+
method: "POST",
|
|
3790
|
+
headers: delegationHeader
|
|
3791
|
+
});
|
|
3792
|
+
if (res.ok) {
|
|
3793
|
+
try {
|
|
3794
|
+
const body = await res.json();
|
|
3795
|
+
return {
|
|
3796
|
+
success: true,
|
|
3797
|
+
status: res.status,
|
|
3798
|
+
activated: body.activated ?? [],
|
|
3799
|
+
skipped: body.skipped ?? []
|
|
3800
|
+
};
|
|
3801
|
+
} catch {
|
|
3802
|
+
return {
|
|
3803
|
+
success: true,
|
|
3804
|
+
status: res.status,
|
|
3805
|
+
activated: [],
|
|
3806
|
+
skipped: []
|
|
3807
|
+
};
|
|
3808
|
+
}
|
|
3561
3809
|
}
|
|
3562
|
-
return action;
|
|
3563
|
-
}
|
|
3564
|
-
function vaultKVPath(base, path) {
|
|
3565
|
-
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
3566
|
-
return `${base}/${normalized}`;
|
|
3567
|
-
}
|
|
3568
|
-
function cloneResourceCapability(entry) {
|
|
3569
3810
|
return {
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
actions: [...entry.actions],
|
|
3574
|
-
...entry.expiryMs !== void 0 ? { expiryMs: entry.expiryMs } : {},
|
|
3575
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3811
|
+
success: false,
|
|
3812
|
+
status: res.status,
|
|
3813
|
+
error: await res.text().catch(() => res.statusText)
|
|
3576
3814
|
};
|
|
3577
3815
|
}
|
|
3578
|
-
|
|
3816
|
+
|
|
3817
|
+
// src/delegations/DelegationManager.ts
|
|
3818
|
+
var DelegationAction = {
|
|
3819
|
+
CREATE: "tinycloud.delegation/create",
|
|
3820
|
+
REVOKE: "tinycloud.delegation/revoke",
|
|
3821
|
+
LIST: "tinycloud.delegation/list",
|
|
3822
|
+
GET: "tinycloud.delegation/get",
|
|
3823
|
+
CHECK: "tinycloud.delegation/check"
|
|
3824
|
+
};
|
|
3825
|
+
function createError(code, message, cause, meta) {
|
|
3579
3826
|
return {
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
3586
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3827
|
+
code,
|
|
3828
|
+
message,
|
|
3829
|
+
service: "delegation",
|
|
3830
|
+
cause,
|
|
3831
|
+
meta
|
|
3587
3832
|
};
|
|
3588
3833
|
}
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3834
|
+
var DelegationManager = class {
|
|
3835
|
+
/**
|
|
3836
|
+
* Creates a new DelegationManager instance.
|
|
3837
|
+
*
|
|
3838
|
+
* @param config - Configuration including hosts, session, and invoke function
|
|
3839
|
+
*/
|
|
3840
|
+
constructor(config) {
|
|
3841
|
+
this.hosts = config.hosts;
|
|
3842
|
+
this.session = config.session;
|
|
3843
|
+
this.invoke = config.invoke;
|
|
3844
|
+
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3845
|
+
}
|
|
3846
|
+
/**
|
|
3847
|
+
* Updates the session (e.g., after re-authentication).
|
|
3848
|
+
*
|
|
3849
|
+
* @param session - New session to use for operations
|
|
3850
|
+
*/
|
|
3851
|
+
updateSession(session) {
|
|
3852
|
+
this.session = session;
|
|
3853
|
+
}
|
|
3854
|
+
/**
|
|
3855
|
+
* Gets the primary host URL.
|
|
3856
|
+
*/
|
|
3857
|
+
get host() {
|
|
3858
|
+
return this.hosts[0];
|
|
3859
|
+
}
|
|
3860
|
+
/**
|
|
3861
|
+
* Executes an invoke operation against the delegation API.
|
|
3862
|
+
*/
|
|
3863
|
+
async invokeOperation(path, action, body) {
|
|
3864
|
+
const headers = this.invoke(this.session, "delegation", path, action);
|
|
3865
|
+
return this.fetchFn(`${this.host}/invoke`, {
|
|
3866
|
+
method: "POST",
|
|
3867
|
+
headers,
|
|
3868
|
+
body
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
/**
|
|
3872
|
+
* Creates a new delegation.
|
|
3873
|
+
*
|
|
3874
|
+
* Delegates specific permissions to another DID for a given path.
|
|
3875
|
+
* The delegatee can then use these permissions to access resources
|
|
3876
|
+
* within the specified scope.
|
|
3877
|
+
*
|
|
3878
|
+
* @param params - Parameters for the delegation
|
|
3879
|
+
* @returns Result containing the created Delegation or an error
|
|
3880
|
+
*
|
|
3881
|
+
* @example
|
|
3882
|
+
* ```typescript
|
|
3883
|
+
* const result = await manager.create({
|
|
3884
|
+
* delegateDID: bob.did,
|
|
3885
|
+
* path: "documents/shared/",
|
|
3886
|
+
* actions: ["tinycloud.kv/get", "tinycloud.kv/put"],
|
|
3887
|
+
* expiry: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
|
|
3888
|
+
* });
|
|
3889
|
+
* ```
|
|
3890
|
+
*/
|
|
3891
|
+
async create(params) {
|
|
3892
|
+
if (!params.delegateDID) {
|
|
3893
|
+
return {
|
|
3894
|
+
ok: false,
|
|
3895
|
+
error: createError(
|
|
3896
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3897
|
+
"delegateDID is required"
|
|
3898
|
+
)
|
|
3899
|
+
};
|
|
3597
3900
|
}
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3901
|
+
if (!params.path) {
|
|
3902
|
+
return {
|
|
3903
|
+
ok: false,
|
|
3904
|
+
error: createError(
|
|
3905
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3906
|
+
"path is required"
|
|
3907
|
+
)
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
if (!params.actions || params.actions.length === 0) {
|
|
3911
|
+
return {
|
|
3912
|
+
ok: false,
|
|
3913
|
+
error: createError(
|
|
3914
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3915
|
+
"at least one action is required"
|
|
3916
|
+
)
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
try {
|
|
3920
|
+
const body = JSON.stringify({
|
|
3921
|
+
delegateDID: params.delegateDID,
|
|
3922
|
+
path: params.path,
|
|
3923
|
+
actions: params.actions,
|
|
3924
|
+
expiry: params.expiry?.toISOString(),
|
|
3925
|
+
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
3926
|
+
statement: params.statement
|
|
3927
|
+
});
|
|
3928
|
+
const response = await this.invokeOperation(
|
|
3929
|
+
params.path,
|
|
3930
|
+
DelegationAction.CREATE,
|
|
3931
|
+
body
|
|
3932
|
+
);
|
|
3933
|
+
if (!response.ok) {
|
|
3934
|
+
const errorText = await response.text();
|
|
3935
|
+
return {
|
|
3936
|
+
ok: false,
|
|
3937
|
+
error: createError(
|
|
3938
|
+
DelegationErrorCodes.CREATION_FAILED,
|
|
3939
|
+
`Failed to create delegation: ${response.status} - ${errorText}`,
|
|
3940
|
+
void 0,
|
|
3941
|
+
{ status: response.status, path: params.path }
|
|
3942
|
+
)
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
const apiResponse = await response.json();
|
|
3946
|
+
const delegation = {
|
|
3947
|
+
cid: apiResponse.cid ?? "",
|
|
3948
|
+
delegateDID: params.delegateDID,
|
|
3949
|
+
spaceId: this.session.spaceId,
|
|
3950
|
+
path: params.path,
|
|
3951
|
+
actions: params.actions,
|
|
3952
|
+
expiry: params.expiry ?? new Date(Date.now() + EXPIRY.SHARE_MS),
|
|
3953
|
+
isRevoked: false,
|
|
3954
|
+
allowSubDelegation: !(params.disableSubDelegation ?? false),
|
|
3955
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3956
|
+
};
|
|
3957
|
+
return { ok: true, data: delegation };
|
|
3958
|
+
} catch (error) {
|
|
3959
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3960
|
+
return {
|
|
3961
|
+
ok: false,
|
|
3962
|
+
error: createError(
|
|
3963
|
+
DelegationErrorCodes.ABORTED,
|
|
3964
|
+
"Request aborted",
|
|
3965
|
+
error
|
|
3966
|
+
)
|
|
3967
|
+
};
|
|
3968
|
+
}
|
|
3969
|
+
return {
|
|
3970
|
+
ok: false,
|
|
3971
|
+
error: createError(
|
|
3972
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3973
|
+
`Network error during delegation creation: ${String(error)}`,
|
|
3974
|
+
error instanceof Error ? error : void 0
|
|
3975
|
+
)
|
|
3976
|
+
};
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
/**
|
|
3980
|
+
* Revokes an existing delegation.
|
|
3981
|
+
*
|
|
3982
|
+
* Once revoked, the delegation can no longer be used to access resources.
|
|
3983
|
+
* This also invalidates any sub-delegations derived from this delegation.
|
|
3984
|
+
*
|
|
3985
|
+
* @param cid - The CID of the delegation to revoke
|
|
3986
|
+
* @returns Result indicating success or an error
|
|
3987
|
+
*
|
|
3988
|
+
* @example
|
|
3989
|
+
* ```typescript
|
|
3990
|
+
* const result = await manager.revoke("bafy...");
|
|
3991
|
+
* if (result.ok) {
|
|
3992
|
+
* console.log("Delegation revoked successfully");
|
|
3993
|
+
* }
|
|
3994
|
+
* ```
|
|
3995
|
+
*/
|
|
3996
|
+
async revoke(cid) {
|
|
3997
|
+
if (!cid) {
|
|
3998
|
+
return {
|
|
3999
|
+
ok: false,
|
|
4000
|
+
error: createError(
|
|
4001
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
4002
|
+
"cid is required"
|
|
4003
|
+
)
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
4006
|
+
try {
|
|
4007
|
+
const body = JSON.stringify({ cid });
|
|
4008
|
+
const response = await this.invokeOperation(
|
|
4009
|
+
cid,
|
|
4010
|
+
DelegationAction.REVOKE,
|
|
4011
|
+
body
|
|
4012
|
+
);
|
|
4013
|
+
if (!response.ok) {
|
|
4014
|
+
const errorText = await response.text();
|
|
4015
|
+
if (response.status === 404) {
|
|
4016
|
+
return {
|
|
4017
|
+
ok: false,
|
|
4018
|
+
error: createError(
|
|
4019
|
+
DelegationErrorCodes.NOT_FOUND,
|
|
4020
|
+
`Delegation not found: ${cid}`
|
|
4021
|
+
)
|
|
4022
|
+
};
|
|
4023
|
+
}
|
|
4024
|
+
return {
|
|
4025
|
+
ok: false,
|
|
4026
|
+
error: createError(
|
|
4027
|
+
DelegationErrorCodes.REVOCATION_FAILED,
|
|
4028
|
+
`Failed to revoke delegation: ${response.status} - ${errorText}`,
|
|
4029
|
+
void 0,
|
|
4030
|
+
{ status: response.status, cid }
|
|
4031
|
+
)
|
|
4032
|
+
};
|
|
3603
4033
|
}
|
|
4034
|
+
return { ok: true, data: void 0 };
|
|
4035
|
+
} catch (error) {
|
|
4036
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4037
|
+
return {
|
|
4038
|
+
ok: false,
|
|
4039
|
+
error: createError(
|
|
4040
|
+
DelegationErrorCodes.ABORTED,
|
|
4041
|
+
"Request aborted",
|
|
4042
|
+
error
|
|
4043
|
+
)
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
return {
|
|
4047
|
+
ok: false,
|
|
4048
|
+
error: createError(
|
|
4049
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4050
|
+
`Network error during delegation revocation: ${String(error)}`,
|
|
4051
|
+
error instanceof Error ? error : void 0
|
|
4052
|
+
)
|
|
4053
|
+
};
|
|
3604
4054
|
}
|
|
3605
|
-
if (existing.description === void 0 && resource.description !== void 0) {
|
|
3606
|
-
existing.description = resource.description;
|
|
3607
|
-
}
|
|
3608
|
-
}
|
|
3609
|
-
return [...byKey.values()];
|
|
3610
|
-
}
|
|
3611
|
-
function capabilitiesReadPermission(space) {
|
|
3612
|
-
return {
|
|
3613
|
-
service: "tinycloud.capabilities",
|
|
3614
|
-
space,
|
|
3615
|
-
path: "",
|
|
3616
|
-
actions: ["tinycloud.capabilities/read"]
|
|
3617
|
-
};
|
|
3618
|
-
}
|
|
3619
|
-
function withCapabilitiesReadForSpaces(resources) {
|
|
3620
|
-
if (resources.length === 0) {
|
|
3621
|
-
return [];
|
|
3622
|
-
}
|
|
3623
|
-
const spaces = new Set(
|
|
3624
|
-
resources.filter((resource) => resource.service !== ENCRYPTION_PERMISSION_SERVICE).map((resource) => resource.space)
|
|
3625
|
-
);
|
|
3626
|
-
return dedupeResources([
|
|
3627
|
-
...resources,
|
|
3628
|
-
...[...spaces].map(capabilitiesReadPermission)
|
|
3629
|
-
]);
|
|
3630
|
-
}
|
|
3631
|
-
function accountRegistryPermission() {
|
|
3632
|
-
return {
|
|
3633
|
-
service: "tinycloud.kv",
|
|
3634
|
-
space: ACCOUNT_REGISTRY_SPACE,
|
|
3635
|
-
path: ACCOUNT_REGISTRY_PATH,
|
|
3636
|
-
actions: ["tinycloud.kv/get", "tinycloud.kv/put", "tinycloud.kv/list"]
|
|
3637
|
-
};
|
|
3638
|
-
}
|
|
3639
|
-
function composeManifestRequest(inputs, options = {}) {
|
|
3640
|
-
if (!Array.isArray(inputs) || inputs.length === 0) {
|
|
3641
|
-
throw new ManifestValidationError(
|
|
3642
|
-
"composeManifestRequest requires at least one manifest"
|
|
3643
|
-
);
|
|
3644
4055
|
}
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4056
|
+
/**
|
|
4057
|
+
* Lists all delegations for the current session's space.
|
|
4058
|
+
*
|
|
4059
|
+
* Returns both delegations created by the current user (as delegator)
|
|
4060
|
+
* and delegations granted to the current user (as delegatee).
|
|
4061
|
+
*
|
|
4062
|
+
* @returns Result containing an array of Delegations or an error
|
|
4063
|
+
*
|
|
4064
|
+
* @example
|
|
4065
|
+
* ```typescript
|
|
4066
|
+
* const result = await manager.list();
|
|
4067
|
+
* if (result.ok) {
|
|
4068
|
+
* for (const delegation of result.data) {
|
|
4069
|
+
* console.log(`${delegation.cid}: ${delegation.path} -> ${delegation.delegateDID}`);
|
|
4070
|
+
* }
|
|
4071
|
+
* }
|
|
4072
|
+
* ```
|
|
4073
|
+
*/
|
|
4074
|
+
async list() {
|
|
4075
|
+
try {
|
|
4076
|
+
const response = await this.invokeOperation("", DelegationAction.LIST);
|
|
4077
|
+
if (!response.ok) {
|
|
4078
|
+
const errorText = await response.text();
|
|
4079
|
+
return {
|
|
4080
|
+
ok: false,
|
|
4081
|
+
error: createError(
|
|
4082
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4083
|
+
`Failed to list delegations: ${response.status} - ${errorText}`,
|
|
4084
|
+
void 0,
|
|
4085
|
+
{ status: response.status }
|
|
4086
|
+
)
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
const data = await response.json();
|
|
4090
|
+
const delegations = data.map((item) => ({
|
|
4091
|
+
cid: item.cid,
|
|
4092
|
+
delegateDID: item.delegateDID,
|
|
4093
|
+
delegatorDID: item.delegatorDID,
|
|
4094
|
+
spaceId: item.spaceId,
|
|
4095
|
+
path: item.path,
|
|
4096
|
+
actions: item.actions,
|
|
4097
|
+
expiry: new Date(item.expiry),
|
|
4098
|
+
isRevoked: item.isRevoked,
|
|
4099
|
+
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
4100
|
+
parentCid: item.parentCid,
|
|
4101
|
+
allowSubDelegation: item.allowSubDelegation
|
|
4102
|
+
}));
|
|
4103
|
+
return { ok: true, data: delegations };
|
|
4104
|
+
} catch (error) {
|
|
4105
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4106
|
+
return {
|
|
4107
|
+
ok: false,
|
|
4108
|
+
error: createError(
|
|
4109
|
+
DelegationErrorCodes.ABORTED,
|
|
4110
|
+
"Request aborted",
|
|
4111
|
+
error
|
|
4112
|
+
)
|
|
4113
|
+
};
|
|
4114
|
+
}
|
|
4115
|
+
return {
|
|
4116
|
+
ok: false,
|
|
4117
|
+
error: createError(
|
|
4118
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4119
|
+
`Network error during delegation list: ${String(error)}`,
|
|
4120
|
+
error instanceof Error ? error : void 0
|
|
4121
|
+
)
|
|
4122
|
+
};
|
|
3666
4123
|
}
|
|
3667
4124
|
}
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
}
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
if (
|
|
3690
|
-
|
|
3691
|
-
|
|
4125
|
+
/**
|
|
4126
|
+
* Gets the full delegation chain for a given delegation.
|
|
4127
|
+
*
|
|
4128
|
+
* Returns the chain of delegations from the root (original delegator)
|
|
4129
|
+
* to the specified delegation, including all intermediate sub-delegations.
|
|
4130
|
+
*
|
|
4131
|
+
* @param cid - The CID of the delegation to get the chain for
|
|
4132
|
+
* @returns Result containing the DelegationChain or an error
|
|
4133
|
+
*
|
|
4134
|
+
* @example
|
|
4135
|
+
* ```typescript
|
|
4136
|
+
* const result = await manager.getChain("bafy...");
|
|
4137
|
+
* if (result.ok) {
|
|
4138
|
+
* console.log("Chain length:", result.data.length);
|
|
4139
|
+
* for (const delegation of result.data) {
|
|
4140
|
+
* console.log(`- ${delegation.delegatorDID} -> ${delegation.delegateDID}`);
|
|
4141
|
+
* }
|
|
4142
|
+
* }
|
|
4143
|
+
* ```
|
|
4144
|
+
*/
|
|
4145
|
+
async getChain(cid) {
|
|
4146
|
+
if (!cid) {
|
|
4147
|
+
return {
|
|
4148
|
+
ok: false,
|
|
4149
|
+
error: createError(
|
|
4150
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
4151
|
+
"cid is required"
|
|
4152
|
+
)
|
|
4153
|
+
};
|
|
4154
|
+
}
|
|
4155
|
+
try {
|
|
4156
|
+
const body = JSON.stringify({ cid, includeChain: true });
|
|
4157
|
+
const response = await this.invokeOperation(
|
|
4158
|
+
cid,
|
|
4159
|
+
DelegationAction.GET,
|
|
4160
|
+
body
|
|
3692
4161
|
);
|
|
4162
|
+
if (!response.ok) {
|
|
4163
|
+
const errorText = await response.text();
|
|
4164
|
+
if (response.status === 404) {
|
|
4165
|
+
return {
|
|
4166
|
+
ok: false,
|
|
4167
|
+
error: createError(
|
|
4168
|
+
DelegationErrorCodes.NOT_FOUND,
|
|
4169
|
+
`Delegation not found: ${cid}`
|
|
4170
|
+
)
|
|
4171
|
+
};
|
|
4172
|
+
}
|
|
4173
|
+
return {
|
|
4174
|
+
ok: false,
|
|
4175
|
+
error: createError(
|
|
4176
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4177
|
+
`Failed to get delegation chain: ${response.status} - ${errorText}`,
|
|
4178
|
+
void 0,
|
|
4179
|
+
{ status: response.status, cid }
|
|
4180
|
+
)
|
|
4181
|
+
};
|
|
4182
|
+
}
|
|
4183
|
+
const data = await response.json();
|
|
4184
|
+
const chain = data.chain.map((item) => ({
|
|
4185
|
+
cid: item.cid,
|
|
4186
|
+
delegateDID: item.delegateDID,
|
|
4187
|
+
delegatorDID: item.delegatorDID,
|
|
4188
|
+
spaceId: item.spaceId,
|
|
4189
|
+
path: item.path,
|
|
4190
|
+
actions: item.actions,
|
|
4191
|
+
expiry: new Date(item.expiry),
|
|
4192
|
+
isRevoked: item.isRevoked,
|
|
4193
|
+
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
4194
|
+
parentCid: item.parentCid,
|
|
4195
|
+
allowSubDelegation: item.allowSubDelegation
|
|
4196
|
+
}));
|
|
4197
|
+
return { ok: true, data: chain };
|
|
4198
|
+
} catch (error) {
|
|
4199
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4200
|
+
return {
|
|
4201
|
+
ok: false,
|
|
4202
|
+
error: createError(
|
|
4203
|
+
DelegationErrorCodes.ABORTED,
|
|
4204
|
+
"Request aborted",
|
|
4205
|
+
error
|
|
4206
|
+
)
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
return {
|
|
4210
|
+
ok: false,
|
|
4211
|
+
error: createError(
|
|
4212
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4213
|
+
`Network error during chain retrieval: ${String(error)}`,
|
|
4214
|
+
error instanceof Error ? error : void 0
|
|
4215
|
+
)
|
|
4216
|
+
};
|
|
3693
4217
|
}
|
|
3694
|
-
|
|
3695
|
-
|
|
4218
|
+
}
|
|
4219
|
+
/**
|
|
4220
|
+
* Checks if the current session has permission for a given path and action.
|
|
4221
|
+
*
|
|
4222
|
+
* This can be used to verify permissions before attempting an operation,
|
|
4223
|
+
* or to implement custom access control logic.
|
|
4224
|
+
*
|
|
4225
|
+
* @param path - The resource path to check
|
|
4226
|
+
* @param action - The action to check (e.g., "tinycloud.kv/get")
|
|
4227
|
+
* @returns Result containing a boolean indicating permission or an error
|
|
4228
|
+
*
|
|
4229
|
+
* @example
|
|
4230
|
+
* ```typescript
|
|
4231
|
+
* const result = await manager.checkPermission("documents/private/", "tinycloud.kv/put");
|
|
4232
|
+
* if (result.ok && result.data) {
|
|
4233
|
+
* console.log("Permission granted");
|
|
4234
|
+
* } else {
|
|
4235
|
+
* console.log("Permission denied");
|
|
4236
|
+
* }
|
|
4237
|
+
* ```
|
|
4238
|
+
*/
|
|
4239
|
+
async checkPermission(path, action) {
|
|
4240
|
+
if (!path) {
|
|
4241
|
+
return {
|
|
4242
|
+
ok: false,
|
|
4243
|
+
error: createError(
|
|
4244
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
4245
|
+
"path is required"
|
|
4246
|
+
)
|
|
4247
|
+
};
|
|
3696
4248
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
4249
|
+
if (!action) {
|
|
4250
|
+
return {
|
|
4251
|
+
ok: false,
|
|
4252
|
+
error: createError(
|
|
4253
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
4254
|
+
"action is required"
|
|
4255
|
+
)
|
|
4256
|
+
};
|
|
4257
|
+
}
|
|
4258
|
+
try {
|
|
4259
|
+
const body = JSON.stringify({ path, action });
|
|
4260
|
+
const response = await this.invokeOperation(
|
|
4261
|
+
path,
|
|
4262
|
+
DelegationAction.CHECK,
|
|
4263
|
+
body
|
|
4264
|
+
);
|
|
4265
|
+
if (!response.ok) {
|
|
4266
|
+
if (response.status === 403) {
|
|
4267
|
+
return { ok: true, data: false };
|
|
3707
4268
|
}
|
|
4269
|
+
const errorText = await response.text();
|
|
4270
|
+
return {
|
|
4271
|
+
ok: false,
|
|
4272
|
+
error: createError(
|
|
4273
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4274
|
+
`Failed to check permission: ${response.status} - ${errorText}`,
|
|
4275
|
+
void 0,
|
|
4276
|
+
{ status: response.status, path, action }
|
|
4277
|
+
)
|
|
4278
|
+
};
|
|
3708
4279
|
}
|
|
4280
|
+
const data = await response.json();
|
|
4281
|
+
return { ok: true, data: data.allowed };
|
|
4282
|
+
} catch (error) {
|
|
4283
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4284
|
+
return {
|
|
4285
|
+
ok: false,
|
|
4286
|
+
error: createError(
|
|
4287
|
+
DelegationErrorCodes.ABORTED,
|
|
4288
|
+
"Request aborted",
|
|
4289
|
+
error
|
|
4290
|
+
)
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
4293
|
+
return {
|
|
4294
|
+
ok: false,
|
|
4295
|
+
error: createError(
|
|
4296
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
4297
|
+
`Network error during permission check: ${String(error)}`,
|
|
4298
|
+
error instanceof Error ? error : void 0
|
|
4299
|
+
)
|
|
4300
|
+
};
|
|
3709
4301
|
}
|
|
3710
4302
|
}
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
4303
|
+
};
|
|
4304
|
+
|
|
4305
|
+
// src/delegations/SharingService.schema.ts
|
|
4306
|
+
var import_zod5 = require("zod");
|
|
4307
|
+
var EncodedShareDataSchema = import_zod5.z.object({
|
|
4308
|
+
/** Private key in JWK format (must include d parameter) */
|
|
4309
|
+
key: JWKSchema.refine(
|
|
4310
|
+
(jwk) => typeof jwk.d === "string" && jwk.d.length > 0,
|
|
4311
|
+
{ message: "JWK must include private key (d parameter)" }
|
|
4312
|
+
),
|
|
4313
|
+
/** DID of the key */
|
|
4314
|
+
keyDid: import_zod5.z.string().min(1, "keyDid is required"),
|
|
4315
|
+
/** The delegation granting access */
|
|
4316
|
+
delegation: DelegationSchema,
|
|
4317
|
+
/** Resource path this link grants access to */
|
|
4318
|
+
path: import_zod5.z.string().min(1, "path is required"),
|
|
4319
|
+
/** TinyCloud host URL */
|
|
4320
|
+
host: import_zod5.z.string().url("host must be a valid URL"),
|
|
4321
|
+
/** Space ID */
|
|
4322
|
+
spaceId: import_zod5.z.string().min(1, "spaceId is required"),
|
|
4323
|
+
/** Schema version (must be 1) */
|
|
4324
|
+
version: import_zod5.z.literal(1)
|
|
4325
|
+
});
|
|
4326
|
+
var ReceiveOptionsSchema = import_zod5.z.object({
|
|
4327
|
+
/**
|
|
4328
|
+
* Whether to automatically create a sub-delegation to the current session key.
|
|
4329
|
+
* Default: true
|
|
4330
|
+
*/
|
|
4331
|
+
autoSubdelegate: import_zod5.z.boolean().optional(),
|
|
4332
|
+
/**
|
|
4333
|
+
* Whether to use the current session key for operations (requires autoSubdelegate).
|
|
4334
|
+
* Default: true
|
|
4335
|
+
*/
|
|
4336
|
+
useSessionKey: import_zod5.z.boolean().optional(),
|
|
4337
|
+
/**
|
|
4338
|
+
* Ingestion options passed to CapabilityKeyRegistry.
|
|
4339
|
+
*/
|
|
4340
|
+
ingestOptions: IngestOptionsSchema.optional()
|
|
4341
|
+
});
|
|
4342
|
+
var SharingServiceConfigSchema = import_zod5.z.object({
|
|
4343
|
+
/** TinyCloud host URLs */
|
|
4344
|
+
hosts: import_zod5.z.array(import_zod5.z.string().url()).min(1, "At least one host URL is required"),
|
|
4345
|
+
/**
|
|
4346
|
+
* Active session for authentication.
|
|
4347
|
+
* Required for generate(), optional for receive().
|
|
4348
|
+
*/
|
|
4349
|
+
session: import_zod5.z.unknown().refine(
|
|
4350
|
+
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
4351
|
+
{ message: "Expected a ServiceSession object or undefined" }
|
|
4352
|
+
).optional(),
|
|
4353
|
+
/** Platform-specific invoke function */
|
|
4354
|
+
invoke: import_zod5.z.unknown().refine((val) => typeof val === "function", {
|
|
4355
|
+
message: "Expected an invoke function"
|
|
4356
|
+
}),
|
|
4357
|
+
/** Optional custom fetch implementation */
|
|
4358
|
+
fetch: import_zod5.z.unknown().refine(
|
|
4359
|
+
(val) => val === void 0 || typeof val === "function",
|
|
4360
|
+
{ message: "Expected a fetch function or undefined" }
|
|
4361
|
+
).optional(),
|
|
4362
|
+
/** Key provider for cryptographic operations */
|
|
4363
|
+
keyProvider: KeyProviderSchema,
|
|
4364
|
+
/** Capability key registry for key/delegation management */
|
|
4365
|
+
registry: import_zod5.z.unknown().refine(
|
|
4366
|
+
(val) => val !== null && typeof val === "object",
|
|
4367
|
+
{ message: "Expected an ICapabilityKeyRegistry object" }
|
|
4368
|
+
),
|
|
4369
|
+
/**
|
|
4370
|
+
* Delegation manager for creating delegations.
|
|
4371
|
+
* Required for generate(), optional for receive().
|
|
4372
|
+
*/
|
|
4373
|
+
delegationManager: import_zod5.z.unknown().refine(
|
|
4374
|
+
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
4375
|
+
{ message: "Expected a DelegationManager object or undefined" }
|
|
4376
|
+
).optional(),
|
|
4377
|
+
/** Factory for creating KV service instances */
|
|
4378
|
+
createKVService: import_zod5.z.unknown().refine(
|
|
4379
|
+
(val) => typeof val === "function",
|
|
4380
|
+
{ message: "Expected a createKVService factory function" }
|
|
4381
|
+
),
|
|
4382
|
+
/** Base URL for sharing links (e.g., "https://share.myapp.com") */
|
|
4383
|
+
baseUrl: import_zod5.z.string().optional(),
|
|
4384
|
+
/**
|
|
4385
|
+
* Custom delegation creation function.
|
|
4386
|
+
*/
|
|
4387
|
+
createDelegation: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4388
|
+
message: "Expected a createDelegation function or undefined"
|
|
4389
|
+
}).optional(),
|
|
4390
|
+
/**
|
|
4391
|
+
* WASM function for client-side delegation creation.
|
|
4392
|
+
*/
|
|
4393
|
+
createDelegationWasm: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4394
|
+
message: "Expected a createDelegationWasm function or undefined"
|
|
4395
|
+
}).optional(),
|
|
4396
|
+
/**
|
|
4397
|
+
* Path prefix for KV operations.
|
|
4398
|
+
*/
|
|
4399
|
+
pathPrefix: import_zod5.z.string().optional(),
|
|
4400
|
+
/**
|
|
4401
|
+
* Session expiry time.
|
|
4402
|
+
*/
|
|
4403
|
+
sessionExpiry: import_zod5.z.date().optional(),
|
|
4404
|
+
/**
|
|
4405
|
+
* Callback to create a DIRECT delegation from wallet to share key.
|
|
4406
|
+
* This is the preferred method for long-lived share links because it
|
|
4407
|
+
* bypasses the session delegation chain entirely.
|
|
4408
|
+
*/
|
|
4409
|
+
onRootDelegationNeeded: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4410
|
+
message: "Expected an onRootDelegationNeeded function or undefined"
|
|
4411
|
+
}).optional()
|
|
4412
|
+
});
|
|
4413
|
+
function validateEncodedShareData(data) {
|
|
4414
|
+
const result = EncodedShareDataSchema.safeParse(data);
|
|
4415
|
+
if (!result.success) {
|
|
4416
|
+
return {
|
|
4417
|
+
ok: false,
|
|
4418
|
+
error: {
|
|
4419
|
+
code: DelegationErrorCodes.VALIDATION_ERROR,
|
|
4420
|
+
message: `Invalid share data: ${result.error.message}`,
|
|
4421
|
+
service: "delegation",
|
|
4422
|
+
meta: { issues: result.error.issues }
|
|
4423
|
+
}
|
|
4424
|
+
};
|
|
3735
4425
|
}
|
|
3736
|
-
return
|
|
4426
|
+
return { ok: true, data: result.data };
|
|
3737
4427
|
}
|
|
3738
4428
|
|
|
3739
4429
|
// src/delegations/SharingService.ts
|
|
@@ -3914,13 +4604,13 @@ var SharingService = class {
|
|
|
3914
4604
|
)
|
|
3915
4605
|
};
|
|
3916
4606
|
}
|
|
3917
|
-
} catch (
|
|
4607
|
+
} catch (err6) {
|
|
3918
4608
|
return {
|
|
3919
4609
|
ok: false,
|
|
3920
4610
|
error: createError2(
|
|
3921
4611
|
DelegationErrorCodes.CREATION_FAILED,
|
|
3922
|
-
`Failed to generate session key for share: ${
|
|
3923
|
-
|
|
4612
|
+
`Failed to generate session key for share: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4613
|
+
err6 instanceof Error ? err6 : void 0
|
|
3924
4614
|
)
|
|
3925
4615
|
};
|
|
3926
4616
|
}
|
|
@@ -3966,7 +4656,7 @@ var SharingService = class {
|
|
|
3966
4656
|
}
|
|
3967
4657
|
delegation = parsed;
|
|
3968
4658
|
}
|
|
3969
|
-
} catch (
|
|
4659
|
+
} catch (err6) {
|
|
3970
4660
|
const fallbackResult = await this.handleSessionExtensionFallback(requestedExpiry);
|
|
3971
4661
|
expiry = fallbackResult.expiry;
|
|
3972
4662
|
const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
|
|
@@ -4164,13 +4854,13 @@ var SharingService = class {
|
|
|
4164
4854
|
allowSubDelegation: true,
|
|
4165
4855
|
createdAt: /* @__PURE__ */ new Date()
|
|
4166
4856
|
};
|
|
4167
|
-
} catch (
|
|
4857
|
+
} catch (err6) {
|
|
4168
4858
|
return {
|
|
4169
4859
|
ok: false,
|
|
4170
4860
|
error: createError2(
|
|
4171
4861
|
DelegationErrorCodes.CREATION_FAILED,
|
|
4172
|
-
`Failed to create delegation via WASM: ${
|
|
4173
|
-
|
|
4862
|
+
`Failed to create delegation via WASM: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4863
|
+
err6 instanceof Error ? err6 : void 0
|
|
4174
4864
|
)
|
|
4175
4865
|
};
|
|
4176
4866
|
}
|
|
@@ -4251,8 +4941,8 @@ var SharingService = class {
|
|
|
4251
4941
|
let activeKey = keyInfo;
|
|
4252
4942
|
if (autoSubdelegate && useSessionKey && this.session) {
|
|
4253
4943
|
try {
|
|
4254
|
-
} catch (
|
|
4255
|
-
console.warn("Auto-subdelegation failed, using ingested key directly:",
|
|
4944
|
+
} catch (err6) {
|
|
4945
|
+
console.warn("Auto-subdelegation failed, using ingested key directly:", err6);
|
|
4256
4946
|
}
|
|
4257
4947
|
}
|
|
4258
4948
|
const authHeader = shareData.delegation.authHeader ?? `Bearer ${shareData.delegation.cid}`;
|
|
@@ -4350,26 +5040,26 @@ var SharingService = class {
|
|
|
4350
5040
|
let jsonString;
|
|
4351
5041
|
try {
|
|
4352
5042
|
jsonString = base64UrlDecode(base64Data);
|
|
4353
|
-
} catch (
|
|
5043
|
+
} catch (err6) {
|
|
4354
5044
|
return {
|
|
4355
5045
|
ok: false,
|
|
4356
5046
|
error: createError2(
|
|
4357
5047
|
DelegationErrorCodes.INVALID_TOKEN,
|
|
4358
|
-
`Failed to decode base64 data: ${
|
|
4359
|
-
|
|
5048
|
+
`Failed to decode base64 data: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
5049
|
+
err6 instanceof Error ? err6 : void 0
|
|
4360
5050
|
)
|
|
4361
5051
|
};
|
|
4362
5052
|
}
|
|
4363
5053
|
let parsed;
|
|
4364
5054
|
try {
|
|
4365
5055
|
parsed = JSON.parse(jsonString);
|
|
4366
|
-
} catch (
|
|
5056
|
+
} catch (err6) {
|
|
4367
5057
|
return {
|
|
4368
5058
|
ok: false,
|
|
4369
5059
|
error: createError2(
|
|
4370
5060
|
DelegationErrorCodes.INVALID_TOKEN,
|
|
4371
|
-
`Failed to parse share data JSON: ${
|
|
4372
|
-
|
|
5061
|
+
`Failed to parse share data JSON: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
5062
|
+
err6 instanceof Error ? err6 : void 0
|
|
4373
5063
|
)
|
|
4374
5064
|
};
|
|
4375
5065
|
}
|
|
@@ -4396,8 +5086,8 @@ function createSharingService(config) {
|
|
|
4396
5086
|
}
|
|
4397
5087
|
|
|
4398
5088
|
// src/authorization/CapabilityKeyRegistry.ts
|
|
4399
|
-
var
|
|
4400
|
-
var
|
|
5089
|
+
var import_sdk_services6 = require("@tinycloud/sdk-services");
|
|
5090
|
+
var SERVICE_NAME3 = "capability-key-registry";
|
|
4401
5091
|
var CapabilityKeyRegistryErrorCodes = {
|
|
4402
5092
|
/** Key not found in registry */
|
|
4403
5093
|
KEY_NOT_FOUND: "KEY_NOT_FOUND",
|
|
@@ -4614,11 +5304,11 @@ var CapabilityKeyRegistry = class {
|
|
|
4614
5304
|
revokeDelegation(cid) {
|
|
4615
5305
|
const stored = this.store.byCid.get(cid);
|
|
4616
5306
|
if (!stored) {
|
|
4617
|
-
return (0,
|
|
4618
|
-
(0,
|
|
5307
|
+
return (0, import_sdk_services6.err)(
|
|
5308
|
+
(0, import_sdk_services6.serviceError)(
|
|
4619
5309
|
CapabilityKeyRegistryErrorCodes.KEY_NOT_FOUND,
|
|
4620
5310
|
`Delegation not found: ${cid}`,
|
|
4621
|
-
|
|
5311
|
+
SERVICE_NAME3
|
|
4622
5312
|
)
|
|
4623
5313
|
);
|
|
4624
5314
|
}
|
|
@@ -4637,7 +5327,7 @@ var CapabilityKeyRegistry = class {
|
|
|
4637
5327
|
}
|
|
4638
5328
|
}
|
|
4639
5329
|
}
|
|
4640
|
-
return (0,
|
|
5330
|
+
return (0, import_sdk_services6.ok)(void 0);
|
|
4641
5331
|
}
|
|
4642
5332
|
// ===========================================================================
|
|
4643
5333
|
// Search
|
|
@@ -4866,8 +5556,8 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
4866
5556
|
response = await fetchFn(`${host}/info`, {
|
|
4867
5557
|
signal: AbortSignal.timeout(5e3)
|
|
4868
5558
|
});
|
|
4869
|
-
} catch (
|
|
4870
|
-
throw new VersionCheckError(host,
|
|
5559
|
+
} catch (err6) {
|
|
5560
|
+
throw new VersionCheckError(host, err6);
|
|
4871
5561
|
}
|
|
4872
5562
|
if (!response.ok) {
|
|
4873
5563
|
throw new VersionCheckError(host);
|
|
@@ -5400,6 +6090,7 @@ function parseRecapCapabilities(parseWasm, siwe) {
|
|
|
5400
6090
|
0 && (module.exports = {
|
|
5401
6091
|
ACCOUNT_REGISTRY_PATH,
|
|
5402
6092
|
ACCOUNT_REGISTRY_SPACE,
|
|
6093
|
+
AccountService,
|
|
5403
6094
|
AutoApproveSpaceCreationHandler,
|
|
5404
6095
|
CapabilityKeyRegistry,
|
|
5405
6096
|
CapabilityKeyRegistryErrorCodes,
|