@unicitylabs/sphere-sdk 0.17.2-dev.2 → 0.17.2
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/connect/index.cjs +7 -4
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.cts +4 -0
- package/dist/connect/index.d.ts +4 -0
- package/dist/connect/index.js +7 -4
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +69 -22
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +69 -22
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +1 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.js +1 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/impl/wallet-api-v2/index.cjs +3 -0
- package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
- package/dist/impl/wallet-api-v2/index.js +3 -0
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +88 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +85 -22
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +40 -6
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +22 -1
- package/dist/modules/payments-v2/index.d.ts +22 -1
- package/dist/modules/payments-v2/index.js +37 -6
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/dist/token-engine/index.cjs +67 -21
- package/dist/token-engine/index.cjs.map +1 -1
- package/dist/token-engine/index.d.cts +28 -4
- package/dist/token-engine/index.d.ts +28 -4
- package/dist/token-engine/index.js +64 -21
- package/dist/token-engine/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.cjs
CHANGED
|
@@ -4624,6 +4624,26 @@ var GroupVisibility = {
|
|
|
4624
4624
|
PRIVATE: "PRIVATE"
|
|
4625
4625
|
};
|
|
4626
4626
|
|
|
4627
|
+
// modules/groupchat/group-id.ts
|
|
4628
|
+
var MAX_SLUG_LENGTH = 24;
|
|
4629
|
+
var RANDOM_BYTES = 8;
|
|
4630
|
+
function groupIdSlug(name) {
|
|
4631
|
+
const slug = name.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/['\u2019]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4632
|
+
if (slug.length <= MAX_SLUG_LENGTH) return slug;
|
|
4633
|
+
const head = slug.slice(0, MAX_SLUG_LENGTH + 1);
|
|
4634
|
+
const hyphen = head.lastIndexOf("-");
|
|
4635
|
+
return hyphen > 0 ? head.slice(0, hyphen) : slug.slice(0, MAX_SLUG_LENGTH);
|
|
4636
|
+
}
|
|
4637
|
+
function newGroupId(name) {
|
|
4638
|
+
const crypto2 = globalThis.crypto;
|
|
4639
|
+
if (typeof crypto2?.getRandomValues !== "function") {
|
|
4640
|
+
throw new SphereError("Creating a group requires crypto.getRandomValues", "INVALID_CONFIG");
|
|
4641
|
+
}
|
|
4642
|
+
const bytes = crypto2.getRandomValues(new Uint8Array(RANDOM_BYTES));
|
|
4643
|
+
const random = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
4644
|
+
return `${groupIdSlug(name) || "group"}-${random}`;
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4627
4647
|
// modules/groupchat/GroupChatModule.ts
|
|
4628
4648
|
function createNip29Filter(data) {
|
|
4629
4649
|
return new import_nostr_js_sdk3.Filter(data);
|
|
@@ -5235,9 +5255,9 @@ var GroupChatModule = class {
|
|
|
5235
5255
|
if (!this.client) return null;
|
|
5236
5256
|
const creatorPubkey = this.getMyPublicKey();
|
|
5237
5257
|
if (!creatorPubkey) return null;
|
|
5238
|
-
const proposedGroupId = options.name.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 20) || this.randomId();
|
|
5239
5258
|
try {
|
|
5240
5259
|
const isPrivate = options.visibility === GroupVisibility.PRIVATE;
|
|
5260
|
+
const proposedGroupId = newGroupId(options.name);
|
|
5241
5261
|
const eventId = await this.client.createAndPublishEvent({
|
|
5242
5262
|
kind: NIP29_KINDS.CREATE_GROUP,
|
|
5243
5263
|
tags: [["h", proposedGroupId]],
|
|
@@ -9869,7 +9889,8 @@ var NFT_MEDIA_TAG = 39053n;
|
|
|
9869
9889
|
var NFT_LINK_TAG = 39054n;
|
|
9870
9890
|
var NFT_SIGNED_TAG = 39055n;
|
|
9871
9891
|
var NFT_FORMAT_VERSION = 1n;
|
|
9872
|
-
var
|
|
9892
|
+
var NFT_DOCUMENT_MEDIA_TYPE = "application/vnd.unicity.nft+cbor";
|
|
9893
|
+
var METADATA_ARITY = 9;
|
|
9873
9894
|
var MEDIA_ARITY = 3;
|
|
9874
9895
|
var LINK_ARITY = 4;
|
|
9875
9896
|
var SIGNED_ARITY = 4;
|
|
@@ -9877,12 +9898,15 @@ var CREATOR_BYTES = 33;
|
|
|
9877
9898
|
var SIGNATURE_BYTES = 65;
|
|
9878
9899
|
var MAX_URI_LENGTH = 2048;
|
|
9879
9900
|
var LINK_SCHEMES = ["https://", "ipfs://", "ar://"];
|
|
9880
|
-
var SIGNED_DOMAIN = "
|
|
9901
|
+
var SIGNED_DOMAIN = new TextEncoder().encode("UNICITY_NFT_SIGNED");
|
|
9881
9902
|
var MEDIA_TYPE_PATTERN = /^[a-z0-9][a-z0-9!#$&^_.+-]{0,126}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,126}$/;
|
|
9882
9903
|
var SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
|
|
9904
|
+
var COLLECTION_ID_PATTERN = /^(?:[0-9a-f]{2}){1,64}$/i;
|
|
9883
9905
|
var LONE_SURROGATE = /\p{Cs}/u;
|
|
9884
9906
|
var CBOR_MAJOR_TYPE_MASK = 224;
|
|
9885
9907
|
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";
|
|
9908
|
+
var COLLECTION_ID_RULE = "must be null or 1\u201364 bytes as even-length hex (2\u2013128 characters)";
|
|
9909
|
+
var DOCUMENT_AS_MEDIA_RULE = `must not be ${NFT_DOCUMENT_MEDIA_TYPE}: a document link is a token's content, never media`;
|
|
9886
9910
|
var UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
9887
9911
|
function refuse(field, rule, cause) {
|
|
9888
9912
|
return new SphereError(`Invalid NFT ${field}: ${rule}`, "VALIDATION_ERROR", cause);
|
|
@@ -9894,6 +9918,7 @@ var fieldName = (prefix, name) => prefix === "" ? name : `${prefix}.${name}`;
|
|
|
9894
9918
|
var isText = (value) => typeof value === "string" && value.length > 0 && !LONE_SURROGATE.test(value);
|
|
9895
9919
|
var isBytes3 = (value, length) => value instanceof Uint8Array && (length === void 0 ? value.length > 0 : value.length === length);
|
|
9896
9920
|
var isMediaType = (value) => typeof value === "string" && MEDIA_TYPE_PATTERN.test(value);
|
|
9921
|
+
var isCollectionId = (value) => typeof value === "string" && COLLECTION_ID_PATTERN.test(value);
|
|
9897
9922
|
var isAttributeValue = (value) => typeof value === "number" ? Number.isSafeInteger(value) : isText(value);
|
|
9898
9923
|
function hasSpaceOrControl(value) {
|
|
9899
9924
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -9936,8 +9961,9 @@ function checkLink(prefix, link) {
|
|
|
9936
9961
|
function checkMediaRef(field, ref) {
|
|
9937
9962
|
if (ref === null) return;
|
|
9938
9963
|
if (ref?.kind === "media") return checkMedia(field, ref);
|
|
9939
|
-
if (ref?.kind
|
|
9940
|
-
|
|
9964
|
+
if (ref?.kind !== "link") throw refuse(field, "must be an NftMedia, an NftLink or null");
|
|
9965
|
+
checkLink(field, ref);
|
|
9966
|
+
ensure(!isNftDocumentLink(ref), fieldName(field, "media_type"), DOCUMENT_AS_MEDIA_RULE);
|
|
9941
9967
|
}
|
|
9942
9968
|
function checkAttributes(attributes) {
|
|
9943
9969
|
ensure(Array.isArray(attributes), "attributes", "must be an array \u2014 [] when there are none");
|
|
@@ -9954,6 +9980,7 @@ function checkMetadata(metadata) {
|
|
|
9954
9980
|
checkOptionalText("external_url", metadata.external_url);
|
|
9955
9981
|
checkAttributes(metadata.attributes);
|
|
9956
9982
|
checkOptionalText("collection", metadata.collection);
|
|
9983
|
+
ensure(metadata.collection_id === null || isCollectionId(metadata.collection_id), "collection_id", COLLECTION_ID_RULE);
|
|
9957
9984
|
}
|
|
9958
9985
|
function checkContent(content) {
|
|
9959
9986
|
switch (content?.kind) {
|
|
@@ -10011,6 +10038,7 @@ function arrayCbor(items) {
|
|
|
10011
10038
|
}
|
|
10012
10039
|
return out;
|
|
10013
10040
|
}
|
|
10041
|
+
var optionalHexBytes = (value) => import_CborSerializer.CborSerializer.encodeNullable(value, (hex) => import_CborSerializer.CborSerializer.encodeByteString(import_HexConverter.HexConverter.decode(hex.toLowerCase())));
|
|
10014
10042
|
function metadataCbor(metadata) {
|
|
10015
10043
|
return versioned(
|
|
10016
10044
|
NFT_METADATA_TAG,
|
|
@@ -10020,7 +10048,8 @@ function metadataCbor(metadata) {
|
|
|
10020
10048
|
mediaRefCbor(metadata.animation_url),
|
|
10021
10049
|
optionalText(metadata.external_url),
|
|
10022
10050
|
arrayCbor(metadata.attributes.map(attributeCbor)),
|
|
10023
|
-
optionalText(metadata.collection)
|
|
10051
|
+
optionalText(metadata.collection),
|
|
10052
|
+
optionalHexBytes(metadata.collection_id)
|
|
10024
10053
|
);
|
|
10025
10054
|
}
|
|
10026
10055
|
function encodeNftContent(content) {
|
|
@@ -10078,13 +10107,14 @@ function decodeMedia(body) {
|
|
|
10078
10107
|
const [, mediaType, bytes] = versionedFields(body, MEDIA_ARITY);
|
|
10079
10108
|
return { kind: "media", media_type: decodeText(mediaType), bytes: import_CborDeserializer.CborDeserializer.decodeByteString(bytes) };
|
|
10080
10109
|
}
|
|
10110
|
+
var decodeHex = (item) => import_HexConverter.HexConverter.encode(import_CborDeserializer.CborDeserializer.decodeByteString(item));
|
|
10081
10111
|
function decodeLink(body) {
|
|
10082
10112
|
const [, mediaType, uri, digest] = versionedFields(body, LINK_ARITY);
|
|
10083
10113
|
return {
|
|
10084
10114
|
kind: "link",
|
|
10085
10115
|
media_type: decodeText(mediaType),
|
|
10086
10116
|
uri: decodeText(uri),
|
|
10087
|
-
sha256:
|
|
10117
|
+
sha256: decodeHex(digest)
|
|
10088
10118
|
};
|
|
10089
10119
|
}
|
|
10090
10120
|
function decodeMetadata(body) {
|
|
@@ -10097,7 +10127,8 @@ function decodeMetadata(body) {
|
|
|
10097
10127
|
animation_url: decodeMediaRef("animation_url", fields[4]),
|
|
10098
10128
|
external_url: decodeOptionalText(fields[5]),
|
|
10099
10129
|
attributes: decodeAttributes(fields[6]),
|
|
10100
|
-
collection: decodeOptionalText(fields[7])
|
|
10130
|
+
collection: decodeOptionalText(fields[7]),
|
|
10131
|
+
collection_id: import_CborDeserializer.CborDeserializer.decodeNullable(fields[8], decodeHex)
|
|
10101
10132
|
};
|
|
10102
10133
|
}
|
|
10103
10134
|
var MEDIA_REF_DECODERS = /* @__PURE__ */ new Map([
|
|
@@ -10143,20 +10174,26 @@ function parseNftPayload(data) {
|
|
|
10143
10174
|
return null;
|
|
10144
10175
|
}
|
|
10145
10176
|
}
|
|
10146
|
-
function
|
|
10177
|
+
function isNftDocumentLink(content) {
|
|
10178
|
+
return content?.kind === "link" && content.media_type === NFT_DOCUMENT_MEDIA_TYPE;
|
|
10179
|
+
}
|
|
10180
|
+
function nftSignedDigest(context, payload) {
|
|
10147
10181
|
const preimage = import_CborSerializer.CborSerializer.encodeArray(
|
|
10148
|
-
import_CborSerializer.CborSerializer.
|
|
10149
|
-
|
|
10150
|
-
|
|
10182
|
+
import_CborSerializer.CborSerializer.encodeByteString(SIGNED_DOMAIN),
|
|
10183
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(NFT_FORMAT_VERSION),
|
|
10184
|
+
import_CborSerializer.CborSerializer.encodeUnsignedInteger(import_NetworkId.NetworkId.fromId(context.networkId).id),
|
|
10185
|
+
import_CborSerializer.CborSerializer.encodeByteString(context.recipientPredicate),
|
|
10186
|
+
import_CborSerializer.CborSerializer.encodeByteString(context.tokenId),
|
|
10187
|
+
import_CborSerializer.CborSerializer.encodeByteString(context.tokenType),
|
|
10151
10188
|
import_CborSerializer.CborSerializer.encodeByteString(payload)
|
|
10152
10189
|
);
|
|
10153
10190
|
return new import_DataHasher.DataHasher(import_HashAlgorithm.HashAlgorithm.SHA256).update(preimage).digest();
|
|
10154
10191
|
}
|
|
10155
|
-
async function verifyNftSignature(signed,
|
|
10192
|
+
async function verifyNftSignature(signed, context) {
|
|
10156
10193
|
try {
|
|
10157
10194
|
if (!import_SigningService.SigningService.isPublicKeyValid(signed.creator)) return "invalid";
|
|
10158
10195
|
const signature = import_Signature.Signature.decode(signed.signature);
|
|
10159
|
-
const digest = await nftSignedDigest(
|
|
10196
|
+
const digest = await nftSignedDigest(context, signed.payload);
|
|
10160
10197
|
return await import_SigningService.SigningService.verifyWithPublicKey(digest, signature, signed.creator) ? "valid" : "invalid";
|
|
10161
10198
|
} catch {
|
|
10162
10199
|
return "invalid";
|
|
@@ -10287,8 +10324,8 @@ function assertMintableData(data) {
|
|
|
10287
10324
|
function nftRecipientCbor(pubkey) {
|
|
10288
10325
|
return import_EncodedPredicate.EncodedPredicate.fromPredicate(import_SignaturePredicate.SignaturePredicate.create(pubkey)).toCBOR();
|
|
10289
10326
|
}
|
|
10290
|
-
async function signPayload(deps, payload,
|
|
10291
|
-
const digest = await nftSignedDigest(
|
|
10327
|
+
async function signPayload(deps, payload, context) {
|
|
10328
|
+
const digest = await nftSignedDigest(context, payload);
|
|
10292
10329
|
const signature = await deps.signingService.sign(digest);
|
|
10293
10330
|
return encodeNftSigned(deps.signingService.publicKey, payload, signature.encode());
|
|
10294
10331
|
}
|
|
@@ -10297,31 +10334,41 @@ async function planNftMint(deps, params) {
|
|
|
10297
10334
|
const tokenType = new import_TokenType.TokenType(params.tokenType).bytes;
|
|
10298
10335
|
const salt = import_TokenSalt.TokenSalt.generate();
|
|
10299
10336
|
const tokenId = await import_TokenId.TokenId.fromSalt(deps.networkId, salt);
|
|
10300
|
-
const data = params.sign ? await signPayload(deps, payload,
|
|
10337
|
+
const data = params.sign ? await signPayload(deps, payload, {
|
|
10338
|
+
networkId: deps.networkId.id,
|
|
10339
|
+
recipientPredicate: nftRecipientCbor(params.recipientPubkey),
|
|
10340
|
+
tokenId: tokenId.bytes,
|
|
10341
|
+
tokenType
|
|
10342
|
+
}) : payload;
|
|
10301
10343
|
assertMintableData(data);
|
|
10302
10344
|
return { data, salt: salt.toBytes(), tokenType, tokenId: import_HexConverter.HexConverter.encode(tokenId.bytes) };
|
|
10303
10345
|
}
|
|
10304
|
-
async function verifyAgainst(signed,
|
|
10346
|
+
async function verifyAgainst(signed, genesisContext) {
|
|
10305
10347
|
try {
|
|
10306
|
-
return await verifyNftSignature(signed,
|
|
10348
|
+
return await verifyNftSignature(signed, genesisContext());
|
|
10307
10349
|
} catch {
|
|
10308
10350
|
return "invalid";
|
|
10309
10351
|
}
|
|
10310
10352
|
}
|
|
10311
|
-
async function readNftData(data,
|
|
10353
|
+
async function readNftData(data, genesisContext) {
|
|
10312
10354
|
const parsed = parseNftPayload(data);
|
|
10313
10355
|
if (parsed === null) return null;
|
|
10314
10356
|
if (parsed.signed === null) return { content: parsed.content, creator: null, signature: "unsigned" };
|
|
10315
10357
|
return {
|
|
10316
10358
|
content: parsed.content,
|
|
10317
10359
|
creator: import_HexConverter.HexConverter.encode(parsed.signed.creator),
|
|
10318
|
-
signature: await verifyAgainst(parsed.signed,
|
|
10360
|
+
signature: await verifyAgainst(parsed.signed, genesisContext)
|
|
10319
10361
|
};
|
|
10320
10362
|
}
|
|
10321
10363
|
async function readTokenNft(token) {
|
|
10322
10364
|
try {
|
|
10323
10365
|
const { genesis } = token.sdkToken;
|
|
10324
|
-
return await readNftData(genesis.data,
|
|
10366
|
+
return await readNftData(genesis.data, () => ({
|
|
10367
|
+
networkId: genesis.networkId.id,
|
|
10368
|
+
recipientPredicate: genesis.recipient.toCBOR(),
|
|
10369
|
+
tokenId: genesis.tokenId.bytes,
|
|
10370
|
+
tokenType: genesis.tokenType.bytes
|
|
10371
|
+
}));
|
|
10325
10372
|
} catch {
|
|
10326
10373
|
return null;
|
|
10327
10374
|
}
|