@tinycloud/sdk-core 2.2.0-beta.1 → 2.2.0-beta.10

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 CHANGED
@@ -36,30 +36,36 @@ __export(index_exports, {
36
36
  CapabilityKeyRegistry: () => CapabilityKeyRegistry,
37
37
  CapabilityKeyRegistryErrorCodes: () => CapabilityKeyRegistryErrorCodes,
38
38
  ClientSessionSchema: () => ClientSessionSchema,
39
+ CloudLocationResolutionError: () => CloudLocationResolutionError,
39
40
  DEFAULT_DEFAULTS: () => DEFAULT_DEFAULTS,
40
41
  DEFAULT_EXPIRY: () => DEFAULT_EXPIRY,
41
42
  DEFAULT_MANIFEST_SPACE: () => DEFAULT_MANIFEST_SPACE,
42
43
  DEFAULT_MANIFEST_VERSION: () => DEFAULT_MANIFEST_VERSION,
43
- DataVaultService: () => import_sdk_services4.DataVaultService,
44
- DatabaseHandle: () => import_sdk_services4.DatabaseHandle,
44
+ DEFAULT_TINYCLOUD_FALLBACK_HOST: () => DEFAULT_TINYCLOUD_FALLBACK_HOST,
45
+ DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL: () => DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
46
+ DataVaultService: () => import_sdk_services5.DataVaultService,
47
+ DatabaseHandle: () => import_sdk_services5.DatabaseHandle,
45
48
  DelegationErrorCodes: () => DelegationErrorCodes,
46
49
  DelegationManager: () => DelegationManager,
47
- DuckDbAction: () => import_sdk_services4.DuckDbAction,
48
- DuckDbDatabaseHandle: () => import_sdk_services4.DuckDbDatabaseHandle,
49
- DuckDbService: () => import_sdk_services4.DuckDbService,
50
+ DuckDbAction: () => import_sdk_services5.DuckDbAction,
51
+ DuckDbDatabaseHandle: () => import_sdk_services5.DuckDbDatabaseHandle,
52
+ DuckDbService: () => import_sdk_services5.DuckDbService,
50
53
  EnsDataSchema: () => EnsDataSchema,
51
- ErrorCodes: () => import_sdk_services4.ErrorCodes,
52
- HooksService: () => import_sdk_services4.HooksService,
53
- KVService: () => import_sdk_services4.KVService,
54
+ ErrorCodes: () => import_sdk_services5.ErrorCodes,
55
+ HooksService: () => import_sdk_services5.HooksService,
56
+ KVService: () => import_sdk_services5.KVService,
57
+ LocationRecordValidationError: () => LocationRecordValidationError,
54
58
  ManifestValidationError: () => ManifestValidationError,
55
59
  PermissionNotInManifestError: () => PermissionNotInManifestError,
56
- PrefixedKVService: () => import_sdk_services4.PrefixedKVService,
60
+ PrefixedKVService: () => import_sdk_services5.PrefixedKVService,
57
61
  ProtocolMismatchError: () => ProtocolMismatchError,
62
+ SECRET_NAME_RE: () => import_sdk_services5.SECRET_NAME_RE,
58
63
  SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
59
64
  SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
60
- SQLAction: () => import_sdk_services4.SQLAction,
61
- SQLService: () => import_sdk_services4.SQLService,
62
- ServiceContext: () => import_sdk_services4.ServiceContext,
65
+ SQLAction: () => import_sdk_services5.SQLAction,
66
+ SQLService: () => import_sdk_services5.SQLService,
67
+ SecretsService: () => import_sdk_services5.SecretsService,
68
+ ServiceContext: () => import_sdk_services5.ServiceContext,
63
69
  SessionExpiredError: () => SessionExpiredError,
64
70
  SharingService: () => SharingService,
65
71
  SilentNotificationHandler: () => SilentNotificationHandler,
@@ -70,41 +76,57 @@ __export(index_exports, {
70
76
  SpaceService: () => SpaceService,
71
77
  TinyCloud: () => TinyCloud,
72
78
  UnsupportedFeatureError: () => UnsupportedFeatureError,
73
- VaultHeaders: () => import_sdk_services4.VaultHeaders,
74
- VaultPublicSpaceKVActions: () => import_sdk_services4.VaultPublicSpaceKVActions,
79
+ VAULT_PERMISSION_SERVICE: () => VAULT_PERMISSION_SERVICE,
80
+ VaultHeaders: () => import_sdk_services5.VaultHeaders,
81
+ VaultPublicSpaceKVActions: () => import_sdk_services5.VaultPublicSpaceKVActions,
75
82
  VersionCheckError: () => VersionCheckError,
76
83
  activateSessionWithHost: () => activateSessionWithHost,
77
84
  applyPrefix: () => applyPrefix,
78
85
  buildSpaceUri: () => buildSpaceUri,
86
+ canonicalLocationPayload: () => canonicalLocationPayload,
87
+ canonicalizeSecretScope: () => import_sdk_services5.canonicalizeSecretScope,
79
88
  checkNodeInfo: () => checkNodeInfo,
80
89
  composeManifestRequest: () => composeManifestRequest,
81
90
  createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
82
91
  createSharingService: () => createSharingService,
83
92
  createSpaceService: () => createSpaceService,
84
- createVaultCrypto: () => import_sdk_services4.createVaultCrypto,
85
- defaultRetryPolicy: () => import_sdk_services4.defaultRetryPolicy,
93
+ createVaultCrypto: () => import_sdk_services5.createVaultCrypto,
94
+ defaultRetryPolicy: () => import_sdk_services5.defaultRetryPolicy,
86
95
  defaultSignStrategy: () => defaultSignStrategy,
87
96
  defaultSpaceCreationHandler: () => defaultSpaceCreationHandler,
88
- err: () => import_sdk_services4.err,
97
+ err: () => import_sdk_services5.err,
89
98
  expandActionShortNames: () => expandActionShortNames,
99
+ expandPermissionEntries: () => expandPermissionEntries,
100
+ expandPermissionEntry: () => expandPermissionEntry,
101
+ fetchLocationRecord: () => fetchLocationRecord,
90
102
  fetchPeerId: () => fetchPeerId,
103
+ httpUrlToMultiaddr: () => httpUrlToMultiaddr,
91
104
  isCapabilitySubset: () => isCapabilitySubset,
92
105
  loadManifest: () => loadManifest,
106
+ locationPayloadForRecord: () => locationPayloadForRecord,
93
107
  makePublicSpaceId: () => makePublicSpaceId,
94
108
  manifestAbilitiesUnion: () => manifestAbilitiesUnion,
109
+ multiaddrToHttpUrl: () => multiaddrToHttpUrl,
95
110
  normalizeDefaults: () => normalizeDefaults,
96
- ok: () => import_sdk_services4.ok,
111
+ ok: () => import_sdk_services5.ok,
97
112
  parseExpiry: () => parseExpiry,
98
113
  parseRecapCapabilities: () => parseRecapCapabilities,
99
114
  parseSpaceUri: () => parseSpaceUri,
115
+ resolveCloudLocation: () => resolveCloudLocation,
100
116
  resolveManifest: () => resolveManifest,
117
+ resolveSecretPath: () => import_sdk_services5.resolveSecretPath,
118
+ resolveTinyCloudHosts: () => resolveTinyCloudHosts,
101
119
  resourceCapabilitiesToAbilitiesMap: () => resourceCapabilitiesToAbilitiesMap,
102
120
  resourceCapabilitiesToSpaceAbilitiesMap: () => resourceCapabilitiesToSpaceAbilitiesMap,
103
- serviceError: () => import_sdk_services4.serviceError,
121
+ serviceError: () => import_sdk_services5.serviceError,
122
+ signLocationRecord: () => signLocationRecord,
104
123
  submitHostDelegation: () => submitHostDelegation,
105
124
  validateClientSession: () => validateClientSession,
125
+ validateLocationRecord: () => validateLocationRecord,
126
+ validateLocationRecordPayload: () => validateLocationRecordPayload,
106
127
  validateManifest: () => validateManifest,
107
- validatePersistedSessionData: () => validatePersistedSessionData
128
+ validatePersistedSessionData: () => validatePersistedSessionData,
129
+ verifyLocationRecord: () => verifyLocationRecord
108
130
  });
109
131
  module.exports = __toCommonJS(index_exports);
110
132
 
@@ -254,6 +276,7 @@ var Space = class {
254
276
  this._id = config.id;
255
277
  this._name = config.name;
256
278
  this._kv = config.createKV(config.id);
279
+ this._vault = config.createVault(config.id);
257
280
  this._delegations = config.createDelegations(config.id);
258
281
  this._sharing = config.createSharing(config.id);
259
282
  this._getInfo = config.getInfo;
@@ -276,6 +299,12 @@ var Space = class {
276
299
  get kv() {
277
300
  return this._kv;
278
301
  }
302
+ /**
303
+ * Data Vault operations scoped to this space.
304
+ */
305
+ get vault() {
306
+ return this._vault;
307
+ }
279
308
  /**
280
309
  * Delegation operations scoped to this space.
281
310
  */
@@ -659,6 +688,8 @@ var SpaceConfigSchema = import_zod4.z.object({
659
688
  name: import_zod4.z.string(),
660
689
  /** Factory function to create a space-scoped KV service */
661
690
  createKV: import_zod4.z.function(),
691
+ /** Factory function to create a space-scoped Data Vault service */
692
+ createVault: import_zod4.z.function(),
662
693
  /** Factory function to create space-scoped delegations */
663
694
  createDelegations: import_zod4.z.function(),
664
695
  /** Factory function to create space-scoped sharing */
@@ -679,6 +710,8 @@ var SpaceServiceConfigSchema = import_zod4.z.object({
679
710
  capabilityRegistry: import_zod4.z.unknown().optional(),
680
711
  /** Factory function to create a space-scoped KV service */
681
712
  createKVService: import_zod4.z.function().optional(),
713
+ /** Factory function to create a space-scoped Data Vault service */
714
+ createVaultService: import_zod4.z.function().optional(),
682
715
  /** User's PKH DID (derived from address or provided explicitly) */
683
716
  userDid: import_zod4.z.string().optional(),
684
717
  /** Optional SharingService for v2 sharing links (client-side) */
@@ -920,6 +953,7 @@ var SpaceService = class {
920
953
  this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
921
954
  this.capabilityRegistry = config.capabilityRegistry;
922
955
  this.createKVServiceFn = config.createKVService;
956
+ this.createVaultServiceFn = config.createVaultService;
923
957
  this._userDid = config.userDid;
924
958
  this.sharingService = config.sharingService;
925
959
  this.createDelegationFn = config.createDelegation;
@@ -934,6 +968,7 @@ var SpaceService = class {
934
968
  if (config.fetch) this.fetchFn = config.fetch;
935
969
  if (config.capabilityRegistry) this.capabilityRegistry = config.capabilityRegistry;
936
970
  if (config.createKVService) this.createKVServiceFn = config.createKVService;
971
+ if (config.createVaultService) this.createVaultServiceFn = config.createVaultService;
937
972
  if (config.userDid !== void 0) this._userDid = config.userDid;
938
973
  if (config.sharingService) this.sharingService = config.sharingService;
939
974
  if (config.createDelegation) this.createDelegationFn = config.createDelegation;
@@ -1216,6 +1251,7 @@ var SpaceService = class {
1216
1251
  id: spaceId,
1217
1252
  name,
1218
1253
  createKV: this.createSpaceScopedKV.bind(this),
1254
+ createVault: this.createSpaceScopedVault.bind(this),
1219
1255
  createDelegations: this.createSpaceScopedDelegations.bind(this),
1220
1256
  createSharing: this.createSpaceScopedSharing.bind(this),
1221
1257
  getInfo: this.getSpaceInfo.bind(this)
@@ -1345,6 +1381,21 @@ var SpaceService = class {
1345
1381
  }
1346
1382
  });
1347
1383
  }
1384
+ /**
1385
+ * Create a space-scoped Data Vault service.
1386
+ */
1387
+ createSpaceScopedVault(spaceId) {
1388
+ if (this.createVaultServiceFn) {
1389
+ return this.createVaultServiceFn(spaceId);
1390
+ }
1391
+ return new Proxy({}, {
1392
+ get: () => {
1393
+ throw new Error(
1394
+ "Vault service factory not configured. Provide createVaultService in SpaceServiceConfig."
1395
+ );
1396
+ }
1397
+ });
1398
+ }
1348
1399
  /**
1349
1400
  * Create space-scoped delegation operations.
1350
1401
  */
@@ -2070,7 +2121,7 @@ var TinyCloud = class _TinyCloud {
2070
2121
  };
2071
2122
 
2072
2123
  // src/index.ts
2073
- var import_sdk_services4 = require("@tinycloud/sdk-services");
2124
+ var import_sdk_services5 = require("@tinycloud/sdk-services");
2074
2125
 
2075
2126
  // src/space.ts
2076
2127
  async function fetchPeerId(host, spaceId) {
@@ -2738,6 +2789,7 @@ function validateEncodedShareData(data) {
2738
2789
 
2739
2790
  // src/manifest.ts
2740
2791
  var import_ms = __toESM(require("ms"), 1);
2792
+ var import_sdk_services3 = require("@tinycloud/sdk-services");
2741
2793
  var ManifestValidationError = class extends Error {
2742
2794
  constructor(message) {
2743
2795
  super(`Manifest validation failed: ${message}`);
@@ -2750,6 +2802,8 @@ var DEFAULT_MANIFEST_VERSION = 1;
2750
2802
  var DEFAULT_MANIFEST_SPACE = "applications";
2751
2803
  var ACCOUNT_REGISTRY_SPACE = "account";
2752
2804
  var ACCOUNT_REGISTRY_PATH = "applications/";
2805
+ var SECRETS_SPACE = "secrets";
2806
+ var VAULT_PERMISSION_SERVICE = "tinycloud.vault";
2753
2807
  var SERVICE_SHORT_TO_LONG = Object.freeze({
2754
2808
  kv: "tinycloud.kv",
2755
2809
  sql: "tinycloud.sql",
@@ -2774,12 +2828,6 @@ var DEFAULT_STANDARD_ENTRIES = [
2774
2828
  space: DEFAULT_MANIFEST_SPACE,
2775
2829
  path: "/",
2776
2830
  actions: ["read", "write"]
2777
- },
2778
- {
2779
- service: "tinycloud.capabilities",
2780
- space: DEFAULT_MANIFEST_SPACE,
2781
- path: "/",
2782
- actions: ["read"]
2783
2831
  }
2784
2832
  ];
2785
2833
  var DEFAULT_ADMIN_ENTRIES = [
@@ -2794,12 +2842,6 @@ var DEFAULT_ADMIN_ENTRIES = [
2794
2842
  space: DEFAULT_MANIFEST_SPACE,
2795
2843
  path: "/",
2796
2844
  actions: ["read", "write", "ddl"]
2797
- },
2798
- {
2799
- service: "tinycloud.capabilities",
2800
- space: DEFAULT_MANIFEST_SPACE,
2801
- path: "/",
2802
- actions: ["read", "admin"]
2803
2845
  }
2804
2846
  ];
2805
2847
  var DEFAULT_ALL_ENTRIES = [
@@ -2820,12 +2862,6 @@ var DEFAULT_ALL_ENTRIES = [
2820
2862
  space: DEFAULT_MANIFEST_SPACE,
2821
2863
  path: "/",
2822
2864
  actions: ["read", "write"]
2823
- },
2824
- {
2825
- service: "tinycloud.capabilities",
2826
- space: DEFAULT_MANIFEST_SPACE,
2827
- path: "/",
2828
- actions: ["read", "admin"]
2829
2865
  }
2830
2866
  ];
2831
2867
  function parseExpiry(duration) {
@@ -2850,6 +2886,20 @@ function expandActionShortNames(service, actions) {
2850
2886
  return `${service}/${a}`;
2851
2887
  });
2852
2888
  }
2889
+ function expandPermissionEntry(entry) {
2890
+ if (entry.service !== VAULT_PERMISSION_SERVICE) {
2891
+ return [
2892
+ {
2893
+ ...entry,
2894
+ actions: expandActionShortNames(entry.service, entry.actions)
2895
+ }
2896
+ ];
2897
+ }
2898
+ return expandVaultPermissionEntry(entry);
2899
+ }
2900
+ function expandPermissionEntries(entries) {
2901
+ return entries.flatMap(expandPermissionEntry);
2902
+ }
2853
2903
  function applyPrefix(prefix, path, skipPrefix) {
2854
2904
  if (skipPrefix) {
2855
2905
  return path;
@@ -2921,8 +2971,49 @@ function validateManifest(input) {
2921
2971
  (p, i) => validatePermissionEntry(p, `permissions[${i}]`)
2922
2972
  );
2923
2973
  }
2974
+ if (m.secrets !== void 0) {
2975
+ validateManifestSecrets(m.secrets);
2976
+ }
2924
2977
  return m;
2925
2978
  }
2979
+ function validateManifestSecrets(secrets) {
2980
+ if (secrets === null || typeof secrets !== "object" || Array.isArray(secrets)) {
2981
+ throw new ManifestValidationError("manifest.secrets must be an object");
2982
+ }
2983
+ for (const [name, spec] of Object.entries(secrets)) {
2984
+ if (!import_sdk_services3.SECRET_NAME_RE.test(name)) {
2985
+ throw new ManifestValidationError(
2986
+ `manifest.secrets.${name} must match ${import_sdk_services3.SECRET_NAME_RE.source}`
2987
+ );
2988
+ }
2989
+ try {
2990
+ (0, import_sdk_services3.resolveSecretPath)(
2991
+ secretNameFromSpec(name, spec),
2992
+ { scope: secretScopeFromSpec(spec) }
2993
+ );
2994
+ } catch (error) {
2995
+ throw new ManifestValidationError(
2996
+ `manifest.secrets.${name}: ${error instanceof Error ? error.message : String(error)}`
2997
+ );
2998
+ }
2999
+ const actions = secretActionsFromSpec(name, spec);
3000
+ if (actions.length === 0) {
3001
+ throw new ManifestValidationError(
3002
+ `manifest.secrets.${name} actions must be non-empty`
3003
+ );
3004
+ }
3005
+ for (const action of actions) {
3006
+ if (typeof action !== "string" || action.length === 0) {
3007
+ throw new ManifestValidationError(
3008
+ `manifest.secrets.${name} actions must be non-empty strings`
3009
+ );
3010
+ }
3011
+ }
3012
+ if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
3013
+ parseExpiry(spec.expiry);
3014
+ }
3015
+ }
3016
+ }
2926
3017
  function validatePermissionEntry(p, path) {
2927
3018
  if (p === null || typeof p !== "object") {
2928
3019
  throw new ManifestValidationError(`${path} must be an object`);
@@ -2946,6 +3037,16 @@ function validatePermissionEntry(p, path) {
2946
3037
  `${path}.actions must be a non-empty array`
2947
3038
  );
2948
3039
  }
3040
+ for (const action of entry.actions) {
3041
+ if (typeof action !== "string" || action.length === 0) {
3042
+ throw new ManifestValidationError(
3043
+ `${path}.actions must contain non-empty strings`
3044
+ );
3045
+ }
3046
+ if (entry.service === VAULT_PERMISSION_SERVICE) {
3047
+ vaultActionExpansion(action);
3048
+ }
3049
+ }
2949
3050
  if (entry.expiry !== void 0) {
2950
3051
  parseExpiry(entry.expiry);
2951
3052
  }
@@ -2975,7 +3076,8 @@ function defaultEntriesForTier(tier) {
2975
3076
  service: e.service,
2976
3077
  space: e.space,
2977
3078
  path: e.path,
2978
- actions: [...e.actions]
3079
+ actions: [...e.actions],
3080
+ ...e.skipPrefix !== void 0 ? { skipPrefix: e.skipPrefix } : {}
2979
3081
  }));
2980
3082
  }
2981
3083
  function resolveManifest(input) {
@@ -2987,9 +3089,14 @@ function resolveManifest(input) {
2987
3089
  const tier = normalizeDefaults(manifest.defaults);
2988
3090
  const defaultEntries = defaultEntriesForTier(tier);
2989
3091
  const explicitEntries = manifest.permissions ?? [];
2990
- const allEntries = [...defaultEntries, ...explicitEntries];
2991
- const resources = allEntries.map(
2992
- (entry) => resolveEntry(entry, prefix, expiryMs, space)
3092
+ const secretEntries = secretEntriesForManifest(manifest.secrets);
3093
+ const allEntries = [
3094
+ ...defaultEntries,
3095
+ ...explicitEntries,
3096
+ ...secretEntries
3097
+ ];
3098
+ const resources = withCapabilitiesReadForSpaces(
3099
+ allEntries.flatMap((entry) => resolveEntry(entry, prefix, expiryMs, space))
2993
3100
  );
2994
3101
  const additionalDelegates = manifest.did === void 0 ? [] : [
2995
3102
  {
@@ -3009,25 +3116,191 @@ function resolveManifest(input) {
3009
3116
  additionalDelegates
3010
3117
  };
3011
3118
  }
3119
+ function normalizeSecretActions(actions) {
3120
+ const out = [];
3121
+ const seen = /* @__PURE__ */ new Set();
3122
+ const add = (action) => {
3123
+ if (!seen.has(action)) {
3124
+ out.push(action);
3125
+ seen.add(action);
3126
+ }
3127
+ };
3128
+ for (const action of actions) {
3129
+ if (action === "read") {
3130
+ add("get");
3131
+ continue;
3132
+ }
3133
+ if (action === "write") {
3134
+ add("put");
3135
+ continue;
3136
+ }
3137
+ if (action === "delete") {
3138
+ add("del");
3139
+ continue;
3140
+ }
3141
+ if (action === "get" || action === "put" || action === "del" || action === "list" || action === "metadata") {
3142
+ add(action);
3143
+ continue;
3144
+ }
3145
+ if (action === "tinycloud.kv/get" || action === "tinycloud.kv/put" || action === "tinycloud.kv/del" || action === "tinycloud.kv/list" || action === "tinycloud.kv/metadata") {
3146
+ add(action);
3147
+ continue;
3148
+ }
3149
+ throw new ManifestValidationError(
3150
+ `unknown secret action ${JSON.stringify(action)}; expected read, write, delete, list, or metadata`
3151
+ );
3152
+ }
3153
+ return out;
3154
+ }
3155
+ function secretNameFromSpec(fallbackName, spec) {
3156
+ if (spec !== null && typeof spec === "object" && !Array.isArray(spec)) {
3157
+ return spec.name ?? fallbackName;
3158
+ }
3159
+ return fallbackName;
3160
+ }
3161
+ function secretScopeFromSpec(spec) {
3162
+ if (spec !== null && typeof spec === "object" && !Array.isArray(spec)) {
3163
+ return spec.scope;
3164
+ }
3165
+ return void 0;
3166
+ }
3167
+ function secretActionsFromSpec(name, spec) {
3168
+ if (spec === true) {
3169
+ return ["read"];
3170
+ }
3171
+ if (typeof spec === "string") {
3172
+ return [spec];
3173
+ }
3174
+ if (Array.isArray(spec)) {
3175
+ return spec;
3176
+ }
3177
+ if (spec === null || typeof spec !== "object") {
3178
+ throw new ManifestValidationError(
3179
+ `manifest.secrets.${name} must be true, a string action, an actions array, or an object`
3180
+ );
3181
+ }
3182
+ if (spec.actions === void 0) {
3183
+ return ["read"];
3184
+ }
3185
+ if (typeof spec.actions === "string") {
3186
+ return [spec.actions];
3187
+ }
3188
+ if (Array.isArray(spec.actions)) {
3189
+ return spec.actions;
3190
+ }
3191
+ throw new ManifestValidationError(
3192
+ `manifest.secrets.${name}.actions must be a string or array`
3193
+ );
3194
+ }
3195
+ function secretEntriesForManifest(secrets) {
3196
+ if (secrets === void 0) {
3197
+ return [];
3198
+ }
3199
+ const entries = [];
3200
+ for (const [name, spec] of Object.entries(secrets)) {
3201
+ const actions = secretActionsFromSpec(name, spec);
3202
+ const secretPath = (0, import_sdk_services3.resolveSecretPath)(
3203
+ secretNameFromSpec(name, spec),
3204
+ { scope: secretScopeFromSpec(spec) }
3205
+ );
3206
+ const extra = spec !== true && typeof spec === "object" && !Array.isArray(spec) ? spec : {};
3207
+ entries.push({
3208
+ service: VAULT_PERMISSION_SERVICE,
3209
+ space: SECRETS_SPACE,
3210
+ path: secretPath.vaultKey,
3211
+ actions: normalizeSecretActions(actions),
3212
+ skipPrefix: true,
3213
+ ...extra.expiry !== void 0 ? { expiry: extra.expiry } : {},
3214
+ ...extra.description !== void 0 ? { description: extra.description } : {}
3215
+ });
3216
+ }
3217
+ return entries;
3218
+ }
3012
3219
  function resolveEntry(entry, prefix, _inheritedExpiryMs, inheritedSpace) {
3013
3220
  const resolvedPath = applyPrefix(
3014
3221
  prefix,
3015
3222
  entry.path,
3016
3223
  entry.skipPrefix === true
3017
3224
  );
3018
- const resolvedActions = expandActionShortNames(entry.service, entry.actions);
3019
3225
  const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
3020
- return {
3021
- service: entry.service,
3226
+ return expandPermissionEntry({
3227
+ ...entry,
3022
3228
  space: entry.space ?? inheritedSpace,
3023
3229
  path: resolvedPath,
3024
- actions: resolvedActions,
3230
+ skipPrefix: true
3231
+ }).map((expanded) => ({
3232
+ service: expanded.service,
3233
+ space: expanded.space ?? inheritedSpace,
3234
+ path: expanded.path,
3235
+ actions: expanded.actions,
3025
3236
  // Only populate `expiryMs` when the entry had its own expiry override.
3026
3237
  // When absent, callers use the parent (delegation or manifest) expiry
3027
3238
  // which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
3028
3239
  ...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {},
3029
3240
  ...entry.description !== void 0 ? { description: entry.description } : {}
3030
- };
3241
+ }));
3242
+ }
3243
+ function expandVaultPermissionEntry(entry) {
3244
+ const byBase = /* @__PURE__ */ new Map();
3245
+ for (const action of entry.actions) {
3246
+ const expansion = vaultActionExpansion(action);
3247
+ for (const base of expansion.bases) {
3248
+ const actions = byBase.get(base) ?? [];
3249
+ if (!actions.includes(expansion.action)) {
3250
+ actions.push(expansion.action);
3251
+ }
3252
+ byBase.set(base, actions);
3253
+ }
3254
+ }
3255
+ return [...byBase.entries()].map(([base, actions]) => ({
3256
+ ...entry,
3257
+ service: "tinycloud.kv",
3258
+ path: vaultKVPath(base, entry.path),
3259
+ actions,
3260
+ skipPrefix: true
3261
+ }));
3262
+ }
3263
+ function vaultActionExpansion(action) {
3264
+ const normalized = normalizeVaultAction(action);
3265
+ if (normalized === "read" || normalized === "get") {
3266
+ return { bases: ["keys", "vault"], action: "tinycloud.kv/get" };
3267
+ }
3268
+ if (normalized === "write" || normalized === "put") {
3269
+ return { bases: ["keys", "vault"], action: "tinycloud.kv/put" };
3270
+ }
3271
+ if (normalized === "delete" || normalized === "del") {
3272
+ return { bases: ["keys", "vault"], action: "tinycloud.kv/del" };
3273
+ }
3274
+ if (normalized === "list") {
3275
+ return { bases: ["vault"], action: "tinycloud.kv/list" };
3276
+ }
3277
+ if (normalized === "head") {
3278
+ return { bases: ["vault"], action: "tinycloud.kv/get" };
3279
+ }
3280
+ if (normalized === "metadata") {
3281
+ return { bases: ["vault"], action: "tinycloud.kv/metadata" };
3282
+ }
3283
+ throw new ManifestValidationError(
3284
+ `unknown vault action ${JSON.stringify(action)}; expected read, write, delete, get, put, del, list, head, or metadata`
3285
+ );
3286
+ }
3287
+ function normalizeVaultAction(action) {
3288
+ if (action.startsWith(`${VAULT_PERMISSION_SERVICE}/`)) {
3289
+ return action.slice(`${VAULT_PERMISSION_SERVICE}/`.length);
3290
+ }
3291
+ if (action.startsWith("tinycloud.kv/")) {
3292
+ return action.slice("tinycloud.kv/".length);
3293
+ }
3294
+ if (action.includes("/")) {
3295
+ throw new ManifestValidationError(
3296
+ `unknown vault action ${JSON.stringify(action)}; expected a tinycloud.vault or tinycloud.kv action`
3297
+ );
3298
+ }
3299
+ return action;
3300
+ }
3301
+ function vaultKVPath(base, path) {
3302
+ const normalized = path.startsWith("/") ? path.slice(1) : path;
3303
+ return `${base}/${normalized}`;
3031
3304
  }
3032
3305
  function cloneResourceCapability(entry) {
3033
3306
  return {
@@ -3072,6 +3345,24 @@ function dedupeResources(resources) {
3072
3345
  }
3073
3346
  return [...byKey.values()];
3074
3347
  }
3348
+ function capabilitiesReadPermission(space) {
3349
+ return {
3350
+ service: "tinycloud.capabilities",
3351
+ space,
3352
+ path: "",
3353
+ actions: ["tinycloud.capabilities/read"]
3354
+ };
3355
+ }
3356
+ function withCapabilitiesReadForSpaces(resources) {
3357
+ if (resources.length === 0) {
3358
+ return [];
3359
+ }
3360
+ const spaces = new Set(resources.map((resource) => resource.space));
3361
+ return dedupeResources([
3362
+ ...resources,
3363
+ ...[...spaces].map(capabilitiesReadPermission)
3364
+ ]);
3365
+ }
3075
3366
  function accountRegistryPermission() {
3076
3367
  return {
3077
3368
  service: "tinycloud.kv",
@@ -3099,6 +3390,7 @@ function composeManifestRequest(inputs, options = {}) {
3099
3390
  if (includeAccountRegistryPermissions) {
3100
3391
  resources.push(accountRegistryPermission());
3101
3392
  }
3393
+ const resourcesWithImplicitCapabilities = withCapabilitiesReadForSpaces(resources);
3102
3394
  const manifestsByAppId = /* @__PURE__ */ new Map();
3103
3395
  for (const manifest of manifests) {
3104
3396
  const current = manifestsByAppId.get(manifest.app_id);
@@ -3118,7 +3410,7 @@ function composeManifestRequest(inputs, options = {}) {
3118
3410
  })) : [];
3119
3411
  return {
3120
3412
  manifests,
3121
- resources: dedupeResources(resources),
3413
+ resources: resourcesWithImplicitCapabilities,
3122
3414
  delegationTargets,
3123
3415
  registryRecords,
3124
3416
  expiryMs: Math.max(...resolved.map((entry) => entry.expiryMs)),
@@ -3839,7 +4131,7 @@ function createSharingService(config) {
3839
4131
  }
3840
4132
 
3841
4133
  // src/authorization/CapabilityKeyRegistry.ts
3842
- var import_sdk_services3 = require("@tinycloud/sdk-services");
4134
+ var import_sdk_services4 = require("@tinycloud/sdk-services");
3843
4135
  var SERVICE_NAME2 = "capability-key-registry";
3844
4136
  var CapabilityKeyRegistryErrorCodes = {
3845
4137
  /** Key not found in registry */
@@ -4057,8 +4349,8 @@ var CapabilityKeyRegistry = class {
4057
4349
  revokeDelegation(cid) {
4058
4350
  const stored = this.store.byCid.get(cid);
4059
4351
  if (!stored) {
4060
- return (0, import_sdk_services3.err)(
4061
- (0, import_sdk_services3.serviceError)(
4352
+ return (0, import_sdk_services4.err)(
4353
+ (0, import_sdk_services4.serviceError)(
4062
4354
  CapabilityKeyRegistryErrorCodes.KEY_NOT_FOUND,
4063
4355
  `Delegation not found: ${cid}`,
4064
4356
  SERVICE_NAME2
@@ -4080,7 +4372,7 @@ var CapabilityKeyRegistry = class {
4080
4372
  }
4081
4373
  }
4082
4374
  }
4083
- return (0, import_sdk_services3.ok)(void 0);
4375
+ return (0, import_sdk_services4.ok)(void 0);
4084
4376
  }
4085
4377
  // ===========================================================================
4086
4378
  // Search
@@ -4330,6 +4622,394 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
4330
4622
  };
4331
4623
  }
4332
4624
 
4625
+ // src/location.ts
4626
+ var import_multiaddr = require("@multiformats/multiaddr");
4627
+ var import_multiaddr_to_uri = require("@multiformats/multiaddr-to-uri");
4628
+ var import_uri_to_multiaddr = require("@multiformats/uri-to-multiaddr");
4629
+ var import_ed25519 = require("@noble/curves/ed25519");
4630
+ var import_basics = require("multiformats/basics");
4631
+ var import_viem = require("viem");
4632
+ var DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL = "https://registry.tinycloud.xyz";
4633
+ var DEFAULT_TINYCLOUD_FALLBACK_HOST = "https://node.tinycloud.xyz";
4634
+ var LocationRecordValidationError = class extends Error {
4635
+ constructor(message) {
4636
+ super(`Location record validation failed: ${message}`);
4637
+ this.name = "LocationRecordValidationError";
4638
+ }
4639
+ };
4640
+ var CloudLocationResolutionError = class extends Error {
4641
+ constructor(subject, attempts) {
4642
+ super(`Unable to resolve TinyCloud location for ${subject}`);
4643
+ this.name = "CloudLocationResolutionError";
4644
+ this.attempts = attempts;
4645
+ }
4646
+ };
4647
+ function locationPayloadForRecord(record) {
4648
+ return {
4649
+ version: record.version,
4650
+ subject: record.subject,
4651
+ multiaddrs: [...record.multiaddrs],
4652
+ updated_at: record.updated_at,
4653
+ sequence: record.sequence
4654
+ };
4655
+ }
4656
+ function canonicalLocationPayload(payload) {
4657
+ return JSON.stringify({
4658
+ version: payload.version,
4659
+ subject: payload.subject,
4660
+ multiaddrs: payload.multiaddrs,
4661
+ updated_at: payload.updated_at,
4662
+ sequence: payload.sequence
4663
+ });
4664
+ }
4665
+ async function signLocationRecord(payload, signer) {
4666
+ validateLocationRecordPayload(payload);
4667
+ const message = canonicalLocationPayload(payload);
4668
+ const signature = signer.type === "did:pkh" ? await signer.signMessage(message) : base64UrlEncode2(
4669
+ await signer.signBytes(new TextEncoder().encode(message))
4670
+ );
4671
+ return { ...payload, signature };
4672
+ }
4673
+ function validateLocationRecordPayload(input) {
4674
+ if (input === null || typeof input !== "object") {
4675
+ throw new LocationRecordValidationError("payload must be an object");
4676
+ }
4677
+ const payload = input;
4678
+ if (payload.version !== 1) {
4679
+ throw new LocationRecordValidationError("version must be 1");
4680
+ }
4681
+ validateSubject(payload.subject);
4682
+ validateMultiaddrs(payload.multiaddrs);
4683
+ if (typeof payload.updated_at !== "string" || Number.isNaN(Date.parse(payload.updated_at))) {
4684
+ throw new LocationRecordValidationError(
4685
+ "updated_at must be an ISO timestamp"
4686
+ );
4687
+ }
4688
+ if (typeof payload.sequence !== "number" || !Number.isSafeInteger(payload.sequence) || payload.sequence < 0) {
4689
+ throw new LocationRecordValidationError(
4690
+ "sequence must be a non-negative safe integer"
4691
+ );
4692
+ }
4693
+ return {
4694
+ version: 1,
4695
+ subject: payload.subject,
4696
+ multiaddrs: [...payload.multiaddrs],
4697
+ updated_at: payload.updated_at,
4698
+ sequence: payload.sequence
4699
+ };
4700
+ }
4701
+ function validateLocationRecord(input) {
4702
+ const payload = validateLocationRecordPayload(input);
4703
+ const signature = input.signature;
4704
+ if (typeof signature !== "string" || signature.length === 0) {
4705
+ throw new LocationRecordValidationError(
4706
+ "signature must be a non-empty string"
4707
+ );
4708
+ }
4709
+ return { ...payload, signature };
4710
+ }
4711
+ async function verifyLocationRecord(input) {
4712
+ const record = validateLocationRecord(input);
4713
+ const payload = canonicalLocationPayload(locationPayloadForRecord(record));
4714
+ if (record.subject.startsWith("did:pkh:")) {
4715
+ return verifyPkhSignature(record.subject, payload, record.signature);
4716
+ }
4717
+ if (record.subject.startsWith("did:key:")) {
4718
+ return verifyDidKeySignature(record.subject, payload, record.signature);
4719
+ }
4720
+ return false;
4721
+ }
4722
+ async function fetchLocationRecord(registryUrl, subject, fetchFn = globalThis.fetch) {
4723
+ const url = `${registryUrl.replace(/\/$/, "")}/v1/locations/${encodeURIComponent(subject)}`;
4724
+ const response = await fetchFn(url);
4725
+ if (response.status === 404) {
4726
+ return null;
4727
+ }
4728
+ if (!response.ok) {
4729
+ throw new Error(`location registry returned HTTP ${response.status}`);
4730
+ }
4731
+ const body = await response.json();
4732
+ if (body.record === void 0) {
4733
+ throw new LocationRecordValidationError("registry response missing record");
4734
+ }
4735
+ return validateLocationRecord(body.record);
4736
+ }
4737
+ async function resolveCloudLocation(subject, options = {}) {
4738
+ validateSubject(subject);
4739
+ const verifyRecords = options.verifyRecords ?? true;
4740
+ const attempts = await Promise.all([
4741
+ resolveExplicit(subject, options.explicitMultiaddrs),
4742
+ resolveBlockchain(subject, options.blockchain, verifyRecords),
4743
+ resolveCentralized(subject, options, verifyRecords),
4744
+ resolveFallback(subject, options.fallbackMultiaddrs)
4745
+ ]);
4746
+ const winner = attempts.find((attempt) => attempt.candidate)?.candidate;
4747
+ if (!winner) {
4748
+ throw new CloudLocationResolutionError(subject, attempts);
4749
+ }
4750
+ return {
4751
+ subject,
4752
+ source: winner.source,
4753
+ multiaddrs: [...winner.multiaddrs],
4754
+ ...winner.record ? { record: winner.record } : {},
4755
+ attempts,
4756
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
4757
+ };
4758
+ }
4759
+ async function resolveTinyCloudHosts(subject, options = {}) {
4760
+ const location = await resolveCloudLocation(subject, {
4761
+ explicitMultiaddrs: hostsToMultiaddrs(options.explicitHosts),
4762
+ blockchain: options.blockchain,
4763
+ centralizedRegistryUrl: options.registryUrl === null ? void 0 : options.registryUrl ?? DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
4764
+ fallbackMultiaddrs: hostsToMultiaddrs(
4765
+ options.fallbackHosts === null ? void 0 : options.fallbackHosts ?? [DEFAULT_TINYCLOUD_FALLBACK_HOST]
4766
+ ),
4767
+ fetch: options.fetch,
4768
+ verifyRecords: options.verifyRecords
4769
+ });
4770
+ return {
4771
+ hosts: location.multiaddrs.map((addr) => multiaddrToHttpUrl(addr)),
4772
+ location
4773
+ };
4774
+ }
4775
+ function multiaddrToHttpUrl(input) {
4776
+ const uri = (0, import_multiaddr_to_uri.multiaddrToUri)((0, import_multiaddr.multiaddr)(input));
4777
+ if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
4778
+ throw new LocationRecordValidationError(
4779
+ `multiaddr does not resolve to http/https: ${input}`
4780
+ );
4781
+ }
4782
+ return uri;
4783
+ }
4784
+ function httpUrlToMultiaddr(input) {
4785
+ const url = new URL(input);
4786
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
4787
+ throw new LocationRecordValidationError("URL must use http or https");
4788
+ }
4789
+ return (0, import_uri_to_multiaddr.uriToMultiaddr)(url.toString()).toString();
4790
+ }
4791
+ function hostsToMultiaddrs(hosts) {
4792
+ if (hosts === void 0 || hosts.length === 0) {
4793
+ return void 0;
4794
+ }
4795
+ return hosts.map(
4796
+ (host) => host.startsWith("/") ? host : httpUrlToMultiaddr(host)
4797
+ );
4798
+ }
4799
+ async function resolveExplicit(subject, multiaddrs) {
4800
+ return resolveAttempt("explicit", async () => {
4801
+ if (multiaddrs === void 0 || multiaddrs.length === 0) {
4802
+ return null;
4803
+ }
4804
+ return toCandidate(subject, "explicit", multiaddrs, false);
4805
+ });
4806
+ }
4807
+ async function resolveBlockchain(subject, resolver, verifyRecords) {
4808
+ return resolveAttempt("blockchain", async () => {
4809
+ if (!resolver) {
4810
+ return null;
4811
+ }
4812
+ return toCandidate(
4813
+ subject,
4814
+ "blockchain",
4815
+ await resolver(subject),
4816
+ verifyRecords
4817
+ );
4818
+ });
4819
+ }
4820
+ async function resolveCentralized(subject, options, verifyRecords) {
4821
+ return resolveAttempt("centralized", async () => {
4822
+ if (!options.centralizedRegistryUrl) {
4823
+ return null;
4824
+ }
4825
+ const record = await fetchLocationRecord(
4826
+ options.centralizedRegistryUrl,
4827
+ subject,
4828
+ options.fetch
4829
+ );
4830
+ return toCandidate(subject, "centralized", record, verifyRecords);
4831
+ });
4832
+ }
4833
+ async function resolveFallback(subject, multiaddrs) {
4834
+ return resolveAttempt("fallback", async () => {
4835
+ if (multiaddrs === void 0 || multiaddrs.length === 0) {
4836
+ return null;
4837
+ }
4838
+ return toCandidate(subject, "fallback", multiaddrs, false);
4839
+ });
4840
+ }
4841
+ async function resolveAttempt(source, resolve) {
4842
+ try {
4843
+ const candidate = await resolve();
4844
+ return candidate ? { source, candidate } : { source };
4845
+ } catch (error) {
4846
+ return {
4847
+ source,
4848
+ error: error instanceof Error ? error : new Error(String(error))
4849
+ };
4850
+ }
4851
+ }
4852
+ async function toCandidate(subject, source, input, verifyRecord) {
4853
+ if (input === null || input === void 0) {
4854
+ return null;
4855
+ }
4856
+ if (Array.isArray(input)) {
4857
+ validateMultiaddrs(input);
4858
+ return { source, multiaddrs: [...input] };
4859
+ }
4860
+ const maybeRecord = input;
4861
+ if (maybeRecord.version === 1 && maybeRecord.signature !== void 0) {
4862
+ const record = validateLocationRecord(input);
4863
+ if (record.subject !== subject) {
4864
+ throw new LocationRecordValidationError(
4865
+ "location record subject does not match requested subject"
4866
+ );
4867
+ }
4868
+ if (verifyRecord && !await verifyLocationRecord(record)) {
4869
+ throw new LocationRecordValidationError(
4870
+ "location record signature is invalid"
4871
+ );
4872
+ }
4873
+ return { source, multiaddrs: [...record.multiaddrs], record };
4874
+ }
4875
+ const candidateInput = input;
4876
+ if (!Array.isArray(candidateInput.multiaddrs)) {
4877
+ throw new LocationRecordValidationError(
4878
+ "candidate multiaddrs must be an array"
4879
+ );
4880
+ }
4881
+ validateMultiaddrs(candidateInput.multiaddrs);
4882
+ if (candidateInput.record !== void 0) {
4883
+ const record = validateLocationRecord(candidateInput.record);
4884
+ if (record.subject !== subject) {
4885
+ throw new LocationRecordValidationError(
4886
+ "location record subject does not match requested subject"
4887
+ );
4888
+ }
4889
+ if (verifyRecord && !await verifyLocationRecord(record)) {
4890
+ throw new LocationRecordValidationError(
4891
+ "location record signature is invalid"
4892
+ );
4893
+ }
4894
+ return { source, multiaddrs: [...candidateInput.multiaddrs], record };
4895
+ }
4896
+ return { source, multiaddrs: [...candidateInput.multiaddrs] };
4897
+ }
4898
+ function validateSubject(subject) {
4899
+ if (typeof subject !== "string" || subject.length === 0) {
4900
+ throw new LocationRecordValidationError(
4901
+ "subject must be a non-empty string"
4902
+ );
4903
+ }
4904
+ if (!subject.startsWith("did:pkh:") && !subject.startsWith("did:key:")) {
4905
+ throw new LocationRecordValidationError(
4906
+ "subject must be did:pkh or did:key"
4907
+ );
4908
+ }
4909
+ }
4910
+ function validateMultiaddrs(input) {
4911
+ if (!Array.isArray(input)) {
4912
+ throw new LocationRecordValidationError("multiaddrs must be an array");
4913
+ }
4914
+ for (const addr of input) {
4915
+ if (typeof addr !== "string" || addr.length === 0) {
4916
+ throw new LocationRecordValidationError(
4917
+ "multiaddr entries must be non-empty strings"
4918
+ );
4919
+ }
4920
+ try {
4921
+ (0, import_multiaddr.multiaddr)(addr);
4922
+ } catch {
4923
+ throw new LocationRecordValidationError(`invalid multiaddr: ${addr}`);
4924
+ }
4925
+ }
4926
+ }
4927
+ async function verifyPkhSignature(did, payload, signature) {
4928
+ const address = did.split(":").at(-1);
4929
+ if (!address || !/^0x[a-fA-F0-9]{40}$/.test(address)) {
4930
+ throw new LocationRecordValidationError(
4931
+ "did:pkh subject must end with an EVM address"
4932
+ );
4933
+ }
4934
+ if (!/^0x[0-9a-fA-F]+$/.test(signature)) {
4935
+ throw new LocationRecordValidationError("did:pkh signature must be hex");
4936
+ }
4937
+ return (0, import_viem.verifyMessage)({
4938
+ address,
4939
+ message: payload,
4940
+ signature
4941
+ });
4942
+ }
4943
+ function verifyDidKeySignature(did, payload, signature) {
4944
+ const publicKey = ed25519PublicKeyFromDidKey(did);
4945
+ const signatureBytes = decodeBase64Url(signature);
4946
+ if (signatureBytes.length !== 64) {
4947
+ throw new LocationRecordValidationError(
4948
+ "did:key signature must be a base64url Ed25519 signature"
4949
+ );
4950
+ }
4951
+ return import_ed25519.ed25519.verify(
4952
+ signatureBytes,
4953
+ new TextEncoder().encode(payload),
4954
+ publicKey
4955
+ );
4956
+ }
4957
+ function ed25519PublicKeyFromDidKey(did) {
4958
+ const identifier = did.slice("did:key:".length);
4959
+ if (!identifier.startsWith("z")) {
4960
+ throw new LocationRecordValidationError(
4961
+ "did:key must use base58btc multibase"
4962
+ );
4963
+ }
4964
+ const bytes = import_basics.bases.base58btc.decode(identifier);
4965
+ if (bytes.length !== 34 || bytes[0] !== 237 || bytes[1] !== 1) {
4966
+ throw new LocationRecordValidationError(
4967
+ "did:key must be an Ed25519 public key"
4968
+ );
4969
+ }
4970
+ return bytes.slice(2);
4971
+ }
4972
+ function base64UrlEncode2(bytes) {
4973
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4974
+ let output = "";
4975
+ for (let i = 0; i < bytes.length; i += 3) {
4976
+ const a = bytes[i];
4977
+ const b = bytes[i + 1];
4978
+ const c = bytes[i + 2];
4979
+ const triplet = a << 16 | (b ?? 0) << 8 | (c ?? 0);
4980
+ output += alphabet[triplet >> 18 & 63];
4981
+ output += alphabet[triplet >> 12 & 63];
4982
+ if (i + 1 < bytes.length) {
4983
+ output += alphabet[triplet >> 6 & 63];
4984
+ }
4985
+ if (i + 2 < bytes.length) {
4986
+ output += alphabet[triplet & 63];
4987
+ }
4988
+ }
4989
+ return output;
4990
+ }
4991
+ function decodeBase64Url(value) {
4992
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4993
+ const bytes = [];
4994
+ let buffer = 0;
4995
+ let bits = 0;
4996
+ for (const char of value) {
4997
+ const index = alphabet.indexOf(char);
4998
+ if (index < 0) {
4999
+ throw new LocationRecordValidationError(
5000
+ "did:key signature must be base64url"
5001
+ );
5002
+ }
5003
+ buffer = buffer << 6 | index;
5004
+ bits += 6;
5005
+ if (bits >= 8) {
5006
+ bits -= 8;
5007
+ bytes.push(buffer >> bits & 255);
5008
+ }
5009
+ }
5010
+ return Uint8Array.from(bytes);
5011
+ }
5012
+
4333
5013
  // src/capabilities.ts
4334
5014
  var PermissionNotInManifestError = class extends Error {
4335
5015
  constructor(missing, granted) {
@@ -4451,10 +5131,13 @@ function parseRecapCapabilities(parseWasm, siwe) {
4451
5131
  CapabilityKeyRegistry,
4452
5132
  CapabilityKeyRegistryErrorCodes,
4453
5133
  ClientSessionSchema,
5134
+ CloudLocationResolutionError,
4454
5135
  DEFAULT_DEFAULTS,
4455
5136
  DEFAULT_EXPIRY,
4456
5137
  DEFAULT_MANIFEST_SPACE,
4457
5138
  DEFAULT_MANIFEST_VERSION,
5139
+ DEFAULT_TINYCLOUD_FALLBACK_HOST,
5140
+ DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
4458
5141
  DataVaultService,
4459
5142
  DatabaseHandle,
4460
5143
  DelegationErrorCodes,
@@ -4466,14 +5149,17 @@ function parseRecapCapabilities(parseWasm, siwe) {
4466
5149
  ErrorCodes,
4467
5150
  HooksService,
4468
5151
  KVService,
5152
+ LocationRecordValidationError,
4469
5153
  ManifestValidationError,
4470
5154
  PermissionNotInManifestError,
4471
5155
  PrefixedKVService,
4472
5156
  ProtocolMismatchError,
5157
+ SECRET_NAME_RE,
4473
5158
  SERVICE_LONG_TO_SHORT,
4474
5159
  SERVICE_SHORT_TO_LONG,
4475
5160
  SQLAction,
4476
5161
  SQLService,
5162
+ SecretsService,
4477
5163
  ServiceContext,
4478
5164
  SessionExpiredError,
4479
5165
  SharingService,
@@ -4485,12 +5171,15 @@ function parseRecapCapabilities(parseWasm, siwe) {
4485
5171
  SpaceService,
4486
5172
  TinyCloud,
4487
5173
  UnsupportedFeatureError,
5174
+ VAULT_PERMISSION_SERVICE,
4488
5175
  VaultHeaders,
4489
5176
  VaultPublicSpaceKVActions,
4490
5177
  VersionCheckError,
4491
5178
  activateSessionWithHost,
4492
5179
  applyPrefix,
4493
5180
  buildSpaceUri,
5181
+ canonicalLocationPayload,
5182
+ canonicalizeSecretScope,
4494
5183
  checkNodeInfo,
4495
5184
  composeManifestRequest,
4496
5185
  createCapabilityKeyRegistry,
@@ -4502,23 +5191,36 @@ function parseRecapCapabilities(parseWasm, siwe) {
4502
5191
  defaultSpaceCreationHandler,
4503
5192
  err,
4504
5193
  expandActionShortNames,
5194
+ expandPermissionEntries,
5195
+ expandPermissionEntry,
5196
+ fetchLocationRecord,
4505
5197
  fetchPeerId,
5198
+ httpUrlToMultiaddr,
4506
5199
  isCapabilitySubset,
4507
5200
  loadManifest,
5201
+ locationPayloadForRecord,
4508
5202
  makePublicSpaceId,
4509
5203
  manifestAbilitiesUnion,
5204
+ multiaddrToHttpUrl,
4510
5205
  normalizeDefaults,
4511
5206
  ok,
4512
5207
  parseExpiry,
4513
5208
  parseRecapCapabilities,
4514
5209
  parseSpaceUri,
5210
+ resolveCloudLocation,
4515
5211
  resolveManifest,
5212
+ resolveSecretPath,
5213
+ resolveTinyCloudHosts,
4516
5214
  resourceCapabilitiesToAbilitiesMap,
4517
5215
  resourceCapabilitiesToSpaceAbilitiesMap,
4518
5216
  serviceError,
5217
+ signLocationRecord,
4519
5218
  submitHostDelegation,
4520
5219
  validateClientSession,
5220
+ validateLocationRecord,
5221
+ validateLocationRecordPayload,
4521
5222
  validateManifest,
4522
- validatePersistedSessionData
5223
+ validatePersistedSessionData,
5224
+ verifyLocationRecord
4523
5225
  });
4524
5226
  //# sourceMappingURL=index.cjs.map