@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.
Files changed (39) hide show
  1. package/dist/connect/index.cjs +7 -4
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.d.cts +4 -0
  4. package/dist/connect/index.d.ts +4 -0
  5. package/dist/connect/index.js +7 -4
  6. package/dist/connect/index.js.map +1 -1
  7. package/dist/core/index.cjs +69 -22
  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 +69 -22
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/impl/browser/connect/index.cjs +1 -1
  14. package/dist/impl/browser/connect/index.cjs.map +1 -1
  15. package/dist/impl/browser/connect/index.js +1 -1
  16. package/dist/impl/browser/connect/index.js.map +1 -1
  17. package/dist/impl/wallet-api-v2/index.cjs +3 -0
  18. package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
  19. package/dist/impl/wallet-api-v2/index.js +3 -0
  20. package/dist/impl/wallet-api-v2/index.js.map +1 -1
  21. package/dist/index.cjs +88 -22
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +22 -1
  24. package/dist/index.d.ts +22 -1
  25. package/dist/index.js +85 -22
  26. package/dist/index.js.map +1 -1
  27. package/dist/modules/payments-v2/index.cjs +40 -6
  28. package/dist/modules/payments-v2/index.cjs.map +1 -1
  29. package/dist/modules/payments-v2/index.d.cts +22 -1
  30. package/dist/modules/payments-v2/index.d.ts +22 -1
  31. package/dist/modules/payments-v2/index.js +37 -6
  32. package/dist/modules/payments-v2/index.js.map +1 -1
  33. package/dist/token-engine/index.cjs +67 -21
  34. package/dist/token-engine/index.cjs.map +1 -1
  35. package/dist/token-engine/index.d.cts +28 -4
  36. package/dist/token-engine/index.d.ts +28 -4
  37. package/dist/token-engine/index.js +64 -21
  38. package/dist/token-engine/index.js.map +1 -1
  39. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -86,6 +86,8 @@ declare const NFT_METADATA_TAG = 39052n;
86
86
  declare const NFT_MEDIA_TAG = 39053n;
87
87
  declare const NFT_LINK_TAG = 39054n;
88
88
  declare const NFT_SIGNED_TAG = 39055n;
89
+ /** The media type of an NftLink that points at a metadata document instead of a media file. */
90
+ declare const NFT_DOCUMENT_MEDIA_TYPE = "application/vnd.unicity.nft+cbor";
89
91
  /** An inline file. */
90
92
  interface NftMedia {
91
93
  readonly kind: 'media';
@@ -115,6 +117,8 @@ interface NftMetadata {
115
117
  readonly external_url: string | null;
116
118
  readonly attributes: readonly NftAttribute[];
117
119
  readonly collection: string | null;
120
+ /** The collection the item claims: 1–64 bytes as even-length hex (decoded lowercase). Never verified here. */
121
+ readonly collection_id: string | null;
118
122
  }
119
123
  type NftContent = NftMetadata | NftMedia | NftLink;
120
124
  type NftSignatureStatus = 'unsigned' | 'valid' | 'invalid';
@@ -127,10 +131,27 @@ interface ParsedNft {
127
131
  readonly signature: Uint8Array;
128
132
  } | null;
129
133
  }
134
+ /** What an NftSigned signature binds besides its payload, exactly as the token's mint records it. */
135
+ interface NftSignatureContext {
136
+ /** The network identifier α (`NetworkId.id`). */
137
+ readonly networkId: number | bigint;
138
+ /** The genesis recipient predicate, as `EncodedPredicate.toCBOR()` bytes. */
139
+ readonly recipientPredicate: Uint8Array;
140
+ /** The 32 raw token id bytes. */
141
+ readonly tokenId: Uint8Array;
142
+ readonly tokenType: Uint8Array;
143
+ }
130
144
  /** Encode one unsigned item. Throws SphereError('…', 'VALIDATION_ERROR') naming the offending field. */
131
145
  declare function encodeNftContent(content: NftContent): Uint8Array;
132
146
  /** Structural parse of a genesis payload. NEVER throws; null = not a recognised NFT. */
133
147
  declare function parseNftPayload(data: Uint8Array | null): ParsedNft | null;
148
+ /**
149
+ * Parse the file a document link points at: exactly one NftMetadata or NftMedia item.
150
+ * NEVER throws; null = not a document. Check the bytes with verifyNftLinkContent first.
151
+ */
152
+ declare function parseNftDocument(bytes: Uint8Array): NftMetadata | NftMedia | null;
153
+ /** Is this an NftLink to a metadata document ({@link NFT_DOCUMENT_MEDIA_TYPE}), resolved with parseNftDocument? */
154
+ declare function isNftDocumentLink(content: NftContent): boolean;
134
155
  /** Does `bytes` match the link's sha256? Pure, sync. */
135
156
  declare function verifyNftLinkContent(link: NftLink, bytes: Uint8Array): boolean;
136
157
 
@@ -4894,4 +4915,4 @@ declare function normalizeAddress(address: string): string;
4894
4915
  */
4895
4916
  declare function addressesMatch(a: string, b: string): boolean;
4896
4917
 
4897
- export { AUTH_CHALLENGE_PREFIX, type AddressInfo, type AddressType, type AggregatorEvent, type AggregatorEventCallback, type AggregatorEventType, type AggregatorProvider, type Asset, type BaseProvider, type BroadcastHandler, type BroadcastMessage, COIN_TYPES, ChallengeTemplateError, type CheckNetworkHealthOptions, CoinGeckoPriceProvider, type CoinlessToken, CommunicationsModule, type CommunicationsModuleConfig, type CommunicationsModuleDependencies, type ComposingIndicator, type ConversationPage, type CreateGroupOptions, DEFAULT_AGGREGATOR_TIMEOUT, DEFAULT_DERIVATION_PATH, DEFAULT_GROUP_RELAYS, DEFAULT_MARKET_API_URL, DEFAULT_NOSTR_RELAYS, type DecryptionProgressCallback, type DerivationMode, type DirectMessage, type DiscoverAddressProgress, type DiscoverAddressesOptions, type DiscoverAddressesResult, type DiscoveredAddress, type EncryptedData, FIELD_ENCRYPTION_HKDF_INFO, FIELD_ENVELOPE_MAX_BYTES, FIELD_ENVELOPE_NONCE_BYTES, FIELD_ENVELOPE_PREFIX, type FullIdentity, type GetConversationPageOptions, GroupChatModule, type GroupChatModuleConfig, type GroupChatModuleDependencies, type GroupData, type GroupMemberData, type GroupMessageData, GroupRole, GroupVisibility, type HealthCheckFn, type HistoryRecord, type Identity, type IdentityConfig, type IncomingBroadcast, type IncomingMessage, type IncomingTransfer, type InitProgress, type InitProgressCallback, type InitProgressStep, type IntentStatus, type IntentType, LIMITS, type LegacyFileParseResult, type LegacyFileParsedData, type LegacyFileType, type LogHandler, type LogLevel, type LoggerConfig, type MarketIntent, MarketModule, type MarketModuleConfig, type MarketModuleDependencies, type MessageHandler, type MintNftRequest, NETWORKS, NFT_LINK_TAG, NFT_MAX_PAYLOAD_BYTES, NFT_MEDIA_TAG, NFT_METADATA_TAG, NFT_SIGNED_TAG, NIP29_KINDS, NOSTR_EVENT_KINDS, type NetworkHealthResult, type NetworkType, type NftAttribute, type NftContent, type NftLink, type NftMedia, type NftMediaRef, type NftMetadata, type NftSignatureStatus, type NftView, type OracleEvent, type OracleEventCallback, type OracleEventType, type OracleProvider, type ParsedAddress, PartialSendConflictError, type PeerInfo, type PostIntentRequest, type PostIntentResult, type PricePlatform, type PriceProvider, type PriceProviderConfig, type ProviderMetadata, type ProviderRole, type ProviderStatus, type ProviderStatusInfo, type RegistryNetwork, SIGN_MESSAGE_PREFIX, STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, STORAGE_PREFIX, type SearchFilters, type SearchIntentResult, type SearchOptions, type SearchResult, type ServiceHealthResult, Sphere, type SphereCreateOptions, SphereError, type SphereErrorCode, type SphereEventHandler, type SphereEventMap, type SphereEventType, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, type SphereStatus, type StorageProvider, TEST_NOSTR_RELAYS, TIMEOUTS, type Token, type TokenDefinition, type TokenIcon, type TokenPrice, TokenRegistry, type TokenStatus, type TokenTransferDetail, type TrackedAddress, type TrackedAddressEntry, type HistoryRecord as TransactionHistoryEntry, type TransferRequest, type TransferResult, type TransferStatus, type TransportEvent, type TransportEventCallback, type TransportEventType, type TransportProvider, type WalletApiTransportConfig, type WalletInfo, type WalletJSON, type WalletJSONExportOptions, type WalletSource, addressesMatch, assertFieldEnvelopeShape, base58Decode, base58Encode, bytesToHex, checkNetworkHealth, coinIdsMatch, createCommunicationsModule, createGroupChatModule, createKeyPair, createMarketModule, createPriceProvider, createSphere, decrypt, decryptField, decryptFieldBytes, decryptJson, decryptMnemonic, decryptSimple, decryptTextFormatKey, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveFieldEncryptionKey, deriveKeyAtPath, doubleSha256, encodeNftContent, encrypt, encryptField, encryptFieldBytes, encryptMnemonic, encryptSimple, extractFromText, findPattern, formatAmount, generateAddressFromMasterKey, generateMasterKey, generateMnemonic, getAddressId, getAddressStorageKey, getCoinIdByName, getCoinIdBySymbol, getPublicKey, getTokenDecimals, getTokenDefinition, getTokenIconUrl, getTokenName, getTokenSymbol, hash160, hashSignMessage, hexToBytes, identityFromMnemonicSync, initSphere, isKnownToken, isPossiblyCommittedSendOutcome, isSphereError, isTextWalletEncrypted, isValidAddress, isValidDirectAddress, isValidNametag, isValidPrivateKey, isWalletTextFormat, loadSphere, logger, mnemonicToSeedSync, normalizeAddress, normalizeCoinId, parseAddress, parseAndDecryptWalletText, parseNftPayload, parseTokenAmount, parseWalletText, randomBytes, randomHex, randomUUID, recoverPubkeyFromSignature, ripemd160, safeParseTokenAmount, sha256, signMessage, sleep, sphereExists, toHumanReadable, validateMnemonic, verifyChallengeTemplate, verifyNftLinkContent, verifySignedMessage };
4918
+ export { AUTH_CHALLENGE_PREFIX, type AddressInfo, type AddressType, type AggregatorEvent, type AggregatorEventCallback, type AggregatorEventType, type AggregatorProvider, type Asset, type BaseProvider, type BroadcastHandler, type BroadcastMessage, COIN_TYPES, ChallengeTemplateError, type CheckNetworkHealthOptions, CoinGeckoPriceProvider, type CoinlessToken, CommunicationsModule, type CommunicationsModuleConfig, type CommunicationsModuleDependencies, type ComposingIndicator, type ConversationPage, type CreateGroupOptions, DEFAULT_AGGREGATOR_TIMEOUT, DEFAULT_DERIVATION_PATH, DEFAULT_GROUP_RELAYS, DEFAULT_MARKET_API_URL, DEFAULT_NOSTR_RELAYS, type DecryptionProgressCallback, type DerivationMode, type DirectMessage, type DiscoverAddressProgress, type DiscoverAddressesOptions, type DiscoverAddressesResult, type DiscoveredAddress, type EncryptedData, FIELD_ENCRYPTION_HKDF_INFO, FIELD_ENVELOPE_MAX_BYTES, FIELD_ENVELOPE_NONCE_BYTES, FIELD_ENVELOPE_PREFIX, type FullIdentity, type GetConversationPageOptions, GroupChatModule, type GroupChatModuleConfig, type GroupChatModuleDependencies, type GroupData, type GroupMemberData, type GroupMessageData, GroupRole, GroupVisibility, type HealthCheckFn, type HistoryRecord, type Identity, type IdentityConfig, type IncomingBroadcast, type IncomingMessage, type IncomingTransfer, type InitProgress, type InitProgressCallback, type InitProgressStep, type IntentStatus, type IntentType, LIMITS, type LegacyFileParseResult, type LegacyFileParsedData, type LegacyFileType, type LogHandler, type LogLevel, type LoggerConfig, type MarketIntent, MarketModule, type MarketModuleConfig, type MarketModuleDependencies, type MessageHandler, type MintNftRequest, NETWORKS, NFT_DOCUMENT_MEDIA_TYPE, NFT_LINK_TAG, NFT_MAX_PAYLOAD_BYTES, NFT_MEDIA_TAG, NFT_METADATA_TAG, NFT_SIGNED_TAG, NIP29_KINDS, NOSTR_EVENT_KINDS, type NetworkHealthResult, type NetworkType, type NftAttribute, type NftContent, type NftLink, type NftMedia, type NftMediaRef, type NftMetadata, type NftSignatureContext, type NftSignatureStatus, type NftView, type OracleEvent, type OracleEventCallback, type OracleEventType, type OracleProvider, type ParsedAddress, PartialSendConflictError, type PeerInfo, type PostIntentRequest, type PostIntentResult, type PricePlatform, type PriceProvider, type PriceProviderConfig, type ProviderMetadata, type ProviderRole, type ProviderStatus, type ProviderStatusInfo, type RegistryNetwork, SIGN_MESSAGE_PREFIX, STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, STORAGE_PREFIX, type SearchFilters, type SearchIntentResult, type SearchOptions, type SearchResult, type ServiceHealthResult, Sphere, type SphereCreateOptions, SphereError, type SphereErrorCode, type SphereEventHandler, type SphereEventMap, type SphereEventType, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, type SphereStatus, type StorageProvider, TEST_NOSTR_RELAYS, TIMEOUTS, type Token, type TokenDefinition, type TokenIcon, type TokenPrice, TokenRegistry, type TokenStatus, type TokenTransferDetail, type TrackedAddress, type TrackedAddressEntry, type HistoryRecord as TransactionHistoryEntry, type TransferRequest, type TransferResult, type TransferStatus, type TransportEvent, type TransportEventCallback, type TransportEventType, type TransportProvider, type WalletApiTransportConfig, type WalletInfo, type WalletJSON, type WalletJSONExportOptions, type WalletSource, addressesMatch, assertFieldEnvelopeShape, base58Decode, base58Encode, bytesToHex, checkNetworkHealth, coinIdsMatch, createCommunicationsModule, createGroupChatModule, createKeyPair, createMarketModule, createPriceProvider, createSphere, decrypt, decryptField, decryptFieldBytes, decryptJson, decryptMnemonic, decryptSimple, decryptTextFormatKey, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveFieldEncryptionKey, deriveKeyAtPath, doubleSha256, encodeNftContent, encrypt, encryptField, encryptFieldBytes, encryptMnemonic, encryptSimple, extractFromText, findPattern, formatAmount, generateAddressFromMasterKey, generateMasterKey, generateMnemonic, getAddressId, getAddressStorageKey, getCoinIdByName, getCoinIdBySymbol, getPublicKey, getTokenDecimals, getTokenDefinition, getTokenIconUrl, getTokenName, getTokenSymbol, hash160, hashSignMessage, hexToBytes, identityFromMnemonicSync, initSphere, isKnownToken, isNftDocumentLink, isPossiblyCommittedSendOutcome, isSphereError, isTextWalletEncrypted, isValidAddress, isValidDirectAddress, isValidNametag, isValidPrivateKey, isWalletTextFormat, loadSphere, logger, mnemonicToSeedSync, normalizeAddress, normalizeCoinId, parseAddress, parseAndDecryptWalletText, parseNftDocument, parseNftPayload, parseTokenAmount, parseWalletText, randomBytes, randomHex, randomUUID, recoverPubkeyFromSignature, ripemd160, safeParseTokenAmount, sha256, signMessage, sleep, sphereExists, toHumanReadable, validateMnemonic, verifyChallengeTemplate, verifyNftLinkContent, verifySignedMessage };
package/dist/index.d.ts CHANGED
@@ -86,6 +86,8 @@ declare const NFT_METADATA_TAG = 39052n;
86
86
  declare const NFT_MEDIA_TAG = 39053n;
87
87
  declare const NFT_LINK_TAG = 39054n;
88
88
  declare const NFT_SIGNED_TAG = 39055n;
89
+ /** The media type of an NftLink that points at a metadata document instead of a media file. */
90
+ declare const NFT_DOCUMENT_MEDIA_TYPE = "application/vnd.unicity.nft+cbor";
89
91
  /** An inline file. */
90
92
  interface NftMedia {
91
93
  readonly kind: 'media';
@@ -115,6 +117,8 @@ interface NftMetadata {
115
117
  readonly external_url: string | null;
116
118
  readonly attributes: readonly NftAttribute[];
117
119
  readonly collection: string | null;
120
+ /** The collection the item claims: 1–64 bytes as even-length hex (decoded lowercase). Never verified here. */
121
+ readonly collection_id: string | null;
118
122
  }
119
123
  type NftContent = NftMetadata | NftMedia | NftLink;
120
124
  type NftSignatureStatus = 'unsigned' | 'valid' | 'invalid';
@@ -127,10 +131,27 @@ interface ParsedNft {
127
131
  readonly signature: Uint8Array;
128
132
  } | null;
129
133
  }
134
+ /** What an NftSigned signature binds besides its payload, exactly as the token's mint records it. */
135
+ interface NftSignatureContext {
136
+ /** The network identifier α (`NetworkId.id`). */
137
+ readonly networkId: number | bigint;
138
+ /** The genesis recipient predicate, as `EncodedPredicate.toCBOR()` bytes. */
139
+ readonly recipientPredicate: Uint8Array;
140
+ /** The 32 raw token id bytes. */
141
+ readonly tokenId: Uint8Array;
142
+ readonly tokenType: Uint8Array;
143
+ }
130
144
  /** Encode one unsigned item. Throws SphereError('…', 'VALIDATION_ERROR') naming the offending field. */
131
145
  declare function encodeNftContent(content: NftContent): Uint8Array;
132
146
  /** Structural parse of a genesis payload. NEVER throws; null = not a recognised NFT. */
133
147
  declare function parseNftPayload(data: Uint8Array | null): ParsedNft | null;
148
+ /**
149
+ * Parse the file a document link points at: exactly one NftMetadata or NftMedia item.
150
+ * NEVER throws; null = not a document. Check the bytes with verifyNftLinkContent first.
151
+ */
152
+ declare function parseNftDocument(bytes: Uint8Array): NftMetadata | NftMedia | null;
153
+ /** Is this an NftLink to a metadata document ({@link NFT_DOCUMENT_MEDIA_TYPE}), resolved with parseNftDocument? */
154
+ declare function isNftDocumentLink(content: NftContent): boolean;
134
155
  /** Does `bytes` match the link's sha256? Pure, sync. */
135
156
  declare function verifyNftLinkContent(link: NftLink, bytes: Uint8Array): boolean;
136
157
 
@@ -4894,4 +4915,4 @@ declare function normalizeAddress(address: string): string;
4894
4915
  */
4895
4916
  declare function addressesMatch(a: string, b: string): boolean;
4896
4917
 
4897
- export { AUTH_CHALLENGE_PREFIX, type AddressInfo, type AddressType, type AggregatorEvent, type AggregatorEventCallback, type AggregatorEventType, type AggregatorProvider, type Asset, type BaseProvider, type BroadcastHandler, type BroadcastMessage, COIN_TYPES, ChallengeTemplateError, type CheckNetworkHealthOptions, CoinGeckoPriceProvider, type CoinlessToken, CommunicationsModule, type CommunicationsModuleConfig, type CommunicationsModuleDependencies, type ComposingIndicator, type ConversationPage, type CreateGroupOptions, DEFAULT_AGGREGATOR_TIMEOUT, DEFAULT_DERIVATION_PATH, DEFAULT_GROUP_RELAYS, DEFAULT_MARKET_API_URL, DEFAULT_NOSTR_RELAYS, type DecryptionProgressCallback, type DerivationMode, type DirectMessage, type DiscoverAddressProgress, type DiscoverAddressesOptions, type DiscoverAddressesResult, type DiscoveredAddress, type EncryptedData, FIELD_ENCRYPTION_HKDF_INFO, FIELD_ENVELOPE_MAX_BYTES, FIELD_ENVELOPE_NONCE_BYTES, FIELD_ENVELOPE_PREFIX, type FullIdentity, type GetConversationPageOptions, GroupChatModule, type GroupChatModuleConfig, type GroupChatModuleDependencies, type GroupData, type GroupMemberData, type GroupMessageData, GroupRole, GroupVisibility, type HealthCheckFn, type HistoryRecord, type Identity, type IdentityConfig, type IncomingBroadcast, type IncomingMessage, type IncomingTransfer, type InitProgress, type InitProgressCallback, type InitProgressStep, type IntentStatus, type IntentType, LIMITS, type LegacyFileParseResult, type LegacyFileParsedData, type LegacyFileType, type LogHandler, type LogLevel, type LoggerConfig, type MarketIntent, MarketModule, type MarketModuleConfig, type MarketModuleDependencies, type MessageHandler, type MintNftRequest, NETWORKS, NFT_LINK_TAG, NFT_MAX_PAYLOAD_BYTES, NFT_MEDIA_TAG, NFT_METADATA_TAG, NFT_SIGNED_TAG, NIP29_KINDS, NOSTR_EVENT_KINDS, type NetworkHealthResult, type NetworkType, type NftAttribute, type NftContent, type NftLink, type NftMedia, type NftMediaRef, type NftMetadata, type NftSignatureStatus, type NftView, type OracleEvent, type OracleEventCallback, type OracleEventType, type OracleProvider, type ParsedAddress, PartialSendConflictError, type PeerInfo, type PostIntentRequest, type PostIntentResult, type PricePlatform, type PriceProvider, type PriceProviderConfig, type ProviderMetadata, type ProviderRole, type ProviderStatus, type ProviderStatusInfo, type RegistryNetwork, SIGN_MESSAGE_PREFIX, STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, STORAGE_PREFIX, type SearchFilters, type SearchIntentResult, type SearchOptions, type SearchResult, type ServiceHealthResult, Sphere, type SphereCreateOptions, SphereError, type SphereErrorCode, type SphereEventHandler, type SphereEventMap, type SphereEventType, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, type SphereStatus, type StorageProvider, TEST_NOSTR_RELAYS, TIMEOUTS, type Token, type TokenDefinition, type TokenIcon, type TokenPrice, TokenRegistry, type TokenStatus, type TokenTransferDetail, type TrackedAddress, type TrackedAddressEntry, type HistoryRecord as TransactionHistoryEntry, type TransferRequest, type TransferResult, type TransferStatus, type TransportEvent, type TransportEventCallback, type TransportEventType, type TransportProvider, type WalletApiTransportConfig, type WalletInfo, type WalletJSON, type WalletJSONExportOptions, type WalletSource, addressesMatch, assertFieldEnvelopeShape, base58Decode, base58Encode, bytesToHex, checkNetworkHealth, coinIdsMatch, createCommunicationsModule, createGroupChatModule, createKeyPair, createMarketModule, createPriceProvider, createSphere, decrypt, decryptField, decryptFieldBytes, decryptJson, decryptMnemonic, decryptSimple, decryptTextFormatKey, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveFieldEncryptionKey, deriveKeyAtPath, doubleSha256, encodeNftContent, encrypt, encryptField, encryptFieldBytes, encryptMnemonic, encryptSimple, extractFromText, findPattern, formatAmount, generateAddressFromMasterKey, generateMasterKey, generateMnemonic, getAddressId, getAddressStorageKey, getCoinIdByName, getCoinIdBySymbol, getPublicKey, getTokenDecimals, getTokenDefinition, getTokenIconUrl, getTokenName, getTokenSymbol, hash160, hashSignMessage, hexToBytes, identityFromMnemonicSync, initSphere, isKnownToken, isPossiblyCommittedSendOutcome, isSphereError, isTextWalletEncrypted, isValidAddress, isValidDirectAddress, isValidNametag, isValidPrivateKey, isWalletTextFormat, loadSphere, logger, mnemonicToSeedSync, normalizeAddress, normalizeCoinId, parseAddress, parseAndDecryptWalletText, parseNftPayload, parseTokenAmount, parseWalletText, randomBytes, randomHex, randomUUID, recoverPubkeyFromSignature, ripemd160, safeParseTokenAmount, sha256, signMessage, sleep, sphereExists, toHumanReadable, validateMnemonic, verifyChallengeTemplate, verifyNftLinkContent, verifySignedMessage };
4918
+ export { AUTH_CHALLENGE_PREFIX, type AddressInfo, type AddressType, type AggregatorEvent, type AggregatorEventCallback, type AggregatorEventType, type AggregatorProvider, type Asset, type BaseProvider, type BroadcastHandler, type BroadcastMessage, COIN_TYPES, ChallengeTemplateError, type CheckNetworkHealthOptions, CoinGeckoPriceProvider, type CoinlessToken, CommunicationsModule, type CommunicationsModuleConfig, type CommunicationsModuleDependencies, type ComposingIndicator, type ConversationPage, type CreateGroupOptions, DEFAULT_AGGREGATOR_TIMEOUT, DEFAULT_DERIVATION_PATH, DEFAULT_GROUP_RELAYS, DEFAULT_MARKET_API_URL, DEFAULT_NOSTR_RELAYS, type DecryptionProgressCallback, type DerivationMode, type DirectMessage, type DiscoverAddressProgress, type DiscoverAddressesOptions, type DiscoverAddressesResult, type DiscoveredAddress, type EncryptedData, FIELD_ENCRYPTION_HKDF_INFO, FIELD_ENVELOPE_MAX_BYTES, FIELD_ENVELOPE_NONCE_BYTES, FIELD_ENVELOPE_PREFIX, type FullIdentity, type GetConversationPageOptions, GroupChatModule, type GroupChatModuleConfig, type GroupChatModuleDependencies, type GroupData, type GroupMemberData, type GroupMessageData, GroupRole, GroupVisibility, type HealthCheckFn, type HistoryRecord, type Identity, type IdentityConfig, type IncomingBroadcast, type IncomingMessage, type IncomingTransfer, type InitProgress, type InitProgressCallback, type InitProgressStep, type IntentStatus, type IntentType, LIMITS, type LegacyFileParseResult, type LegacyFileParsedData, type LegacyFileType, type LogHandler, type LogLevel, type LoggerConfig, type MarketIntent, MarketModule, type MarketModuleConfig, type MarketModuleDependencies, type MessageHandler, type MintNftRequest, NETWORKS, NFT_DOCUMENT_MEDIA_TYPE, NFT_LINK_TAG, NFT_MAX_PAYLOAD_BYTES, NFT_MEDIA_TAG, NFT_METADATA_TAG, NFT_SIGNED_TAG, NIP29_KINDS, NOSTR_EVENT_KINDS, type NetworkHealthResult, type NetworkType, type NftAttribute, type NftContent, type NftLink, type NftMedia, type NftMediaRef, type NftMetadata, type NftSignatureContext, type NftSignatureStatus, type NftView, type OracleEvent, type OracleEventCallback, type OracleEventType, type OracleProvider, type ParsedAddress, PartialSendConflictError, type PeerInfo, type PostIntentRequest, type PostIntentResult, type PricePlatform, type PriceProvider, type PriceProviderConfig, type ProviderMetadata, type ProviderRole, type ProviderStatus, type ProviderStatusInfo, type RegistryNetwork, SIGN_MESSAGE_PREFIX, STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, STORAGE_PREFIX, type SearchFilters, type SearchIntentResult, type SearchOptions, type SearchResult, type ServiceHealthResult, Sphere, type SphereCreateOptions, SphereError, type SphereErrorCode, type SphereEventHandler, type SphereEventMap, type SphereEventType, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, type SphereStatus, type StorageProvider, TEST_NOSTR_RELAYS, TIMEOUTS, type Token, type TokenDefinition, type TokenIcon, type TokenPrice, TokenRegistry, type TokenStatus, type TokenTransferDetail, type TrackedAddress, type TrackedAddressEntry, type HistoryRecord as TransactionHistoryEntry, type TransferRequest, type TransferResult, type TransferStatus, type TransportEvent, type TransportEventCallback, type TransportEventType, type TransportProvider, type WalletApiTransportConfig, type WalletInfo, type WalletJSON, type WalletJSONExportOptions, type WalletSource, addressesMatch, assertFieldEnvelopeShape, base58Decode, base58Encode, bytesToHex, checkNetworkHealth, coinIdsMatch, createCommunicationsModule, createGroupChatModule, createKeyPair, createMarketModule, createPriceProvider, createSphere, decrypt, decryptField, decryptFieldBytes, decryptJson, decryptMnemonic, decryptSimple, decryptTextFormatKey, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveFieldEncryptionKey, deriveKeyAtPath, doubleSha256, encodeNftContent, encrypt, encryptField, encryptFieldBytes, encryptMnemonic, encryptSimple, extractFromText, findPattern, formatAmount, generateAddressFromMasterKey, generateMasterKey, generateMnemonic, getAddressId, getAddressStorageKey, getCoinIdByName, getCoinIdBySymbol, getPublicKey, getTokenDecimals, getTokenDefinition, getTokenIconUrl, getTokenName, getTokenSymbol, hash160, hashSignMessage, hexToBytes, identityFromMnemonicSync, initSphere, isKnownToken, isNftDocumentLink, isPossiblyCommittedSendOutcome, isSphereError, isTextWalletEncrypted, isValidAddress, isValidDirectAddress, isValidNametag, isValidPrivateKey, isWalletTextFormat, loadSphere, logger, mnemonicToSeedSync, normalizeAddress, normalizeCoinId, parseAddress, parseAndDecryptWalletText, parseNftDocument, parseNftPayload, parseTokenAmount, parseWalletText, randomBytes, randomHex, randomUUID, recoverPubkeyFromSignature, ripemd160, safeParseTokenAmount, sha256, signMessage, sleep, sphereExists, toHumanReadable, validateMnemonic, verifyChallengeTemplate, verifyNftLinkContent, verifySignedMessage };
package/dist/index.js CHANGED
@@ -4558,6 +4558,26 @@ var GroupVisibility = {
4558
4558
  PRIVATE: "PRIVATE"
4559
4559
  };
4560
4560
 
4561
+ // modules/groupchat/group-id.ts
4562
+ var MAX_SLUG_LENGTH = 24;
4563
+ var RANDOM_BYTES = 8;
4564
+ function groupIdSlug(name) {
4565
+ const slug = name.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/['\u2019]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4566
+ if (slug.length <= MAX_SLUG_LENGTH) return slug;
4567
+ const head = slug.slice(0, MAX_SLUG_LENGTH + 1);
4568
+ const hyphen = head.lastIndexOf("-");
4569
+ return hyphen > 0 ? head.slice(0, hyphen) : slug.slice(0, MAX_SLUG_LENGTH);
4570
+ }
4571
+ function newGroupId(name) {
4572
+ const crypto2 = globalThis.crypto;
4573
+ if (typeof crypto2?.getRandomValues !== "function") {
4574
+ throw new SphereError("Creating a group requires crypto.getRandomValues", "INVALID_CONFIG");
4575
+ }
4576
+ const bytes = crypto2.getRandomValues(new Uint8Array(RANDOM_BYTES));
4577
+ const random = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4578
+ return `${groupIdSlug(name) || "group"}-${random}`;
4579
+ }
4580
+
4561
4581
  // modules/groupchat/GroupChatModule.ts
4562
4582
  function createNip29Filter(data) {
4563
4583
  return new Filter3(data);
@@ -5169,9 +5189,9 @@ var GroupChatModule = class {
5169
5189
  if (!this.client) return null;
5170
5190
  const creatorPubkey = this.getMyPublicKey();
5171
5191
  if (!creatorPubkey) return null;
5172
- const proposedGroupId = options.name.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 20) || this.randomId();
5173
5192
  try {
5174
5193
  const isPrivate = options.visibility === GroupVisibility.PRIVATE;
5194
+ const proposedGroupId = newGroupId(options.name);
5175
5195
  const eventId = await this.client.createAndPublishEvent({
5176
5196
  kind: NIP29_KINDS.CREATE_GROUP,
5177
5197
  tags: [["h", proposedGroupId]],
@@ -9802,7 +9822,8 @@ var NFT_MEDIA_TAG = 39053n;
9802
9822
  var NFT_LINK_TAG = 39054n;
9803
9823
  var NFT_SIGNED_TAG = 39055n;
9804
9824
  var NFT_FORMAT_VERSION = 1n;
9805
- var METADATA_ARITY = 8;
9825
+ var NFT_DOCUMENT_MEDIA_TYPE = "application/vnd.unicity.nft+cbor";
9826
+ var METADATA_ARITY = 9;
9806
9827
  var MEDIA_ARITY = 3;
9807
9828
  var LINK_ARITY = 4;
9808
9829
  var SIGNED_ARITY = 4;
@@ -9810,12 +9831,15 @@ var CREATOR_BYTES = 33;
9810
9831
  var SIGNATURE_BYTES = 65;
9811
9832
  var MAX_URI_LENGTH = 2048;
9812
9833
  var LINK_SCHEMES = ["https://", "ipfs://", "ar://"];
9813
- var SIGNED_DOMAIN = "NftSigned";
9834
+ var SIGNED_DOMAIN = new TextEncoder().encode("UNICITY_NFT_SIGNED");
9814
9835
  var MEDIA_TYPE_PATTERN = /^[a-z0-9][a-z0-9!#$&^_.+-]{0,126}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,126}$/;
9815
9836
  var SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
9837
+ var COLLECTION_ID_PATTERN = /^(?:[0-9a-f]{2}){1,64}$/i;
9816
9838
  var LONE_SURROGATE = /\p{Cs}/u;
9817
9839
  var CBOR_MAJOR_TYPE_MASK = 224;
9818
9840
  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";
9841
+ var COLLECTION_ID_RULE = "must be null or 1\u201364 bytes as even-length hex (2\u2013128 characters)";
9842
+ var DOCUMENT_AS_MEDIA_RULE = `must not be ${NFT_DOCUMENT_MEDIA_TYPE}: a document link is a token's content, never media`;
9819
9843
  var UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
9820
9844
  function refuse(field, rule, cause) {
9821
9845
  return new SphereError(`Invalid NFT ${field}: ${rule}`, "VALIDATION_ERROR", cause);
@@ -9827,6 +9851,7 @@ var fieldName = (prefix, name) => prefix === "" ? name : `${prefix}.${name}`;
9827
9851
  var isText = (value) => typeof value === "string" && value.length > 0 && !LONE_SURROGATE.test(value);
9828
9852
  var isBytes3 = (value, length) => value instanceof Uint8Array && (length === void 0 ? value.length > 0 : value.length === length);
9829
9853
  var isMediaType = (value) => typeof value === "string" && MEDIA_TYPE_PATTERN.test(value);
9854
+ var isCollectionId = (value) => typeof value === "string" && COLLECTION_ID_PATTERN.test(value);
9830
9855
  var isAttributeValue = (value) => typeof value === "number" ? Number.isSafeInteger(value) : isText(value);
9831
9856
  function hasSpaceOrControl(value) {
9832
9857
  for (let i = 0; i < value.length; i++) {
@@ -9869,8 +9894,9 @@ function checkLink(prefix, link) {
9869
9894
  function checkMediaRef(field, ref) {
9870
9895
  if (ref === null) return;
9871
9896
  if (ref?.kind === "media") return checkMedia(field, ref);
9872
- if (ref?.kind === "link") return checkLink(field, ref);
9873
- throw refuse(field, "must be an NftMedia, an NftLink or null");
9897
+ if (ref?.kind !== "link") throw refuse(field, "must be an NftMedia, an NftLink or null");
9898
+ checkLink(field, ref);
9899
+ ensure(!isNftDocumentLink(ref), fieldName(field, "media_type"), DOCUMENT_AS_MEDIA_RULE);
9874
9900
  }
9875
9901
  function checkAttributes(attributes) {
9876
9902
  ensure(Array.isArray(attributes), "attributes", "must be an array \u2014 [] when there are none");
@@ -9887,6 +9913,7 @@ function checkMetadata(metadata) {
9887
9913
  checkOptionalText("external_url", metadata.external_url);
9888
9914
  checkAttributes(metadata.attributes);
9889
9915
  checkOptionalText("collection", metadata.collection);
9916
+ ensure(metadata.collection_id === null || isCollectionId(metadata.collection_id), "collection_id", COLLECTION_ID_RULE);
9890
9917
  }
9891
9918
  function checkContent(content) {
9892
9919
  switch (content?.kind) {
@@ -9944,6 +9971,7 @@ function arrayCbor(items) {
9944
9971
  }
9945
9972
  return out;
9946
9973
  }
9974
+ var optionalHexBytes = (value) => CborSerializer.encodeNullable(value, (hex) => CborSerializer.encodeByteString(HexConverter.decode(hex.toLowerCase())));
9947
9975
  function metadataCbor(metadata) {
9948
9976
  return versioned(
9949
9977
  NFT_METADATA_TAG,
@@ -9953,7 +9981,8 @@ function metadataCbor(metadata) {
9953
9981
  mediaRefCbor(metadata.animation_url),
9954
9982
  optionalText(metadata.external_url),
9955
9983
  arrayCbor(metadata.attributes.map(attributeCbor)),
9956
- optionalText(metadata.collection)
9984
+ optionalText(metadata.collection),
9985
+ optionalHexBytes(metadata.collection_id)
9957
9986
  );
9958
9987
  }
9959
9988
  function encodeNftContent(content) {
@@ -10011,13 +10040,14 @@ function decodeMedia(body) {
10011
10040
  const [, mediaType, bytes] = versionedFields(body, MEDIA_ARITY);
10012
10041
  return { kind: "media", media_type: decodeText(mediaType), bytes: CborDeserializer.decodeByteString(bytes) };
10013
10042
  }
10043
+ var decodeHex = (item) => HexConverter.encode(CborDeserializer.decodeByteString(item));
10014
10044
  function decodeLink(body) {
10015
10045
  const [, mediaType, uri, digest] = versionedFields(body, LINK_ARITY);
10016
10046
  return {
10017
10047
  kind: "link",
10018
10048
  media_type: decodeText(mediaType),
10019
10049
  uri: decodeText(uri),
10020
- sha256: HexConverter.encode(CborDeserializer.decodeByteString(digest))
10050
+ sha256: decodeHex(digest)
10021
10051
  };
10022
10052
  }
10023
10053
  function decodeMetadata(body) {
@@ -10030,7 +10060,8 @@ function decodeMetadata(body) {
10030
10060
  animation_url: decodeMediaRef("animation_url", fields[4]),
10031
10061
  external_url: decodeOptionalText(fields[5]),
10032
10062
  attributes: decodeAttributes(fields[6]),
10033
- collection: decodeOptionalText(fields[7])
10063
+ collection: decodeOptionalText(fields[7]),
10064
+ collection_id: CborDeserializer.decodeNullable(fields[8], decodeHex)
10034
10065
  };
10035
10066
  }
10036
10067
  var MEDIA_REF_DECODERS = /* @__PURE__ */ new Map([
@@ -10042,6 +10073,10 @@ var UNSIGNED_DECODERS = /* @__PURE__ */ new Map([
10042
10073
  [NFT_MEDIA_TAG, decodeMedia],
10043
10074
  [NFT_LINK_TAG, decodeLink]
10044
10075
  ]);
10076
+ var DOCUMENT_DECODERS = /* @__PURE__ */ new Map([
10077
+ [NFT_METADATA_TAG, decodeMetadata],
10078
+ [NFT_MEDIA_TAG, decodeMedia]
10079
+ ]);
10045
10080
  function decodeBody(decoders, field, tag, body) {
10046
10081
  const decode = decoders.get(tag);
10047
10082
  if (decode === void 0) throw refuse(field, `tag ${tag} is not allowed here`);
@@ -10076,20 +10111,35 @@ function parseNftPayload(data) {
10076
10111
  return null;
10077
10112
  }
10078
10113
  }
10079
- function nftSignedDigest(tokenIdCbor, recipientPredicateCbor, payload) {
10114
+ function parseNftDocument(bytes) {
10115
+ try {
10116
+ const document = decodeItem(DOCUMENT_DECODERS, "document", bytes);
10117
+ checkContent(document);
10118
+ return document;
10119
+ } catch {
10120
+ return null;
10121
+ }
10122
+ }
10123
+ function isNftDocumentLink(content) {
10124
+ return content?.kind === "link" && content.media_type === NFT_DOCUMENT_MEDIA_TYPE;
10125
+ }
10126
+ function nftSignedDigest(context, payload) {
10080
10127
  const preimage = CborSerializer.encodeArray(
10081
- CborSerializer.encodeTextString(SIGNED_DOMAIN),
10082
- tokenIdCbor,
10083
- recipientPredicateCbor,
10128
+ CborSerializer.encodeByteString(SIGNED_DOMAIN),
10129
+ CborSerializer.encodeUnsignedInteger(NFT_FORMAT_VERSION),
10130
+ CborSerializer.encodeUnsignedInteger(NetworkId.fromId(context.networkId).id),
10131
+ CborSerializer.encodeByteString(context.recipientPredicate),
10132
+ CborSerializer.encodeByteString(context.tokenId),
10133
+ CborSerializer.encodeByteString(context.tokenType),
10084
10134
  CborSerializer.encodeByteString(payload)
10085
10135
  );
10086
10136
  return new DataHasher(HashAlgorithm.SHA256).update(preimage).digest();
10087
10137
  }
10088
- async function verifyNftSignature(signed, tokenIdCbor, recipientPredicateCbor) {
10138
+ async function verifyNftSignature(signed, context) {
10089
10139
  try {
10090
10140
  if (!SigningService.isPublicKeyValid(signed.creator)) return "invalid";
10091
10141
  const signature = Signature.decode(signed.signature);
10092
- const digest = await nftSignedDigest(tokenIdCbor, recipientPredicateCbor, signed.payload);
10142
+ const digest = await nftSignedDigest(context, signed.payload);
10093
10143
  return await SigningService.verifyWithPublicKey(digest, signature, signed.creator) ? "valid" : "invalid";
10094
10144
  } catch {
10095
10145
  return "invalid";
@@ -10223,8 +10273,8 @@ function assertMintableData(data) {
10223
10273
  function nftRecipientCbor(pubkey) {
10224
10274
  return EncodedPredicate.fromPredicate(SignaturePredicate.create(pubkey)).toCBOR();
10225
10275
  }
10226
- async function signPayload(deps, payload, tokenId, recipientPubkey) {
10227
- const digest = await nftSignedDigest(tokenId.toCBOR(), nftRecipientCbor(recipientPubkey), payload);
10276
+ async function signPayload(deps, payload, context) {
10277
+ const digest = await nftSignedDigest(context, payload);
10228
10278
  const signature = await deps.signingService.sign(digest);
10229
10279
  return encodeNftSigned(deps.signingService.publicKey, payload, signature.encode());
10230
10280
  }
@@ -10233,31 +10283,41 @@ async function planNftMint(deps, params) {
10233
10283
  const tokenType = new TokenType(params.tokenType).bytes;
10234
10284
  const salt = TokenSalt.generate();
10235
10285
  const tokenId = await TokenId.fromSalt(deps.networkId, salt);
10236
- const data = params.sign ? await signPayload(deps, payload, tokenId, params.recipientPubkey) : payload;
10286
+ const data = params.sign ? await signPayload(deps, payload, {
10287
+ networkId: deps.networkId.id,
10288
+ recipientPredicate: nftRecipientCbor(params.recipientPubkey),
10289
+ tokenId: tokenId.bytes,
10290
+ tokenType
10291
+ }) : payload;
10237
10292
  assertMintableData(data);
10238
10293
  return { data, salt: salt.toBytes(), tokenType, tokenId: HexConverter.encode(tokenId.bytes) };
10239
10294
  }
10240
- async function verifyAgainst(signed, tokenIdCbor, genesisRecipientCbor) {
10295
+ async function verifyAgainst(signed, genesisContext) {
10241
10296
  try {
10242
- return await verifyNftSignature(signed, tokenIdCbor, genesisRecipientCbor());
10297
+ return await verifyNftSignature(signed, genesisContext());
10243
10298
  } catch {
10244
10299
  return "invalid";
10245
10300
  }
10246
10301
  }
10247
- async function readNftData(data, tokenIdCbor, genesisRecipientCbor) {
10302
+ async function readNftData(data, genesisContext) {
10248
10303
  const parsed = parseNftPayload(data);
10249
10304
  if (parsed === null) return null;
10250
10305
  if (parsed.signed === null) return { content: parsed.content, creator: null, signature: "unsigned" };
10251
10306
  return {
10252
10307
  content: parsed.content,
10253
10308
  creator: HexConverter.encode(parsed.signed.creator),
10254
- signature: await verifyAgainst(parsed.signed, tokenIdCbor, genesisRecipientCbor)
10309
+ signature: await verifyAgainst(parsed.signed, genesisContext)
10255
10310
  };
10256
10311
  }
10257
10312
  async function readTokenNft(token) {
10258
10313
  try {
10259
10314
  const { genesis } = token.sdkToken;
10260
- return await readNftData(genesis.data, genesis.tokenId.toCBOR(), () => genesis.recipient.toCBOR());
10315
+ return await readNftData(genesis.data, () => ({
10316
+ networkId: genesis.networkId.id,
10317
+ recipientPredicate: genesis.recipient.toCBOR(),
10318
+ tokenId: genesis.tokenId.bytes,
10319
+ tokenType: genesis.tokenType.bytes
10320
+ }));
10261
10321
  } catch {
10262
10322
  return null;
10263
10323
  }
@@ -20725,6 +20785,7 @@ export {
20725
20785
  LIMITS,
20726
20786
  MarketModule,
20727
20787
  NETWORKS,
20788
+ NFT_DOCUMENT_MEDIA_TYPE,
20728
20789
  NFT_LINK_TAG,
20729
20790
  NFT_MAX_PAYLOAD_BYTES,
20730
20791
  NFT_MEDIA_TAG,
@@ -20803,6 +20864,7 @@ export {
20803
20864
  identityFromMnemonicSync,
20804
20865
  initSphere,
20805
20866
  isKnownToken,
20867
+ isNftDocumentLink,
20806
20868
  isPhoneNumber2 as isPhoneNumber,
20807
20869
  isPossiblyCommittedSendOutcome,
20808
20870
  isSphereError,
@@ -20820,6 +20882,7 @@ export {
20820
20882
  normalizeNametag2 as normalizeNametag,
20821
20883
  parseAddress,
20822
20884
  parseAndDecryptWalletText,
20885
+ parseNftDocument,
20823
20886
  parseNftPayload,
20824
20887
  parseTokenAmount,
20825
20888
  parseWalletText,