@tinycloud/sdk-core 2.4.0-beta.2 → 2.4.0-beta.6
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 +1724 -1360
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -59
- package/dist/index.d.ts +141 -59
- package/dist/index.js +1576 -1209
- 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
|
});
|
|
@@ -2331,1409 +2332,1771 @@ var TinyCloud = class _TinyCloud {
|
|
|
2331
2332
|
}
|
|
2332
2333
|
};
|
|
2333
2334
|
|
|
2334
|
-
// src/
|
|
2335
|
-
var
|
|
2335
|
+
// src/account/AccountService.ts
|
|
2336
|
+
var import_sdk_services5 = require("@tinycloud/sdk-services");
|
|
2336
2337
|
|
|
2337
|
-
// src/
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
)
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
throw new Error(`Failed to get peer ID: ${res.status} - ${error}`);
|
|
2338
|
+
// src/manifest.ts
|
|
2339
|
+
var import_ms = __toESM(require("ms"), 1);
|
|
2340
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
2341
|
+
var ManifestValidationError = class extends Error {
|
|
2342
|
+
constructor(message) {
|
|
2343
|
+
super(`Manifest validation failed: ${message}`);
|
|
2344
|
+
this.name = "ManifestValidationError";
|
|
2345
2345
|
}
|
|
2346
|
-
|
|
2346
|
+
};
|
|
2347
|
+
var DEFAULT_EXPIRY = "30d";
|
|
2348
|
+
var DEFAULT_DEFAULTS = true;
|
|
2349
|
+
var DEFAULT_MANIFEST_VERSION = 1;
|
|
2350
|
+
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
2351
|
+
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
2352
|
+
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
2353
|
+
var SECRETS_SPACE = "secrets";
|
|
2354
|
+
var VAULT_PERMISSION_SERVICE = "tinycloud.vault";
|
|
2355
|
+
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
2356
|
+
kv: "tinycloud.kv",
|
|
2357
|
+
sql: "tinycloud.sql",
|
|
2358
|
+
duckdb: "tinycloud.duckdb",
|
|
2359
|
+
capabilities: "tinycloud.capabilities",
|
|
2360
|
+
hooks: "tinycloud.hooks",
|
|
2361
|
+
encryption: "tinycloud.encryption"
|
|
2362
|
+
});
|
|
2363
|
+
var ENCRYPTION_PERMISSION_SERVICE = "tinycloud.encryption";
|
|
2364
|
+
var ENCRYPTION_MANIFEST_SPACE = "encryption";
|
|
2365
|
+
var SERVICE_LONG_TO_SHORT = Object.freeze(
|
|
2366
|
+
Object.fromEntries(
|
|
2367
|
+
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
2368
|
+
)
|
|
2369
|
+
);
|
|
2370
|
+
var DEFAULT_STANDARD_ENTRIES = [
|
|
2371
|
+
{
|
|
2372
|
+
service: "tinycloud.kv",
|
|
2373
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2374
|
+
path: "/",
|
|
2375
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2376
|
+
},
|
|
2377
|
+
{
|
|
2378
|
+
service: "tinycloud.sql",
|
|
2379
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2380
|
+
path: "/",
|
|
2381
|
+
actions: ["read", "write"]
|
|
2382
|
+
}
|
|
2383
|
+
];
|
|
2384
|
+
var DEFAULT_ADMIN_ENTRIES = [
|
|
2385
|
+
{
|
|
2386
|
+
service: "tinycloud.kv",
|
|
2387
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2388
|
+
path: "/",
|
|
2389
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
service: "tinycloud.sql",
|
|
2393
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2394
|
+
path: "/",
|
|
2395
|
+
actions: ["read", "write", "ddl"]
|
|
2396
|
+
}
|
|
2397
|
+
];
|
|
2398
|
+
var DEFAULT_ALL_ENTRIES = [
|
|
2399
|
+
{
|
|
2400
|
+
service: "tinycloud.kv",
|
|
2401
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2402
|
+
path: "/",
|
|
2403
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
service: "tinycloud.sql",
|
|
2407
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2408
|
+
path: "/",
|
|
2409
|
+
actions: ["read", "write", "ddl"]
|
|
2410
|
+
},
|
|
2411
|
+
{
|
|
2412
|
+
service: "tinycloud.duckdb",
|
|
2413
|
+
space: DEFAULT_MANIFEST_SPACE,
|
|
2414
|
+
path: "/",
|
|
2415
|
+
actions: ["read", "write"]
|
|
2416
|
+
}
|
|
2417
|
+
];
|
|
2418
|
+
function parseExpiry(duration) {
|
|
2419
|
+
if (typeof duration !== "string" || duration.length === 0) {
|
|
2420
|
+
throw new ManifestValidationError(
|
|
2421
|
+
`expiry must be a non-empty duration string (got ${JSON.stringify(duration)})`
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2424
|
+
const parsed = (0, import_ms.default)(duration);
|
|
2425
|
+
if (typeof parsed !== "number" || !Number.isFinite(parsed) || parsed <= 0) {
|
|
2426
|
+
throw new ManifestValidationError(
|
|
2427
|
+
`invalid expiry duration: ${JSON.stringify(duration)}`
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
return parsed;
|
|
2347
2431
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2432
|
+
function expandActionShortNames(service, actions) {
|
|
2433
|
+
return actions.map((a) => {
|
|
2434
|
+
if (a.includes("/")) {
|
|
2435
|
+
return a;
|
|
2436
|
+
}
|
|
2437
|
+
return `${service}/${a}`;
|
|
2352
2438
|
});
|
|
2353
|
-
return {
|
|
2354
|
-
success: res.ok,
|
|
2355
|
-
status: res.status,
|
|
2356
|
-
error: res.ok ? void 0 : await res.text().catch(() => res.statusText)
|
|
2357
|
-
};
|
|
2358
2439
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2440
|
+
function expandPermissionEntry(entry) {
|
|
2441
|
+
if (entry.service === ENCRYPTION_PERMISSION_SERVICE) {
|
|
2442
|
+
return expandEncryptionPermissionEntry(entry);
|
|
2443
|
+
}
|
|
2444
|
+
if (entry.service !== VAULT_PERMISSION_SERVICE) {
|
|
2445
|
+
return [
|
|
2446
|
+
{
|
|
2447
|
+
...entry,
|
|
2448
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2449
|
+
}
|
|
2450
|
+
];
|
|
2451
|
+
}
|
|
2452
|
+
return expandVaultPermissionEntry(entry);
|
|
2453
|
+
}
|
|
2454
|
+
function expandEncryptionPermissionEntry(entry) {
|
|
2455
|
+
if (typeof entry.path !== "string" || !entry.path.startsWith("urn:tinycloud:encryption:")) {
|
|
2456
|
+
throw new ManifestValidationError(
|
|
2457
|
+
`tinycloud.encryption entries require path to be a networkId URN (got ${JSON.stringify(entry.path)})`
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
const normalizedActions = [];
|
|
2461
|
+
for (const action of entry.actions) {
|
|
2462
|
+
if (action === "decrypt" || action === "tinycloud.encryption/decrypt") {
|
|
2463
|
+
normalizedActions.push("tinycloud.encryption/decrypt");
|
|
2464
|
+
continue;
|
|
2465
|
+
}
|
|
2466
|
+
if (action === "network.create" || action === "tinycloud.encryption/network.create") {
|
|
2467
|
+
normalizedActions.push("tinycloud.encryption/network.create");
|
|
2468
|
+
continue;
|
|
2469
|
+
}
|
|
2470
|
+
if (action === "network.revoke" || action === "tinycloud.encryption/network.revoke") {
|
|
2471
|
+
normalizedActions.push("tinycloud.encryption/network.revoke");
|
|
2472
|
+
continue;
|
|
2473
|
+
}
|
|
2474
|
+
if (action.includes("/")) {
|
|
2475
|
+
throw new ManifestValidationError(
|
|
2476
|
+
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
2477
|
+
);
|
|
2380
2478
|
}
|
|
2479
|
+
throw new ManifestValidationError(
|
|
2480
|
+
`unknown encryption action ${JSON.stringify(action)}; expected decrypt, network.create, or network.revoke`
|
|
2481
|
+
);
|
|
2381
2482
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2483
|
+
const dedupedActions = [];
|
|
2484
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2485
|
+
for (const a of normalizedActions) {
|
|
2486
|
+
if (!seen.has(a)) {
|
|
2487
|
+
dedupedActions.push(a);
|
|
2488
|
+
seen.add(a);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
return [
|
|
2492
|
+
{
|
|
2493
|
+
service: ENCRYPTION_PERMISSION_SERVICE,
|
|
2494
|
+
space: ENCRYPTION_MANIFEST_SPACE,
|
|
2495
|
+
path: entry.path,
|
|
2496
|
+
actions: dedupedActions,
|
|
2497
|
+
skipPrefix: true,
|
|
2498
|
+
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
2499
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2500
|
+
}
|
|
2501
|
+
];
|
|
2387
2502
|
}
|
|
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
|
-
};
|
|
2503
|
+
function expandPermissionEntries(entries) {
|
|
2504
|
+
return entries.flatMap(expandPermissionEntry);
|
|
2405
2505
|
}
|
|
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);
|
|
2506
|
+
function applyPrefix(prefix, path, skipPrefix) {
|
|
2507
|
+
if (skipPrefix) {
|
|
2508
|
+
return path;
|
|
2417
2509
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
*
|
|
2421
|
-
* @param session - New session to use for operations
|
|
2422
|
-
*/
|
|
2423
|
-
updateSession(session) {
|
|
2424
|
-
this.session = session;
|
|
2510
|
+
if (prefix === "") {
|
|
2511
|
+
return path;
|
|
2425
2512
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
*/
|
|
2429
|
-
get host() {
|
|
2430
|
-
return this.hosts[0];
|
|
2513
|
+
if (path.startsWith("/")) {
|
|
2514
|
+
return `${prefix}${path}`;
|
|
2431
2515
|
}
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
body
|
|
2441
|
-
});
|
|
2516
|
+
return `${prefix}/${path}`;
|
|
2517
|
+
}
|
|
2518
|
+
async function loadManifest(url) {
|
|
2519
|
+
const fetchFn = globalThis.fetch;
|
|
2520
|
+
if (typeof fetchFn !== "function") {
|
|
2521
|
+
throw new ManifestValidationError(
|
|
2522
|
+
"loadManifest requires a global fetch; pass the manifest object directly on runtimes without fetch"
|
|
2523
|
+
);
|
|
2442
2524
|
}
|
|
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
|
-
|
|
2525
|
+
const res = await fetchFn(url);
|
|
2526
|
+
if (!res.ok) {
|
|
2527
|
+
throw new ManifestValidationError(
|
|
2528
|
+
`failed to fetch manifest from ${url}: HTTP ${res.status}`
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2531
|
+
const json = await res.json();
|
|
2532
|
+
return validateManifest(json);
|
|
2533
|
+
}
|
|
2534
|
+
function validateManifest(input) {
|
|
2535
|
+
if (input === null || typeof input !== "object") {
|
|
2536
|
+
throw new ManifestValidationError("manifest must be an object");
|
|
2537
|
+
}
|
|
2538
|
+
const m = input;
|
|
2539
|
+
if (m.manifest_version !== void 0 && m.manifest_version !== DEFAULT_MANIFEST_VERSION) {
|
|
2540
|
+
throw new ManifestValidationError(
|
|
2541
|
+
`manifest.manifest_version must be ${DEFAULT_MANIFEST_VERSION}`
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
if (typeof m.app_id !== "string" || m.app_id.length === 0) {
|
|
2545
|
+
throw new ManifestValidationError(
|
|
2546
|
+
"manifest.app_id is required and must be a non-empty string"
|
|
2547
|
+
);
|
|
2548
|
+
}
|
|
2549
|
+
if (typeof m.name !== "string" || m.name.length === 0) {
|
|
2550
|
+
throw new ManifestValidationError(
|
|
2551
|
+
"manifest.name is required and must be a non-empty string"
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
if (m.did !== void 0 && (typeof m.did !== "string" || m.did.length === 0)) {
|
|
2555
|
+
throw new ManifestValidationError(
|
|
2556
|
+
"manifest.did must be a non-empty DID string"
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
if (m.space !== void 0 && (typeof m.space !== "string" || m.space.length === 0)) {
|
|
2560
|
+
throw new ManifestValidationError(
|
|
2561
|
+
"manifest.space must be a non-empty string"
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
if (m.expiry !== void 0) {
|
|
2565
|
+
parseExpiry(m.expiry);
|
|
2566
|
+
}
|
|
2567
|
+
if (m.permissions !== void 0) {
|
|
2568
|
+
if (!Array.isArray(m.permissions)) {
|
|
2569
|
+
throw new ManifestValidationError(
|
|
2570
|
+
"manifest.permissions must be an array"
|
|
2571
|
+
);
|
|
2481
2572
|
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2573
|
+
m.permissions.forEach(
|
|
2574
|
+
(p, i) => validatePermissionEntry(p, `permissions[${i}]`)
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
if (m.secrets !== void 0) {
|
|
2578
|
+
validateManifestSecrets(m.secrets);
|
|
2579
|
+
}
|
|
2580
|
+
return m;
|
|
2581
|
+
}
|
|
2582
|
+
function validateManifestSecrets(secrets) {
|
|
2583
|
+
if (secrets === null || typeof secrets !== "object" || Array.isArray(secrets)) {
|
|
2584
|
+
throw new ManifestValidationError("manifest.secrets must be an object");
|
|
2585
|
+
}
|
|
2586
|
+
for (const [name, spec] of Object.entries(secrets)) {
|
|
2587
|
+
if (!import_sdk_services4.SECRET_NAME_RE.test(name)) {
|
|
2588
|
+
throw new ManifestValidationError(
|
|
2589
|
+
`manifest.secrets.${name} must match ${import_sdk_services4.SECRET_NAME_RE.source}`
|
|
2590
|
+
);
|
|
2490
2591
|
}
|
|
2491
2592
|
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
|
|
2593
|
+
(0, import_sdk_services4.resolveSecretPath)(
|
|
2594
|
+
secretNameFromSpec(name, spec),
|
|
2595
|
+
{ scope: secretScopeFromSpec(spec) }
|
|
2504
2596
|
);
|
|
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
2597
|
} catch (error) {
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
error: createError(
|
|
2535
|
-
DelegationErrorCodes.ABORTED,
|
|
2536
|
-
"Request aborted",
|
|
2537
|
-
error
|
|
2538
|
-
)
|
|
2539
|
-
};
|
|
2540
|
-
}
|
|
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
|
-
}
|
|
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
|
-
};
|
|
2598
|
+
throw new ManifestValidationError(
|
|
2599
|
+
`manifest.secrets.${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
2600
|
+
);
|
|
2577
2601
|
}
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
DelegationAction.REVOKE,
|
|
2583
|
-
body
|
|
2602
|
+
const actions = secretActionsFromSpec(name, spec);
|
|
2603
|
+
if (actions.length === 0) {
|
|
2604
|
+
throw new ManifestValidationError(
|
|
2605
|
+
`manifest.secrets.${name} actions must be non-empty`
|
|
2584
2606
|
);
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
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
|
-
};
|
|
2607
|
+
}
|
|
2608
|
+
for (const action of actions) {
|
|
2609
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
2610
|
+
throw new ManifestValidationError(
|
|
2611
|
+
`manifest.secrets.${name} actions must be non-empty strings`
|
|
2612
|
+
);
|
|
2605
2613
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
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
|
-
};
|
|
2614
|
+
}
|
|
2615
|
+
if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
|
|
2616
|
+
parseExpiry(spec.expiry);
|
|
2617
|
+
}
|
|
2997
2618
|
}
|
|
2998
|
-
return { ok: true, data: result.data };
|
|
2999
2619
|
}
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
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"]
|
|
2620
|
+
function validatePermissionEntry(p, path) {
|
|
2621
|
+
if (p === null || typeof p !== "object") {
|
|
2622
|
+
throw new ManifestValidationError(`${path} must be an object`);
|
|
3045
2623
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
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"]
|
|
2624
|
+
const entry = p;
|
|
2625
|
+
if (typeof entry.service !== "string" || entry.service.length === 0) {
|
|
2626
|
+
throw new ManifestValidationError(`${path}.service is required`);
|
|
3059
2627
|
}
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
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"]
|
|
2628
|
+
if (entry.space !== void 0 && (typeof entry.space !== "string" || entry.space.length === 0)) {
|
|
2629
|
+
throw new ManifestValidationError(
|
|
2630
|
+
`${path}.space must be a non-empty string`
|
|
2631
|
+
);
|
|
3079
2632
|
}
|
|
3080
|
-
|
|
3081
|
-
function parseExpiry(duration) {
|
|
3082
|
-
if (typeof duration !== "string" || duration.length === 0) {
|
|
2633
|
+
if (typeof entry.path !== "string") {
|
|
3083
2634
|
throw new ManifestValidationError(
|
|
3084
|
-
|
|
2635
|
+
`${path}.path is required (use "" or "/" for root)`
|
|
3085
2636
|
);
|
|
3086
2637
|
}
|
|
3087
|
-
|
|
3088
|
-
if (typeof parsed !== "number" || !Number.isFinite(parsed) || parsed <= 0) {
|
|
2638
|
+
if (!Array.isArray(entry.actions) || entry.actions.length === 0) {
|
|
3089
2639
|
throw new ManifestValidationError(
|
|
3090
|
-
|
|
2640
|
+
`${path}.actions must be a non-empty array`
|
|
3091
2641
|
);
|
|
3092
2642
|
}
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
return a;
|
|
2643
|
+
for (const action of entry.actions) {
|
|
2644
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
2645
|
+
throw new ManifestValidationError(
|
|
2646
|
+
`${path}.actions must contain non-empty strings`
|
|
2647
|
+
);
|
|
3099
2648
|
}
|
|
3100
|
-
|
|
3101
|
-
|
|
2649
|
+
if (entry.service === VAULT_PERMISSION_SERVICE) {
|
|
2650
|
+
vaultActionExpansion(action);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
if (entry.expiry !== void 0) {
|
|
2654
|
+
parseExpiry(entry.expiry);
|
|
2655
|
+
}
|
|
3102
2656
|
}
|
|
3103
|
-
function
|
|
3104
|
-
if (
|
|
3105
|
-
return
|
|
2657
|
+
function normalizeDefaults(value) {
|
|
2658
|
+
if (value === void 0) {
|
|
2659
|
+
return DEFAULT_DEFAULTS;
|
|
3106
2660
|
}
|
|
3107
|
-
if (
|
|
3108
|
-
return
|
|
3109
|
-
{
|
|
3110
|
-
...entry,
|
|
3111
|
-
actions: expandActionShortNames(entry.service, entry.actions)
|
|
3112
|
-
}
|
|
3113
|
-
];
|
|
2661
|
+
if (typeof value === "boolean") {
|
|
2662
|
+
return value;
|
|
3114
2663
|
}
|
|
3115
|
-
|
|
2664
|
+
if (typeof value !== "string") {
|
|
2665
|
+
return true;
|
|
2666
|
+
}
|
|
2667
|
+
const normalized = value.trim().toLowerCase();
|
|
2668
|
+
if (normalized === "admin" || normalized === "all") {
|
|
2669
|
+
return normalized;
|
|
2670
|
+
}
|
|
2671
|
+
return true;
|
|
2672
|
+
}
|
|
2673
|
+
function defaultEntriesForTier(tier) {
|
|
2674
|
+
if (tier === false) {
|
|
2675
|
+
return [];
|
|
2676
|
+
}
|
|
2677
|
+
const source = tier === "admin" ? DEFAULT_ADMIN_ENTRIES : tier === "all" ? DEFAULT_ALL_ENTRIES : DEFAULT_STANDARD_ENTRIES;
|
|
2678
|
+
return source.map((e) => ({
|
|
2679
|
+
service: e.service,
|
|
2680
|
+
space: e.space,
|
|
2681
|
+
path: e.path,
|
|
2682
|
+
actions: [...e.actions],
|
|
2683
|
+
...e.skipPrefix !== void 0 ? { skipPrefix: e.skipPrefix } : {}
|
|
2684
|
+
}));
|
|
2685
|
+
}
|
|
2686
|
+
function resolveManifest(input) {
|
|
2687
|
+
const manifest = validateManifest(input);
|
|
2688
|
+
const prefix = manifest.prefix !== void 0 ? manifest.prefix : manifest.app_id;
|
|
2689
|
+
const space = manifest.space ?? DEFAULT_MANIFEST_SPACE;
|
|
2690
|
+
const expiryMs = parseExpiry(manifest.expiry ?? DEFAULT_EXPIRY);
|
|
2691
|
+
const includePublicSpace = manifest.includePublicSpace ?? true;
|
|
2692
|
+
const tier = normalizeDefaults(manifest.defaults);
|
|
2693
|
+
const defaultEntries = defaultEntriesForTier(tier);
|
|
2694
|
+
const explicitEntries = manifest.permissions ?? [];
|
|
2695
|
+
const secretEntries = secretEntriesForManifest(manifest.secrets);
|
|
2696
|
+
const allEntries = [
|
|
2697
|
+
...defaultEntries,
|
|
2698
|
+
...explicitEntries,
|
|
2699
|
+
...secretEntries
|
|
2700
|
+
];
|
|
2701
|
+
const resources = withCapabilitiesReadForSpaces(
|
|
2702
|
+
allEntries.flatMap((entry) => resolveEntry(entry, prefix, expiryMs, space))
|
|
2703
|
+
);
|
|
2704
|
+
const additionalDelegates = manifest.did === void 0 ? [] : [
|
|
2705
|
+
{
|
|
2706
|
+
did: manifest.did,
|
|
2707
|
+
name: manifest.name,
|
|
2708
|
+
expiryMs,
|
|
2709
|
+
permissions: resources.map(cloneResourceCapability)
|
|
2710
|
+
}
|
|
2711
|
+
];
|
|
2712
|
+
return {
|
|
2713
|
+
app_id: manifest.app_id,
|
|
2714
|
+
...manifest.did !== void 0 ? { did: manifest.did } : {},
|
|
2715
|
+
space,
|
|
2716
|
+
resources,
|
|
2717
|
+
expiryMs,
|
|
2718
|
+
includePublicSpace,
|
|
2719
|
+
additionalDelegates
|
|
2720
|
+
};
|
|
3116
2721
|
}
|
|
3117
|
-
function
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
)
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
2722
|
+
function normalizeSecretActions(actions) {
|
|
2723
|
+
const out = [];
|
|
2724
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2725
|
+
const add = (action) => {
|
|
2726
|
+
if (!seen.has(action)) {
|
|
2727
|
+
out.push(action);
|
|
2728
|
+
seen.add(action);
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
for (const action of actions) {
|
|
2732
|
+
if (action === "read") {
|
|
2733
|
+
add("get");
|
|
3127
2734
|
continue;
|
|
3128
2735
|
}
|
|
3129
|
-
if (action === "
|
|
3130
|
-
|
|
2736
|
+
if (action === "write") {
|
|
2737
|
+
add("put");
|
|
3131
2738
|
continue;
|
|
3132
2739
|
}
|
|
3133
|
-
if (action === "
|
|
3134
|
-
|
|
2740
|
+
if (action === "delete") {
|
|
2741
|
+
add("del");
|
|
3135
2742
|
continue;
|
|
3136
2743
|
}
|
|
3137
|
-
if (action
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
2744
|
+
if (action === "get" || action === "put" || action === "del" || action === "list" || action === "metadata") {
|
|
2745
|
+
add(action);
|
|
2746
|
+
continue;
|
|
2747
|
+
}
|
|
2748
|
+
if (action === "tinycloud.kv/get" || action === "tinycloud.kv/put" || action === "tinycloud.kv/del" || action === "tinycloud.kv/list" || action === "tinycloud.kv/metadata") {
|
|
2749
|
+
add(action);
|
|
2750
|
+
continue;
|
|
3141
2751
|
}
|
|
3142
2752
|
throw new ManifestValidationError(
|
|
3143
|
-
`unknown
|
|
2753
|
+
`unknown secret action ${JSON.stringify(action)}; expected read, write, delete, list, or metadata`
|
|
3144
2754
|
);
|
|
3145
2755
|
}
|
|
3146
|
-
|
|
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);
|
|
2756
|
+
return out;
|
|
3168
2757
|
}
|
|
3169
|
-
function
|
|
3170
|
-
if (
|
|
3171
|
-
return
|
|
3172
|
-
}
|
|
3173
|
-
if (prefix === "") {
|
|
3174
|
-
return path;
|
|
3175
|
-
}
|
|
3176
|
-
if (path.startsWith("/")) {
|
|
3177
|
-
return `${prefix}${path}`;
|
|
2758
|
+
function secretNameFromSpec(fallbackName, spec) {
|
|
2759
|
+
if (spec !== null && typeof spec === "object" && !Array.isArray(spec)) {
|
|
2760
|
+
return spec.name ?? fallbackName;
|
|
3178
2761
|
}
|
|
3179
|
-
return
|
|
2762
|
+
return fallbackName;
|
|
3180
2763
|
}
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
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
|
-
);
|
|
2764
|
+
function secretScopeFromSpec(spec) {
|
|
2765
|
+
if (spec !== null && typeof spec === "object" && !Array.isArray(spec)) {
|
|
2766
|
+
return spec.scope;
|
|
3193
2767
|
}
|
|
3194
|
-
|
|
3195
|
-
return validateManifest(json);
|
|
2768
|
+
return void 0;
|
|
3196
2769
|
}
|
|
3197
|
-
function
|
|
3198
|
-
if (
|
|
3199
|
-
|
|
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
|
-
);
|
|
2770
|
+
function secretActionsFromSpec(name, spec) {
|
|
2771
|
+
if (spec === true) {
|
|
2772
|
+
return ["read"];
|
|
3211
2773
|
}
|
|
3212
|
-
if (typeof
|
|
3213
|
-
|
|
3214
|
-
"manifest.name is required and must be a non-empty string"
|
|
3215
|
-
);
|
|
2774
|
+
if (typeof spec === "string") {
|
|
2775
|
+
return [spec];
|
|
3216
2776
|
}
|
|
3217
|
-
if (
|
|
3218
|
-
|
|
3219
|
-
"manifest.did must be a non-empty DID string"
|
|
3220
|
-
);
|
|
2777
|
+
if (Array.isArray(spec)) {
|
|
2778
|
+
return spec;
|
|
3221
2779
|
}
|
|
3222
|
-
if (
|
|
2780
|
+
if (spec === null || typeof spec !== "object") {
|
|
3223
2781
|
throw new ManifestValidationError(
|
|
3224
|
-
|
|
2782
|
+
`manifest.secrets.${name} must be true, a string action, an actions array, or an object`
|
|
3225
2783
|
);
|
|
3226
2784
|
}
|
|
3227
|
-
if (
|
|
3228
|
-
|
|
2785
|
+
if (spec.actions === void 0) {
|
|
2786
|
+
return ["read"];
|
|
3229
2787
|
}
|
|
3230
|
-
if (
|
|
3231
|
-
|
|
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
|
-
);
|
|
2788
|
+
if (typeof spec.actions === "string") {
|
|
2789
|
+
return [spec.actions];
|
|
3239
2790
|
}
|
|
3240
|
-
if (
|
|
3241
|
-
|
|
2791
|
+
if (Array.isArray(spec.actions)) {
|
|
2792
|
+
return spec.actions;
|
|
3242
2793
|
}
|
|
3243
|
-
|
|
2794
|
+
throw new ManifestValidationError(
|
|
2795
|
+
`manifest.secrets.${name}.actions must be a string or array`
|
|
2796
|
+
);
|
|
3244
2797
|
}
|
|
3245
|
-
function
|
|
3246
|
-
if (secrets ===
|
|
3247
|
-
|
|
2798
|
+
function secretEntriesForManifest(secrets) {
|
|
2799
|
+
if (secrets === void 0) {
|
|
2800
|
+
return [];
|
|
3248
2801
|
}
|
|
2802
|
+
const entries = [];
|
|
3249
2803
|
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
2804
|
const actions = secretActionsFromSpec(name, spec);
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
2805
|
+
const secretPath = (0, import_sdk_services4.resolveSecretPath)(
|
|
2806
|
+
secretNameFromSpec(name, spec),
|
|
2807
|
+
{ scope: secretScopeFromSpec(spec) }
|
|
2808
|
+
);
|
|
2809
|
+
const extra = spec !== true && typeof spec === "object" && !Array.isArray(spec) ? spec : {};
|
|
2810
|
+
entries.push({
|
|
2811
|
+
service: VAULT_PERMISSION_SERVICE,
|
|
2812
|
+
space: SECRETS_SPACE,
|
|
2813
|
+
path: secretPath.vaultKey,
|
|
2814
|
+
actions: normalizeSecretActions(actions),
|
|
2815
|
+
skipPrefix: true,
|
|
2816
|
+
...extra.expiry !== void 0 ? { expiry: extra.expiry } : {},
|
|
2817
|
+
...extra.description !== void 0 ? { description: extra.description } : {}
|
|
2818
|
+
});
|
|
2819
|
+
}
|
|
2820
|
+
return entries;
|
|
2821
|
+
}
|
|
2822
|
+
function resolveEntry(entry, prefix, _inheritedExpiryMs, inheritedSpace) {
|
|
2823
|
+
const skipPrefixForEntry = entry.skipPrefix === true || entry.service === ENCRYPTION_PERMISSION_SERVICE;
|
|
2824
|
+
const resolvedPath = applyPrefix(prefix, entry.path, skipPrefixForEntry);
|
|
2825
|
+
const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
|
|
2826
|
+
return expandPermissionEntry({
|
|
2827
|
+
...entry,
|
|
2828
|
+
space: entry.space ?? inheritedSpace,
|
|
2829
|
+
path: resolvedPath,
|
|
2830
|
+
skipPrefix: true
|
|
2831
|
+
}).map((expanded) => ({
|
|
2832
|
+
service: expanded.service,
|
|
2833
|
+
space: expanded.space ?? inheritedSpace,
|
|
2834
|
+
path: expanded.path,
|
|
2835
|
+
actions: expanded.actions,
|
|
2836
|
+
// Only populate `expiryMs` when the entry had its own expiry override.
|
|
2837
|
+
// When absent, callers use the parent (delegation or manifest) expiry
|
|
2838
|
+
// which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
|
|
2839
|
+
...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {},
|
|
2840
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2841
|
+
}));
|
|
2842
|
+
}
|
|
2843
|
+
function expandVaultPermissionEntry(entry) {
|
|
2844
|
+
const byBase = /* @__PURE__ */ new Map();
|
|
2845
|
+
for (const action of entry.actions) {
|
|
2846
|
+
const expansion = vaultActionExpansion(action);
|
|
2847
|
+
for (const base of expansion.bases) {
|
|
2848
|
+
const actions = byBase.get(base) ?? [];
|
|
2849
|
+
if (!actions.includes(expansion.action)) {
|
|
2850
|
+
actions.push(expansion.action);
|
|
3276
2851
|
}
|
|
2852
|
+
byBase.set(base, actions);
|
|
3277
2853
|
}
|
|
3278
|
-
if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
|
|
3279
|
-
parseExpiry(spec.expiry);
|
|
3280
|
-
}
|
|
3281
2854
|
}
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
2855
|
+
return [...byBase.entries()].map(([base, actions]) => ({
|
|
2856
|
+
...entry,
|
|
2857
|
+
service: "tinycloud.kv",
|
|
2858
|
+
path: vaultKVPath(base, entry.path),
|
|
2859
|
+
actions,
|
|
2860
|
+
skipPrefix: true
|
|
2861
|
+
}));
|
|
2862
|
+
}
|
|
2863
|
+
function vaultActionExpansion(action) {
|
|
2864
|
+
const normalized = normalizeVaultAction(action);
|
|
2865
|
+
if (normalized === "read" || normalized === "get") {
|
|
2866
|
+
return { bases: ["vault"], action: "tinycloud.kv/get" };
|
|
2867
|
+
}
|
|
2868
|
+
if (normalized === "write" || normalized === "put") {
|
|
2869
|
+
return { bases: ["vault"], action: "tinycloud.kv/put" };
|
|
2870
|
+
}
|
|
2871
|
+
if (normalized === "delete" || normalized === "del") {
|
|
2872
|
+
return { bases: ["vault"], action: "tinycloud.kv/del" };
|
|
3286
2873
|
}
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
throw new ManifestValidationError(`${path}.service is required`);
|
|
2874
|
+
if (normalized === "list") {
|
|
2875
|
+
return { bases: ["vault"], action: "tinycloud.kv/list" };
|
|
3290
2876
|
}
|
|
3291
|
-
if (
|
|
3292
|
-
|
|
3293
|
-
`${path}.space must be a non-empty string`
|
|
3294
|
-
);
|
|
2877
|
+
if (normalized === "head") {
|
|
2878
|
+
return { bases: ["vault"], action: "tinycloud.kv/get" };
|
|
3295
2879
|
}
|
|
3296
|
-
if (
|
|
3297
|
-
|
|
3298
|
-
`${path}.path is required (use "" or "/" for root)`
|
|
3299
|
-
);
|
|
2880
|
+
if (normalized === "metadata") {
|
|
2881
|
+
return { bases: ["vault"], action: "tinycloud.kv/metadata" };
|
|
3300
2882
|
}
|
|
3301
|
-
|
|
2883
|
+
throw new ManifestValidationError(
|
|
2884
|
+
`unknown vault action ${JSON.stringify(action)}; expected read, write, delete, get, put, del, list, head, or metadata`
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
function normalizeVaultAction(action) {
|
|
2888
|
+
if (action.startsWith(`${VAULT_PERMISSION_SERVICE}/`)) {
|
|
2889
|
+
return action.slice(`${VAULT_PERMISSION_SERVICE}/`.length);
|
|
2890
|
+
}
|
|
2891
|
+
if (action.startsWith("tinycloud.kv/")) {
|
|
2892
|
+
return action.slice("tinycloud.kv/".length);
|
|
2893
|
+
}
|
|
2894
|
+
if (action.includes("/")) {
|
|
3302
2895
|
throw new ManifestValidationError(
|
|
3303
|
-
|
|
2896
|
+
`unknown vault action ${JSON.stringify(action)}; expected a tinycloud.vault or tinycloud.kv action`
|
|
3304
2897
|
);
|
|
3305
2898
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
2899
|
+
return action;
|
|
2900
|
+
}
|
|
2901
|
+
function vaultKVPath(base, path) {
|
|
2902
|
+
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
2903
|
+
return `${base}/${normalized}`;
|
|
2904
|
+
}
|
|
2905
|
+
function cloneResourceCapability(entry) {
|
|
2906
|
+
return {
|
|
2907
|
+
service: entry.service,
|
|
2908
|
+
space: entry.space,
|
|
2909
|
+
path: entry.path,
|
|
2910
|
+
actions: [...entry.actions],
|
|
2911
|
+
...entry.expiryMs !== void 0 ? { expiryMs: entry.expiryMs } : {},
|
|
2912
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
function clonePermissionEntry(entry) {
|
|
2916
|
+
return {
|
|
2917
|
+
service: entry.service,
|
|
2918
|
+
...entry.space !== void 0 ? { space: entry.space } : {},
|
|
2919
|
+
path: entry.path,
|
|
2920
|
+
actions: [...entry.actions],
|
|
2921
|
+
...entry.skipPrefix !== void 0 ? { skipPrefix: entry.skipPrefix } : {},
|
|
2922
|
+
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
2923
|
+
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
function dedupeResources(resources) {
|
|
2927
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2928
|
+
for (const resource of resources) {
|
|
2929
|
+
const key = `${resource.service}\0${resource.space}\0${resource.path}\0${resource.expiryMs ?? ""}`;
|
|
2930
|
+
const existing = byKey.get(key);
|
|
2931
|
+
if (existing === void 0) {
|
|
2932
|
+
byKey.set(key, cloneResourceCapability(resource));
|
|
2933
|
+
continue;
|
|
3311
2934
|
}
|
|
3312
|
-
|
|
3313
|
-
|
|
2935
|
+
const seen = new Set(existing.actions);
|
|
2936
|
+
for (const action of resource.actions) {
|
|
2937
|
+
if (!seen.has(action)) {
|
|
2938
|
+
existing.actions.push(action);
|
|
2939
|
+
seen.add(action);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
if (existing.description === void 0 && resource.description !== void 0) {
|
|
2943
|
+
existing.description = resource.description;
|
|
3314
2944
|
}
|
|
3315
2945
|
}
|
|
3316
|
-
|
|
3317
|
-
parseExpiry(entry.expiry);
|
|
3318
|
-
}
|
|
2946
|
+
return [...byKey.values()];
|
|
3319
2947
|
}
|
|
3320
|
-
function
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
}
|
|
3327
|
-
if (typeof value !== "string") {
|
|
3328
|
-
return true;
|
|
3329
|
-
}
|
|
3330
|
-
const normalized = value.trim().toLowerCase();
|
|
3331
|
-
if (normalized === "admin" || normalized === "all") {
|
|
3332
|
-
return normalized;
|
|
3333
|
-
}
|
|
3334
|
-
return true;
|
|
2948
|
+
function capabilitiesReadPermission(space) {
|
|
2949
|
+
return {
|
|
2950
|
+
service: "tinycloud.capabilities",
|
|
2951
|
+
space,
|
|
2952
|
+
path: "",
|
|
2953
|
+
actions: ["tinycloud.capabilities/read"]
|
|
2954
|
+
};
|
|
3335
2955
|
}
|
|
3336
|
-
function
|
|
3337
|
-
if (
|
|
2956
|
+
function withCapabilitiesReadForSpaces(resources) {
|
|
2957
|
+
if (resources.length === 0) {
|
|
3338
2958
|
return [];
|
|
3339
2959
|
}
|
|
3340
|
-
const
|
|
3341
|
-
|
|
3342
|
-
service: e.service,
|
|
3343
|
-
space: e.space,
|
|
3344
|
-
path: e.path,
|
|
3345
|
-
actions: [...e.actions],
|
|
3346
|
-
...e.skipPrefix !== void 0 ? { skipPrefix: e.skipPrefix } : {}
|
|
3347
|
-
}));
|
|
3348
|
-
}
|
|
3349
|
-
function resolveManifest(input) {
|
|
3350
|
-
const manifest = validateManifest(input);
|
|
3351
|
-
const prefix = manifest.prefix !== void 0 ? manifest.prefix : manifest.app_id;
|
|
3352
|
-
const space = manifest.space ?? DEFAULT_MANIFEST_SPACE;
|
|
3353
|
-
const expiryMs = parseExpiry(manifest.expiry ?? DEFAULT_EXPIRY);
|
|
3354
|
-
const includePublicSpace = manifest.includePublicSpace ?? true;
|
|
3355
|
-
const tier = normalizeDefaults(manifest.defaults);
|
|
3356
|
-
const defaultEntries = defaultEntriesForTier(tier);
|
|
3357
|
-
const explicitEntries = manifest.permissions ?? [];
|
|
3358
|
-
const secretEntries = secretEntriesForManifest(manifest.secrets);
|
|
3359
|
-
const allEntries = [
|
|
3360
|
-
...defaultEntries,
|
|
3361
|
-
...explicitEntries,
|
|
3362
|
-
...secretEntries
|
|
3363
|
-
];
|
|
3364
|
-
const resources = withCapabilitiesReadForSpaces(
|
|
3365
|
-
allEntries.flatMap((entry) => resolveEntry(entry, prefix, expiryMs, space))
|
|
2960
|
+
const spaces = new Set(
|
|
2961
|
+
resources.filter((resource) => resource.service !== ENCRYPTION_PERMISSION_SERVICE).map((resource) => resource.space)
|
|
3366
2962
|
);
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
}
|
|
3374
|
-
];
|
|
2963
|
+
return dedupeResources([
|
|
2964
|
+
...resources,
|
|
2965
|
+
...[...spaces].map(capabilitiesReadPermission)
|
|
2966
|
+
]);
|
|
2967
|
+
}
|
|
2968
|
+
function accountRegistryPermission() {
|
|
3375
2969
|
return {
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
expiryMs,
|
|
3381
|
-
includePublicSpace,
|
|
3382
|
-
additionalDelegates
|
|
2970
|
+
service: "tinycloud.kv",
|
|
2971
|
+
space: ACCOUNT_REGISTRY_SPACE,
|
|
2972
|
+
path: ACCOUNT_REGISTRY_PATH,
|
|
2973
|
+
actions: ["tinycloud.kv/get", "tinycloud.kv/put", "tinycloud.kv/list"]
|
|
3383
2974
|
};
|
|
3384
2975
|
}
|
|
3385
|
-
function
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
2976
|
+
function composeManifestRequest(inputs, options = {}) {
|
|
2977
|
+
if (!Array.isArray(inputs) || inputs.length === 0) {
|
|
2978
|
+
throw new ManifestValidationError(
|
|
2979
|
+
"composeManifestRequest requires at least one manifest"
|
|
2980
|
+
);
|
|
2981
|
+
}
|
|
2982
|
+
const includeAccountRegistryPermissions = options.includeAccountRegistryPermissions ?? true;
|
|
2983
|
+
const manifests = inputs.map(validateManifest);
|
|
2984
|
+
const resolved = manifests.map(resolveManifest);
|
|
2985
|
+
const resources = resolved.flatMap((entry) => entry.resources);
|
|
2986
|
+
const delegationTargets = resolved.flatMap(
|
|
2987
|
+
(entry) => entry.additionalDelegates.map((delegate) => ({
|
|
2988
|
+
...delegate,
|
|
2989
|
+
permissions: dedupeResources(delegate.permissions)
|
|
2990
|
+
}))
|
|
2991
|
+
);
|
|
2992
|
+
if (includeAccountRegistryPermissions) {
|
|
2993
|
+
resources.push(accountRegistryPermission());
|
|
2994
|
+
}
|
|
2995
|
+
const resourcesWithImplicitCapabilities = withCapabilitiesReadForSpaces(resources);
|
|
2996
|
+
const manifestsByAppId = /* @__PURE__ */ new Map();
|
|
2997
|
+
for (const manifest of manifests) {
|
|
2998
|
+
const current = manifestsByAppId.get(manifest.app_id);
|
|
2999
|
+
if (current === void 0) {
|
|
3000
|
+
manifestsByAppId.set(manifest.app_id, [manifest]);
|
|
3001
|
+
} else {
|
|
3002
|
+
current.push(manifest);
|
|
3392
3003
|
}
|
|
3004
|
+
}
|
|
3005
|
+
const registryRecords = includeAccountRegistryPermissions ? [...manifestsByAppId.entries()].map(([app_id, appManifests]) => ({
|
|
3006
|
+
key: `${ACCOUNT_REGISTRY_PATH}${app_id}`,
|
|
3007
|
+
app_id,
|
|
3008
|
+
manifests: appManifests.map((manifest) => ({
|
|
3009
|
+
...manifest,
|
|
3010
|
+
permissions: manifest.permissions?.map(clonePermissionEntry)
|
|
3011
|
+
}))
|
|
3012
|
+
})) : [];
|
|
3013
|
+
return {
|
|
3014
|
+
manifests,
|
|
3015
|
+
resources: resourcesWithImplicitCapabilities,
|
|
3016
|
+
delegationTargets,
|
|
3017
|
+
registryRecords,
|
|
3018
|
+
expiryMs: Math.max(...resolved.map((entry) => entry.expiryMs)),
|
|
3019
|
+
includePublicSpace: resolved.some((entry) => entry.includePublicSpace)
|
|
3393
3020
|
};
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
if (
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
if (action === "delete") {
|
|
3404
|
-
add("del");
|
|
3405
|
-
continue;
|
|
3021
|
+
}
|
|
3022
|
+
function resourceCapabilitiesToAbilitiesMap(resources) {
|
|
3023
|
+
const out = {};
|
|
3024
|
+
for (const r of resources) {
|
|
3025
|
+
const shortService = SERVICE_LONG_TO_SHORT[r.service];
|
|
3026
|
+
if (shortService === void 0) {
|
|
3027
|
+
throw new ManifestValidationError(
|
|
3028
|
+
`unknown service '${r.service}' \u2014 no short-form mapping. Known services: ${Object.keys(SERVICE_LONG_TO_SHORT).join(", ")}`
|
|
3029
|
+
);
|
|
3406
3030
|
}
|
|
3407
|
-
if (
|
|
3408
|
-
|
|
3409
|
-
continue;
|
|
3031
|
+
if (out[shortService] === void 0) {
|
|
3032
|
+
out[shortService] = {};
|
|
3410
3033
|
}
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3034
|
+
const pathsMap = out[shortService];
|
|
3035
|
+
const existing = pathsMap[r.path];
|
|
3036
|
+
if (existing === void 0) {
|
|
3037
|
+
pathsMap[r.path] = [...r.actions];
|
|
3038
|
+
} else {
|
|
3039
|
+
const seen = new Set(existing);
|
|
3040
|
+
for (const action of r.actions) {
|
|
3041
|
+
if (!seen.has(action)) {
|
|
3042
|
+
existing.push(action);
|
|
3043
|
+
seen.add(action);
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3414
3046
|
}
|
|
3415
|
-
throw new ManifestValidationError(
|
|
3416
|
-
`unknown secret action ${JSON.stringify(action)}; expected read, write, delete, list, or metadata`
|
|
3417
|
-
);
|
|
3418
3047
|
}
|
|
3419
3048
|
return out;
|
|
3420
3049
|
}
|
|
3421
|
-
function
|
|
3422
|
-
|
|
3423
|
-
|
|
3050
|
+
function resourceCapabilitiesToSpaceAbilitiesMap(resources) {
|
|
3051
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
3052
|
+
for (const resource of resources) {
|
|
3053
|
+
const entries = grouped.get(resource.space);
|
|
3054
|
+
if (entries === void 0) {
|
|
3055
|
+
grouped.set(resource.space, [resource]);
|
|
3056
|
+
} else {
|
|
3057
|
+
entries.push(resource);
|
|
3058
|
+
}
|
|
3424
3059
|
}
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
if (spec !== null && typeof spec === "object" && !Array.isArray(spec)) {
|
|
3429
|
-
return spec.scope;
|
|
3060
|
+
const out = {};
|
|
3061
|
+
for (const [space, entries] of grouped.entries()) {
|
|
3062
|
+
out[space] = resourceCapabilitiesToAbilitiesMap(entries);
|
|
3430
3063
|
}
|
|
3431
|
-
return
|
|
3064
|
+
return out;
|
|
3432
3065
|
}
|
|
3433
|
-
function
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3066
|
+
function manifestAbilitiesUnion(resolved) {
|
|
3067
|
+
const all = [...resolved.resources];
|
|
3068
|
+
for (const delegate of resolved.additionalDelegates) {
|
|
3069
|
+
for (const perm of delegate.permissions) {
|
|
3070
|
+
all.push(perm);
|
|
3071
|
+
}
|
|
3439
3072
|
}
|
|
3440
|
-
|
|
3441
|
-
|
|
3073
|
+
return resourceCapabilitiesToAbilitiesMap(all);
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
// src/account/AccountService.ts
|
|
3077
|
+
var SERVICE_NAME2 = "account";
|
|
3078
|
+
var ACCOUNT_INDEX_DB = "account";
|
|
3079
|
+
var AccountService = class {
|
|
3080
|
+
constructor(config) {
|
|
3081
|
+
this.config = config;
|
|
3082
|
+
this.applications = {
|
|
3083
|
+
list: async () => {
|
|
3084
|
+
const kvResult = this.accountKV();
|
|
3085
|
+
if (!kvResult.ok) return kvResult;
|
|
3086
|
+
const listed = await kvResult.data.list({ prefix: ACCOUNT_REGISTRY_PATH });
|
|
3087
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3088
|
+
const applications = [];
|
|
3089
|
+
for (const key of listed.data.keys) {
|
|
3090
|
+
const loaded = await kvResult.data.get(key);
|
|
3091
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3092
|
+
applications.push(applicationFromRecord(key, loaded.data.data));
|
|
3093
|
+
}
|
|
3094
|
+
applications.sort((a, b) => a.appId.localeCompare(b.appId));
|
|
3095
|
+
return (0, import_sdk_services5.ok)(applications);
|
|
3096
|
+
},
|
|
3097
|
+
get: async (appId) => {
|
|
3098
|
+
const kvResult = this.accountKV();
|
|
3099
|
+
if (!kvResult.ok) return kvResult;
|
|
3100
|
+
const key = applicationKey(appId);
|
|
3101
|
+
const loaded = await kvResult.data.get(key);
|
|
3102
|
+
if (!loaded.ok) return accountErr(loaded.error);
|
|
3103
|
+
return (0, import_sdk_services5.ok)(applicationFromRecord(key, loaded.data.data));
|
|
3104
|
+
},
|
|
3105
|
+
register: async (manifest) => {
|
|
3106
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
3107
|
+
const request = composeManifestRequest(manifests);
|
|
3108
|
+
if (request.registryRecords.length === 0) {
|
|
3109
|
+
return (0, import_sdk_services5.err)(
|
|
3110
|
+
(0, import_sdk_services5.serviceError)(
|
|
3111
|
+
"INVALID_MANIFEST",
|
|
3112
|
+
"Manifest did not produce an account application registry record",
|
|
3113
|
+
SERVICE_NAME2
|
|
3114
|
+
)
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
await this.config.ensureAccountSpaceHosted?.();
|
|
3118
|
+
const kvResult = this.accountKV();
|
|
3119
|
+
if (!kvResult.ok) return kvResult;
|
|
3120
|
+
let registered;
|
|
3121
|
+
for (const record of request.registryRecords) {
|
|
3122
|
+
const stored = {
|
|
3123
|
+
app_id: record.app_id,
|
|
3124
|
+
manifests: record.manifests,
|
|
3125
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3126
|
+
};
|
|
3127
|
+
const written = await kvResult.data.put(record.key, stored);
|
|
3128
|
+
if (!written.ok) return accountErr(written.error);
|
|
3129
|
+
registered = applicationFromRecord(record.key, stored);
|
|
3130
|
+
}
|
|
3131
|
+
return (0, import_sdk_services5.ok)(registered);
|
|
3132
|
+
},
|
|
3133
|
+
remove: async (appId) => {
|
|
3134
|
+
const kvResult = this.accountKV();
|
|
3135
|
+
if (!kvResult.ok) return kvResult;
|
|
3136
|
+
const removed = await kvResult.data.delete(applicationKey(appId));
|
|
3137
|
+
if (!removed.ok) return accountErr(removed.error);
|
|
3138
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3139
|
+
}
|
|
3140
|
+
};
|
|
3141
|
+
this.delegations = {
|
|
3142
|
+
list: async (options = {}) => {
|
|
3143
|
+
const spaces = await this.config.getSpaces().list();
|
|
3144
|
+
if (!spaces.ok) return accountErr(spaces.error);
|
|
3145
|
+
const targetSpaces = options.space ? spaces.data.filter((space) => space.id === options.space || space.name === options.space) : spaces.data;
|
|
3146
|
+
const delegations = [];
|
|
3147
|
+
for (const space of targetSpaces) {
|
|
3148
|
+
const scoped = this.config.getSpaces().get(space.id).delegations;
|
|
3149
|
+
if (options.direction !== "received") {
|
|
3150
|
+
const granted = await scoped.list();
|
|
3151
|
+
if (!granted.ok) return accountErr(granted.error);
|
|
3152
|
+
delegations.push(...granted.data.map((d) => mapDelegation(d, space, "granted")));
|
|
3153
|
+
}
|
|
3154
|
+
if (options.direction !== "granted") {
|
|
3155
|
+
const received = await scoped.listReceived();
|
|
3156
|
+
if (!received.ok) return accountErr(received.error);
|
|
3157
|
+
delegations.push(...received.data.map((d) => mapDelegation(d, space, "received")));
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
delegations.sort((a, b) => a.spaceId.localeCompare(b.spaceId) || a.cid.localeCompare(b.cid));
|
|
3161
|
+
return (0, import_sdk_services5.ok)(delegations);
|
|
3162
|
+
},
|
|
3163
|
+
revoke: async (options) => {
|
|
3164
|
+
const space = await this.resolveSpace(options.space);
|
|
3165
|
+
if (!space.ok) return space;
|
|
3166
|
+
const revoked = await this.config.getSpaces().get(space.data.id).delegations.revoke(options.cid);
|
|
3167
|
+
if (!revoked.ok) return accountErr(revoked.error);
|
|
3168
|
+
return (0, import_sdk_services5.ok)(void 0);
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
this.index = {
|
|
3172
|
+
rebuild: async () => {
|
|
3173
|
+
const dbResult = this.accountDb();
|
|
3174
|
+
if (!dbResult.ok) return dbResult;
|
|
3175
|
+
const applications = await this.applications.list();
|
|
3176
|
+
if (!applications.ok) return applications;
|
|
3177
|
+
const delegations = await this.delegations.list();
|
|
3178
|
+
if (!delegations.ok) return delegations;
|
|
3179
|
+
const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3180
|
+
const statements = [
|
|
3181
|
+
...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
|
|
3182
|
+
{ sql: "DELETE FROM applications" },
|
|
3183
|
+
{ sql: "DELETE FROM delegations" },
|
|
3184
|
+
{ sql: "DELETE FROM sync_state" },
|
|
3185
|
+
...applications.data.map((app) => ({
|
|
3186
|
+
sql: "INSERT INTO applications (app_id, name, description, updated_at, manifest_json) VALUES (?, ?, ?, ?, ?)",
|
|
3187
|
+
params: [
|
|
3188
|
+
app.appId,
|
|
3189
|
+
app.name ?? null,
|
|
3190
|
+
app.description ?? null,
|
|
3191
|
+
app.updatedAt ?? syncedAt,
|
|
3192
|
+
JSON.stringify(app.manifests)
|
|
3193
|
+
]
|
|
3194
|
+
})),
|
|
3195
|
+
...delegations.data.map((delegation) => ({
|
|
3196
|
+
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
3197
|
+
params: [
|
|
3198
|
+
delegation.cid,
|
|
3199
|
+
delegation.direction,
|
|
3200
|
+
delegation.spaceId,
|
|
3201
|
+
delegation.spaceName ?? null,
|
|
3202
|
+
delegation.counterpartyDid,
|
|
3203
|
+
delegation.delegateDid,
|
|
3204
|
+
delegation.delegatorDid ?? null,
|
|
3205
|
+
delegation.path,
|
|
3206
|
+
JSON.stringify(delegation.actions),
|
|
3207
|
+
delegation.expiry.toISOString(),
|
|
3208
|
+
delegation.status,
|
|
3209
|
+
delegation.createdAt?.toISOString() ?? null,
|
|
3210
|
+
syncedAt
|
|
3211
|
+
]
|
|
3212
|
+
})),
|
|
3213
|
+
{
|
|
3214
|
+
sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
|
|
3215
|
+
params: ["applications", syncedAt, applications.data.length]
|
|
3216
|
+
},
|
|
3217
|
+
{
|
|
3218
|
+
sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
|
|
3219
|
+
params: ["delegations", syncedAt, delegations.data.length]
|
|
3220
|
+
}
|
|
3221
|
+
];
|
|
3222
|
+
const rebuilt = await dbResult.data.batch(statements);
|
|
3223
|
+
if (!rebuilt.ok) return accountErr(rebuilt.error);
|
|
3224
|
+
return (0, import_sdk_services5.ok)({
|
|
3225
|
+
database: ACCOUNT_INDEX_DB,
|
|
3226
|
+
applications: applications.data.length,
|
|
3227
|
+
delegations: delegations.data.length,
|
|
3228
|
+
syncedAt
|
|
3229
|
+
});
|
|
3230
|
+
},
|
|
3231
|
+
applications: {
|
|
3232
|
+
list: async () => {
|
|
3233
|
+
const dbResult = this.accountDb();
|
|
3234
|
+
if (!dbResult.ok) return dbResult;
|
|
3235
|
+
const queried = await dbResult.data.query(
|
|
3236
|
+
"SELECT app_id, name, description, updated_at, manifest_json FROM applications ORDER BY app_id"
|
|
3237
|
+
);
|
|
3238
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3239
|
+
return (0, import_sdk_services5.ok)(queried.data.rows.map(indexedApplicationFromRow));
|
|
3240
|
+
}
|
|
3241
|
+
},
|
|
3242
|
+
delegations: {
|
|
3243
|
+
list: async (options = {}) => {
|
|
3244
|
+
const dbResult = this.accountDb();
|
|
3245
|
+
if (!dbResult.ok) return dbResult;
|
|
3246
|
+
const where = [];
|
|
3247
|
+
const params = [];
|
|
3248
|
+
if (options.direction && options.direction !== "all") {
|
|
3249
|
+
where.push("direction = ?");
|
|
3250
|
+
params.push(options.direction);
|
|
3251
|
+
}
|
|
3252
|
+
if (options.space) {
|
|
3253
|
+
where.push("(space_id = ? OR space_name = ?)");
|
|
3254
|
+
params.push(options.space, options.space);
|
|
3255
|
+
}
|
|
3256
|
+
const queried = await dbResult.data.query(
|
|
3257
|
+
`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`,
|
|
3258
|
+
params
|
|
3259
|
+
);
|
|
3260
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3261
|
+
return (0, import_sdk_services5.ok)(queried.data.rows.map(indexedDelegationFromRow));
|
|
3262
|
+
}
|
|
3263
|
+
},
|
|
3264
|
+
query: async (sql, params) => {
|
|
3265
|
+
const dbResult = this.accountDb();
|
|
3266
|
+
if (!dbResult.ok) return dbResult;
|
|
3267
|
+
const queried = await dbResult.data.query(sql, params);
|
|
3268
|
+
if (!queried.ok) return accountErr(queried.error);
|
|
3269
|
+
return (0, import_sdk_services5.ok)(queried.data);
|
|
3270
|
+
}
|
|
3271
|
+
};
|
|
3442
3272
|
}
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
);
|
|
3273
|
+
async status() {
|
|
3274
|
+
const apps = await this.applications.list();
|
|
3275
|
+
if (!apps.ok) return apps;
|
|
3276
|
+
const delegations = await this.delegations.list();
|
|
3277
|
+
if (!delegations.ok) return delegations;
|
|
3278
|
+
return (0, import_sdk_services5.ok)({
|
|
3279
|
+
did: this.config.getDid(),
|
|
3280
|
+
host: this.config.getHost(),
|
|
3281
|
+
primarySpaceId: this.config.getPrimarySpaceId(),
|
|
3282
|
+
accountSpaceId: this.config.getAccountSpaceId(),
|
|
3283
|
+
applications: apps.data.length,
|
|
3284
|
+
grantedDelegations: delegations.data.filter((d) => d.direction === "granted").length,
|
|
3285
|
+
receivedDelegations: delegations.data.filter((d) => d.direction === "received").length
|
|
3286
|
+
});
|
|
3447
3287
|
}
|
|
3448
|
-
|
|
3449
|
-
|
|
3288
|
+
accountKV() {
|
|
3289
|
+
const accountSpaceId = this.config.getAccountSpaceId();
|
|
3290
|
+
if (!accountSpaceId) {
|
|
3291
|
+
return (0, import_sdk_services5.err)(
|
|
3292
|
+
(0, import_sdk_services5.serviceError)(
|
|
3293
|
+
"ACCOUNT_SPACE_UNAVAILABLE",
|
|
3294
|
+
"Account space is unavailable. Sign in with a wallet-backed profile first.",
|
|
3295
|
+
SERVICE_NAME2
|
|
3296
|
+
)
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3299
|
+
return (0, import_sdk_services5.ok)(this.config.getSpaces().get(accountSpaceId).kv);
|
|
3450
3300
|
}
|
|
3451
|
-
|
|
3452
|
-
|
|
3301
|
+
accountDb() {
|
|
3302
|
+
const db = this.config.getAccountDb?.();
|
|
3303
|
+
if (!db) {
|
|
3304
|
+
return (0, import_sdk_services5.err)(
|
|
3305
|
+
(0, import_sdk_services5.serviceError)(
|
|
3306
|
+
"ACCOUNT_INDEX_UNAVAILABLE",
|
|
3307
|
+
"Account index database is unavailable. Sign in with a wallet-backed profile first.",
|
|
3308
|
+
SERVICE_NAME2
|
|
3309
|
+
)
|
|
3310
|
+
);
|
|
3311
|
+
}
|
|
3312
|
+
return (0, import_sdk_services5.ok)(db);
|
|
3453
3313
|
}
|
|
3454
|
-
|
|
3455
|
-
|
|
3314
|
+
async resolveSpace(space) {
|
|
3315
|
+
const listed = await this.config.getSpaces().list();
|
|
3316
|
+
if (!listed.ok) return accountErr(listed.error);
|
|
3317
|
+
const found = listed.data.find((candidate) => candidate.id === space || candidate.name === space);
|
|
3318
|
+
if (!found) {
|
|
3319
|
+
return (0, import_sdk_services5.err)(
|
|
3320
|
+
(0, import_sdk_services5.serviceError)("SPACE_NOT_FOUND", `No account space found for ${JSON.stringify(space)}`, SERVICE_NAME2)
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3323
|
+
return (0, import_sdk_services5.ok)(found);
|
|
3456
3324
|
}
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3325
|
+
};
|
|
3326
|
+
var ACCOUNT_INDEX_SCHEMA = [
|
|
3327
|
+
`CREATE TABLE IF NOT EXISTS applications (
|
|
3328
|
+
app_id TEXT PRIMARY KEY,
|
|
3329
|
+
name TEXT,
|
|
3330
|
+
description TEXT,
|
|
3331
|
+
updated_at TEXT,
|
|
3332
|
+
manifest_json TEXT NOT NULL
|
|
3333
|
+
)`,
|
|
3334
|
+
`CREATE TABLE IF NOT EXISTS delegations (
|
|
3335
|
+
cid TEXT PRIMARY KEY,
|
|
3336
|
+
direction TEXT NOT NULL,
|
|
3337
|
+
space_id TEXT NOT NULL,
|
|
3338
|
+
space_name TEXT,
|
|
3339
|
+
counterparty_did TEXT NOT NULL,
|
|
3340
|
+
delegate_did TEXT NOT NULL,
|
|
3341
|
+
delegator_did TEXT,
|
|
3342
|
+
path TEXT NOT NULL,
|
|
3343
|
+
actions_json TEXT NOT NULL,
|
|
3344
|
+
expiry TEXT NOT NULL,
|
|
3345
|
+
status TEXT NOT NULL,
|
|
3346
|
+
created_at TEXT,
|
|
3347
|
+
updated_at TEXT NOT NULL
|
|
3348
|
+
)`,
|
|
3349
|
+
`CREATE TABLE IF NOT EXISTS sync_state (
|
|
3350
|
+
source TEXT PRIMARY KEY,
|
|
3351
|
+
synced_at TEXT NOT NULL,
|
|
3352
|
+
count INTEGER NOT NULL
|
|
3353
|
+
)`,
|
|
3354
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_direction ON delegations(direction)",
|
|
3355
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_space ON delegations(space_id)",
|
|
3356
|
+
"CREATE INDEX IF NOT EXISTS idx_delegations_counterparty ON delegations(counterparty_did)"
|
|
3357
|
+
];
|
|
3358
|
+
function applicationKey(appId) {
|
|
3359
|
+
return `${ACCOUNT_REGISTRY_PATH}${appId}`;
|
|
3460
3360
|
}
|
|
3461
|
-
function
|
|
3462
|
-
|
|
3463
|
-
return [];
|
|
3464
|
-
}
|
|
3465
|
-
const entries = [];
|
|
3466
|
-
for (const [name, spec] of Object.entries(secrets)) {
|
|
3467
|
-
const actions = secretActionsFromSpec(name, spec);
|
|
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
|
-
});
|
|
3482
|
-
}
|
|
3483
|
-
return entries;
|
|
3361
|
+
function appIdFromKey(key) {
|
|
3362
|
+
return key.startsWith(ACCOUNT_REGISTRY_PATH) ? key.slice(ACCOUNT_REGISTRY_PATH.length) : key;
|
|
3484
3363
|
}
|
|
3485
|
-
function
|
|
3486
|
-
const
|
|
3487
|
-
const
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
}
|
|
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
|
-
}));
|
|
3364
|
+
function applicationFromRecord(key, record) {
|
|
3365
|
+
const manifests = Array.isArray(record.manifests) ? record.manifests : [];
|
|
3366
|
+
const first = manifests[0];
|
|
3367
|
+
return {
|
|
3368
|
+
appId: record.app_id ?? record.appId ?? first?.app_id ?? appIdFromKey(key),
|
|
3369
|
+
manifests,
|
|
3370
|
+
updatedAt: record.updated_at ?? record.updatedAt,
|
|
3371
|
+
name: first?.name,
|
|
3372
|
+
description: first?.description
|
|
3373
|
+
};
|
|
3505
3374
|
}
|
|
3506
|
-
function
|
|
3507
|
-
const
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
byBase.set(base, actions);
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
return [...byBase.entries()].map(([base, actions]) => ({
|
|
3519
|
-
...entry,
|
|
3520
|
-
service: "tinycloud.kv",
|
|
3521
|
-
path: vaultKVPath(base, entry.path),
|
|
3522
|
-
actions,
|
|
3523
|
-
skipPrefix: true
|
|
3524
|
-
}));
|
|
3375
|
+
function indexedApplicationFromRow(row) {
|
|
3376
|
+
const [appId, name, description, updatedAt, manifestJson] = row;
|
|
3377
|
+
return {
|
|
3378
|
+
appId,
|
|
3379
|
+
name: name ?? void 0,
|
|
3380
|
+
description: description ?? void 0,
|
|
3381
|
+
updatedAt: updatedAt ?? void 0,
|
|
3382
|
+
manifests: JSON.parse(manifestJson)
|
|
3383
|
+
};
|
|
3525
3384
|
}
|
|
3526
|
-
function
|
|
3527
|
-
const
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3385
|
+
function indexedDelegationFromRow(row) {
|
|
3386
|
+
const [
|
|
3387
|
+
cid,
|
|
3388
|
+
direction,
|
|
3389
|
+
spaceId,
|
|
3390
|
+
spaceName,
|
|
3391
|
+
counterpartyDid,
|
|
3392
|
+
delegateDid,
|
|
3393
|
+
delegatorDid,
|
|
3394
|
+
path,
|
|
3395
|
+
actionsJson,
|
|
3396
|
+
expiry,
|
|
3397
|
+
status,
|
|
3398
|
+
createdAt
|
|
3399
|
+
] = row;
|
|
3400
|
+
return {
|
|
3401
|
+
cid,
|
|
3402
|
+
direction,
|
|
3403
|
+
spaceId,
|
|
3404
|
+
spaceName: spaceName ?? void 0,
|
|
3405
|
+
counterpartyDid,
|
|
3406
|
+
delegateDid,
|
|
3407
|
+
delegatorDid: delegatorDid ?? void 0,
|
|
3408
|
+
path,
|
|
3409
|
+
actions: JSON.parse(actionsJson),
|
|
3410
|
+
expiry: new Date(expiry),
|
|
3411
|
+
status,
|
|
3412
|
+
createdAt: createdAt ? new Date(createdAt) : void 0
|
|
3413
|
+
};
|
|
3549
3414
|
}
|
|
3550
|
-
function
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3415
|
+
function mapDelegation(delegation, space, direction) {
|
|
3416
|
+
return {
|
|
3417
|
+
cid: delegation.cid,
|
|
3418
|
+
direction,
|
|
3419
|
+
spaceId: delegation.spaceId || space.id,
|
|
3420
|
+
spaceName: space.name,
|
|
3421
|
+
counterpartyDid: direction === "granted" ? delegation.delegateDID : delegation.delegatorDID ?? delegation.delegateDID,
|
|
3422
|
+
delegateDid: delegation.delegateDID,
|
|
3423
|
+
delegatorDid: delegation.delegatorDID,
|
|
3424
|
+
path: delegation.path,
|
|
3425
|
+
actions: delegation.actions,
|
|
3426
|
+
expiry: delegation.expiry,
|
|
3427
|
+
status: delegation.isRevoked ? "revoked" : delegation.expiry.getTime() <= Date.now() ? "expired" : "active",
|
|
3428
|
+
createdAt: delegation.createdAt
|
|
3429
|
+
};
|
|
3430
|
+
}
|
|
3431
|
+
function accountErr(error) {
|
|
3432
|
+
return (0, import_sdk_services5.err)((0, import_sdk_services5.serviceError)(error.code, error.message, SERVICE_NAME2, { cause: error.cause, meta: error.meta }));
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
// src/index.ts
|
|
3436
|
+
var import_sdk_services7 = require("@tinycloud/sdk-services");
|
|
3437
|
+
|
|
3438
|
+
// src/space.ts
|
|
3439
|
+
async function fetchPeerId(host, spaceId) {
|
|
3440
|
+
const res = await fetch(
|
|
3441
|
+
`${host}/peer/generate/${encodeURIComponent(spaceId)}`
|
|
3442
|
+
);
|
|
3443
|
+
if (!res.ok) {
|
|
3444
|
+
const error = await res.text().catch(() => res.statusText);
|
|
3445
|
+
throw new Error(`Failed to get peer ID: ${res.status} - ${error}`);
|
|
3556
3446
|
}
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3447
|
+
return res.text();
|
|
3448
|
+
}
|
|
3449
|
+
async function submitHostDelegation(host, headers) {
|
|
3450
|
+
const res = await fetch(`${host}/delegate`, {
|
|
3451
|
+
method: "POST",
|
|
3452
|
+
headers
|
|
3453
|
+
});
|
|
3454
|
+
return {
|
|
3455
|
+
success: res.ok,
|
|
3456
|
+
status: res.status,
|
|
3457
|
+
error: res.ok ? void 0 : await res.text().catch(() => res.statusText)
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
async function activateSessionWithHost(host, delegationHeader) {
|
|
3461
|
+
const res = await fetch(`${host}/delegate`, {
|
|
3462
|
+
method: "POST",
|
|
3463
|
+
headers: delegationHeader
|
|
3464
|
+
});
|
|
3465
|
+
if (res.ok) {
|
|
3466
|
+
try {
|
|
3467
|
+
const body = await res.json();
|
|
3468
|
+
return {
|
|
3469
|
+
success: true,
|
|
3470
|
+
status: res.status,
|
|
3471
|
+
activated: body.activated ?? [],
|
|
3472
|
+
skipped: body.skipped ?? []
|
|
3473
|
+
};
|
|
3474
|
+
} catch {
|
|
3475
|
+
return {
|
|
3476
|
+
success: true,
|
|
3477
|
+
status: res.status,
|
|
3478
|
+
activated: [],
|
|
3479
|
+
skipped: []
|
|
3480
|
+
};
|
|
3481
|
+
}
|
|
3561
3482
|
}
|
|
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
3483
|
return {
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
actions: [...entry.actions],
|
|
3574
|
-
...entry.expiryMs !== void 0 ? { expiryMs: entry.expiryMs } : {},
|
|
3575
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3484
|
+
success: false,
|
|
3485
|
+
status: res.status,
|
|
3486
|
+
error: await res.text().catch(() => res.statusText)
|
|
3576
3487
|
};
|
|
3577
3488
|
}
|
|
3578
|
-
|
|
3489
|
+
|
|
3490
|
+
// src/delegations/DelegationManager.ts
|
|
3491
|
+
var DelegationAction = {
|
|
3492
|
+
CREATE: "tinycloud.delegation/create",
|
|
3493
|
+
REVOKE: "tinycloud.delegation/revoke",
|
|
3494
|
+
LIST: "tinycloud.delegation/list",
|
|
3495
|
+
GET: "tinycloud.delegation/get",
|
|
3496
|
+
CHECK: "tinycloud.delegation/check"
|
|
3497
|
+
};
|
|
3498
|
+
function createError(code, message, cause, meta) {
|
|
3579
3499
|
return {
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {},
|
|
3586
|
-
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
3500
|
+
code,
|
|
3501
|
+
message,
|
|
3502
|
+
service: "delegation",
|
|
3503
|
+
cause,
|
|
3504
|
+
meta
|
|
3587
3505
|
};
|
|
3588
3506
|
}
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3507
|
+
var DelegationManager = class {
|
|
3508
|
+
/**
|
|
3509
|
+
* Creates a new DelegationManager instance.
|
|
3510
|
+
*
|
|
3511
|
+
* @param config - Configuration including hosts, session, and invoke function
|
|
3512
|
+
*/
|
|
3513
|
+
constructor(config) {
|
|
3514
|
+
this.hosts = config.hosts;
|
|
3515
|
+
this.session = config.session;
|
|
3516
|
+
this.invoke = config.invoke;
|
|
3517
|
+
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3518
|
+
}
|
|
3519
|
+
/**
|
|
3520
|
+
* Updates the session (e.g., after re-authentication).
|
|
3521
|
+
*
|
|
3522
|
+
* @param session - New session to use for operations
|
|
3523
|
+
*/
|
|
3524
|
+
updateSession(session) {
|
|
3525
|
+
this.session = session;
|
|
3526
|
+
}
|
|
3527
|
+
/**
|
|
3528
|
+
* Gets the primary host URL.
|
|
3529
|
+
*/
|
|
3530
|
+
get host() {
|
|
3531
|
+
return this.hosts[0];
|
|
3532
|
+
}
|
|
3533
|
+
/**
|
|
3534
|
+
* Executes an invoke operation against the delegation API.
|
|
3535
|
+
*/
|
|
3536
|
+
async invokeOperation(path, action, body) {
|
|
3537
|
+
const headers = this.invoke(this.session, "delegation", path, action);
|
|
3538
|
+
return this.fetchFn(`${this.host}/invoke`, {
|
|
3539
|
+
method: "POST",
|
|
3540
|
+
headers,
|
|
3541
|
+
body
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3544
|
+
/**
|
|
3545
|
+
* Creates a new delegation.
|
|
3546
|
+
*
|
|
3547
|
+
* Delegates specific permissions to another DID for a given path.
|
|
3548
|
+
* The delegatee can then use these permissions to access resources
|
|
3549
|
+
* within the specified scope.
|
|
3550
|
+
*
|
|
3551
|
+
* @param params - Parameters for the delegation
|
|
3552
|
+
* @returns Result containing the created Delegation or an error
|
|
3553
|
+
*
|
|
3554
|
+
* @example
|
|
3555
|
+
* ```typescript
|
|
3556
|
+
* const result = await manager.create({
|
|
3557
|
+
* delegateDID: bob.did,
|
|
3558
|
+
* path: "documents/shared/",
|
|
3559
|
+
* actions: ["tinycloud.kv/get", "tinycloud.kv/put"],
|
|
3560
|
+
* expiry: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
|
|
3561
|
+
* });
|
|
3562
|
+
* ```
|
|
3563
|
+
*/
|
|
3564
|
+
async create(params) {
|
|
3565
|
+
if (!params.delegateDID) {
|
|
3566
|
+
return {
|
|
3567
|
+
ok: false,
|
|
3568
|
+
error: createError(
|
|
3569
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3570
|
+
"delegateDID is required"
|
|
3571
|
+
)
|
|
3572
|
+
};
|
|
3597
3573
|
}
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3574
|
+
if (!params.path) {
|
|
3575
|
+
return {
|
|
3576
|
+
ok: false,
|
|
3577
|
+
error: createError(
|
|
3578
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3579
|
+
"path is required"
|
|
3580
|
+
)
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3583
|
+
if (!params.actions || params.actions.length === 0) {
|
|
3584
|
+
return {
|
|
3585
|
+
ok: false,
|
|
3586
|
+
error: createError(
|
|
3587
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3588
|
+
"at least one action is required"
|
|
3589
|
+
)
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
try {
|
|
3593
|
+
const body = JSON.stringify({
|
|
3594
|
+
delegateDID: params.delegateDID,
|
|
3595
|
+
path: params.path,
|
|
3596
|
+
actions: params.actions,
|
|
3597
|
+
expiry: params.expiry?.toISOString(),
|
|
3598
|
+
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
3599
|
+
statement: params.statement
|
|
3600
|
+
});
|
|
3601
|
+
const response = await this.invokeOperation(
|
|
3602
|
+
params.path,
|
|
3603
|
+
DelegationAction.CREATE,
|
|
3604
|
+
body
|
|
3605
|
+
);
|
|
3606
|
+
if (!response.ok) {
|
|
3607
|
+
const errorText = await response.text();
|
|
3608
|
+
return {
|
|
3609
|
+
ok: false,
|
|
3610
|
+
error: createError(
|
|
3611
|
+
DelegationErrorCodes.CREATION_FAILED,
|
|
3612
|
+
`Failed to create delegation: ${response.status} - ${errorText}`,
|
|
3613
|
+
void 0,
|
|
3614
|
+
{ status: response.status, path: params.path }
|
|
3615
|
+
)
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3618
|
+
const apiResponse = await response.json();
|
|
3619
|
+
const delegation = {
|
|
3620
|
+
cid: apiResponse.cid ?? "",
|
|
3621
|
+
delegateDID: params.delegateDID,
|
|
3622
|
+
spaceId: this.session.spaceId,
|
|
3623
|
+
path: params.path,
|
|
3624
|
+
actions: params.actions,
|
|
3625
|
+
expiry: params.expiry ?? new Date(Date.now() + EXPIRY.SHARE_MS),
|
|
3626
|
+
isRevoked: false,
|
|
3627
|
+
allowSubDelegation: !(params.disableSubDelegation ?? false),
|
|
3628
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3629
|
+
};
|
|
3630
|
+
return { ok: true, data: delegation };
|
|
3631
|
+
} catch (error) {
|
|
3632
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3633
|
+
return {
|
|
3634
|
+
ok: false,
|
|
3635
|
+
error: createError(
|
|
3636
|
+
DelegationErrorCodes.ABORTED,
|
|
3637
|
+
"Request aborted",
|
|
3638
|
+
error
|
|
3639
|
+
)
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
return {
|
|
3643
|
+
ok: false,
|
|
3644
|
+
error: createError(
|
|
3645
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3646
|
+
`Network error during delegation creation: ${String(error)}`,
|
|
3647
|
+
error instanceof Error ? error : void 0
|
|
3648
|
+
)
|
|
3649
|
+
};
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
/**
|
|
3653
|
+
* Revokes an existing delegation.
|
|
3654
|
+
*
|
|
3655
|
+
* Once revoked, the delegation can no longer be used to access resources.
|
|
3656
|
+
* This also invalidates any sub-delegations derived from this delegation.
|
|
3657
|
+
*
|
|
3658
|
+
* @param cid - The CID of the delegation to revoke
|
|
3659
|
+
* @returns Result indicating success or an error
|
|
3660
|
+
*
|
|
3661
|
+
* @example
|
|
3662
|
+
* ```typescript
|
|
3663
|
+
* const result = await manager.revoke("bafy...");
|
|
3664
|
+
* if (result.ok) {
|
|
3665
|
+
* console.log("Delegation revoked successfully");
|
|
3666
|
+
* }
|
|
3667
|
+
* ```
|
|
3668
|
+
*/
|
|
3669
|
+
async revoke(cid) {
|
|
3670
|
+
if (!cid) {
|
|
3671
|
+
return {
|
|
3672
|
+
ok: false,
|
|
3673
|
+
error: createError(
|
|
3674
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3675
|
+
"cid is required"
|
|
3676
|
+
)
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3679
|
+
try {
|
|
3680
|
+
const body = JSON.stringify({ cid });
|
|
3681
|
+
const response = await this.invokeOperation(
|
|
3682
|
+
cid,
|
|
3683
|
+
DelegationAction.REVOKE,
|
|
3684
|
+
body
|
|
3685
|
+
);
|
|
3686
|
+
if (!response.ok) {
|
|
3687
|
+
const errorText = await response.text();
|
|
3688
|
+
if (response.status === 404) {
|
|
3689
|
+
return {
|
|
3690
|
+
ok: false,
|
|
3691
|
+
error: createError(
|
|
3692
|
+
DelegationErrorCodes.NOT_FOUND,
|
|
3693
|
+
`Delegation not found: ${cid}`
|
|
3694
|
+
)
|
|
3695
|
+
};
|
|
3696
|
+
}
|
|
3697
|
+
return {
|
|
3698
|
+
ok: false,
|
|
3699
|
+
error: createError(
|
|
3700
|
+
DelegationErrorCodes.REVOCATION_FAILED,
|
|
3701
|
+
`Failed to revoke delegation: ${response.status} - ${errorText}`,
|
|
3702
|
+
void 0,
|
|
3703
|
+
{ status: response.status, cid }
|
|
3704
|
+
)
|
|
3705
|
+
};
|
|
3603
3706
|
}
|
|
3707
|
+
return { ok: true, data: void 0 };
|
|
3708
|
+
} catch (error) {
|
|
3709
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3710
|
+
return {
|
|
3711
|
+
ok: false,
|
|
3712
|
+
error: createError(
|
|
3713
|
+
DelegationErrorCodes.ABORTED,
|
|
3714
|
+
"Request aborted",
|
|
3715
|
+
error
|
|
3716
|
+
)
|
|
3717
|
+
};
|
|
3718
|
+
}
|
|
3719
|
+
return {
|
|
3720
|
+
ok: false,
|
|
3721
|
+
error: createError(
|
|
3722
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3723
|
+
`Network error during delegation revocation: ${String(error)}`,
|
|
3724
|
+
error instanceof Error ? error : void 0
|
|
3725
|
+
)
|
|
3726
|
+
};
|
|
3604
3727
|
}
|
|
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
3728
|
}
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3729
|
+
/**
|
|
3730
|
+
* Lists all delegations for the current session's space.
|
|
3731
|
+
*
|
|
3732
|
+
* Returns both delegations created by the current user (as delegator)
|
|
3733
|
+
* and delegations granted to the current user (as delegatee).
|
|
3734
|
+
*
|
|
3735
|
+
* @returns Result containing an array of Delegations or an error
|
|
3736
|
+
*
|
|
3737
|
+
* @example
|
|
3738
|
+
* ```typescript
|
|
3739
|
+
* const result = await manager.list();
|
|
3740
|
+
* if (result.ok) {
|
|
3741
|
+
* for (const delegation of result.data) {
|
|
3742
|
+
* console.log(`${delegation.cid}: ${delegation.path} -> ${delegation.delegateDID}`);
|
|
3743
|
+
* }
|
|
3744
|
+
* }
|
|
3745
|
+
* ```
|
|
3746
|
+
*/
|
|
3747
|
+
async list() {
|
|
3748
|
+
try {
|
|
3749
|
+
const response = await this.invokeOperation("", DelegationAction.LIST);
|
|
3750
|
+
if (!response.ok) {
|
|
3751
|
+
const errorText = await response.text();
|
|
3752
|
+
return {
|
|
3753
|
+
ok: false,
|
|
3754
|
+
error: createError(
|
|
3755
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3756
|
+
`Failed to list delegations: ${response.status} - ${errorText}`,
|
|
3757
|
+
void 0,
|
|
3758
|
+
{ status: response.status }
|
|
3759
|
+
)
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
const data = await response.json();
|
|
3763
|
+
const delegations = data.map((item) => ({
|
|
3764
|
+
cid: item.cid,
|
|
3765
|
+
delegateDID: item.delegateDID,
|
|
3766
|
+
delegatorDID: item.delegatorDID,
|
|
3767
|
+
spaceId: item.spaceId,
|
|
3768
|
+
path: item.path,
|
|
3769
|
+
actions: item.actions,
|
|
3770
|
+
expiry: new Date(item.expiry),
|
|
3771
|
+
isRevoked: item.isRevoked,
|
|
3772
|
+
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
3773
|
+
parentCid: item.parentCid,
|
|
3774
|
+
allowSubDelegation: item.allowSubDelegation
|
|
3775
|
+
}));
|
|
3776
|
+
return { ok: true, data: delegations };
|
|
3777
|
+
} catch (error) {
|
|
3778
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3779
|
+
return {
|
|
3780
|
+
ok: false,
|
|
3781
|
+
error: createError(
|
|
3782
|
+
DelegationErrorCodes.ABORTED,
|
|
3783
|
+
"Request aborted",
|
|
3784
|
+
error
|
|
3785
|
+
)
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
return {
|
|
3789
|
+
ok: false,
|
|
3790
|
+
error: createError(
|
|
3791
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3792
|
+
`Network error during delegation list: ${String(error)}`,
|
|
3793
|
+
error instanceof Error ? error : void 0
|
|
3794
|
+
)
|
|
3795
|
+
};
|
|
3666
3796
|
}
|
|
3667
3797
|
}
|
|
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
|
-
|
|
3798
|
+
/**
|
|
3799
|
+
* Gets the full delegation chain for a given delegation.
|
|
3800
|
+
*
|
|
3801
|
+
* Returns the chain of delegations from the root (original delegator)
|
|
3802
|
+
* to the specified delegation, including all intermediate sub-delegations.
|
|
3803
|
+
*
|
|
3804
|
+
* @param cid - The CID of the delegation to get the chain for
|
|
3805
|
+
* @returns Result containing the DelegationChain or an error
|
|
3806
|
+
*
|
|
3807
|
+
* @example
|
|
3808
|
+
* ```typescript
|
|
3809
|
+
* const result = await manager.getChain("bafy...");
|
|
3810
|
+
* if (result.ok) {
|
|
3811
|
+
* console.log("Chain length:", result.data.length);
|
|
3812
|
+
* for (const delegation of result.data) {
|
|
3813
|
+
* console.log(`- ${delegation.delegatorDID} -> ${delegation.delegateDID}`);
|
|
3814
|
+
* }
|
|
3815
|
+
* }
|
|
3816
|
+
* ```
|
|
3817
|
+
*/
|
|
3818
|
+
async getChain(cid) {
|
|
3819
|
+
if (!cid) {
|
|
3820
|
+
return {
|
|
3821
|
+
ok: false,
|
|
3822
|
+
error: createError(
|
|
3823
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3824
|
+
"cid is required"
|
|
3825
|
+
)
|
|
3826
|
+
};
|
|
3827
|
+
}
|
|
3828
|
+
try {
|
|
3829
|
+
const body = JSON.stringify({ cid, includeChain: true });
|
|
3830
|
+
const response = await this.invokeOperation(
|
|
3831
|
+
cid,
|
|
3832
|
+
DelegationAction.GET,
|
|
3833
|
+
body
|
|
3692
3834
|
);
|
|
3835
|
+
if (!response.ok) {
|
|
3836
|
+
const errorText = await response.text();
|
|
3837
|
+
if (response.status === 404) {
|
|
3838
|
+
return {
|
|
3839
|
+
ok: false,
|
|
3840
|
+
error: createError(
|
|
3841
|
+
DelegationErrorCodes.NOT_FOUND,
|
|
3842
|
+
`Delegation not found: ${cid}`
|
|
3843
|
+
)
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
return {
|
|
3847
|
+
ok: false,
|
|
3848
|
+
error: createError(
|
|
3849
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3850
|
+
`Failed to get delegation chain: ${response.status} - ${errorText}`,
|
|
3851
|
+
void 0,
|
|
3852
|
+
{ status: response.status, cid }
|
|
3853
|
+
)
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
const data = await response.json();
|
|
3857
|
+
const chain = data.chain.map((item) => ({
|
|
3858
|
+
cid: item.cid,
|
|
3859
|
+
delegateDID: item.delegateDID,
|
|
3860
|
+
delegatorDID: item.delegatorDID,
|
|
3861
|
+
spaceId: item.spaceId,
|
|
3862
|
+
path: item.path,
|
|
3863
|
+
actions: item.actions,
|
|
3864
|
+
expiry: new Date(item.expiry),
|
|
3865
|
+
isRevoked: item.isRevoked,
|
|
3866
|
+
createdAt: item.createdAt ? new Date(item.createdAt) : void 0,
|
|
3867
|
+
parentCid: item.parentCid,
|
|
3868
|
+
allowSubDelegation: item.allowSubDelegation
|
|
3869
|
+
}));
|
|
3870
|
+
return { ok: true, data: chain };
|
|
3871
|
+
} catch (error) {
|
|
3872
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3873
|
+
return {
|
|
3874
|
+
ok: false,
|
|
3875
|
+
error: createError(
|
|
3876
|
+
DelegationErrorCodes.ABORTED,
|
|
3877
|
+
"Request aborted",
|
|
3878
|
+
error
|
|
3879
|
+
)
|
|
3880
|
+
};
|
|
3881
|
+
}
|
|
3882
|
+
return {
|
|
3883
|
+
ok: false,
|
|
3884
|
+
error: createError(
|
|
3885
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3886
|
+
`Network error during chain retrieval: ${String(error)}`,
|
|
3887
|
+
error instanceof Error ? error : void 0
|
|
3888
|
+
)
|
|
3889
|
+
};
|
|
3693
3890
|
}
|
|
3694
|
-
|
|
3695
|
-
|
|
3891
|
+
}
|
|
3892
|
+
/**
|
|
3893
|
+
* Checks if the current session has permission for a given path and action.
|
|
3894
|
+
*
|
|
3895
|
+
* This can be used to verify permissions before attempting an operation,
|
|
3896
|
+
* or to implement custom access control logic.
|
|
3897
|
+
*
|
|
3898
|
+
* @param path - The resource path to check
|
|
3899
|
+
* @param action - The action to check (e.g., "tinycloud.kv/get")
|
|
3900
|
+
* @returns Result containing a boolean indicating permission or an error
|
|
3901
|
+
*
|
|
3902
|
+
* @example
|
|
3903
|
+
* ```typescript
|
|
3904
|
+
* const result = await manager.checkPermission("documents/private/", "tinycloud.kv/put");
|
|
3905
|
+
* if (result.ok && result.data) {
|
|
3906
|
+
* console.log("Permission granted");
|
|
3907
|
+
* } else {
|
|
3908
|
+
* console.log("Permission denied");
|
|
3909
|
+
* }
|
|
3910
|
+
* ```
|
|
3911
|
+
*/
|
|
3912
|
+
async checkPermission(path, action) {
|
|
3913
|
+
if (!path) {
|
|
3914
|
+
return {
|
|
3915
|
+
ok: false,
|
|
3916
|
+
error: createError(
|
|
3917
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3918
|
+
"path is required"
|
|
3919
|
+
)
|
|
3920
|
+
};
|
|
3696
3921
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3922
|
+
if (!action) {
|
|
3923
|
+
return {
|
|
3924
|
+
ok: false,
|
|
3925
|
+
error: createError(
|
|
3926
|
+
DelegationErrorCodes.INVALID_INPUT,
|
|
3927
|
+
"action is required"
|
|
3928
|
+
)
|
|
3929
|
+
};
|
|
3930
|
+
}
|
|
3931
|
+
try {
|
|
3932
|
+
const body = JSON.stringify({ path, action });
|
|
3933
|
+
const response = await this.invokeOperation(
|
|
3934
|
+
path,
|
|
3935
|
+
DelegationAction.CHECK,
|
|
3936
|
+
body
|
|
3937
|
+
);
|
|
3938
|
+
if (!response.ok) {
|
|
3939
|
+
if (response.status === 403) {
|
|
3940
|
+
return { ok: true, data: false };
|
|
3707
3941
|
}
|
|
3942
|
+
const errorText = await response.text();
|
|
3943
|
+
return {
|
|
3944
|
+
ok: false,
|
|
3945
|
+
error: createError(
|
|
3946
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3947
|
+
`Failed to check permission: ${response.status} - ${errorText}`,
|
|
3948
|
+
void 0,
|
|
3949
|
+
{ status: response.status, path, action }
|
|
3950
|
+
)
|
|
3951
|
+
};
|
|
3708
3952
|
}
|
|
3953
|
+
const data = await response.json();
|
|
3954
|
+
return { ok: true, data: data.allowed };
|
|
3955
|
+
} catch (error) {
|
|
3956
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3957
|
+
return {
|
|
3958
|
+
ok: false,
|
|
3959
|
+
error: createError(
|
|
3960
|
+
DelegationErrorCodes.ABORTED,
|
|
3961
|
+
"Request aborted",
|
|
3962
|
+
error
|
|
3963
|
+
)
|
|
3964
|
+
};
|
|
3965
|
+
}
|
|
3966
|
+
return {
|
|
3967
|
+
ok: false,
|
|
3968
|
+
error: createError(
|
|
3969
|
+
DelegationErrorCodes.NETWORK_ERROR,
|
|
3970
|
+
`Network error during permission check: ${String(error)}`,
|
|
3971
|
+
error instanceof Error ? error : void 0
|
|
3972
|
+
)
|
|
3973
|
+
};
|
|
3709
3974
|
}
|
|
3710
3975
|
}
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3976
|
+
};
|
|
3977
|
+
|
|
3978
|
+
// src/delegations/SharingService.schema.ts
|
|
3979
|
+
var import_zod5 = require("zod");
|
|
3980
|
+
var EncodedShareDataSchema = import_zod5.z.object({
|
|
3981
|
+
/** Private key in JWK format (must include d parameter) */
|
|
3982
|
+
key: JWKSchema.refine(
|
|
3983
|
+
(jwk) => typeof jwk.d === "string" && jwk.d.length > 0,
|
|
3984
|
+
{ message: "JWK must include private key (d parameter)" }
|
|
3985
|
+
),
|
|
3986
|
+
/** DID of the key */
|
|
3987
|
+
keyDid: import_zod5.z.string().min(1, "keyDid is required"),
|
|
3988
|
+
/** The delegation granting access */
|
|
3989
|
+
delegation: DelegationSchema,
|
|
3990
|
+
/** Resource path this link grants access to */
|
|
3991
|
+
path: import_zod5.z.string().min(1, "path is required"),
|
|
3992
|
+
/** TinyCloud host URL */
|
|
3993
|
+
host: import_zod5.z.string().url("host must be a valid URL"),
|
|
3994
|
+
/** Space ID */
|
|
3995
|
+
spaceId: import_zod5.z.string().min(1, "spaceId is required"),
|
|
3996
|
+
/** Schema version (must be 1) */
|
|
3997
|
+
version: import_zod5.z.literal(1)
|
|
3998
|
+
});
|
|
3999
|
+
var ReceiveOptionsSchema = import_zod5.z.object({
|
|
4000
|
+
/**
|
|
4001
|
+
* Whether to automatically create a sub-delegation to the current session key.
|
|
4002
|
+
* Default: true
|
|
4003
|
+
*/
|
|
4004
|
+
autoSubdelegate: import_zod5.z.boolean().optional(),
|
|
4005
|
+
/**
|
|
4006
|
+
* Whether to use the current session key for operations (requires autoSubdelegate).
|
|
4007
|
+
* Default: true
|
|
4008
|
+
*/
|
|
4009
|
+
useSessionKey: import_zod5.z.boolean().optional(),
|
|
4010
|
+
/**
|
|
4011
|
+
* Ingestion options passed to CapabilityKeyRegistry.
|
|
4012
|
+
*/
|
|
4013
|
+
ingestOptions: IngestOptionsSchema.optional()
|
|
4014
|
+
});
|
|
4015
|
+
var SharingServiceConfigSchema = import_zod5.z.object({
|
|
4016
|
+
/** TinyCloud host URLs */
|
|
4017
|
+
hosts: import_zod5.z.array(import_zod5.z.string().url()).min(1, "At least one host URL is required"),
|
|
4018
|
+
/**
|
|
4019
|
+
* Active session for authentication.
|
|
4020
|
+
* Required for generate(), optional for receive().
|
|
4021
|
+
*/
|
|
4022
|
+
session: import_zod5.z.unknown().refine(
|
|
4023
|
+
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
4024
|
+
{ message: "Expected a ServiceSession object or undefined" }
|
|
4025
|
+
).optional(),
|
|
4026
|
+
/** Platform-specific invoke function */
|
|
4027
|
+
invoke: import_zod5.z.unknown().refine((val) => typeof val === "function", {
|
|
4028
|
+
message: "Expected an invoke function"
|
|
4029
|
+
}),
|
|
4030
|
+
/** Optional custom fetch implementation */
|
|
4031
|
+
fetch: import_zod5.z.unknown().refine(
|
|
4032
|
+
(val) => val === void 0 || typeof val === "function",
|
|
4033
|
+
{ message: "Expected a fetch function or undefined" }
|
|
4034
|
+
).optional(),
|
|
4035
|
+
/** Key provider for cryptographic operations */
|
|
4036
|
+
keyProvider: KeyProviderSchema,
|
|
4037
|
+
/** Capability key registry for key/delegation management */
|
|
4038
|
+
registry: import_zod5.z.unknown().refine(
|
|
4039
|
+
(val) => val !== null && typeof val === "object",
|
|
4040
|
+
{ message: "Expected an ICapabilityKeyRegistry object" }
|
|
4041
|
+
),
|
|
4042
|
+
/**
|
|
4043
|
+
* Delegation manager for creating delegations.
|
|
4044
|
+
* Required for generate(), optional for receive().
|
|
4045
|
+
*/
|
|
4046
|
+
delegationManager: import_zod5.z.unknown().refine(
|
|
4047
|
+
(val) => val === void 0 || val !== null && typeof val === "object",
|
|
4048
|
+
{ message: "Expected a DelegationManager object or undefined" }
|
|
4049
|
+
).optional(),
|
|
4050
|
+
/** Factory for creating KV service instances */
|
|
4051
|
+
createKVService: import_zod5.z.unknown().refine(
|
|
4052
|
+
(val) => typeof val === "function",
|
|
4053
|
+
{ message: "Expected a createKVService factory function" }
|
|
4054
|
+
),
|
|
4055
|
+
/** Base URL for sharing links (e.g., "https://share.myapp.com") */
|
|
4056
|
+
baseUrl: import_zod5.z.string().optional(),
|
|
4057
|
+
/**
|
|
4058
|
+
* Custom delegation creation function.
|
|
4059
|
+
*/
|
|
4060
|
+
createDelegation: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4061
|
+
message: "Expected a createDelegation function or undefined"
|
|
4062
|
+
}).optional(),
|
|
4063
|
+
/**
|
|
4064
|
+
* WASM function for client-side delegation creation.
|
|
4065
|
+
*/
|
|
4066
|
+
createDelegationWasm: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4067
|
+
message: "Expected a createDelegationWasm function or undefined"
|
|
4068
|
+
}).optional(),
|
|
4069
|
+
/**
|
|
4070
|
+
* Path prefix for KV operations.
|
|
4071
|
+
*/
|
|
4072
|
+
pathPrefix: import_zod5.z.string().optional(),
|
|
4073
|
+
/**
|
|
4074
|
+
* Session expiry time.
|
|
4075
|
+
*/
|
|
4076
|
+
sessionExpiry: import_zod5.z.date().optional(),
|
|
4077
|
+
/**
|
|
4078
|
+
* Callback to create a DIRECT delegation from wallet to share key.
|
|
4079
|
+
* This is the preferred method for long-lived share links because it
|
|
4080
|
+
* bypasses the session delegation chain entirely.
|
|
4081
|
+
*/
|
|
4082
|
+
onRootDelegationNeeded: import_zod5.z.unknown().refine((val) => val === void 0 || typeof val === "function", {
|
|
4083
|
+
message: "Expected an onRootDelegationNeeded function or undefined"
|
|
4084
|
+
}).optional()
|
|
4085
|
+
});
|
|
4086
|
+
function validateEncodedShareData(data) {
|
|
4087
|
+
const result = EncodedShareDataSchema.safeParse(data);
|
|
4088
|
+
if (!result.success) {
|
|
4089
|
+
return {
|
|
4090
|
+
ok: false,
|
|
4091
|
+
error: {
|
|
4092
|
+
code: DelegationErrorCodes.VALIDATION_ERROR,
|
|
4093
|
+
message: `Invalid share data: ${result.error.message}`,
|
|
4094
|
+
service: "delegation",
|
|
4095
|
+
meta: { issues: result.error.issues }
|
|
4096
|
+
}
|
|
4097
|
+
};
|
|
3735
4098
|
}
|
|
3736
|
-
return
|
|
4099
|
+
return { ok: true, data: result.data };
|
|
3737
4100
|
}
|
|
3738
4101
|
|
|
3739
4102
|
// src/delegations/SharingService.ts
|
|
@@ -3914,13 +4277,13 @@ var SharingService = class {
|
|
|
3914
4277
|
)
|
|
3915
4278
|
};
|
|
3916
4279
|
}
|
|
3917
|
-
} catch (
|
|
4280
|
+
} catch (err6) {
|
|
3918
4281
|
return {
|
|
3919
4282
|
ok: false,
|
|
3920
4283
|
error: createError2(
|
|
3921
4284
|
DelegationErrorCodes.CREATION_FAILED,
|
|
3922
|
-
`Failed to generate session key for share: ${
|
|
3923
|
-
|
|
4285
|
+
`Failed to generate session key for share: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4286
|
+
err6 instanceof Error ? err6 : void 0
|
|
3924
4287
|
)
|
|
3925
4288
|
};
|
|
3926
4289
|
}
|
|
@@ -3966,7 +4329,7 @@ var SharingService = class {
|
|
|
3966
4329
|
}
|
|
3967
4330
|
delegation = parsed;
|
|
3968
4331
|
}
|
|
3969
|
-
} catch (
|
|
4332
|
+
} catch (err6) {
|
|
3970
4333
|
const fallbackResult = await this.handleSessionExtensionFallback(requestedExpiry);
|
|
3971
4334
|
expiry = fallbackResult.expiry;
|
|
3972
4335
|
const delegationResult = await this.createSessionDelegation(plainDID, fullPath, actions, expiry);
|
|
@@ -4164,13 +4527,13 @@ var SharingService = class {
|
|
|
4164
4527
|
allowSubDelegation: true,
|
|
4165
4528
|
createdAt: /* @__PURE__ */ new Date()
|
|
4166
4529
|
};
|
|
4167
|
-
} catch (
|
|
4530
|
+
} catch (err6) {
|
|
4168
4531
|
return {
|
|
4169
4532
|
ok: false,
|
|
4170
4533
|
error: createError2(
|
|
4171
4534
|
DelegationErrorCodes.CREATION_FAILED,
|
|
4172
|
-
`Failed to create delegation via WASM: ${
|
|
4173
|
-
|
|
4535
|
+
`Failed to create delegation via WASM: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4536
|
+
err6 instanceof Error ? err6 : void 0
|
|
4174
4537
|
)
|
|
4175
4538
|
};
|
|
4176
4539
|
}
|
|
@@ -4251,8 +4614,8 @@ var SharingService = class {
|
|
|
4251
4614
|
let activeKey = keyInfo;
|
|
4252
4615
|
if (autoSubdelegate && useSessionKey && this.session) {
|
|
4253
4616
|
try {
|
|
4254
|
-
} catch (
|
|
4255
|
-
console.warn("Auto-subdelegation failed, using ingested key directly:",
|
|
4617
|
+
} catch (err6) {
|
|
4618
|
+
console.warn("Auto-subdelegation failed, using ingested key directly:", err6);
|
|
4256
4619
|
}
|
|
4257
4620
|
}
|
|
4258
4621
|
const authHeader = shareData.delegation.authHeader ?? `Bearer ${shareData.delegation.cid}`;
|
|
@@ -4350,26 +4713,26 @@ var SharingService = class {
|
|
|
4350
4713
|
let jsonString;
|
|
4351
4714
|
try {
|
|
4352
4715
|
jsonString = base64UrlDecode(base64Data);
|
|
4353
|
-
} catch (
|
|
4716
|
+
} catch (err6) {
|
|
4354
4717
|
return {
|
|
4355
4718
|
ok: false,
|
|
4356
4719
|
error: createError2(
|
|
4357
4720
|
DelegationErrorCodes.INVALID_TOKEN,
|
|
4358
|
-
`Failed to decode base64 data: ${
|
|
4359
|
-
|
|
4721
|
+
`Failed to decode base64 data: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4722
|
+
err6 instanceof Error ? err6 : void 0
|
|
4360
4723
|
)
|
|
4361
4724
|
};
|
|
4362
4725
|
}
|
|
4363
4726
|
let parsed;
|
|
4364
4727
|
try {
|
|
4365
4728
|
parsed = JSON.parse(jsonString);
|
|
4366
|
-
} catch (
|
|
4729
|
+
} catch (err6) {
|
|
4367
4730
|
return {
|
|
4368
4731
|
ok: false,
|
|
4369
4732
|
error: createError2(
|
|
4370
4733
|
DelegationErrorCodes.INVALID_TOKEN,
|
|
4371
|
-
`Failed to parse share data JSON: ${
|
|
4372
|
-
|
|
4734
|
+
`Failed to parse share data JSON: ${err6 instanceof Error ? err6.message : String(err6)}`,
|
|
4735
|
+
err6 instanceof Error ? err6 : void 0
|
|
4373
4736
|
)
|
|
4374
4737
|
};
|
|
4375
4738
|
}
|
|
@@ -4396,8 +4759,8 @@ function createSharingService(config) {
|
|
|
4396
4759
|
}
|
|
4397
4760
|
|
|
4398
4761
|
// src/authorization/CapabilityKeyRegistry.ts
|
|
4399
|
-
var
|
|
4400
|
-
var
|
|
4762
|
+
var import_sdk_services6 = require("@tinycloud/sdk-services");
|
|
4763
|
+
var SERVICE_NAME3 = "capability-key-registry";
|
|
4401
4764
|
var CapabilityKeyRegistryErrorCodes = {
|
|
4402
4765
|
/** Key not found in registry */
|
|
4403
4766
|
KEY_NOT_FOUND: "KEY_NOT_FOUND",
|
|
@@ -4614,11 +4977,11 @@ var CapabilityKeyRegistry = class {
|
|
|
4614
4977
|
revokeDelegation(cid) {
|
|
4615
4978
|
const stored = this.store.byCid.get(cid);
|
|
4616
4979
|
if (!stored) {
|
|
4617
|
-
return (0,
|
|
4618
|
-
(0,
|
|
4980
|
+
return (0, import_sdk_services6.err)(
|
|
4981
|
+
(0, import_sdk_services6.serviceError)(
|
|
4619
4982
|
CapabilityKeyRegistryErrorCodes.KEY_NOT_FOUND,
|
|
4620
4983
|
`Delegation not found: ${cid}`,
|
|
4621
|
-
|
|
4984
|
+
SERVICE_NAME3
|
|
4622
4985
|
)
|
|
4623
4986
|
);
|
|
4624
4987
|
}
|
|
@@ -4637,7 +5000,7 @@ var CapabilityKeyRegistry = class {
|
|
|
4637
5000
|
}
|
|
4638
5001
|
}
|
|
4639
5002
|
}
|
|
4640
|
-
return (0,
|
|
5003
|
+
return (0, import_sdk_services6.ok)(void 0);
|
|
4641
5004
|
}
|
|
4642
5005
|
// ===========================================================================
|
|
4643
5006
|
// Search
|
|
@@ -4866,8 +5229,8 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
4866
5229
|
response = await fetchFn(`${host}/info`, {
|
|
4867
5230
|
signal: AbortSignal.timeout(5e3)
|
|
4868
5231
|
});
|
|
4869
|
-
} catch (
|
|
4870
|
-
throw new VersionCheckError(host,
|
|
5232
|
+
} catch (err6) {
|
|
5233
|
+
throw new VersionCheckError(host, err6);
|
|
4871
5234
|
}
|
|
4872
5235
|
if (!response.ok) {
|
|
4873
5236
|
throw new VersionCheckError(host);
|
|
@@ -5400,6 +5763,7 @@ function parseRecapCapabilities(parseWasm, siwe) {
|
|
|
5400
5763
|
0 && (module.exports = {
|
|
5401
5764
|
ACCOUNT_REGISTRY_PATH,
|
|
5402
5765
|
ACCOUNT_REGISTRY_SPACE,
|
|
5766
|
+
AccountService,
|
|
5403
5767
|
AutoApproveSpaceCreationHandler,
|
|
5404
5768
|
CapabilityKeyRegistry,
|
|
5405
5769
|
CapabilityKeyRegistryErrorCodes,
|