@tinycloud/sdk-core 3.1.0-beta.8 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4207,6 +4207,32 @@ function parseCompactUcanAuthorization(input, expectedCid) {
4207
4207
  throw new Error("compact UCAN CID does not match exact Authorization bytes");
4208
4208
  return { authorization: input, cid: cid2, header, payload };
4209
4209
  }
4210
+ var SignedCompactAttenuationSchema = z2.record(z2.record(z2.array(z2.unknown()).min(1)));
4211
+ function parseSignedCompactUcanAttenuation(input, expectedCid) {
4212
+ if (typeof input !== "string" || /\s/.test(input))
4213
+ throw new Error("Authorization must be compact UCAN bytes");
4214
+ const segments = input.split(".");
4215
+ if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
4216
+ throw new Error("Authorization must have three compact segments");
4217
+ const [headerSegment, payloadSegment, signatureSegment] = segments;
4218
+ const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64Url2(headerSegment)));
4219
+ const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64Url2(payloadSegment)));
4220
+ if (!isRecordValue(headerValue) || !isRecordValue(headerValue.jwk) || headerValue.alg !== "EdDSA" || headerValue.typ !== "JWT" || headerValue.ucv !== "0.10.0" || headerValue.jwk.kty !== "OKP" || headerValue.jwk.crv !== "Ed25519" || !isRecordValue(payloadValue) || typeof payloadValue.iss !== "string")
4221
+ throw new Error("Authorization has an invalid signed UCAN header or issuer");
4222
+ const att = SignedCompactAttenuationSchema.parse(payloadValue.att);
4223
+ const principal = payloadValue.iss.split("#", 1)[0];
4224
+ const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
4225
+ const publicKey = didMaterial.length === 34 && didMaterial[0] === 237 && didMaterial[1] === 1 ? didMaterial.slice(2) : new Uint8Array();
4226
+ const jwkKey = typeof headerValue.jwk.x === "string" ? decodeBase64Url2(headerValue.jwk.x) : new Uint8Array();
4227
+ if (publicKey.length !== 32 || !equalBytes(publicKey, jwkKey))
4228
+ throw new Error("compact UCAN JWK does not bind issuer");
4229
+ const signature = decodeBase64Url2(signatureSegment);
4230
+ if (!ed255193.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
4231
+ throw new Error("compact UCAN signature is invalid");
4232
+ const cid2 = CID.createV1(85, create(30, blake3(new TextEncoder().encode(input)))).toString();
4233
+ if (expectedCid !== void 0 && cid2 !== expectedCid) throw new Error("compact UCAN CID does not match exact Authorization bytes");
4234
+ return { cid: cid2, payload: { att } };
4235
+ }
4210
4236
  function parsePolicySessionUcan(authorization, expectedProofs) {
4211
4237
  const parsed = parseCompactUcanAuthorization(authorization);
4212
4238
  const fact = parsed.payload.fct[0];
@@ -6694,7 +6720,7 @@ var DelegationManager = class {
6694
6720
  * }
6695
6721
  * ```
6696
6722
  */
6697
- async revoke(cid2) {
6723
+ async revoke(cid2, options2) {
6698
6724
  if (!cid2) {
6699
6725
  return {
6700
6726
  ok: false,
@@ -6714,15 +6740,20 @@ var DelegationManager = class {
6714
6740
  )
6715
6741
  };
6716
6742
  }
6717
- const headers = this.invokeAny(
6718
- this.session,
6719
- [{
6720
- resource: `urn:cid:${cid2}`,
6721
- service: "delegation",
6722
- path: "",
6723
- action: DelegationAction.REVOKE
6724
- }]
6725
- );
6743
+ const entry = {
6744
+ resource: `urn:cid:${cid2}`,
6745
+ ...options2?.targetSpaceId === void 0 ? {} : { spaceId: options2.targetSpaceId },
6746
+ service: "delegation",
6747
+ path: "",
6748
+ action: DelegationAction.REVOKE
6749
+ };
6750
+ if (options2?.authorityCid !== void 0) {
6751
+ Object.defineProperty(entry, "revokeAuthorityCid", {
6752
+ value: options2.authorityCid,
6753
+ enumerable: false
6754
+ });
6755
+ }
6756
+ const headers = this.invokeAny(this.session, [entry]);
6726
6757
  const response = await this.fetchFn(`${this.host}/revoke`, {
6727
6758
  method: "POST",
6728
6759
  headers
@@ -6880,7 +6911,8 @@ var DelegationManager = class {
6880
6911
  )
6881
6912
  };
6882
6913
  }
6883
- if (!this.accountSpaceId) {
6914
+ const accountSpaceId = this.accountSpaceId;
6915
+ if (!accountSpaceId) {
6884
6916
  return {
6885
6917
  ok: false,
6886
6918
  error: createError(
@@ -6891,7 +6923,7 @@ var DelegationManager = class {
6891
6923
  }
6892
6924
  try {
6893
6925
  const invocationHeaders = this.invokeAny(this.session, [{
6894
- spaceId: this.accountSpaceId,
6926
+ spaceId: accountSpaceId,
6895
6927
  service: "delegation",
6896
6928
  path: "",
6897
6929
  action: DelegationAction.LIST
@@ -8189,8 +8221,17 @@ function canonicalizeRecapCaveats(caveats) {
8189
8221
  }
8190
8222
  return `[${branches.join(",")}]`;
8191
8223
  }
8224
+ var EXPLICIT_ONLY_ACTIONS = {
8225
+ "tinycloud.kv/sync": true,
8226
+ "tinycloud.kv/retain": true
8227
+ };
8228
+ function isExplicitOnlyAction(action) {
8229
+ return Object.prototype.hasOwnProperty.call(EXPLICIT_ONLY_ACTIONS, action);
8230
+ }
8192
8231
  function actionContains(grantedAction, requestedAction) {
8193
- if (grantedAction === "*" || grantedAction === requestedAction) return true;
8232
+ if (grantedAction === requestedAction) return true;
8233
+ if (isExplicitOnlyAction(requestedAction)) return false;
8234
+ if (grantedAction === "*") return true;
8194
8235
  if (!grantedAction.endsWith("/*")) return false;
8195
8236
  const service = grantedAction.slice(0, -2);
8196
8237
  return requestedAction === service || requestedAction.startsWith(`${service}/`);
@@ -10877,7 +10918,9 @@ var SharingService = class {
10877
10918
  if (delegation.allowSubDelegation === false) continue;
10878
10919
  if (!this.pathMatches(delegation.path || "", path)) continue;
10879
10920
  const delegationActions = delegation.actions || [];
10880
- if (!actions.every((action) => delegationActions.includes(action) || delegationActions.includes("*"))) {
10921
+ if (!actions.every(
10922
+ (action) => delegationActions.some((granted) => actionContains(granted, action))
10923
+ )) {
10881
10924
  continue;
10882
10925
  }
10883
10926
  if ((delegation.caveats?.length ?? 0) > 0) {
@@ -13965,6 +14008,56 @@ var AccountService = class {
13965
14008
  await this.upsertSpacesIndexQuietly(registered);
13966
14009
  return ok3({ spaces: registered, recoveredFromBatchError: batchResult.error });
13967
14010
  },
14011
+ /**
14012
+ * Register only spaces without a registry record (TC-800). Existing
14013
+ * records, including renamed or archived ones, are kept byte-for-byte.
14014
+ * Bootstrap repair uses this on populated accounts.
14015
+ */
14016
+ registerMissing: async (spaces) => {
14017
+ if (spaces.length === 0) return ok3([]);
14018
+ await this.config.ensureAccountSpaceHosted?.();
14019
+ const kvResult = this.accountKV();
14020
+ if (!kvResult.ok) return kvResult;
14021
+ const kv = kvResult.data;
14022
+ const stored = spaces.map((space) => spaceRecordFromInput(space));
14023
+ const keys = stored.map((record2) => spaceKey(record2.space_id));
14024
+ const read2 = await kv.batchGet(keys);
14025
+ if (!read2.ok) return accountErr(read2.error);
14026
+ const byKey = new Map(read2.data.results.map((result) => [result.key, result.result]));
14027
+ const final = new Array(keys.length);
14028
+ const missing = [];
14029
+ for (let i = 0; i < keys.length; i++) {
14030
+ const key = keys[i];
14031
+ const result = byKey.get(key);
14032
+ if (!result) {
14033
+ return err3(serviceError4(
14034
+ ErrorCodes4.NETWORK_ERROR,
14035
+ `KV batch read omitted requested key ${JSON.stringify(key)}`,
14036
+ SERVICE_NAME2
14037
+ ));
14038
+ }
14039
+ if (result.ok) {
14040
+ final[i] = spaceFromRecord(key, result.data.data);
14041
+ } else if (result.error.code === ErrorCodes4.KV_NOT_FOUND) {
14042
+ missing.push({ index: i, key, record: stored[i] });
14043
+ } else {
14044
+ return accountErr(result.error);
14045
+ }
14046
+ }
14047
+ const creates = await Promise.all(missing.map(async ({ index, key, record: record2 }) => {
14048
+ const written = await kv.put(key, record2, { ifNoneMatch: "*" });
14049
+ if (written.ok) return { index, result: ok3(spaceFromRecord(key, record2)) };
14050
+ const raced = await kv.get(key);
14051
+ if (raced.ok) return { index, result: ok3(spaceFromRecord(key, raced.data.data)) };
14052
+ return { index, result: err3(written.error) };
14053
+ }));
14054
+ for (const { index, result } of creates) {
14055
+ if (!result.ok) return accountErr(result.error);
14056
+ final[index] = result.data;
14057
+ }
14058
+ await this.upsertSpacesIndexQuietly(final);
14059
+ return ok3(final);
14060
+ },
13968
14061
  syncAccessible: async () => {
13969
14062
  const synced = await this.syncAccessibleSpaces({ tolerateStorageFull: false });
13970
14063
  return synced.ok ? ok3(synced.data.spaces) : synced;
@@ -16030,10 +16123,12 @@ import {
16030
16123
  BOOTSTRAP_SESSION_REQUESTS,
16031
16124
  BOOTSTRAP_SPACE_MANIFESTS,
16032
16125
  BOOTSTRAP_SPACE_NAMES,
16126
+ AGENTS_SPACE,
16033
16127
  SECRET_RECORDS_SCHEMA,
16034
16128
  TINYCLOUD_ACCOUNT_SPACE_MANIFEST,
16035
16129
  TINYCLOUD_APPLICATIONS_SPACE_MANIFEST,
16036
16130
  TINYCLOUD_DEFAULT_SPACE_MANIFEST,
16131
+ TINYCLOUD_AGENTS_SPACE_MANIFEST,
16037
16132
  TINYCLOUD_PUBLIC_SPACE_MANIFEST,
16038
16133
  TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
16039
16134
  bootstrapEncryptionNetworkId,
@@ -18528,6 +18623,7 @@ export {
18528
18623
  ACCOUNT_MANIFEST_PERMISSIONS2 as ACCOUNT_MANIFEST_PERMISSIONS,
18529
18624
  ACCOUNT_REGISTRY_PATH,
18530
18625
  ACCOUNT_REGISTRY_SPACE,
18626
+ AGENTS_SPACE,
18531
18627
  ATTESTED_ENFORCER_BINDING_V2_SCHEMA,
18532
18628
  AccountService,
18533
18629
  AutoApproveSpaceCreationHandler,
@@ -18700,6 +18796,7 @@ export {
18700
18796
  SpaceErrorCodes,
18701
18797
  SpaceService,
18702
18798
  TINYCLOUD_ACCOUNT_SPACE_MANIFEST,
18799
+ TINYCLOUD_AGENTS_SPACE_MANIFEST,
18703
18800
  TINYCLOUD_APPLICATIONS_SPACE_MANIFEST,
18704
18801
  TINYCLOUD_CANONICAL_IDENTITY_CLAIM,
18705
18802
  TINYCLOUD_DEFAULT_SPACE_MANIFEST,
@@ -18844,6 +18941,7 @@ export {
18844
18941
  isCapabilitySubset,
18845
18942
  isDigest,
18846
18943
  isEvmAddress,
18944
+ isExplicitOnlyAction,
18847
18945
  isNetworkId,
18848
18946
  isPlausibleOpenKeyActionId,
18849
18947
  isStorageFullError2 as isStorageFullError,
@@ -18882,6 +18980,7 @@ export {
18882
18980
  parseSecretCatalogKey,
18883
18981
  parseShareArtifact,
18884
18982
  parseShareUrl,
18983
+ parseSignedCompactUcanAttenuation,
18885
18984
  parseSpaceUri,
18886
18985
  pkhDid,
18887
18986
  policyCidFromCanonicalBytes,