@tinycloud/sdk-core 3.1.0-beta.10 → 3.1.0-beta.12

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
@@ -43,6 +43,7 @@ __export(index_exports, {
43
43
  ACCOUNT_MANIFEST_PERMISSIONS: () => import_bootstrap4.ACCOUNT_MANIFEST_PERMISSIONS,
44
44
  ACCOUNT_REGISTRY_PATH: () => ACCOUNT_REGISTRY_PATH,
45
45
  ACCOUNT_REGISTRY_SPACE: () => ACCOUNT_REGISTRY_SPACE,
46
+ AGENTS_SPACE: () => import_bootstrap4.AGENTS_SPACE,
46
47
  ATTESTED_ENFORCER_BINDING_V2_SCHEMA: () => ATTESTED_ENFORCER_BINDING_V2_SCHEMA,
47
48
  AccountService: () => AccountService,
48
49
  AutoApproveSpaceCreationHandler: () => AutoApproveSpaceCreationHandler,
@@ -215,6 +216,7 @@ __export(index_exports, {
215
216
  SpaceErrorCodes: () => SpaceErrorCodes,
216
217
  SpaceService: () => SpaceService,
217
218
  TINYCLOUD_ACCOUNT_SPACE_MANIFEST: () => import_bootstrap4.TINYCLOUD_ACCOUNT_SPACE_MANIFEST,
219
+ TINYCLOUD_AGENTS_SPACE_MANIFEST: () => import_bootstrap4.TINYCLOUD_AGENTS_SPACE_MANIFEST,
218
220
  TINYCLOUD_APPLICATIONS_SPACE_MANIFEST: () => import_bootstrap4.TINYCLOUD_APPLICATIONS_SPACE_MANIFEST,
219
221
  TINYCLOUD_CANONICAL_IDENTITY_CLAIM: () => TINYCLOUD_CANONICAL_IDENTITY_CLAIM,
220
222
  TINYCLOUD_DEFAULT_SPACE_MANIFEST: () => import_bootstrap4.TINYCLOUD_DEFAULT_SPACE_MANIFEST,
@@ -398,6 +400,7 @@ __export(index_exports, {
398
400
  parseSecretCatalogKey: () => import_sdk_services9.parseSecretCatalogKey,
399
401
  parseShareArtifact: () => parseShareArtifact,
400
402
  parseShareUrl: () => parseShareUrl,
403
+ parseSignedCompactUcanAttenuation: () => parseSignedCompactUcanAttenuation,
401
404
  parseSpaceUri: () => parseSpaceUri,
402
405
  pkhDid: () => pkhDid,
403
406
  policyCidFromCanonicalBytes: () => policyCidFromCanonicalBytes,
@@ -4680,6 +4683,32 @@ function parseCompactUcanAuthorization(input, expectedCid) {
4680
4683
  throw new Error("compact UCAN CID does not match exact Authorization bytes");
4681
4684
  return { authorization: input, cid: cid2, header, payload };
4682
4685
  }
4686
+ var SignedCompactAttenuationSchema = import_zod2.z.record(import_zod2.z.record(import_zod2.z.array(import_zod2.z.unknown()).min(1)));
4687
+ function parseSignedCompactUcanAttenuation(input, expectedCid) {
4688
+ if (typeof input !== "string" || /\s/.test(input))
4689
+ throw new Error("Authorization must be compact UCAN bytes");
4690
+ const segments = input.split(".");
4691
+ if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
4692
+ throw new Error("Authorization must have three compact segments");
4693
+ const [headerSegment, payloadSegment, signatureSegment] = segments;
4694
+ const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64Url2(headerSegment)));
4695
+ const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64Url2(payloadSegment)));
4696
+ 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")
4697
+ throw new Error("Authorization has an invalid signed UCAN header or issuer");
4698
+ const att = SignedCompactAttenuationSchema.parse(payloadValue.att);
4699
+ const principal = payloadValue.iss.split("#", 1)[0];
4700
+ const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
4701
+ const publicKey = didMaterial.length === 34 && didMaterial[0] === 237 && didMaterial[1] === 1 ? didMaterial.slice(2) : new Uint8Array();
4702
+ const jwkKey = typeof headerValue.jwk.x === "string" ? decodeBase64Url2(headerValue.jwk.x) : new Uint8Array();
4703
+ if (publicKey.length !== 32 || !equalBytes(publicKey, jwkKey))
4704
+ throw new Error("compact UCAN JWK does not bind issuer");
4705
+ const signature = decodeBase64Url2(signatureSegment);
4706
+ if (!import_ed255193.ed25519.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
4707
+ throw new Error("compact UCAN signature is invalid");
4708
+ const cid2 = CID.createV1(85, create(30, (0, import_blake3.blake3)(new TextEncoder().encode(input)))).toString();
4709
+ if (expectedCid !== void 0 && cid2 !== expectedCid) throw new Error("compact UCAN CID does not match exact Authorization bytes");
4710
+ return { cid: cid2, payload: { att } };
4711
+ }
4683
4712
  function parsePolicySessionUcan(authorization, expectedProofs) {
4684
4713
  const parsed = parseCompactUcanAuthorization(authorization);
4685
4714
  const fact = parsed.payload.fct[0];
@@ -7167,7 +7196,7 @@ var DelegationManager = class {
7167
7196
  * }
7168
7197
  * ```
7169
7198
  */
7170
- async revoke(cid2) {
7199
+ async revoke(cid2, options2) {
7171
7200
  if (!cid2) {
7172
7201
  return {
7173
7202
  ok: false,
@@ -7187,15 +7216,20 @@ var DelegationManager = class {
7187
7216
  )
7188
7217
  };
7189
7218
  }
7190
- const headers = this.invokeAny(
7191
- this.session,
7192
- [{
7193
- resource: `urn:cid:${cid2}`,
7194
- service: "delegation",
7195
- path: "",
7196
- action: DelegationAction.REVOKE
7197
- }]
7198
- );
7219
+ const entry = {
7220
+ resource: `urn:cid:${cid2}`,
7221
+ ...options2?.targetSpaceId === void 0 ? {} : { spaceId: options2.targetSpaceId },
7222
+ service: "delegation",
7223
+ path: "",
7224
+ action: DelegationAction.REVOKE
7225
+ };
7226
+ if (options2?.authorityCid !== void 0) {
7227
+ Object.defineProperty(entry, "revokeAuthorityCid", {
7228
+ value: options2.authorityCid,
7229
+ enumerable: false
7230
+ });
7231
+ }
7232
+ const headers = this.invokeAny(this.session, [entry]);
7199
7233
  const response = await this.fetchFn(`${this.host}/revoke`, {
7200
7234
  method: "POST",
7201
7235
  headers
@@ -7353,7 +7387,8 @@ var DelegationManager = class {
7353
7387
  )
7354
7388
  };
7355
7389
  }
7356
- if (!this.accountSpaceId) {
7390
+ const accountSpaceId = this.accountSpaceId;
7391
+ if (!accountSpaceId) {
7357
7392
  return {
7358
7393
  ok: false,
7359
7394
  error: createError(
@@ -7364,7 +7399,7 @@ var DelegationManager = class {
7364
7399
  }
7365
7400
  try {
7366
7401
  const invocationHeaders = this.invokeAny(this.session, [{
7367
- spaceId: this.accountSpaceId,
7402
+ spaceId: accountSpaceId,
7368
7403
  service: "delegation",
7369
7404
  path: "",
7370
7405
  action: DelegationAction.LIST
@@ -14408,6 +14443,56 @@ var AccountService = class {
14408
14443
  await this.upsertSpacesIndexQuietly(registered);
14409
14444
  return (0, import_sdk_services7.ok)({ spaces: registered, recoveredFromBatchError: batchResult.error });
14410
14445
  },
14446
+ /**
14447
+ * Register only spaces without a registry record (TC-800). Existing
14448
+ * records, including renamed or archived ones, are kept byte-for-byte.
14449
+ * Bootstrap repair uses this on populated accounts.
14450
+ */
14451
+ registerMissing: async (spaces) => {
14452
+ if (spaces.length === 0) return (0, import_sdk_services7.ok)([]);
14453
+ await this.config.ensureAccountSpaceHosted?.();
14454
+ const kvResult = this.accountKV();
14455
+ if (!kvResult.ok) return kvResult;
14456
+ const kv = kvResult.data;
14457
+ const stored = spaces.map((space) => spaceRecordFromInput(space));
14458
+ const keys = stored.map((record2) => spaceKey(record2.space_id));
14459
+ const read2 = await kv.batchGet(keys);
14460
+ if (!read2.ok) return accountErr(read2.error);
14461
+ const byKey = new Map(read2.data.results.map((result) => [result.key, result.result]));
14462
+ const final = new Array(keys.length);
14463
+ const missing = [];
14464
+ for (let i = 0; i < keys.length; i++) {
14465
+ const key = keys[i];
14466
+ const result = byKey.get(key);
14467
+ if (!result) {
14468
+ return (0, import_sdk_services7.err)((0, import_sdk_services7.serviceError)(
14469
+ import_sdk_services7.ErrorCodes.NETWORK_ERROR,
14470
+ `KV batch read omitted requested key ${JSON.stringify(key)}`,
14471
+ SERVICE_NAME2
14472
+ ));
14473
+ }
14474
+ if (result.ok) {
14475
+ final[i] = spaceFromRecord(key, result.data.data);
14476
+ } else if (result.error.code === import_sdk_services7.ErrorCodes.KV_NOT_FOUND) {
14477
+ missing.push({ index: i, key, record: stored[i] });
14478
+ } else {
14479
+ return accountErr(result.error);
14480
+ }
14481
+ }
14482
+ const creates = await Promise.all(missing.map(async ({ index, key, record: record2 }) => {
14483
+ const written = await kv.put(key, record2, { ifNoneMatch: "*" });
14484
+ if (written.ok) return { index, result: (0, import_sdk_services7.ok)(spaceFromRecord(key, record2)) };
14485
+ const raced = await kv.get(key);
14486
+ if (raced.ok) return { index, result: (0, import_sdk_services7.ok)(spaceFromRecord(key, raced.data.data)) };
14487
+ return { index, result: (0, import_sdk_services7.err)(written.error) };
14488
+ }));
14489
+ for (const { index, result } of creates) {
14490
+ if (!result.ok) return accountErr(result.error);
14491
+ final[index] = result.data;
14492
+ }
14493
+ await this.upsertSpacesIndexQuietly(final);
14494
+ return (0, import_sdk_services7.ok)(final);
14495
+ },
14411
14496
  syncAccessible: async () => {
14412
14497
  const synced = await this.syncAccessibleSpaces({ tolerateStorageFull: false });
14413
14498
  return synced.ok ? (0, import_sdk_services7.ok)(synced.data.spaces) : synced;