@alephium/web3 0.14.0 → 0.14.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.
@@ -1,10 +1,24 @@
1
+ import 'cross-fetch/polyfill';
1
2
  export interface NFTMetadata {
2
3
  name: string;
3
- description: string;
4
+ description?: string;
4
5
  image: string;
6
+ attributes?: [
7
+ {
8
+ trait_type: string;
9
+ value: string | number | boolean;
10
+ }
11
+ ];
5
12
  }
6
13
  export interface NFTCollectionMetadata {
7
14
  name: string;
8
15
  description: string;
9
16
  image: string;
10
17
  }
18
+ export declare const validNFTMetadataFields: string[];
19
+ export declare const validNFTMetadataAttributesFields: string[];
20
+ export declare const validNFTMetadataAttributeTypes: string[];
21
+ export declare const validNFTCollectionMetadataFields: string[];
22
+ export declare function validateNFTMetadata(metadata: any): NFTMetadata;
23
+ export declare function validateNFTCollectionMetadata(metadata: any): NFTCollectionMetadata;
24
+ export declare function validateEnumerableNFTBaseUri(nftBaseUri: string, maxSupply: number): Promise<NFTMetadata[]>;
@@ -17,3 +17,103 @@ You should have received a copy of the GNU Lesser General Public License
17
17
  along with the library. If not, see <http://www.gnu.org/licenses/>.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.validateEnumerableNFTBaseUri = exports.validateNFTCollectionMetadata = exports.validateNFTMetadata = exports.validNFTCollectionMetadataFields = exports.validNFTMetadataAttributeTypes = exports.validNFTMetadataAttributesFields = exports.validNFTMetadataFields = void 0;
21
+ // JSON Schema for the NFT metadata, which is pointed to by the value
22
+ // returned from the `getTokenUri` method of the NFT contract
23
+ require("cross-fetch/polyfill");
24
+ exports.validNFTMetadataFields = ['name', 'description', 'image', 'attributes'];
25
+ exports.validNFTMetadataAttributesFields = ['trait_type', 'value'];
26
+ exports.validNFTMetadataAttributeTypes = ['string', 'number', 'boolean'];
27
+ exports.validNFTCollectionMetadataFields = ['name', 'description', 'image'];
28
+ function validateNFTMetadata(metadata) {
29
+ Object.keys(metadata).forEach((key) => {
30
+ if (!exports.validNFTMetadataFields.includes(key)) {
31
+ throw new Error(`Invalid field ${key}, only ${exports.validNFTMetadataFields} are allowed`);
32
+ }
33
+ });
34
+ const name = validateNonEmptyString(metadata, 'name');
35
+ const description = validateNonEmptyStringIfExists(metadata, 'description');
36
+ const image = validateNonEmptyString(metadata, 'image');
37
+ const attributes = validateNFTMetadataAttributes(metadata['attributes']);
38
+ return { name, description, image, attributes };
39
+ }
40
+ exports.validateNFTMetadata = validateNFTMetadata;
41
+ function validateNFTCollectionMetadata(metadata) {
42
+ Object.keys(metadata).forEach((key) => {
43
+ if (!exports.validNFTCollectionMetadataFields.includes(key)) {
44
+ throw new Error(`Invalid field ${key}, only ${exports.validNFTCollectionMetadataFields} are allowed`);
45
+ }
46
+ });
47
+ const name = validateNonEmptyString(metadata, 'name');
48
+ const description = validateNonEmptyString(metadata, 'description');
49
+ const image = validateNonEmptyString(metadata, 'image');
50
+ return { name, description, image };
51
+ }
52
+ exports.validateNFTCollectionMetadata = validateNFTCollectionMetadata;
53
+ async function validateEnumerableNFTBaseUri(nftBaseUri, maxSupply) {
54
+ if (isInteger(maxSupply) && maxSupply > 0) {
55
+ const nftMetadataz = [];
56
+ for (let i = 0; i < maxSupply; i++) {
57
+ const nftMetadata = await fetchNFTMetadata(nftBaseUri, i);
58
+ const validatedNFTMetadata = validateNFTMetadata(nftMetadata);
59
+ nftMetadataz.push(validatedNFTMetadata);
60
+ }
61
+ return nftMetadataz;
62
+ }
63
+ else {
64
+ throw new Error('maxSupply should be a positive integer');
65
+ }
66
+ }
67
+ exports.validateEnumerableNFTBaseUri = validateEnumerableNFTBaseUri;
68
+ function validateNFTMetadataAttributes(attributes) {
69
+ if (!!attributes) {
70
+ if (!Array.isArray(attributes)) {
71
+ throw new Error(`Field 'attributes' should be an array`);
72
+ }
73
+ attributes.forEach((item) => {
74
+ if (typeof item !== 'object') {
75
+ throw new Error(`Field 'attributes' should be an array of objects`);
76
+ }
77
+ Object.keys(item).forEach((key) => {
78
+ if (!exports.validNFTMetadataAttributesFields.includes(key)) {
79
+ throw new Error(`Invalid field ${key} for attributes, only ${exports.validNFTMetadataAttributesFields} are allowed`);
80
+ }
81
+ });
82
+ validateNonEmptyString(item, 'trait_type');
83
+ validateNonEmptyAttributeValue(item, 'value');
84
+ });
85
+ }
86
+ return attributes;
87
+ }
88
+ function validateNonEmptyString(obj, field) {
89
+ const value = obj[`${field}`];
90
+ if (!(typeof value === 'string' && value !== '')) {
91
+ throw new Error(`JSON field '${field}' is not a non empty string`);
92
+ }
93
+ return value;
94
+ }
95
+ function validateNonEmptyStringIfExists(obj, field) {
96
+ const value = obj[`${field}`];
97
+ if (value !== undefined && !(typeof value === 'string' && value !== '')) {
98
+ throw new Error(`JSON field '${field}' is not a non empty string`);
99
+ }
100
+ return value;
101
+ }
102
+ function validateNonEmptyAttributeValue(obj, field) {
103
+ const value = obj[`${field}`];
104
+ if (!((typeof value === 'string' && value !== '') || typeof value === 'number' || typeof value === 'boolean')) {
105
+ throw new Error(`Attribute value should be a non empty string, number or boolean`);
106
+ }
107
+ return value;
108
+ }
109
+ async function fetchNFTMetadata(nftBaseUri, index) {
110
+ try {
111
+ return await (await fetch(`${nftBaseUri}${index}`)).json();
112
+ }
113
+ catch (e) {
114
+ throw new Error(`Error fetching NFT metadata from ${nftBaseUri}${index}: ${e}`);
115
+ }
116
+ }
117
+ function isInteger(num) {
118
+ return num === parseInt(num.toString(), 10);
119
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alephium/web3",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "A JS/TS library to interact with the Alephium platform",
5
5
  "license": "GPL",
6
6
  "main": "dist/src/index.js",
package/src/token/nft.ts CHANGED
@@ -18,10 +18,19 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
18
18
 
19
19
  // JSON Schema for the NFT metadata, which is pointed to by the value
20
20
  // returned from the `getTokenUri` method of the NFT contract
21
+
22
+ import 'cross-fetch/polyfill'
23
+
21
24
  export interface NFTMetadata {
22
25
  name: string
23
- description: string
26
+ description?: string
24
27
  image: string
28
+ attributes?: [
29
+ {
30
+ trait_type: string
31
+ value: string | number | boolean
32
+ }
33
+ ]
25
34
  }
26
35
 
27
36
  // JSON Schema for the NFT Collection metadata, which is pointed to by
@@ -32,3 +41,117 @@ export interface NFTCollectionMetadata {
32
41
  description: string
33
42
  image: string
34
43
  }
44
+
45
+ export const validNFTMetadataFields = ['name', 'description', 'image', 'attributes']
46
+ export const validNFTMetadataAttributesFields = ['trait_type', 'value']
47
+ export const validNFTMetadataAttributeTypes = ['string', 'number', 'boolean']
48
+ export const validNFTCollectionMetadataFields = ['name', 'description', 'image']
49
+
50
+ export function validateNFTMetadata(metadata: any): NFTMetadata {
51
+ Object.keys(metadata).forEach((key) => {
52
+ if (!validNFTMetadataFields.includes(key)) {
53
+ throw new Error(`Invalid field ${key}, only ${validNFTMetadataFields} are allowed`)
54
+ }
55
+ })
56
+
57
+ const name = validateNonEmptyString(metadata, 'name')
58
+ const description = validateNonEmptyStringIfExists(metadata, 'description')
59
+ const image = validateNonEmptyString(metadata, 'image')
60
+ const attributes = validateNFTMetadataAttributes(metadata['attributes'])
61
+
62
+ return { name, description, image, attributes }
63
+ }
64
+
65
+ export function validateNFTCollectionMetadata(metadata: any): NFTCollectionMetadata {
66
+ Object.keys(metadata).forEach((key) => {
67
+ if (!validNFTCollectionMetadataFields.includes(key)) {
68
+ throw new Error(`Invalid field ${key}, only ${validNFTCollectionMetadataFields} are allowed`)
69
+ }
70
+ })
71
+
72
+ const name = validateNonEmptyString(metadata, 'name')
73
+ const description = validateNonEmptyString(metadata, 'description')
74
+ const image = validateNonEmptyString(metadata, 'image')
75
+
76
+ return { name, description, image }
77
+ }
78
+
79
+ export async function validateEnumerableNFTBaseUri(nftBaseUri: string, maxSupply: number): Promise<NFTMetadata[]> {
80
+ if (isInteger(maxSupply) && maxSupply > 0) {
81
+ const nftMetadataz: NFTMetadata[] = []
82
+
83
+ for (let i = 0; i < maxSupply; i++) {
84
+ const nftMetadata = await fetchNFTMetadata(nftBaseUri, i)
85
+ const validatedNFTMetadata = validateNFTMetadata(nftMetadata)
86
+ nftMetadataz.push(validatedNFTMetadata)
87
+ }
88
+
89
+ return nftMetadataz
90
+ } else {
91
+ throw new Error('maxSupply should be a positive integer')
92
+ }
93
+ }
94
+
95
+ function validateNFTMetadataAttributes(attributes: any): NFTMetadata['attributes'] {
96
+ if (!!attributes) {
97
+ if (!Array.isArray(attributes)) {
98
+ throw new Error(`Field 'attributes' should be an array`)
99
+ }
100
+
101
+ attributes.forEach((item) => {
102
+ if (typeof item !== 'object') {
103
+ throw new Error(`Field 'attributes' should be an array of objects`)
104
+ }
105
+
106
+ Object.keys(item).forEach((key) => {
107
+ if (!validNFTMetadataAttributesFields.includes(key)) {
108
+ throw new Error(`Invalid field ${key} for attributes, only ${validNFTMetadataAttributesFields} are allowed`)
109
+ }
110
+ })
111
+
112
+ validateNonEmptyString(item, 'trait_type')
113
+ validateNonEmptyAttributeValue(item, 'value')
114
+ })
115
+ }
116
+
117
+ return attributes as NFTMetadata['attributes']
118
+ }
119
+
120
+ function validateNonEmptyString(obj: object, field: string): string {
121
+ const value = obj[`${field}`]
122
+ if (!(typeof value === 'string' && value !== '')) {
123
+ throw new Error(`JSON field '${field}' is not a non empty string`)
124
+ }
125
+
126
+ return value
127
+ }
128
+
129
+ function validateNonEmptyStringIfExists(obj: object, field: string): string {
130
+ const value = obj[`${field}`]
131
+ if (value !== undefined && !(typeof value === 'string' && value !== '')) {
132
+ throw new Error(`JSON field '${field}' is not a non empty string`)
133
+ }
134
+
135
+ return value
136
+ }
137
+
138
+ function validateNonEmptyAttributeValue(obj: object, field: string): string | number | boolean {
139
+ const value = obj[`${field}`]
140
+ if (!((typeof value === 'string' && value !== '') || typeof value === 'number' || typeof value === 'boolean')) {
141
+ throw new Error(`Attribute value should be a non empty string, number or boolean`)
142
+ }
143
+
144
+ return value
145
+ }
146
+
147
+ async function fetchNFTMetadata(nftBaseUri: string, index: number) {
148
+ try {
149
+ return await (await fetch(`${nftBaseUri}${index}`)).json()
150
+ } catch (e) {
151
+ throw new Error(`Error fetching NFT metadata from ${nftBaseUri}${index}: ${e}`)
152
+ }
153
+ }
154
+
155
+ function isInteger(num: number) {
156
+ return num === parseInt(num.toString(), 10)
157
+ }