@tinycloud/sdk-core 3.10.0 → 3.11.0-beta.1

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
@@ -140,6 +140,8 @@ __export(index_exports, {
140
140
  MAX_SECRET_SCOPE_LENGTH: () => import_sdk_services10.MAX_SECRET_SCOPE_LENGTH,
141
141
  MAX_SHARE_ARTIFACT_BYTES: () => MAX_SHARE_ARTIFACT_BYTES,
142
142
  MAX_SHARE_CONTENT_BYTES: () => MAX_SHARE_CONTENT_BYTES,
143
+ MAX_SIWE_EXPIRY_MS: () => MAX_SIWE_EXPIRY_MS,
144
+ MAX_UCAN_EXPIRY_MS: () => MAX_UCAN_EXPIRY_MS,
143
145
  ManifestValidationError: () => ManifestValidationError,
144
146
  MemorySenderShareKeyStorage: () => MemorySenderShareKeyStorage,
145
147
  MemorySenderShareRecordStorage: () => MemorySenderShareRecordStorage,
@@ -259,6 +261,7 @@ __export(index_exports, {
259
261
  admitPolicyCredentialV4: () => admitPolicyCredentialV4,
260
262
  appSecretScope: () => import_sdk_services10.appSecretScope,
261
263
  applyPrefix: () => applyPrefix,
264
+ assertExpiryWithinTechnicalLimit: () => assertExpiryWithinTechnicalLimit,
262
265
  assertSpaceCreationAllowed: () => assertSpaceCreationAllowed,
263
266
  authorizationVerdictOf: () => import_sdk_services10.authorizationVerdictOf,
264
267
  bootstrapEncryptionNetworkId: () => import_bootstrap4.bootstrapEncryptionNetworkId,
@@ -288,6 +291,7 @@ __export(index_exports, {
288
291
  canonicalizeSecretScope: () => import_sdk_services10.canonicalizeSecretScope,
289
292
  canonicalizeSignedObjectUnsigned: () => canonicalizeSignedObjectUnsigned,
290
293
  canonicalizeUnifiedPolicyCapability: () => canonicalizeUnifiedPolicyCapability,
294
+ checkChangedExpiration: () => checkChangedExpiration,
291
295
  checkDecryptInvocationInput: () => import_sdk_services10.checkDecryptInvocationInput,
292
296
  checkNodeInfo: () => checkNodeInfo,
293
297
  classifyRegistryLookup: () => classifyRegistryLookup,
@@ -475,6 +479,7 @@ __export(index_exports, {
475
479
  signedObjectIdFor: () => signedObjectIdFor,
476
480
  storageUsageState: () => import_sdk_services10.storageUsageState,
477
481
  submitHostDelegation: () => submitHostDelegation,
482
+ technicalExpiryRefusal: () => technicalExpiryRefusal,
478
483
  tinyCloudDebugLogger: () => import_sdk_services10.tinyCloudDebugLogger,
479
484
  toSignedObjectError: () => toSignedObjectError,
480
485
  unauthorizedRecapCapabilities: () => unauthorizedRecapCapabilities,
@@ -11126,15 +11131,27 @@ var SIGNED_READ_URL_MS = 5 * 60 * 1e3;
11126
11131
  var SESSION_MS = 30 * 24 * 60 * 60 * 1e3;
11127
11132
  var SHARE_MS = 7 * 24 * 60 * 60 * 1e3;
11128
11133
  var APP_MS = 30 * 24 * 60 * 60 * 1e3;
11129
- var MAX_MS = 10 * 365 * 24 * 60 * 60 * 1e3;
11130
11134
  var EXPIRY = {
11131
11135
  EPHEMERAL_MS,
11132
11136
  SIGNED_READ_URL_MS,
11133
11137
  SESSION_MS,
11134
11138
  SHARE_MS,
11135
- APP_MS,
11136
- MAX_MS
11139
+ APP_MS
11137
11140
  };
11141
+ var MAX_SIWE_EXPIRY_MS = 253402300799e3;
11142
+ var MAX_UCAN_EXPIRY_MS = 9007199254e3;
11143
+ function technicalExpiryRefusal(expiresAt, kind) {
11144
+ const ms2 = Number(expiresAt);
11145
+ const siwe = kind === "siwe";
11146
+ const last = siwe ? "9999-12-31" : "2255-06-05";
11147
+ if (!Number.isFinite(ms2) || ms2 < 0) return `expiry is not a valid date or is too far away to hold; choose one before ${last}`;
11148
+ if (ms2 <= (siwe ? MAX_SIWE_EXPIRY_MS : MAX_UCAN_EXPIRY_MS)) return null;
11149
+ return `expiry is later than ${last}, ${siwe ? "the latest date a TinyCloud signed message can carry" : "the latest date an agent or share delegation can carry (UCAN limit); a delegation signed by the wallet (delegateTo with forceWalletSign: true) can go to 9999-12-31"}; choose an earlier expiry`;
11150
+ }
11151
+ function assertExpiryWithinTechnicalLimit(expiresAt, kind) {
11152
+ const refusal = technicalExpiryRefusal(expiresAt, kind);
11153
+ if (refusal) throw new Error(refusal);
11154
+ }
11138
11155
  var DEFAULT_SIGNED_READ_URL_EXPIRY_MS = EXPIRY.SIGNED_READ_URL_MS;
11139
11156
 
11140
11157
  // src/delegations/SharingService.ts
@@ -16679,7 +16696,7 @@ function diffImmutableSiweFields(original, signed, options2) {
16679
16696
  "requestId",
16680
16697
  "nonRecapResources"
16681
16698
  ];
16682
- const keys = options2?.originalHasRecap ? baseKeys : [...baseKeys, "statement"];
16699
+ const keys = (options2?.originalHasRecap ? baseKeys : [...baseKeys, "statement"]).filter((key) => !(options2?.allowExpirationChange === true && key === "expirationTime"));
16683
16700
  const diffs = [];
16684
16701
  for (const key of keys) {
16685
16702
  const a = original[key] ?? "";
@@ -16690,6 +16707,62 @@ function diffImmutableSiweFields(original, signed, options2) {
16690
16707
  }
16691
16708
  return diffs;
16692
16709
  }
16710
+ var CHANGED_EXPIRY_MIN_REMAINING_MS = 6e4;
16711
+ var ISO_INSTANT = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
16712
+ function parseInstantMs(value) {
16713
+ const match = value === void 0 ? null : ISO_INSTANT.exec(value);
16714
+ if (!match || value === void 0) return void 0;
16715
+ const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
16716
+ if (new Date(Date.UTC(year, month - 1, day)).getUTCDate() !== day) return void 0;
16717
+ const ms2 = Date.parse(value);
16718
+ return Number.isFinite(ms2) ? ms2 : void 0;
16719
+ }
16720
+ var EXPIRATION_LINE = /^Expiration Time:/;
16721
+ function hasCanonicalExpirationLine(siwe) {
16722
+ if (siwe.includes("\r")) return false;
16723
+ const lines = siwe.split("\n");
16724
+ const index = lines.findIndex((line) => EXPIRATION_LINE.test(line));
16725
+ if (index < 0 || !/^Expiration Time: \S+$/.test(lines[index])) return false;
16726
+ const resources = lines.indexOf("Resources:", 4);
16727
+ return resources < 0 || index < resources;
16728
+ }
16729
+ function checkChangedExpiration(input) {
16730
+ const nowMs = input.now instanceof Date ? input.now.getTime() : input.now;
16731
+ if (!Number.isFinite(nowMs)) return "expiry check needs a finite current time";
16732
+ const maxMs = input.maxExpiresAt === void 0 ? void 0 : input.maxExpiresAt instanceof Date ? input.maxExpiresAt.getTime() : input.maxExpiresAt;
16733
+ if (maxMs !== void 0 && !Number.isFinite(new Date(maxMs).getTime())) return "expiry check needs a finite maximum";
16734
+ const originalHasRecap = input.originalHasRecap ?? /(?:^|\n)-\s+urn:recap:/i.test(input.preparedSiwe);
16735
+ const countLines = (siwe) => siwe.split(/\r?\n/).filter((line) => EXPIRATION_LINE.test(line)).length;
16736
+ if (countLines(input.preparedSiwe) !== 1 || countLines(input.signedSiwe) !== 1) {
16737
+ return "expiry check needs exactly one Expiration Time line in both messages";
16738
+ }
16739
+ if (!hasCanonicalExpirationLine(input.signedSiwe)) {
16740
+ return "the Expiration Time line is not in canonical SIWE form";
16741
+ }
16742
+ const prepared = extractImmutableSiweFields(input.preparedSiwe);
16743
+ const signed = extractImmutableSiweFields(input.signedSiwe);
16744
+ const drift = diffImmutableSiweFields(prepared, signed, { originalHasRecap, allowExpirationChange: true });
16745
+ if (drift.length > 0) return `altered immutable SIWE fields: ${drift.join(", ")}`;
16746
+ if (signed.expirationTime === prepared.expirationTime) return null;
16747
+ const expiresAt = parseInstantMs(signed.expirationTime);
16748
+ if (expiresAt === void 0) {
16749
+ const later = Date.parse(signed.expirationTime ?? "");
16750
+ return later > MAX_SIWE_EXPIRY_MS ? technicalExpiryRefusal(later, "siwe") : "expiry is not a valid timestamp";
16751
+ }
16752
+ if (expiresAt <= nowMs + CHANGED_EXPIRY_MIN_REMAINING_MS) {
16753
+ return "expiry must be more than 60 seconds from now; choose a longer expiry";
16754
+ }
16755
+ for (const [label, value] of [["Issued At", prepared.issuedAt], ["Not Before", prepared.notBefore]]) {
16756
+ if (value === void 0 || value === "") continue;
16757
+ const bound = parseInstantMs(value);
16758
+ if (bound === void 0) return `${label} is not a valid timestamp`;
16759
+ if (expiresAt <= bound) return `expiry must be after ${label}; choose a later expiry`;
16760
+ }
16761
+ if (maxMs !== void 0 && expiresAt > maxMs) {
16762
+ return `expiry is later than the maximum for this request (the latest allowed is ${new Date(maxMs).toISOString()}); choose an earlier expiry`;
16763
+ }
16764
+ return technicalExpiryRefusal(expiresAt, "siwe");
16765
+ }
16693
16766
  function extractRecapAttenuations(siwe) {
16694
16767
  const merged = {};
16695
16768
  const lines = siwe.split(/\r?\n/);