@tinycloud/sdk-core 3.0.0-beta.5 → 3.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -103,6 +103,7 @@ __export(policy_exports, {
103
103
  policyV2DigestHex: () => policyV2DigestHex,
104
104
  projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
105
105
  projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
106
+ registerPolicyV3: () => registerPolicyV3,
106
107
  renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
107
108
  requestPolicyChallengeV3: () => requestPolicyChallengeV3,
108
109
  revokePolicyRootV3: () => revokePolicyRootV3,
@@ -3341,7 +3342,8 @@ var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
3341
3342
  var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
3342
3343
  async function requestPolicyChallengeV3(input) {
3343
3344
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3344
- const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
3345
+ const policyRuntimePath = policyRuntimeBasePath(input.policyRuntimePath);
3346
+ const response = await fetchFn(new URL(`${policyRuntimePath}/challenges`, input.nodeOrigin), {
3345
3347
  method: "POST",
3346
3348
  redirect: "error",
3347
3349
  signal: input.signal,
@@ -3354,12 +3356,19 @@ async function requestPolicyChallengeV3(input) {
3354
3356
  throw new Error("policy challenge binding is invalid");
3355
3357
  return value;
3356
3358
  }
3359
+ function policyRuntimeBasePath(value) {
3360
+ const path = value ?? "/policy/v3";
3361
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
3362
+ throw new Error("policy runtime path is invalid");
3363
+ }
3364
+ return path;
3365
+ }
3357
3366
  async function mintPolicySessionV3(input) {
3358
3367
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3359
3368
  const challenge = input.challenge ?? await requestPolicyChallengeV3(input);
3360
3369
  if (challenge.policyCid !== input.policyCid || challenge.recipientDid !== input.recipientDid)
3361
3370
  throw new Error("policy challenge binding is invalid");
3362
- const response = await fetchFn(new URL("/share/v3/policy/delegations", input.nodeOrigin), {
3371
+ const response = await fetchFn(new URL("/policy/v3/delegations", input.nodeOrigin), {
3363
3372
  method: "POST",
3364
3373
  redirect: "error",
3365
3374
  signal: input.signal,
@@ -3421,7 +3430,7 @@ function verifyPolicyRootStatusCheckpointV3(input) {
3421
3430
  }
3422
3431
  async function getPolicyRootStatusV3(input) {
3423
3432
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3424
- const response = await fetchFn(new URL(`/share/v3/policy/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3433
+ const response = await fetchFn(new URL(`/policy/v3/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3425
3434
  method: "GET",
3426
3435
  redirect: "error",
3427
3436
  headers: { accept: "application/json" }
@@ -3480,7 +3489,7 @@ async function renewPolicyRootStatusV3(input) {
3480
3489
  };
3481
3490
  const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
3482
3491
  if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
3483
- const response = await fetchFn(new URL("/share/v3/policy/status", input.nodeOrigin), {
3492
+ const response = await fetchFn(new URL("/policy/v3/status", input.nodeOrigin), {
3484
3493
  method: "POST",
3485
3494
  redirect: "error",
3486
3495
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -3735,6 +3744,133 @@ function contentSourceDigestHex(input) {
3735
3744
  )
3736
3745
  );
3737
3746
  }
3747
+ function exactObject(value, keys, label) {
3748
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
3749
+ throw new Error(`${label} is invalid`);
3750
+ }
3751
+ const record2 = value;
3752
+ if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) {
3753
+ throw new Error(`${label} is invalid`);
3754
+ }
3755
+ return record2;
3756
+ }
3757
+ function didKeyEd25519PublicKey(value) {
3758
+ const principal = value.split("#", 1)[0];
3759
+ if (!principal.startsWith("did:key:")) {
3760
+ throw new Error("policy enforcer binding signer is invalid");
3761
+ }
3762
+ const material = base58btc.decode(principal.slice("did:key:".length));
3763
+ if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
3764
+ throw new Error("policy enforcer binding signer is invalid");
3765
+ }
3766
+ return material.slice(2);
3767
+ }
3768
+ async function registerPolicyV3(input) {
3769
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3770
+ const rootExpiresAt = new Date(input.rootExpiresAt);
3771
+ const canonicalRootExpiresAt = new Date(
3772
+ Math.floor(rootExpiresAt.getTime() / 1e3) * 1e3
3773
+ ).toISOString().replace(/\.000Z$/, "Z");
3774
+ if (!Number.isFinite(rootExpiresAt.getTime()) || canonicalRootExpiresAt !== input.rootExpiresAt || rootExpiresAt.getTime() <= Date.now()) {
3775
+ throw new Error("policy root expiry is invalid");
3776
+ }
3777
+ const bindingResponse = await fetchFn(
3778
+ new URL("/policy/v3/enforcer-bindings", input.nodeOrigin),
3779
+ {
3780
+ method: "POST",
3781
+ redirect: "error",
3782
+ signal: input.signal,
3783
+ headers: { accept: "application/json", "content-type": "application/json" },
3784
+ body: JSON.stringify({
3785
+ rootExpiresAt: input.rootExpiresAt,
3786
+ enforcerDid: input.enforcerDid
3787
+ })
3788
+ }
3789
+ );
3790
+ if (!bindingResponse.ok) {
3791
+ throw new Error(`policy enforcer binding rejected (${bindingResponse.status})`);
3792
+ }
3793
+ const binding = exactObject(
3794
+ await bindingResponse.json(),
3795
+ [
3796
+ "schema",
3797
+ "enforcerDid",
3798
+ "nodeAudience",
3799
+ "attestationBindingDigestHex",
3800
+ "issuedAt",
3801
+ "expiresAt",
3802
+ "signature"
3803
+ ],
3804
+ "policy enforcer binding"
3805
+ );
3806
+ const signature = exactObject(
3807
+ binding.signature,
3808
+ ["suite", "signerDid", "value"],
3809
+ "policy enforcer binding signature"
3810
+ );
3811
+ const expectedBindingDigestHex = hex(
3812
+ (0, import_sha256.sha256)(
3813
+ new TextEncoder().encode(
3814
+ jcsCanonicalize({
3815
+ enforcerDid: input.enforcerDid,
3816
+ nodeAudience: input.expectedNodeAudience
3817
+ })
3818
+ )
3819
+ )
3820
+ );
3821
+ if (binding.schema !== ATTESTED_ENFORCER_BINDING_V2_SCHEMA || binding.enforcerDid !== input.enforcerDid || binding.nodeAudience !== input.expectedNodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || binding.expiresAt !== input.rootExpiresAt || typeof binding.issuedAt !== "string" || Date.parse(binding.issuedAt) > Date.now() || signature.suite !== "Ed25519" || signature.signerDid !== input.expectedNodeAudience || typeof signature.value !== "string") {
3822
+ throw new Error("policy enforcer binding is invalid");
3823
+ }
3824
+ const { signature: _signature, ...unsignedBinding } = binding;
3825
+ const signedBinding = (0, import_sha256.sha256)(
3826
+ new TextEncoder().encode(
3827
+ `xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0${jcsCanonicalize(unsignedBinding)}`
3828
+ )
3829
+ );
3830
+ if (!import_ed255192.ed25519.verify(
3831
+ decodeBase64Url(signature.value),
3832
+ signedBinding,
3833
+ didKeyEd25519PublicKey(input.expectedNodeAudience),
3834
+ { zip215: false }
3835
+ )) {
3836
+ throw new Error("policy enforcer binding signature is invalid");
3837
+ }
3838
+ const response = await fetchFn(
3839
+ new URL("/policy/v3/policies", input.nodeOrigin),
3840
+ {
3841
+ method: "POST",
3842
+ redirect: "error",
3843
+ signal: input.signal,
3844
+ headers: { accept: "application/json", "content-type": "application/json" },
3845
+ body: JSON.stringify({
3846
+ policyCid: input.policyCid,
3847
+ policy: input.policy,
3848
+ policyRoot: input.policyRoot.authorization.replace(/^Bearer\s+/i, ""),
3849
+ enforcementRoot: input.enforcementRoot.authorization.replace(/^Bearer\s+/i, ""),
3850
+ contentSourceDigestHex: input.contentSourceDigestHex,
3851
+ nativeProjectionHashHex: input.nativeProjectionHashHex,
3852
+ attestedEnforcerBinding: binding
3853
+ })
3854
+ }
3855
+ );
3856
+ if (!response.ok) {
3857
+ throw new Error(`policy registration rejected (${response.status})`);
3858
+ }
3859
+ const receipt = exactObject(
3860
+ await response.json(),
3861
+ ["policyCid", "policyRootCid", "enforcementRootCid"],
3862
+ "policy registration response"
3863
+ );
3864
+ if (receipt.policyCid !== input.policyCid || receipt.policyRootCid !== input.policyRoot.cid || receipt.enforcementRootCid !== input.enforcementRoot.cid) {
3865
+ throw new Error("policy registration response binding is invalid");
3866
+ }
3867
+ return {
3868
+ policyCid: input.policyCid,
3869
+ policyRootCid: input.policyRoot.cid,
3870
+ enforcementRootCid: input.enforcementRoot.cid,
3871
+ attestedEnforcerBinding: binding
3872
+ };
3873
+ }
3738
3874
  function policyDigestHex(policy) {
3739
3875
  const canonicalPolicy = {
3740
3876
  ...policy,
@@ -4420,6 +4556,7 @@ async function admitPolicyCredentialV3(input) {
4420
4556
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4421
4557
  const challenge = await requestPolicyChallengeV3({
4422
4558
  nodeOrigin,
4559
+ policyRuntimePath: input.policyRuntimePath,
4423
4560
  policyCid: input.policyCid,
4424
4561
  recipientDid: input.credential.holderDid,
4425
4562
  requestedCapabilities: input.requestedCapabilities,
@@ -4432,7 +4569,7 @@ async function admitPolicyCredentialV3(input) {
4432
4569
  challenge
4433
4570
  });
4434
4571
  const response = await fetchFn(
4435
- new URL("/share/v3/policy/delegations", nodeOrigin),
4572
+ new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
4436
4573
  {
4437
4574
  method: "POST",
4438
4575
  redirect: "error",
@@ -4477,6 +4614,7 @@ async function admitPolicyCredentialV4(input) {
4477
4614
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4478
4615
  const challenge = await requestPolicyChallengeV3({
4479
4616
  nodeOrigin,
4617
+ policyRuntimePath: input.policyRuntimePath,
4480
4618
  policyCid: input.policyCid,
4481
4619
  recipientDid: input.credential.holderDid,
4482
4620
  requestedCapabilities: input.requestedCapabilities,
@@ -4488,7 +4626,7 @@ async function admitPolicyCredentialV4(input) {
4488
4626
  policy,
4489
4627
  challenge
4490
4628
  });
4491
- const response = await fetchFn(new URL("/share/v3/policy/delegations", nodeOrigin), {
4629
+ const response = await fetchFn(new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin), {
4492
4630
  method: "POST",
4493
4631
  redirect: "error",
4494
4632
  signal: input.signal,
@@ -4515,7 +4653,21 @@ async function admitPolicyCredentialV4(input) {
4515
4653
  enforcerDid: input.expectedEnforcerDid
4516
4654
  });
4517
4655
  if (session.cid !== value.sessionCid || session.aud !== input.credential.holderDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.credential.holderDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation)) throw new Error("policy delegation signed binding is invalid");
4656
+ const importResponse = await fetchFn(new URL("/delegate", nodeOrigin), {
4657
+ method: "POST",
4658
+ redirect: "error",
4659
+ signal: input.signal,
4660
+ headers: { Authorization: session.authorization }
4661
+ });
4662
+ if (!importResponse.ok) throw new Error(`delegation import rejected (${importResponse.status})`);
4518
4663
  input.signal?.throwIfAborted();
4519
- return Object.freeze({ challenge, presentation, session });
4664
+ return Object.freeze({ challenge, presentation, session, delegationImported: true });
4665
+ }
4666
+ function policyRuntimeBasePath2(value) {
4667
+ const path = value ?? "/policy/v3";
4668
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
4669
+ throw new Error("policy runtime path is invalid");
4670
+ }
4671
+ return path;
4520
4672
  }
4521
4673
  //# sourceMappingURL=index.cjs.map