From 913c217a6da706f8acd3d60d556092bef7447415 Mon Sep 17 00:00:00 2001 From: Martynas Kazlauskas Date: Wed, 12 Jan 2022 10:44:20 +0200 Subject: [PATCH] feat(wallet): add types for NFT metadata --- packages/wallet/src/NftMetadata/types.ts | 59 +++++++++++++++++++ .../wallet/test/NftMetadata/types.test.ts | 34 +++++++++++ 2 files changed, 93 insertions(+) create mode 100644 packages/wallet/src/NftMetadata/types.ts create mode 100644 packages/wallet/test/NftMetadata/types.test.ts diff --git a/packages/wallet/src/NftMetadata/types.ts b/packages/wallet/src/NftMetadata/types.ts new file mode 100644 index 00000000000..7770c5ba8fb --- /dev/null +++ b/packages/wallet/src/NftMetadata/types.ts @@ -0,0 +1,59 @@ +/* eslint-disable wrap-regex */ +import { Cardano, InvalidStringError } from '@cardano-sdk/core'; + +export type Uri = Cardano.util.OpaqueString<'Uri'>; +export const Uri = (uri: string) => { + if (/^[a-z]+:\/\/.+/.test(uri)) { + return uri as unknown as Uri; + } + throw new InvalidStringError( + 'Expected Uri to start with "[protocol]://", where protocol is usually "https" or "ipfs"' + ); +}; + +export type ImageMediaType = Cardano.util.OpaqueString<'ImageMediaType'>; +export const ImageMediaType = (mediaType: string) => { + if (/^image\/.+$/.test(mediaType)) { + return mediaType as unknown as ImageMediaType; + } + throw new InvalidStringError('Expected media type to be "image/*"'); +}; + +export type MediaType = Cardano.util.OpaqueString<'MediaType'>; +export const MediaType = (mediaType: string) => { + if (/^[a-z]+\/.+$/.test(mediaType)) { + return mediaType as unknown as MediaType; + } + throw new InvalidStringError('Expected media type to be "*/*"'); +}; + +/** + * https://cips.cardano.org/cips/cip25/ + */ +export interface NftMetadataFile { + name: string; + mediaType: MediaType; + src: Uri | Uri[]; + otherProperties?: { + [key: string]: Cardano.Metadatum; + }; +} + +/** + * https://cips.cardano.org/cips/cip25/ + */ +export interface NftMetadata { + name: string; + image: Uri | Uri[]; + version: string; + mediaType?: ImageMediaType; + files?: NftMetadataFile[]; + description?: string | string[]; + otherProperties?: { + [key: string]: Cardano.Metadatum; + }; +} + +export interface NftMetadataProvider { + (asset: Cardano.Asset): Promise; +} diff --git a/packages/wallet/test/NftMetadata/types.test.ts b/packages/wallet/test/NftMetadata/types.test.ts new file mode 100644 index 00000000000..0155a4696a0 --- /dev/null +++ b/packages/wallet/test/NftMetadata/types.test.ts @@ -0,0 +1,34 @@ +import * as NftMetadata from '../../src/NftMetadata'; +import { InvalidStringError } from '@cardano-sdk/core'; + +describe('NftMetadata/types', () => { + describe('Uri', () => { + it('accepts a string starting with protocol://', () => { + expect(() => NftMetadata.Uri('http://some.url')).not.toThrow(); + expect(() => NftMetadata.Uri('ipfs://abc123')).not.toThrow(); + }); + it('throws for string without protocol:// prefix', () => { + expect(() => NftMetadata.Uri('abc123')).toThrowError(InvalidStringError); + }); + }); + + describe('ImageMediaType', () => { + it('accepts a string starting with image/', () => { + expect(() => NftMetadata.ImageMediaType('image/svg+xml')).not.toThrow(); + }); + it('throws for non-image media type', () => { + expect(() => NftMetadata.ImageMediaType('video/webm')).toThrowError(InvalidStringError); + }); + }); + + describe('MediaType', () => { + it('accepts any media type in format "type/subtype"', () => { + expect(() => NftMetadata.MediaType('image/svg+xml')).not.toThrow(); + expect(() => NftMetadata.MediaType('video/mp4')).not.toThrow(); + expect(() => NftMetadata.MediaType('audio/x-wav')).not.toThrow(); + }); + it('throws for incorrectly formatted media type', () => { + expect(() => NftMetadata.MediaType('videomp4')).toThrowError(InvalidStringError); + }); + }); +});