@unicitylabs/sphere-sdk 0.17.2-dev.1 → 0.17.2-dev.3

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.
Files changed (47) hide show
  1. package/dist/connect/index.cjs +202 -8
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.d.cts +81 -4
  4. package/dist/connect/index.d.ts +81 -4
  5. package/dist/connect/index.js +202 -8
  6. package/dist/connect/index.js.map +1 -1
  7. package/dist/core/index.cjs +48 -21
  8. package/dist/core/index.cjs.map +1 -1
  9. package/dist/core/index.d.cts +2 -0
  10. package/dist/core/index.d.ts +2 -0
  11. package/dist/core/index.js +48 -21
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/impl/browser/connect/index.cjs +17 -5
  14. package/dist/impl/browser/connect/index.cjs.map +1 -1
  15. package/dist/impl/browser/connect/index.d.cts +3 -1
  16. package/dist/impl/browser/connect/index.d.ts +3 -1
  17. package/dist/impl/browser/connect/index.js +17 -5
  18. package/dist/impl/browser/connect/index.js.map +1 -1
  19. package/dist/impl/nodejs/connect/index.cjs +16 -4
  20. package/dist/impl/nodejs/connect/index.cjs.map +1 -1
  21. package/dist/impl/nodejs/connect/index.d.cts +1 -1
  22. package/dist/impl/nodejs/connect/index.d.ts +1 -1
  23. package/dist/impl/nodejs/connect/index.js +16 -4
  24. package/dist/impl/nodejs/connect/index.js.map +1 -1
  25. package/dist/impl/wallet-api-v2/index.cjs +3 -0
  26. package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
  27. package/dist/impl/wallet-api-v2/index.js +3 -0
  28. package/dist/impl/wallet-api-v2/index.js.map +1 -1
  29. package/dist/index.cjs +67 -21
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +22 -1
  32. package/dist/index.d.ts +22 -1
  33. package/dist/index.js +64 -21
  34. package/dist/index.js.map +1 -1
  35. package/dist/modules/payments-v2/index.cjs +40 -6
  36. package/dist/modules/payments-v2/index.cjs.map +1 -1
  37. package/dist/modules/payments-v2/index.d.cts +22 -1
  38. package/dist/modules/payments-v2/index.d.ts +22 -1
  39. package/dist/modules/payments-v2/index.js +37 -6
  40. package/dist/modules/payments-v2/index.js.map +1 -1
  41. package/dist/token-engine/index.cjs +67 -21
  42. package/dist/token-engine/index.cjs.map +1 -1
  43. package/dist/token-engine/index.d.cts +28 -4
  44. package/dist/token-engine/index.d.ts +28 -4
  45. package/dist/token-engine/index.js +64 -21
  46. package/dist/token-engine/index.js.map +1 -1
  47. package/package.json +1 -1
@@ -9869,7 +9869,8 @@ var NFT_MEDIA_TAG = 39053n;
9869
9869
  var NFT_LINK_TAG = 39054n;
9870
9870
  var NFT_SIGNED_TAG = 39055n;
9871
9871
  var NFT_FORMAT_VERSION = 1n;
9872
- var METADATA_ARITY = 8;
9872
+ var NFT_DOCUMENT_MEDIA_TYPE = "application/vnd.unicity.nft+cbor";
9873
+ var METADATA_ARITY = 9;
9873
9874
  var MEDIA_ARITY = 3;
9874
9875
  var LINK_ARITY = 4;
9875
9876
  var SIGNED_ARITY = 4;
@@ -9877,12 +9878,15 @@ var CREATOR_BYTES = 33;
9877
9878
  var SIGNATURE_BYTES = 65;
9878
9879
  var MAX_URI_LENGTH = 2048;
9879
9880
  var LINK_SCHEMES = ["https://", "ipfs://", "ar://"];
9880
- var SIGNED_DOMAIN = "NftSigned";
9881
+ var SIGNED_DOMAIN = new TextEncoder().encode("UNICITY_NFT_SIGNED");
9881
9882
  var MEDIA_TYPE_PATTERN = /^[a-z0-9][a-z0-9!#$&^_.+-]{0,126}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,126}$/;
9882
9883
  var SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
9884
+ var COLLECTION_ID_PATTERN = /^(?:[0-9a-f]{2}){1,64}$/i;
9883
9885
  var LONE_SURROGATE = /\p{Cs}/u;
9884
9886
  var CBOR_MAJOR_TYPE_MASK = 224;
9885
9887
  var ATTRIBUTE_VALUE_RULE = "must be non-empty text or an integer within \xB1(2^53 \u2212 1) \u2014 write decimals and larger numbers as text";
9888
+ var COLLECTION_ID_RULE = "must be null or 1\u201364 bytes as even-length hex (2\u2013128 characters)";
9889
+ var DOCUMENT_AS_MEDIA_RULE = `must not be ${NFT_DOCUMENT_MEDIA_TYPE}: a document link is a token's content, never media`;
9886
9890
  var UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
9887
9891
  function refuse(field, rule, cause) {
9888
9892
  return new SphereError(`Invalid NFT ${field}: ${rule}`, "VALIDATION_ERROR", cause);
@@ -9894,6 +9898,7 @@ var fieldName = (prefix, name) => prefix === "" ? name : `${prefix}.${name}`;
9894
9898
  var isText = (value) => typeof value === "string" && value.length > 0 && !LONE_SURROGATE.test(value);
9895
9899
  var isBytes3 = (value, length) => value instanceof Uint8Array && (length === void 0 ? value.length > 0 : value.length === length);
9896
9900
  var isMediaType = (value) => typeof value === "string" && MEDIA_TYPE_PATTERN.test(value);
9901
+ var isCollectionId = (value) => typeof value === "string" && COLLECTION_ID_PATTERN.test(value);
9897
9902
  var isAttributeValue = (value) => typeof value === "number" ? Number.isSafeInteger(value) : isText(value);
9898
9903
  function hasSpaceOrControl(value) {
9899
9904
  for (let i = 0; i < value.length; i++) {
@@ -9936,8 +9941,9 @@ function checkLink(prefix, link) {
9936
9941
  function checkMediaRef(field, ref) {
9937
9942
  if (ref === null) return;
9938
9943
  if (ref?.kind === "media") return checkMedia(field, ref);
9939
- if (ref?.kind === "link") return checkLink(field, ref);
9940
- throw refuse(field, "must be an NftMedia, an NftLink or null");
9944
+ if (ref?.kind !== "link") throw refuse(field, "must be an NftMedia, an NftLink or null");
9945
+ checkLink(field, ref);
9946
+ ensure(!isNftDocumentLink(ref), fieldName(field, "media_type"), DOCUMENT_AS_MEDIA_RULE);
9941
9947
  }
9942
9948
  function checkAttributes(attributes) {
9943
9949
  ensure(Array.isArray(attributes), "attributes", "must be an array \u2014 [] when there are none");
@@ -9954,6 +9960,7 @@ function checkMetadata(metadata) {
9954
9960
  checkOptionalText("external_url", metadata.external_url);
9955
9961
  checkAttributes(metadata.attributes);
9956
9962
  checkOptionalText("collection", metadata.collection);
9963
+ ensure(metadata.collection_id === null || isCollectionId(metadata.collection_id), "collection_id", COLLECTION_ID_RULE);
9957
9964
  }
9958
9965
  function checkContent(content) {
9959
9966
  switch (content?.kind) {
@@ -10011,6 +10018,7 @@ function arrayCbor(items) {
10011
10018
  }
10012
10019
  return out;
10013
10020
  }
10021
+ var optionalHexBytes = (value) => import_CborSerializer.CborSerializer.encodeNullable(value, (hex) => import_CborSerializer.CborSerializer.encodeByteString(import_HexConverter.HexConverter.decode(hex.toLowerCase())));
10014
10022
  function metadataCbor(metadata) {
10015
10023
  return versioned(
10016
10024
  NFT_METADATA_TAG,
@@ -10020,7 +10028,8 @@ function metadataCbor(metadata) {
10020
10028
  mediaRefCbor(metadata.animation_url),
10021
10029
  optionalText(metadata.external_url),
10022
10030
  arrayCbor(metadata.attributes.map(attributeCbor)),
10023
- optionalText(metadata.collection)
10031
+ optionalText(metadata.collection),
10032
+ optionalHexBytes(metadata.collection_id)
10024
10033
  );
10025
10034
  }
10026
10035
  function encodeNftContent(content) {
@@ -10078,13 +10087,14 @@ function decodeMedia(body) {
10078
10087
  const [, mediaType, bytes] = versionedFields(body, MEDIA_ARITY);
10079
10088
  return { kind: "media", media_type: decodeText(mediaType), bytes: import_CborDeserializer.CborDeserializer.decodeByteString(bytes) };
10080
10089
  }
10090
+ var decodeHex = (item) => import_HexConverter.HexConverter.encode(import_CborDeserializer.CborDeserializer.decodeByteString(item));
10081
10091
  function decodeLink(body) {
10082
10092
  const [, mediaType, uri, digest] = versionedFields(body, LINK_ARITY);
10083
10093
  return {
10084
10094
  kind: "link",
10085
10095
  media_type: decodeText(mediaType),
10086
10096
  uri: decodeText(uri),
10087
- sha256: import_HexConverter.HexConverter.encode(import_CborDeserializer.CborDeserializer.decodeByteString(digest))
10097
+ sha256: decodeHex(digest)
10088
10098
  };
10089
10099
  }
10090
10100
  function decodeMetadata(body) {
@@ -10097,7 +10107,8 @@ function decodeMetadata(body) {
10097
10107
  animation_url: decodeMediaRef("animation_url", fields[4]),
10098
10108
  external_url: decodeOptionalText(fields[5]),
10099
10109
  attributes: decodeAttributes(fields[6]),
10100
- collection: decodeOptionalText(fields[7])
10110
+ collection: decodeOptionalText(fields[7]),
10111
+ collection_id: import_CborDeserializer.CborDeserializer.decodeNullable(fields[8], decodeHex)
10101
10112
  };
10102
10113
  }
10103
10114
  var MEDIA_REF_DECODERS = /* @__PURE__ */ new Map([
@@ -10143,20 +10154,26 @@ function parseNftPayload(data) {
10143
10154
  return null;
10144
10155
  }
10145
10156
  }
10146
- function nftSignedDigest(tokenIdCbor, recipientPredicateCbor, payload) {
10157
+ function isNftDocumentLink(content) {
10158
+ return content?.kind === "link" && content.media_type === NFT_DOCUMENT_MEDIA_TYPE;
10159
+ }
10160
+ function nftSignedDigest(context, payload) {
10147
10161
  const preimage = import_CborSerializer.CborSerializer.encodeArray(
10148
- import_CborSerializer.CborSerializer.encodeTextString(SIGNED_DOMAIN),
10149
- tokenIdCbor,
10150
- recipientPredicateCbor,
10162
+ import_CborSerializer.CborSerializer.encodeByteString(SIGNED_DOMAIN),
10163
+ import_CborSerializer.CborSerializer.encodeUnsignedInteger(NFT_FORMAT_VERSION),
10164
+ import_CborSerializer.CborSerializer.encodeUnsignedInteger(import_NetworkId.NetworkId.fromId(context.networkId).id),
10165
+ import_CborSerializer.CborSerializer.encodeByteString(context.recipientPredicate),
10166
+ import_CborSerializer.CborSerializer.encodeByteString(context.tokenId),
10167
+ import_CborSerializer.CborSerializer.encodeByteString(context.tokenType),
10151
10168
  import_CborSerializer.CborSerializer.encodeByteString(payload)
10152
10169
  );
10153
10170
  return new import_DataHasher.DataHasher(import_HashAlgorithm.HashAlgorithm.SHA256).update(preimage).digest();
10154
10171
  }
10155
- async function verifyNftSignature(signed, tokenIdCbor, recipientPredicateCbor) {
10172
+ async function verifyNftSignature(signed, context) {
10156
10173
  try {
10157
10174
  if (!import_SigningService.SigningService.isPublicKeyValid(signed.creator)) return "invalid";
10158
10175
  const signature = import_Signature.Signature.decode(signed.signature);
10159
- const digest = await nftSignedDigest(tokenIdCbor, recipientPredicateCbor, signed.payload);
10176
+ const digest = await nftSignedDigest(context, signed.payload);
10160
10177
  return await import_SigningService.SigningService.verifyWithPublicKey(digest, signature, signed.creator) ? "valid" : "invalid";
10161
10178
  } catch {
10162
10179
  return "invalid";
@@ -10287,8 +10304,8 @@ function assertMintableData(data) {
10287
10304
  function nftRecipientCbor(pubkey) {
10288
10305
  return import_EncodedPredicate.EncodedPredicate.fromPredicate(import_SignaturePredicate.SignaturePredicate.create(pubkey)).toCBOR();
10289
10306
  }
10290
- async function signPayload(deps, payload, tokenId, recipientPubkey) {
10291
- const digest = await nftSignedDigest(tokenId.toCBOR(), nftRecipientCbor(recipientPubkey), payload);
10307
+ async function signPayload(deps, payload, context) {
10308
+ const digest = await nftSignedDigest(context, payload);
10292
10309
  const signature = await deps.signingService.sign(digest);
10293
10310
  return encodeNftSigned(deps.signingService.publicKey, payload, signature.encode());
10294
10311
  }
@@ -10297,31 +10314,41 @@ async function planNftMint(deps, params) {
10297
10314
  const tokenType = new import_TokenType.TokenType(params.tokenType).bytes;
10298
10315
  const salt = import_TokenSalt.TokenSalt.generate();
10299
10316
  const tokenId = await import_TokenId.TokenId.fromSalt(deps.networkId, salt);
10300
- const data = params.sign ? await signPayload(deps, payload, tokenId, params.recipientPubkey) : payload;
10317
+ const data = params.sign ? await signPayload(deps, payload, {
10318
+ networkId: deps.networkId.id,
10319
+ recipientPredicate: nftRecipientCbor(params.recipientPubkey),
10320
+ tokenId: tokenId.bytes,
10321
+ tokenType
10322
+ }) : payload;
10301
10323
  assertMintableData(data);
10302
10324
  return { data, salt: salt.toBytes(), tokenType, tokenId: import_HexConverter.HexConverter.encode(tokenId.bytes) };
10303
10325
  }
10304
- async function verifyAgainst(signed, tokenIdCbor, genesisRecipientCbor) {
10326
+ async function verifyAgainst(signed, genesisContext) {
10305
10327
  try {
10306
- return await verifyNftSignature(signed, tokenIdCbor, genesisRecipientCbor());
10328
+ return await verifyNftSignature(signed, genesisContext());
10307
10329
  } catch {
10308
10330
  return "invalid";
10309
10331
  }
10310
10332
  }
10311
- async function readNftData(data, tokenIdCbor, genesisRecipientCbor) {
10333
+ async function readNftData(data, genesisContext) {
10312
10334
  const parsed = parseNftPayload(data);
10313
10335
  if (parsed === null) return null;
10314
10336
  if (parsed.signed === null) return { content: parsed.content, creator: null, signature: "unsigned" };
10315
10337
  return {
10316
10338
  content: parsed.content,
10317
10339
  creator: import_HexConverter.HexConverter.encode(parsed.signed.creator),
10318
- signature: await verifyAgainst(parsed.signed, tokenIdCbor, genesisRecipientCbor)
10340
+ signature: await verifyAgainst(parsed.signed, genesisContext)
10319
10341
  };
10320
10342
  }
10321
10343
  async function readTokenNft(token) {
10322
10344
  try {
10323
10345
  const { genesis } = token.sdkToken;
10324
- return await readNftData(genesis.data, genesis.tokenId.toCBOR(), () => genesis.recipient.toCBOR());
10346
+ return await readNftData(genesis.data, () => ({
10347
+ networkId: genesis.networkId.id,
10348
+ recipientPredicate: genesis.recipient.toCBOR(),
10349
+ tokenId: genesis.tokenId.bytes,
10350
+ tokenType: genesis.tokenType.bytes
10351
+ }));
10325
10352
  } catch {
10326
10353
  return null;
10327
10354
  }