@carrot-foundation/schemas 0.1.39 → 0.1.41
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/index.cjs +589 -524
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +466 -673
- package/dist/index.d.ts +466 -673
- package/dist/index.js +589 -522
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/ipfs/collection/collection.example.json +3 -7
- package/schemas/ipfs/collection/collection.schema.json +17 -130
- package/schemas/ipfs/credit/credit.example.json +3 -7
- package/schemas/ipfs/credit/credit.schema.json +17 -130
- package/schemas/ipfs/credit-purchase-receipt/credit-purchase-receipt.example.json +3 -7
- package/schemas/ipfs/credit-purchase-receipt/credit-purchase-receipt.schema.json +144 -243
- package/schemas/ipfs/credit-retirement-receipt/credit-retirement-receipt.example.json +3 -7
- package/schemas/ipfs/credit-retirement-receipt/credit-retirement-receipt.schema.json +143 -239
- package/schemas/ipfs/gas-id/gas-id.example.json +4 -9
- package/schemas/ipfs/gas-id/gas-id.schema.json +63 -206
- package/schemas/ipfs/mass-id/mass-id.example.json +88 -188
- package/schemas/ipfs/mass-id/mass-id.schema.json +675 -646
- package/schemas/ipfs/mass-id-audit/mass-id-audit.example.json +3 -7
- package/schemas/ipfs/mass-id-audit/mass-id-audit.schema.json +28 -150
- package/schemas/ipfs/methodology/methodology.example.json +3 -28
- package/schemas/ipfs/methodology/methodology.schema.json +20 -145
- package/schemas/ipfs/recycled-id/recycled-id.example.json +5 -10
- package/schemas/ipfs/recycled-id/recycled-id.schema.json +62 -203
package/dist/index.js
CHANGED
|
@@ -3,14 +3,12 @@ import 'fs';
|
|
|
3
3
|
import 'path';
|
|
4
4
|
|
|
5
5
|
// src/mass-id/mass-id.attributes.ts
|
|
6
|
-
var
|
|
7
|
-
|
|
6
|
+
var nativeDateParse = Date.parse.bind(Date);
|
|
7
|
+
var ISO_TIMESTAMP_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
8
|
+
var UuidSchema = z.uuidv4().meta({
|
|
9
|
+
title: "UUID V4",
|
|
8
10
|
description: "A universally unique identifier version 4",
|
|
9
|
-
examples: [
|
|
10
|
-
"ad44dd3f-f176-4b98-bf78-5ee6e77d0530",
|
|
11
|
-
"6f520d88-864d-432d-bf9f-5c3166c4818f",
|
|
12
|
-
"f77afa89-1c58-40fd-9bf5-8a86703a8af4"
|
|
13
|
-
]
|
|
11
|
+
examples: ["ad44dd3f-f176-4b98-bf78-5ee6e77d0530"]
|
|
14
12
|
});
|
|
15
13
|
var EthereumAddressSchema = z.string().regex(
|
|
16
14
|
/^0x[a-f0-9]{40}$/,
|
|
@@ -18,27 +16,33 @@ var EthereumAddressSchema = z.string().regex(
|
|
|
18
16
|
).meta({
|
|
19
17
|
title: "Ethereum Address",
|
|
20
18
|
description: "A valid Ethereum address in hexadecimal format",
|
|
21
|
-
examples: [
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
examples: ["0x1234567890abcdef1234567890abcdef12345678"]
|
|
20
|
+
});
|
|
21
|
+
var IsoTimestampSchema = z.string().regex(
|
|
22
|
+
ISO_TIMESTAMP_REGEX,
|
|
23
|
+
"Must be a valid ISO 8601 timestamp with timezone information"
|
|
24
|
+
).superRefine((value, ctx) => {
|
|
25
|
+
const parsed = nativeDateParse(value);
|
|
26
|
+
if (Number.isNaN(parsed)) {
|
|
27
|
+
ctx.addIssue({
|
|
28
|
+
code: "custom",
|
|
29
|
+
message: "Must be a valid ISO 8601 timestamp with timezone information"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
28
32
|
}).meta({
|
|
29
33
|
title: "ISO Timestamp",
|
|
30
34
|
description: "ISO 8601 formatted timestamp with timezone information",
|
|
31
|
-
examples: ["2024-12-05T11:02:47.000Z"
|
|
35
|
+
examples: ["2024-12-05T11:02:47.000Z"]
|
|
32
36
|
});
|
|
33
37
|
var IsoDateSchema = z.iso.date("Must be a valid ISO 8601 date (YYYY-MM-DD)").meta({
|
|
34
38
|
title: "ISO Date",
|
|
35
39
|
description: "ISO 8601 formatted date in YYYY-MM-DD format",
|
|
36
|
-
examples: ["2024-12-05"
|
|
40
|
+
examples: ["2024-12-05"]
|
|
37
41
|
});
|
|
38
42
|
var UnixTimestampSchema = z.number().int().positive().meta({
|
|
39
43
|
title: "Unix Timestamp",
|
|
40
44
|
description: "Unix timestamp in milliseconds since epoch (January 1, 1970 00:00:00 UTC)",
|
|
41
|
-
examples: [17040672e5
|
|
45
|
+
examples: [17040672e5]
|
|
42
46
|
});
|
|
43
47
|
var IsoCountryCodeSchema = z.string().regex(/^[A-Z]{2}$/, "Must be a valid ISO 3166-1 alpha-2 country code").meta({
|
|
44
48
|
title: "ISO Country Code",
|
|
@@ -55,15 +59,20 @@ var IsoAdministrativeDivisionCodeSchema = z.string().regex(
|
|
|
55
59
|
});
|
|
56
60
|
var LatitudeSchema = z.number().min(-90).max(90).multipleOf(1e-3).meta({
|
|
57
61
|
title: "Latitude",
|
|
58
|
-
description: "Geographic latitude coordinate in decimal degrees with maximum 3 decimal places precision (~100m-1km accuracy for city-level
|
|
62
|
+
description: "Geographic latitude coordinate in decimal degrees with maximum 3 decimal places precision (~100m-1km accuracy for city-level)",
|
|
59
63
|
examples: [-0.02, -20.38, 40.713]
|
|
60
64
|
});
|
|
61
65
|
var LongitudeSchema = z.number().min(-180).max(180).multipleOf(1e-3).meta({
|
|
62
66
|
title: "Longitude",
|
|
63
|
-
description: "Geographic longitude coordinate in decimal degrees with maximum 3 decimal places precision (~100m-1km accuracy for city-level
|
|
67
|
+
description: "Geographic longitude coordinate in decimal degrees with maximum 3 decimal places precision (~100m-1km accuracy for city-level)",
|
|
64
68
|
examples: [-51.06, -40.34, -74.006]
|
|
65
69
|
});
|
|
66
|
-
var
|
|
70
|
+
var NonNegativeFloatSchema = z.number().min(0).meta({
|
|
71
|
+
title: "Non-Negative Float",
|
|
72
|
+
description: "Floating-point number that is zero or positive",
|
|
73
|
+
examples: [0, 45.2, 72.5]
|
|
74
|
+
});
|
|
75
|
+
var WeightKgSchema = NonNegativeFloatSchema.meta({
|
|
67
76
|
title: "Weight (kg)",
|
|
68
77
|
description: "Weight measurement in kilograms",
|
|
69
78
|
examples: [3e3, 1500, 500]
|
|
@@ -127,7 +136,7 @@ var WasteTypeSchema = NonEmptyStringSchema.max(100).meta({
|
|
|
127
136
|
var WasteSubtypeSchema = NonEmptyStringSchema.max(100).meta({
|
|
128
137
|
title: "Waste Subtype",
|
|
129
138
|
description: "Specific subcategory of waste within a waste type",
|
|
130
|
-
examples: ["Food, Food Waste and Beverages", "
|
|
139
|
+
examples: ["Food, Food Waste and Beverages", "Domestic Sludge"]
|
|
131
140
|
});
|
|
132
141
|
var ParticipantRoleSchema = NonEmptyStringSchema.max(100).meta({
|
|
133
142
|
title: "Participant Role",
|
|
@@ -139,29 +148,15 @@ var ParticipantNameSchema = NonEmptyStringSchema.max(100).meta({
|
|
|
139
148
|
description: "Name of a participant in the waste management system",
|
|
140
149
|
examples: ["Enlatados Produ\xE7\xE3o", "Eco Reciclagem", "Green Tech Corp"]
|
|
141
150
|
});
|
|
142
|
-
var
|
|
143
|
-
"Collection Point",
|
|
144
|
-
"Recycling Facility",
|
|
145
|
-
"Administrative Office",
|
|
146
|
-
"Other"
|
|
147
|
-
]).meta({
|
|
148
|
-
title: "Facility Type",
|
|
149
|
-
description: "Type of facility in the waste management chain",
|
|
150
|
-
examples: [
|
|
151
|
-
"Collection Point",
|
|
152
|
-
"Recycling Facility",
|
|
153
|
-
"Administrative Office"
|
|
154
|
-
]
|
|
155
|
-
});
|
|
156
|
-
var BlockchainChainIdSchema = z.number().int().min(1).meta({
|
|
151
|
+
var BlockchainChainIdSchema = z.union([z.literal(137), z.literal(80002)]).meta({
|
|
157
152
|
title: "Chain ID",
|
|
158
|
-
description: "
|
|
159
|
-
examples: [
|
|
153
|
+
description: "Supported Polygon chain identifiers",
|
|
154
|
+
examples: [137, 80002]
|
|
160
155
|
});
|
|
161
|
-
var BlockchainNetworkNameSchema =
|
|
156
|
+
var BlockchainNetworkNameSchema = z.enum(["Polygon", "Amoy"]).meta({
|
|
162
157
|
title: "Blockchain Network Name",
|
|
163
|
-
description: "
|
|
164
|
-
examples: ["Polygon", "
|
|
158
|
+
description: "Supported Polygon network names",
|
|
159
|
+
examples: ["Polygon", "Amoy"]
|
|
165
160
|
});
|
|
166
161
|
var SmartContractAddressSchema = EthereumAddressSchema.meta({
|
|
167
162
|
title: "Smart Contract Address",
|
|
@@ -175,7 +170,7 @@ var SmartContractSchema = z.strictObject({
|
|
|
175
170
|
title: "Smart Contract",
|
|
176
171
|
description: "Smart contract details for on-chain references"
|
|
177
172
|
});
|
|
178
|
-
var PercentageSchema =
|
|
173
|
+
var PercentageSchema = NonNegativeFloatSchema.max(100).meta({
|
|
179
174
|
title: "Percentage",
|
|
180
175
|
description: "Percentage value between 0 and 100",
|
|
181
176
|
examples: [50, 75.5, 100]
|
|
@@ -190,11 +185,6 @@ var PositiveIntegerSchema = z.number().int().min(1).meta({
|
|
|
190
185
|
description: "Integer value that is greater than zero",
|
|
191
186
|
examples: [1, 123, 456]
|
|
192
187
|
});
|
|
193
|
-
var NonNegativeFloatSchema = z.number().min(0).meta({
|
|
194
|
-
title: "Non-Negative Float",
|
|
195
|
-
description: "Floating-point number that is zero or positive",
|
|
196
|
-
examples: [0, 45.2, 72.5]
|
|
197
|
-
});
|
|
198
188
|
var CreditTypeSchema = NonEmptyStringSchema.max(100).meta({
|
|
199
189
|
title: "Credit Type",
|
|
200
190
|
description: "Type of credit issued",
|
|
@@ -209,7 +199,7 @@ var HoursSchema = z.number().min(0).multipleOf(0.1).meta({
|
|
|
209
199
|
description: "Time duration in hours with 0.1 hour precision",
|
|
210
200
|
examples: [72.5, 24, 168.5]
|
|
211
201
|
});
|
|
212
|
-
var MinutesSchema =
|
|
202
|
+
var MinutesSchema = NonNegativeIntegerSchema.meta({
|
|
213
203
|
title: "Minutes",
|
|
214
204
|
description: "Time duration in minutes",
|
|
215
205
|
examples: [4350, 1440, 10110]
|
|
@@ -239,7 +229,7 @@ var TokenIdSchema = NonEmptyStringSchema.regex(
|
|
|
239
229
|
).meta({
|
|
240
230
|
title: "Token ID",
|
|
241
231
|
description: "Numeric identifier for blockchain tokens as string",
|
|
242
|
-
examples: ["
|
|
232
|
+
examples: ["456789", "1000000"]
|
|
243
233
|
});
|
|
244
234
|
var HexColorSchema = NonEmptyStringSchema.regex(
|
|
245
235
|
/^#[0-9A-F]{6}$/,
|
|
@@ -247,41 +237,28 @@ var HexColorSchema = NonEmptyStringSchema.regex(
|
|
|
247
237
|
).meta({
|
|
248
238
|
title: "Hex Color",
|
|
249
239
|
description: "Hexadecimal color code with hash prefix",
|
|
250
|
-
examples: ["#2D5A27", "#FF5733"
|
|
240
|
+
examples: ["#2D5A27", "#FF5733"]
|
|
251
241
|
});
|
|
252
242
|
var Sha256HashSchema = z.hash("sha256", {
|
|
253
|
-
error: "Must be a
|
|
243
|
+
error: "Must be a SHA-256 hash as 32-byte hex string"
|
|
254
244
|
}).meta({
|
|
255
245
|
format: void 0,
|
|
256
|
-
title: "
|
|
246
|
+
title: "SHA-256 Hash",
|
|
257
247
|
description: "SHA-256 cryptographic hash as hexadecimal string",
|
|
258
248
|
examples: [
|
|
259
|
-
"87f633634cc4b02f628685651f0a29b7bfa22a0bd841f725c6772dd00a58d489"
|
|
260
|
-
"6e83b8e6373847bbdc056549bedda38dc88854ce41ba4fca11e0fc6ce3e07ef6"
|
|
261
|
-
]
|
|
262
|
-
});
|
|
263
|
-
var Keccak256HashSchema = Sha256HashSchema.meta({
|
|
264
|
-
title: "Keccak256 Hash",
|
|
265
|
-
description: "Keccak256 cryptographic hash as hexadecimal string",
|
|
266
|
-
examples: [
|
|
267
|
-
"ac08c3cf2e175e55961d6affdb38bc24591b84ceef7f3707c69ae3d52c148b2f",
|
|
268
|
-
"b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2"
|
|
249
|
+
"87f633634cc4b02f628685651f0a29b7bfa22a0bd841f725c6772dd00a58d489"
|
|
269
250
|
]
|
|
270
251
|
});
|
|
271
252
|
var ExternalIdSchema = UuidSchema.meta({
|
|
272
253
|
title: "External ID",
|
|
273
|
-
description: "UUID identifier for external system references"
|
|
274
|
-
examples: [
|
|
275
|
-
"ad44dd3f-f176-4b98-bf78-5ee6e77d0530",
|
|
276
|
-
"b2c4e6f8-a1b3-4c5d-9e8f-123456789abc"
|
|
277
|
-
]
|
|
254
|
+
description: "UUID identifier for external system references"
|
|
278
255
|
});
|
|
279
|
-
var ExternalUrlSchema = z.url(
|
|
256
|
+
var ExternalUrlSchema = z.url().meta({
|
|
280
257
|
title: "External URL",
|
|
281
|
-
description: "
|
|
258
|
+
description: "URL pointing to external resources",
|
|
282
259
|
examples: [
|
|
283
|
-
"https://explore.carrot.eco/
|
|
284
|
-
"https://carrot.eco/
|
|
260
|
+
"https://explore.carrot.eco/",
|
|
261
|
+
"https://https://whitepaper.carrot.eco/"
|
|
285
262
|
]
|
|
286
263
|
});
|
|
287
264
|
var RecordSchemaTypeSchema = z.enum([
|
|
@@ -312,21 +289,6 @@ var CreditTokenSymbolSchema = TokenSymbolSchema.meta({
|
|
|
312
289
|
description: "Symbol of the credit token (e.g., C-CARB, C-BIOW)",
|
|
313
290
|
examples: ["C-CARB", "C-BIOW"]
|
|
314
291
|
});
|
|
315
|
-
var RecordRelationshipTypeSchema = z.enum([
|
|
316
|
-
"collection",
|
|
317
|
-
"credit",
|
|
318
|
-
"gas-id",
|
|
319
|
-
"mass-id",
|
|
320
|
-
"mass-id-audit",
|
|
321
|
-
"methodology",
|
|
322
|
-
"credit-purchase-receipt",
|
|
323
|
-
"credit-retirement-receipt",
|
|
324
|
-
"recycled-id"
|
|
325
|
-
]).meta({
|
|
326
|
-
title: "Relationship Type",
|
|
327
|
-
description: "Type of relationship between different entities in the system",
|
|
328
|
-
examples: ["mass-id", "collection", "credit-purchase-receipt"]
|
|
329
|
-
});
|
|
330
292
|
function uniqueArrayItems(schema, errorMessage = "Array items must be unique") {
|
|
331
293
|
return z.array(schema).refine((items) => new Set(items).size === items.length, {
|
|
332
294
|
message: errorMessage
|
|
@@ -365,10 +327,10 @@ var ParticipantSchema = z.strictObject({
|
|
|
365
327
|
title: "Participant",
|
|
366
328
|
description: "A participant in the waste management supply chain"
|
|
367
329
|
});
|
|
368
|
-
var PrecisionLevelSchema = z.enum(["
|
|
330
|
+
var PrecisionLevelSchema = z.enum(["city", "region", "country"]).meta({
|
|
369
331
|
title: "Coordinate Precision Level",
|
|
370
332
|
description: "Level of coordinate precision",
|
|
371
|
-
examples: ["city"
|
|
333
|
+
examples: ["city"]
|
|
372
334
|
});
|
|
373
335
|
var CoordinatesSchema = z.strictObject({
|
|
374
336
|
latitude: LatitudeSchema,
|
|
@@ -392,8 +354,7 @@ var LocationSchema = z.strictObject({
|
|
|
392
354
|
title: "Responsible Participant ID Hash",
|
|
393
355
|
description: "Anonymized ID of the participant responsible for this location"
|
|
394
356
|
}),
|
|
395
|
-
coordinates: CoordinatesSchema
|
|
396
|
-
facility_type: FacilityTypeSchema.optional()
|
|
357
|
+
coordinates: CoordinatesSchema
|
|
397
358
|
}).meta({
|
|
398
359
|
title: "Location",
|
|
399
360
|
description: "Geographic location with address and coordinate information"
|
|
@@ -611,70 +572,20 @@ var ParticipantRewardsSchema = z.strictObject({
|
|
|
611
572
|
title: "Participant Rewards",
|
|
612
573
|
description: "Rewards distribution to participants"
|
|
613
574
|
});
|
|
614
|
-
var SchemaHashSchema =
|
|
615
|
-
Keccak256HashSchema,
|
|
616
|
-
z.string().regex(
|
|
617
|
-
/^0x[a-fA-F0-9]{64}$/,
|
|
618
|
-
"Must be a Keccak256 hash as 0x-prefixed hex string"
|
|
619
|
-
)
|
|
620
|
-
]).meta({
|
|
575
|
+
var SchemaHashSchema = Sha256HashSchema.meta({
|
|
621
576
|
title: "Schema Hash",
|
|
622
|
-
description: "
|
|
623
|
-
examples: [
|
|
624
|
-
"ac08c3cf2e175e55961d6affdb38bc24591b84ceef7f3707c69ae3d52c148b2f",
|
|
625
|
-
"0xac08c3cf2e175e55961d6affdb38bc24591b84ceef7f3707c69ae3d52c148b2f"
|
|
626
|
-
]
|
|
577
|
+
description: "SHA-256 hash of the JSON Schema this record was validated against"
|
|
627
578
|
});
|
|
628
579
|
var SchemaInfoSchema = z.strictObject({
|
|
629
580
|
hash: SchemaHashSchema,
|
|
630
|
-
type: RecordSchemaTypeSchema
|
|
631
|
-
title: "Schema Type",
|
|
632
|
-
description: "Type/category of this schema"
|
|
633
|
-
}),
|
|
581
|
+
type: RecordSchemaTypeSchema,
|
|
634
582
|
version: SemanticVersionSchema.meta({
|
|
635
583
|
title: "Schema Version",
|
|
636
584
|
description: "Version of the schema, using semantic versioning"
|
|
637
585
|
})
|
|
638
586
|
}).meta({
|
|
639
|
-
title: "Schema Information"
|
|
640
|
-
|
|
641
|
-
var RecordCreatorSchema = z.strictObject({
|
|
642
|
-
name: z.string().meta({
|
|
643
|
-
title: "Creator Name",
|
|
644
|
-
description: "Company or individual name that created this record",
|
|
645
|
-
examples: ["Carrot Foundation"]
|
|
646
|
-
}),
|
|
647
|
-
id: UuidSchema.meta({
|
|
648
|
-
title: "Creator ID",
|
|
649
|
-
description: "Unique identifier for the creator"
|
|
650
|
-
})
|
|
651
|
-
}).meta({
|
|
652
|
-
title: "Creator",
|
|
653
|
-
description: "Entity that created this record"
|
|
654
|
-
});
|
|
655
|
-
var RecordRelationshipSchema = z.strictObject({
|
|
656
|
-
target_uri: IpfsUriSchema.meta({
|
|
657
|
-
title: "Target IPFS URI",
|
|
658
|
-
description: "Target IPFS URI of the referenced record"
|
|
659
|
-
}),
|
|
660
|
-
type: RecordRelationshipTypeSchema.meta({
|
|
661
|
-
title: "Relationship Type",
|
|
662
|
-
description: "Type of relationship to the referenced record"
|
|
663
|
-
}),
|
|
664
|
-
description: z.string().optional().meta({
|
|
665
|
-
title: "Relationship Description",
|
|
666
|
-
description: "Human-readable description of the relationship",
|
|
667
|
-
examples: [
|
|
668
|
-
"This record supersedes the previous version",
|
|
669
|
-
"Related carbon credit batch",
|
|
670
|
-
"Source document for this verification",
|
|
671
|
-
"Child record derived from this parent",
|
|
672
|
-
"Updated version of original record"
|
|
673
|
-
]
|
|
674
|
-
})
|
|
675
|
-
}).meta({
|
|
676
|
-
title: "Relationship",
|
|
677
|
-
description: "Relationship to another IPFS record"
|
|
587
|
+
title: "Schema Information",
|
|
588
|
+
description: "Information about the schema used to validate this record"
|
|
678
589
|
});
|
|
679
590
|
var RecordEnvironmentSchema = z.strictObject({
|
|
680
591
|
blockchain_network: z.enum(["mainnet", "testnet"]).meta({
|
|
@@ -690,8 +601,8 @@ var RecordEnvironmentSchema = z.strictObject({
|
|
|
690
601
|
description: "Name of the data set for this record"
|
|
691
602
|
})
|
|
692
603
|
}).meta({
|
|
693
|
-
title: "Environment",
|
|
694
|
-
description: "Environment information"
|
|
604
|
+
title: "Record Environment",
|
|
605
|
+
description: "Environment information for the record"
|
|
695
606
|
});
|
|
696
607
|
var BaseIpfsSchema = z.strictObject({
|
|
697
608
|
$schema: z.url("Must be a valid URI").meta({
|
|
@@ -704,14 +615,8 @@ var BaseIpfsSchema = z.strictObject({
|
|
|
704
615
|
title: "Created At",
|
|
705
616
|
description: "ISO 8601 creation timestamp for this record"
|
|
706
617
|
}),
|
|
707
|
-
external_id: ExternalIdSchema
|
|
708
|
-
|
|
709
|
-
description: "Off-chain reference ID (UUID from Carrot backend)"
|
|
710
|
-
}),
|
|
711
|
-
external_url: ExternalUrlSchema.meta({
|
|
712
|
-
title: "External URL",
|
|
713
|
-
description: "External URL of the content"
|
|
714
|
-
}),
|
|
618
|
+
external_id: ExternalIdSchema,
|
|
619
|
+
external_url: ExternalUrlSchema,
|
|
715
620
|
original_content_hash: Sha256HashSchema.meta({
|
|
716
621
|
title: "Original Content Hash",
|
|
717
622
|
description: "SHA-256 hash of the original JSON content including private data before schema validation"
|
|
@@ -720,11 +625,6 @@ var BaseIpfsSchema = z.strictObject({
|
|
|
720
625
|
title: "Content Hash",
|
|
721
626
|
description: "SHA-256 hash of RFC 8785 canonicalized JSON after schema validation"
|
|
722
627
|
}),
|
|
723
|
-
creator: RecordCreatorSchema.optional(),
|
|
724
|
-
relationships: z.array(RecordRelationshipSchema).optional().meta({
|
|
725
|
-
title: "Relationships",
|
|
726
|
-
description: "References to other IPFS records this record relates to"
|
|
727
|
-
}),
|
|
728
628
|
environment: RecordEnvironmentSchema.optional(),
|
|
729
629
|
data: z.record(z.string(), z.unknown()).optional().meta({
|
|
730
630
|
title: "Custom Data",
|
|
@@ -734,6 +634,11 @@ var BaseIpfsSchema = z.strictObject({
|
|
|
734
634
|
title: "Base IPFS Record",
|
|
735
635
|
description: "Base fields for all Carrot IPFS records, providing common structure for any JSON content stored in IPFS"
|
|
736
636
|
});
|
|
637
|
+
var BLOCKCHAIN_NETWORK_CONFIG = {
|
|
638
|
+
mainnet: { chain_id: 137, network_name: "Polygon" },
|
|
639
|
+
testnet: { chain_id: 80002, network_name: "Amoy" }
|
|
640
|
+
};
|
|
641
|
+
var ALLOWED_BLOCKCHAIN_NETWORKS = Object.values(BLOCKCHAIN_NETWORK_CONFIG);
|
|
737
642
|
var NftSchemaTypeSchema = RecordSchemaTypeSchema.extract([
|
|
738
643
|
"MassID",
|
|
739
644
|
"RecycledID",
|
|
@@ -752,14 +657,27 @@ var BlockchainReferenceSchema = z.strictObject({
|
|
|
752
657
|
title: "Chain ID",
|
|
753
658
|
description: "Blockchain chain ID"
|
|
754
659
|
}),
|
|
755
|
-
network_name:
|
|
756
|
-
title: "Network Name",
|
|
757
|
-
description: "Name of the blockchain network"
|
|
758
|
-
}),
|
|
660
|
+
network_name: BlockchainNetworkNameSchema,
|
|
759
661
|
token_id: TokenIdSchema.meta({
|
|
760
662
|
title: "Token ID",
|
|
761
663
|
description: "NFT token ID"
|
|
762
664
|
})
|
|
665
|
+
}).superRefine((value, ctx) => {
|
|
666
|
+
const matchedNetwork = ALLOWED_BLOCKCHAIN_NETWORKS.find(
|
|
667
|
+
(network) => network.chain_id === value.chain_id && network.network_name === value.network_name
|
|
668
|
+
);
|
|
669
|
+
if (!matchedNetwork) {
|
|
670
|
+
ctx.addIssue({
|
|
671
|
+
code: "custom",
|
|
672
|
+
message: "chain_id and network_name must match a supported network: 137/Polygon (mainnet) or 80002/Amoy (testnet)",
|
|
673
|
+
path: ["chain_id"]
|
|
674
|
+
});
|
|
675
|
+
ctx.addIssue({
|
|
676
|
+
code: "custom",
|
|
677
|
+
message: "chain_id and network_name must match a supported network: 137/Polygon (mainnet) or 80002/Amoy (testnet)",
|
|
678
|
+
path: ["network_name"]
|
|
679
|
+
});
|
|
680
|
+
}
|
|
763
681
|
}).meta({
|
|
764
682
|
title: "Blockchain Information",
|
|
765
683
|
description: "Blockchain-specific information for the NFT"
|
|
@@ -904,6 +822,26 @@ var NftIpfsSchema = BaseIpfsSchema.safeExtend({
|
|
|
904
822
|
]
|
|
905
823
|
]
|
|
906
824
|
})
|
|
825
|
+
}).superRefine((value, ctx) => {
|
|
826
|
+
const environmentNetwork = value.environment?.blockchain_network;
|
|
827
|
+
if (!environmentNetwork) {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
const config = BLOCKCHAIN_NETWORK_CONFIG[environmentNetwork];
|
|
831
|
+
if (value.blockchain.chain_id !== config.chain_id) {
|
|
832
|
+
ctx.addIssue({
|
|
833
|
+
code: "custom",
|
|
834
|
+
message: `blockchain.chain_id must be ${config.chain_id} when environment.blockchain_network is ${environmentNetwork}`,
|
|
835
|
+
path: ["blockchain", "chain_id"]
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
if (value.blockchain.network_name !== config.network_name) {
|
|
839
|
+
ctx.addIssue({
|
|
840
|
+
code: "custom",
|
|
841
|
+
message: `blockchain.network_name must be ${config.network_name} when environment.blockchain_network is ${environmentNetwork}`,
|
|
842
|
+
path: ["blockchain", "network_name"]
|
|
843
|
+
});
|
|
844
|
+
}
|
|
907
845
|
}).meta({
|
|
908
846
|
title: "NFT IPFS Record",
|
|
909
847
|
description: "NFT-specific fields for Carrot IPFS records"
|
|
@@ -916,7 +854,7 @@ function buildSchemaUrl(schemaPath) {
|
|
|
916
854
|
return `${getSchemaBaseUrl()}/${cleanPath}`;
|
|
917
855
|
}
|
|
918
856
|
function getSchemaVersionOrDefault() {
|
|
919
|
-
return "0.1.
|
|
857
|
+
return "0.1.41";
|
|
920
858
|
}
|
|
921
859
|
var MethodologyAttributeSchema = NftAttributeSchema.safeExtend({
|
|
922
860
|
trait_type: z.literal("Methodology"),
|
|
@@ -1034,10 +972,6 @@ var AuditRuleDefinitionSchema = z.strictObject({
|
|
|
1034
972
|
"https://github.com/carrot-foundation/methodologies/blob/main/bold-carbon/rules/waste-mass-unique.js"
|
|
1035
973
|
]
|
|
1036
974
|
}),
|
|
1037
|
-
mandatory: z.boolean().meta({
|
|
1038
|
-
title: "Mandatory",
|
|
1039
|
-
description: "Whether this rule is mandatory for methodology compliance"
|
|
1040
|
-
}),
|
|
1041
975
|
execution_order: PositiveIntegerSchema.meta({
|
|
1042
976
|
title: "Rule Execution Order",
|
|
1043
977
|
description: "Sequential order in which this rule must be executed"
|
|
@@ -1416,6 +1350,294 @@ function validateAttributesForItems(params) {
|
|
|
1416
1350
|
}
|
|
1417
1351
|
});
|
|
1418
1352
|
}
|
|
1353
|
+
var IbamaWasteClassificationSchema = z.string().regex(/^\d{2} \d{2} \d{2}\*?$/, "Invalid Ibama code format").meta({
|
|
1354
|
+
title: "Ibama Classification Code",
|
|
1355
|
+
description: "Ibama waste classification code in the format NN NN NN with required spaces and optional trailing *",
|
|
1356
|
+
examples: ["20 01 01", "20 01 01*", "04 02 20"]
|
|
1357
|
+
});
|
|
1358
|
+
var MassIDLocalClassificationSchema = z.strictObject({
|
|
1359
|
+
code: IbamaWasteClassificationSchema,
|
|
1360
|
+
system: z.literal("Ibama").meta({
|
|
1361
|
+
title: "Classification System",
|
|
1362
|
+
description: "Authority or standard providing the classification code",
|
|
1363
|
+
examples: ["Ibama"]
|
|
1364
|
+
})
|
|
1365
|
+
}).meta({
|
|
1366
|
+
title: "Local Classification",
|
|
1367
|
+
description: "Regulatory classification reference for the waste material",
|
|
1368
|
+
examples: [{ code: "04 02 20", system: "Ibama" }]
|
|
1369
|
+
});
|
|
1370
|
+
var MassIDWastePropertiesSchema = z.strictObject({
|
|
1371
|
+
type: WasteTypeSchema.meta({
|
|
1372
|
+
title: "Waste Type",
|
|
1373
|
+
description: "Waste material category",
|
|
1374
|
+
examples: ["Organic"]
|
|
1375
|
+
}),
|
|
1376
|
+
subtype: WasteSubtypeSchema.meta({
|
|
1377
|
+
title: "Waste Subtype",
|
|
1378
|
+
description: "Specific subcategory of waste material",
|
|
1379
|
+
examples: ["Food, Food Waste and Beverages"]
|
|
1380
|
+
}),
|
|
1381
|
+
local_classification: MassIDLocalClassificationSchema.optional(),
|
|
1382
|
+
net_weight: WeightKgSchema.meta({
|
|
1383
|
+
title: "Net Weight (kg)",
|
|
1384
|
+
description: "Net weight of the waste batch in kilograms (kg)",
|
|
1385
|
+
examples: [3e3]
|
|
1386
|
+
})
|
|
1387
|
+
}).meta({
|
|
1388
|
+
title: "Waste Properties",
|
|
1389
|
+
description: "Standardized waste material properties and regulatory information"
|
|
1390
|
+
});
|
|
1391
|
+
var MassIDAttachmentTypeSchema = z.enum(["Recycling Manifest", "Transport Manifest"]).meta({
|
|
1392
|
+
title: "Attachment Type",
|
|
1393
|
+
description: "Type of supporting attachment linked to a MassID event",
|
|
1394
|
+
examples: ["Recycling Manifest", "Transport Manifest"]
|
|
1395
|
+
});
|
|
1396
|
+
var MassIDAttachmentSchema = z.strictObject({
|
|
1397
|
+
type: MassIDAttachmentTypeSchema,
|
|
1398
|
+
document_number: NonEmptyStringSchema.max(50).optional().meta({
|
|
1399
|
+
title: "Document Number",
|
|
1400
|
+
description: "Official document number if applicable",
|
|
1401
|
+
examples: ["2353", "12345"]
|
|
1402
|
+
}),
|
|
1403
|
+
issued_at: IsoTimestampSchema.optional().meta({
|
|
1404
|
+
title: "Issued At",
|
|
1405
|
+
description: "ISO 8601 timestamp when the attachment was issued"
|
|
1406
|
+
}),
|
|
1407
|
+
event_id: UuidSchema.meta({
|
|
1408
|
+
title: "Event ID",
|
|
1409
|
+
description: "Identifier of the event this attachment belongs to"
|
|
1410
|
+
})
|
|
1411
|
+
}).meta({
|
|
1412
|
+
title: "MassID Attachment",
|
|
1413
|
+
description: "Attachment associated with a specific MassID event, linked by event_id"
|
|
1414
|
+
});
|
|
1415
|
+
var MassIDBaseEventSchema = z.strictObject({
|
|
1416
|
+
event_id: UuidSchema.meta({
|
|
1417
|
+
title: "Event ID",
|
|
1418
|
+
description: "Unique event identifier"
|
|
1419
|
+
}),
|
|
1420
|
+
description: NonEmptyStringSchema.max(200).optional().meta({
|
|
1421
|
+
title: "Event Description",
|
|
1422
|
+
description: "Detailed description of what happened during this event",
|
|
1423
|
+
examples: [
|
|
1424
|
+
"Waste collected from residential area using collection truck",
|
|
1425
|
+
"Material sorted into recyclable and non-recyclable fractions",
|
|
1426
|
+
"Waste transferred to authorized recycling facility"
|
|
1427
|
+
]
|
|
1428
|
+
}),
|
|
1429
|
+
timestamp: IsoTimestampSchema.meta({
|
|
1430
|
+
title: "Event Timestamp",
|
|
1431
|
+
description: "ISO 8601 timestamp when the event occurred"
|
|
1432
|
+
}),
|
|
1433
|
+
participant_id_hash: Sha256HashSchema.meta({
|
|
1434
|
+
title: "Participant ID Hash",
|
|
1435
|
+
description: "Reference to participant in the participants array"
|
|
1436
|
+
}),
|
|
1437
|
+
location_id_hash: Sha256HashSchema.meta({
|
|
1438
|
+
title: "Location ID Hash",
|
|
1439
|
+
description: "Reference to location in the locations array"
|
|
1440
|
+
}),
|
|
1441
|
+
weight: WeightKgSchema.optional().meta({
|
|
1442
|
+
title: "Event Weight (kg)",
|
|
1443
|
+
description: "Mass weight after this event in kilograms (kg)"
|
|
1444
|
+
})
|
|
1445
|
+
}).meta({
|
|
1446
|
+
title: "MassID Base Event",
|
|
1447
|
+
description: "Base MassID event definition shared across event types"
|
|
1448
|
+
});
|
|
1449
|
+
var buildMassIDEventSchema = (eventName, description) => MassIDBaseEventSchema.safeExtend({
|
|
1450
|
+
event_name: z.literal(eventName).meta({
|
|
1451
|
+
title: "Event Name",
|
|
1452
|
+
description: `${eventName} event discriminator`,
|
|
1453
|
+
examples: [eventName]
|
|
1454
|
+
})
|
|
1455
|
+
}).meta({
|
|
1456
|
+
title: `${eventName} Event`,
|
|
1457
|
+
description
|
|
1458
|
+
});
|
|
1459
|
+
var PickUpEventSchema = buildMassIDEventSchema(
|
|
1460
|
+
"Pick-up",
|
|
1461
|
+
"Waste picked up from the origin location"
|
|
1462
|
+
).safeExtend({
|
|
1463
|
+
data: z.strictObject({
|
|
1464
|
+
vehicle_type: NonEmptyStringSchema.max(50).optional().meta({
|
|
1465
|
+
title: "Vehicle Type",
|
|
1466
|
+
description: "Type of vehicle used for pick-up operations",
|
|
1467
|
+
examples: ["Truck", "Van", "Compactor"]
|
|
1468
|
+
})
|
|
1469
|
+
}).optional().meta({
|
|
1470
|
+
title: "Pick-up Event Data",
|
|
1471
|
+
description: "Vehicle information associated with the pick-up event"
|
|
1472
|
+
})
|
|
1473
|
+
});
|
|
1474
|
+
var WeighingEventSchema = buildMassIDEventSchema(
|
|
1475
|
+
"Weighing",
|
|
1476
|
+
"Waste weighed at a facility"
|
|
1477
|
+
).safeExtend({
|
|
1478
|
+
data: z.strictObject({
|
|
1479
|
+
weighing_capture_method: NonEmptyStringSchema.max(100).optional().meta({
|
|
1480
|
+
title: "Weighing Capture Method",
|
|
1481
|
+
description: "Method used to capture the weight measurement",
|
|
1482
|
+
examples: [
|
|
1483
|
+
"Digital scale integration",
|
|
1484
|
+
"Manual entry",
|
|
1485
|
+
"Automated capture via IoT scale"
|
|
1486
|
+
]
|
|
1487
|
+
}),
|
|
1488
|
+
scale_type: NonEmptyStringSchema.max(50).optional().meta({
|
|
1489
|
+
title: "Scale Type",
|
|
1490
|
+
description: "Type of scale used to weigh the load",
|
|
1491
|
+
examples: ["Weighbridge (Truck Scale)", "Axle scale"]
|
|
1492
|
+
}),
|
|
1493
|
+
container_type: NonEmptyStringSchema.max(50).optional().meta({
|
|
1494
|
+
title: "Container Type",
|
|
1495
|
+
description: "Type of container holding the waste during weighing",
|
|
1496
|
+
examples: ["Roll-off container", "Front loader bin"]
|
|
1497
|
+
}),
|
|
1498
|
+
vehicle_type: NonEmptyStringSchema.max(50).optional().meta({
|
|
1499
|
+
title: "Vehicle Type",
|
|
1500
|
+
description: "Type of vehicle used during weighing",
|
|
1501
|
+
examples: ["Truck", "Trailer"]
|
|
1502
|
+
}),
|
|
1503
|
+
container_capacity: WeightKgSchema.optional().meta({
|
|
1504
|
+
title: "Container Capacity (kg)",
|
|
1505
|
+
description: "Maximum container capacity in kilograms",
|
|
1506
|
+
examples: [12e3]
|
|
1507
|
+
}),
|
|
1508
|
+
gross_weight: WeightKgSchema.optional().meta({
|
|
1509
|
+
title: "Gross Weight (kg)",
|
|
1510
|
+
description: "Total weight including vehicle/container before tare",
|
|
1511
|
+
examples: [9500]
|
|
1512
|
+
}),
|
|
1513
|
+
tare: WeightKgSchema.optional().meta({
|
|
1514
|
+
title: "Tare Weight (kg)",
|
|
1515
|
+
description: "Weight of the empty vehicle or container",
|
|
1516
|
+
examples: [3500]
|
|
1517
|
+
})
|
|
1518
|
+
}).optional().meta({
|
|
1519
|
+
title: "Weighing Event Data",
|
|
1520
|
+
description: "Weighing operational details including capture method, equipment, and weights"
|
|
1521
|
+
})
|
|
1522
|
+
});
|
|
1523
|
+
var DropOffEventSchema = buildMassIDEventSchema(
|
|
1524
|
+
"Drop-off",
|
|
1525
|
+
"Waste delivered to a destination location"
|
|
1526
|
+
);
|
|
1527
|
+
var SortingEventSchema = buildMassIDEventSchema(
|
|
1528
|
+
"Sorting",
|
|
1529
|
+
"Sorting or segregation of waste materials"
|
|
1530
|
+
).safeExtend({
|
|
1531
|
+
data: z.strictObject({
|
|
1532
|
+
initial_weight: WeightKgSchema.optional().meta({
|
|
1533
|
+
title: "Initial Weight (kg)",
|
|
1534
|
+
description: "Weight of the material entering the sorting process in kilograms",
|
|
1535
|
+
examples: [5e3]
|
|
1536
|
+
}),
|
|
1537
|
+
deducted_weight: WeightKgSchema.optional().meta({
|
|
1538
|
+
title: "Deducted Weight (kg)",
|
|
1539
|
+
description: "Weight removed during sorting (e.g., contaminants or moisture) in kilograms",
|
|
1540
|
+
examples: [250]
|
|
1541
|
+
})
|
|
1542
|
+
}).optional().meta({
|
|
1543
|
+
title: "Sorting Event Data",
|
|
1544
|
+
description: "Weights associated with sorting, including initial and deducted amounts"
|
|
1545
|
+
})
|
|
1546
|
+
});
|
|
1547
|
+
var RecyclingEventSchema = buildMassIDEventSchema(
|
|
1548
|
+
"Recycling",
|
|
1549
|
+
"Waste processed or recycled at the destination"
|
|
1550
|
+
);
|
|
1551
|
+
var MassIDEventSchema = z.discriminatedUnion("event_name", [
|
|
1552
|
+
PickUpEventSchema,
|
|
1553
|
+
WeighingEventSchema,
|
|
1554
|
+
DropOffEventSchema,
|
|
1555
|
+
SortingEventSchema,
|
|
1556
|
+
RecyclingEventSchema
|
|
1557
|
+
]).meta({
|
|
1558
|
+
title: "MassID Event",
|
|
1559
|
+
description: "Lifecycle event describing custody, processing, documentation, or recycling steps"
|
|
1560
|
+
});
|
|
1561
|
+
var MassIDEventsSchema = z.array(MassIDEventSchema).min(1).superRefine((events, ctx) => {
|
|
1562
|
+
events.forEach((event, index) => {
|
|
1563
|
+
if (index === 0) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const previousEvent = events[index - 1];
|
|
1567
|
+
if (event.timestamp < previousEvent.timestamp) {
|
|
1568
|
+
ctx.addIssue({
|
|
1569
|
+
code: "custom",
|
|
1570
|
+
path: [index, "timestamp"],
|
|
1571
|
+
message: "Events must be ordered by timestamp"
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1575
|
+
}).meta({
|
|
1576
|
+
title: "MassID Events",
|
|
1577
|
+
description: "Chronological sequence of custody transfer, processing, and recycling events"
|
|
1578
|
+
});
|
|
1579
|
+
var MassIDDataSchema = z.strictObject({
|
|
1580
|
+
waste_properties: MassIDWastePropertiesSchema,
|
|
1581
|
+
locations: uniqueBy(
|
|
1582
|
+
LocationSchema,
|
|
1583
|
+
(loc) => loc.id_hash,
|
|
1584
|
+
"Location ID hashes must be unique"
|
|
1585
|
+
).min(1).meta({
|
|
1586
|
+
title: "Locations",
|
|
1587
|
+
description: "All locations referenced in this MassID, indexed by ID"
|
|
1588
|
+
}),
|
|
1589
|
+
participants: uniqueBy(
|
|
1590
|
+
ParticipantSchema,
|
|
1591
|
+
(participant) => participant.id_hash,
|
|
1592
|
+
"Participant ID hashes must be unique"
|
|
1593
|
+
).min(1).meta({
|
|
1594
|
+
title: "Participants",
|
|
1595
|
+
description: "All participants referenced in this MassID, indexed by ID"
|
|
1596
|
+
}),
|
|
1597
|
+
events: MassIDEventsSchema,
|
|
1598
|
+
attachments: z.array(MassIDAttachmentSchema).optional().meta({
|
|
1599
|
+
title: "Attachments",
|
|
1600
|
+
description: "Supporting documents associated with events, linked by event_id"
|
|
1601
|
+
})
|
|
1602
|
+
}).refine((data) => {
|
|
1603
|
+
const participantIdSet = new Set(
|
|
1604
|
+
data.participants.map((participant) => participant.id_hash)
|
|
1605
|
+
);
|
|
1606
|
+
const eventParticipantIds = data.events.map(
|
|
1607
|
+
(event) => event.participant_id_hash
|
|
1608
|
+
);
|
|
1609
|
+
const allEventParticipantsExist = eventParticipantIds.every(
|
|
1610
|
+
(participantId) => participantIdSet.has(participantId)
|
|
1611
|
+
);
|
|
1612
|
+
return allEventParticipantsExist;
|
|
1613
|
+
}, "All participant ID hashes in events must exist in participants array").refine((data) => {
|
|
1614
|
+
const locationIdSet = new Set(
|
|
1615
|
+
data.locations.map((location) => location.id_hash)
|
|
1616
|
+
);
|
|
1617
|
+
const eventLocationIds = data.events.map((event) => event.location_id_hash);
|
|
1618
|
+
const allEventLocationsExist = eventLocationIds.every(
|
|
1619
|
+
(locationId) => locationIdSet.has(locationId)
|
|
1620
|
+
);
|
|
1621
|
+
return allEventLocationsExist;
|
|
1622
|
+
}, "All location ID hashes in events must exist in locations array").refine((data) => {
|
|
1623
|
+
if (!data.attachments || data.attachments.length === 0) {
|
|
1624
|
+
return true;
|
|
1625
|
+
}
|
|
1626
|
+
const eventIdSet = new Set(data.events.map((event) => event.event_id));
|
|
1627
|
+
return data.attachments.every(
|
|
1628
|
+
(attachment) => eventIdSet.has(attachment.event_id)
|
|
1629
|
+
);
|
|
1630
|
+
}, "All attachments must reference an existing event by event_id").refine((data) => {
|
|
1631
|
+
const participantIdSet = new Set(
|
|
1632
|
+
data.participants.map((participant) => participant.id_hash)
|
|
1633
|
+
);
|
|
1634
|
+
return data.locations.every(
|
|
1635
|
+
(location) => participantIdSet.has(location.responsible_participant_id_hash)
|
|
1636
|
+
);
|
|
1637
|
+
}, "All responsible participant ID hashes in locations must exist in participants array").meta({
|
|
1638
|
+
title: "MassID Data",
|
|
1639
|
+
description: "MassID data containing waste tracking events and supporting information"
|
|
1640
|
+
});
|
|
1419
1641
|
|
|
1420
1642
|
// src/mass-id/mass-id.attributes.ts
|
|
1421
1643
|
var MassIDAttributeWasteTypeSchema = NftAttributeSchema.safeExtend({
|
|
@@ -1423,22 +1645,22 @@ var MassIDAttributeWasteTypeSchema = NftAttributeSchema.safeExtend({
|
|
|
1423
1645
|
value: WasteTypeSchema
|
|
1424
1646
|
}).meta({
|
|
1425
1647
|
title: "Waste Type Attribute",
|
|
1426
|
-
description: "
|
|
1648
|
+
description: "Primary waste material category (e.g., Organic, Paper, Glass, Metal)"
|
|
1427
1649
|
});
|
|
1428
1650
|
var MassIDAttributeWasteSubtypeSchema = NftAttributeSchema.safeExtend({
|
|
1429
1651
|
trait_type: z.literal("Waste Subtype"),
|
|
1430
1652
|
value: WasteSubtypeSchema
|
|
1431
1653
|
}).meta({
|
|
1432
1654
|
title: "Waste Subtype Attribute",
|
|
1433
|
-
description: "
|
|
1655
|
+
description: "Regulatory or operational waste subtype (e.g., Food, Food Waste and Beverages)"
|
|
1434
1656
|
});
|
|
1435
1657
|
var MassIDAttributeWeightSchema = NftAttributeSchema.safeExtend({
|
|
1436
1658
|
trait_type: z.literal("Weight (kg)"),
|
|
1437
1659
|
value: WeightKgSchema,
|
|
1438
1660
|
display_type: z.literal("number")
|
|
1439
1661
|
}).meta({
|
|
1440
|
-
title: "Weight Attribute",
|
|
1441
|
-
description: "
|
|
1662
|
+
title: "Weight Attribute (kg)",
|
|
1663
|
+
description: "Net batch weight in kilograms (kg) for this MassID"
|
|
1442
1664
|
});
|
|
1443
1665
|
var MassIDAttributeOriginCountrySchema = OriginCountryAttributeSchema.safeExtend({
|
|
1444
1666
|
value: CountryNameSchema
|
|
@@ -1451,84 +1673,70 @@ var MassIDAttributeOriginDivisionSchema = NftAttributeSchema.safeExtend({
|
|
|
1451
1673
|
value: AdministrativeDivisionSchema
|
|
1452
1674
|
}).meta({
|
|
1453
1675
|
title: "Origin Administrative Division Attribute",
|
|
1454
|
-
description: "
|
|
1676
|
+
description: "State/province where the waste was generated (ISO 3166-2 preferred)"
|
|
1455
1677
|
});
|
|
1456
|
-
var
|
|
1457
|
-
trait_type: z.literal("Vehicle Type"),
|
|
1678
|
+
var MassIDAttributePickUpVehicleTypeSchema = NftAttributeSchema.safeExtend({
|
|
1679
|
+
trait_type: z.literal("Pick-up Vehicle Type"),
|
|
1458
1680
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1459
|
-
title: "Vehicle Type",
|
|
1460
|
-
description: "Type of vehicle used for waste
|
|
1461
|
-
examples: ["
|
|
1681
|
+
title: "Pick-up Vehicle Type",
|
|
1682
|
+
description: "Type of vehicle used for waste pick-up operations",
|
|
1683
|
+
examples: ["Truck", "Box Truck", "Flatbed Truck", "Roll-off Truck"]
|
|
1462
1684
|
})
|
|
1463
1685
|
}).meta({
|
|
1464
|
-
title: "Vehicle Type Attribute",
|
|
1465
|
-
description: "Vehicle type
|
|
1686
|
+
title: "Pick-up Vehicle Type Attribute",
|
|
1687
|
+
description: "Vehicle type used during pick-up"
|
|
1466
1688
|
});
|
|
1467
1689
|
var MassIDAttributeRecyclingMethodSchema = NftAttributeSchema.safeExtend({
|
|
1468
1690
|
trait_type: z.literal("Recycling Method"),
|
|
1469
1691
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1470
1692
|
title: "Recycling Method",
|
|
1471
1693
|
description: "Method used for recycling or processing the waste",
|
|
1472
|
-
examples: [
|
|
1473
|
-
"Composting",
|
|
1474
|
-
"Mechanical Recycling",
|
|
1475
|
-
"Incineration with Energy Recovery"
|
|
1476
|
-
]
|
|
1694
|
+
examples: ["Composting", "Mechanical Recycling", "Anaerobic Digestion"]
|
|
1477
1695
|
})
|
|
1478
1696
|
}).meta({
|
|
1479
1697
|
title: "Recycling Method Attribute",
|
|
1480
|
-
description: "
|
|
1481
|
-
});
|
|
1482
|
-
var MassIDAttributeProcessingTimeSchema = NftAttributeSchema.safeExtend({
|
|
1483
|
-
trait_type: z.literal("Processing Time (hours)"),
|
|
1484
|
-
value: HoursSchema,
|
|
1485
|
-
trait_description: NonEmptyStringSchema.max(200).optional().meta({
|
|
1486
|
-
title: "Processing Time Description",
|
|
1487
|
-
description: "Custom description for the processing time"
|
|
1488
|
-
})
|
|
1489
|
-
}).meta({
|
|
1490
|
-
title: "Processing Time Attribute",
|
|
1491
|
-
description: "Processing time attribute with optional trait description"
|
|
1698
|
+
description: "Process applied to this mass (e.g., composting, mechanical recycling)"
|
|
1492
1699
|
});
|
|
1493
1700
|
var MassIDAttributeLocalWasteClassificationIdSchema = NftAttributeSchema.safeExtend({
|
|
1494
1701
|
trait_type: z.literal("Local Waste Classification ID"),
|
|
1495
|
-
value:
|
|
1496
|
-
title: "Local Waste Classification ID",
|
|
1497
|
-
description: "Local or regional waste classification identifier",
|
|
1498
|
-
examples: ["04 02 20", "IBAMA-A001", "EWC-150101"]
|
|
1499
|
-
})
|
|
1702
|
+
value: IbamaWasteClassificationSchema
|
|
1500
1703
|
}).meta({
|
|
1501
1704
|
title: "Local Waste Classification ID Attribute",
|
|
1502
|
-
description: "
|
|
1705
|
+
description: "Regulatory waste classification code (e.g., Ibama format NN NN NN[*])",
|
|
1706
|
+
examples: ["20 01 01", "20 01 01*", "04 02 20"]
|
|
1503
1707
|
});
|
|
1504
1708
|
var MassIDAttributeRecyclingManifestCodeSchema = NftAttributeSchema.safeExtend({
|
|
1505
|
-
trait_type: z.literal("Recycling Manifest
|
|
1709
|
+
trait_type: z.literal("Recycling Manifest Number"),
|
|
1506
1710
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1507
|
-
title: "Recycling Manifest
|
|
1508
|
-
description: "
|
|
1509
|
-
examples: ["
|
|
1711
|
+
title: "Recycling Manifest Number",
|
|
1712
|
+
description: "Official recycling manifest identifier",
|
|
1713
|
+
examples: ["2353", "REC-MANIFEST-789", "RC12345"]
|
|
1510
1714
|
})
|
|
1511
1715
|
}).meta({
|
|
1512
|
-
title: "Recycling Manifest
|
|
1513
|
-
description: "
|
|
1716
|
+
title: "Recycling Manifest Number Attribute",
|
|
1717
|
+
description: "Official recycling manifest number issued by recycling authority (optional)"
|
|
1514
1718
|
});
|
|
1515
1719
|
var MassIDAttributeTransportManifestCodeSchema = NftAttributeSchema.safeExtend({
|
|
1516
|
-
trait_type: z.literal("Transport Manifest
|
|
1720
|
+
trait_type: z.literal("Transport Manifest Number"),
|
|
1517
1721
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1518
|
-
title: "Transport Manifest
|
|
1519
|
-
description: "
|
|
1520
|
-
examples: ["
|
|
1722
|
+
title: "Transport Manifest Number",
|
|
1723
|
+
description: "Official transport manifest identifier",
|
|
1724
|
+
examples: ["4126", "TRN-67890", "TRANS-MANIFEST-456"]
|
|
1521
1725
|
})
|
|
1522
1726
|
}).meta({
|
|
1523
|
-
title: "Transport Manifest
|
|
1524
|
-
description: "
|
|
1727
|
+
title: "Transport Manifest Number Attribute",
|
|
1728
|
+
description: "Official transport manifest number issued by logistics/transport authority (optional)"
|
|
1525
1729
|
});
|
|
1526
1730
|
var MassIDAttributeWeighingCaptureMethodSchema = NftAttributeSchema.safeExtend({
|
|
1527
1731
|
trait_type: z.literal("Weighing Capture Method"),
|
|
1528
1732
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1529
1733
|
title: "Weighing Capture Method",
|
|
1530
1734
|
description: "Method used to capture weight data",
|
|
1531
|
-
examples: [
|
|
1735
|
+
examples: [
|
|
1736
|
+
"Digital scale integration",
|
|
1737
|
+
"Manual entry",
|
|
1738
|
+
"Automated capture via IoT scale"
|
|
1739
|
+
]
|
|
1532
1740
|
})
|
|
1533
1741
|
}).meta({
|
|
1534
1742
|
title: "Weighing Capture Method Attribute",
|
|
@@ -1541,8 +1749,8 @@ var MassIDAttributeScaleTypeSchema = NftAttributeSchema.safeExtend({
|
|
|
1541
1749
|
description: "Type of scale used for weighing",
|
|
1542
1750
|
examples: [
|
|
1543
1751
|
"Weighbridge (Truck Scale)",
|
|
1752
|
+
"Axle scale",
|
|
1544
1753
|
"Floor Scale",
|
|
1545
|
-
"Bench Scale",
|
|
1546
1754
|
"Crane Scale"
|
|
1547
1755
|
]
|
|
1548
1756
|
})
|
|
@@ -1550,35 +1758,36 @@ var MassIDAttributeScaleTypeSchema = NftAttributeSchema.safeExtend({
|
|
|
1550
1758
|
title: "Scale Type Attribute",
|
|
1551
1759
|
description: "Scale type attribute (optional)"
|
|
1552
1760
|
});
|
|
1553
|
-
var MassIDAttributeContainerTypeSchema = NftAttributeSchema.safeExtend({
|
|
1554
|
-
trait_type: z.literal("Container Type"),
|
|
1555
|
-
value: NonEmptyStringSchema.max(100).meta({
|
|
1556
|
-
title: "Container Type",
|
|
1557
|
-
description: "Type of container used for waste storage or transport",
|
|
1558
|
-
examples: ["Truck", "Dumpster", "Roll-off Container", "Compactor", "Bin"]
|
|
1559
|
-
})
|
|
1560
|
-
}).meta({
|
|
1561
|
-
title: "Container Type Attribute",
|
|
1562
|
-
description: "Container type attribute (optional)"
|
|
1563
|
-
});
|
|
1564
1761
|
var MassIDAttributePickUpDateSchema = NftAttributeSchema.safeExtend({
|
|
1565
1762
|
trait_type: z.literal("Pick-up Date"),
|
|
1566
1763
|
value: UnixTimestampSchema.meta({
|
|
1567
1764
|
title: "Pick-up Date",
|
|
1568
1765
|
description: "Unix timestamp in milliseconds when the waste was picked up from the source",
|
|
1569
|
-
examples: [
|
|
1766
|
+
examples: [1733396567e3]
|
|
1570
1767
|
}),
|
|
1571
1768
|
display_type: z.literal("date")
|
|
1572
1769
|
}).meta({
|
|
1573
1770
|
title: "Pick-up Date Attribute",
|
|
1574
1771
|
description: "Pick-up date attribute with Unix timestamp"
|
|
1575
1772
|
});
|
|
1773
|
+
var MassIDAttributeDropOffDateSchema = NftAttributeSchema.safeExtend({
|
|
1774
|
+
trait_type: z.literal("Drop-off Date"),
|
|
1775
|
+
value: UnixTimestampSchema.meta({
|
|
1776
|
+
title: "Drop-off Date",
|
|
1777
|
+
description: "Unix timestamp in milliseconds when the waste was dropped off at the destination",
|
|
1778
|
+
examples: [1733407367e3]
|
|
1779
|
+
}),
|
|
1780
|
+
display_type: z.literal("date")
|
|
1781
|
+
}).meta({
|
|
1782
|
+
title: "Drop-off Date Attribute",
|
|
1783
|
+
description: "Drop-off date attribute with Unix timestamp"
|
|
1784
|
+
});
|
|
1576
1785
|
var MassIDAttributeRecyclingDateSchema = NftAttributeSchema.safeExtend({
|
|
1577
1786
|
trait_type: z.literal("Recycling Date"),
|
|
1578
1787
|
value: UnixTimestampSchema.meta({
|
|
1579
1788
|
title: "Recycling Date",
|
|
1580
1789
|
description: "Unix timestamp in milliseconds when the waste was recycled/processed",
|
|
1581
|
-
examples: [
|
|
1790
|
+
examples: [1733657567e3]
|
|
1582
1791
|
}),
|
|
1583
1792
|
display_type: z.literal("date")
|
|
1584
1793
|
}).meta({
|
|
@@ -1593,308 +1802,24 @@ var MassIDAttributesSchema = uniqueBy(
|
|
|
1593
1802
|
MassIDAttributeOriginCountrySchema,
|
|
1594
1803
|
MassIDAttributeOriginMunicipalitySchema,
|
|
1595
1804
|
MassIDAttributeOriginDivisionSchema,
|
|
1596
|
-
|
|
1805
|
+
MassIDAttributePickUpVehicleTypeSchema,
|
|
1597
1806
|
MassIDAttributeRecyclingMethodSchema,
|
|
1598
|
-
MassIDAttributeProcessingTimeSchema,
|
|
1599
1807
|
MassIDAttributeLocalWasteClassificationIdSchema,
|
|
1600
1808
|
MassIDAttributeRecyclingManifestCodeSchema,
|
|
1601
1809
|
MassIDAttributeTransportManifestCodeSchema,
|
|
1602
1810
|
MassIDAttributeWeighingCaptureMethodSchema,
|
|
1603
1811
|
MassIDAttributeScaleTypeSchema,
|
|
1604
|
-
MassIDAttributeContainerTypeSchema,
|
|
1605
1812
|
MassIDAttributePickUpDateSchema,
|
|
1813
|
+
MassIDAttributeDropOffDateSchema,
|
|
1606
1814
|
MassIDAttributeRecyclingDateSchema
|
|
1607
1815
|
]),
|
|
1608
1816
|
(attr) => attr.trait_type
|
|
1609
|
-
).min(
|
|
1817
|
+
).min(11).max(16).meta({
|
|
1610
1818
|
title: "MassID Attributes",
|
|
1611
|
-
description: "MassID NFT attributes array
|
|
1612
|
-
});
|
|
1613
|
-
var MassIDLocalClassificationSchema = z.strictObject({
|
|
1614
|
-
code: NonEmptyStringSchema.max(20).meta({
|
|
1615
|
-
title: "Classification Code",
|
|
1616
|
-
description: "Local waste classification code",
|
|
1617
|
-
examples: ["20 01 01", "D001", "EWC-150101", "IBAMA-A001"]
|
|
1618
|
-
}),
|
|
1619
|
-
description: NonEmptyStringSchema.max(200).meta({
|
|
1620
|
-
title: "Classification Description",
|
|
1621
|
-
description: "Local waste classification description",
|
|
1622
|
-
examples: [
|
|
1623
|
-
"Paper and cardboard packaging",
|
|
1624
|
-
"Ignitable waste",
|
|
1625
|
-
"Paper and cardboard packaging waste",
|
|
1626
|
-
"Municipal solid waste - organic fraction"
|
|
1627
|
-
]
|
|
1628
|
-
}),
|
|
1629
|
-
system: z.enum(["IBAMA"]).meta({
|
|
1630
|
-
title: "Classification System",
|
|
1631
|
-
description: "Classification system name - currently supports IBAMA (Instituto Brasileiro do Meio Ambiente e dos Recursos Naturais Renov\xE1veis)",
|
|
1632
|
-
examples: ["IBAMA"]
|
|
1633
|
-
})
|
|
1634
|
-
}).meta({
|
|
1635
|
-
title: "Local Classification",
|
|
1636
|
-
description: "Local or regional waste classification codes and descriptions"
|
|
1637
|
-
});
|
|
1638
|
-
var MassIDMeasurementUnitSchema = z.enum(["kg", "ton"]).meta({
|
|
1639
|
-
title: "Measurement Unit",
|
|
1640
|
-
description: "Unit of measurement for the waste quantity",
|
|
1641
|
-
examples: ["kg", "ton"]
|
|
1642
|
-
});
|
|
1643
|
-
var MassIDWastePropertiesSchema = z.strictObject({
|
|
1644
|
-
type: WasteTypeSchema.meta({
|
|
1645
|
-
title: "Waste Type",
|
|
1646
|
-
description: "Waste material category"
|
|
1647
|
-
}),
|
|
1648
|
-
subtype: WasteSubtypeSchema.meta({
|
|
1649
|
-
title: "Waste Subtype",
|
|
1650
|
-
description: "Specific subcategory of waste material"
|
|
1651
|
-
}),
|
|
1652
|
-
local_classification: MassIDLocalClassificationSchema.optional(),
|
|
1653
|
-
measurement_unit: MassIDMeasurementUnitSchema,
|
|
1654
|
-
net_weight: NonNegativeFloatSchema.meta({
|
|
1655
|
-
title: "Net Weight",
|
|
1656
|
-
description: "Net weight of the waste batch in the specified measurement unit"
|
|
1657
|
-
})
|
|
1658
|
-
}).meta({
|
|
1659
|
-
title: "Waste Properties",
|
|
1660
|
-
description: "Standardized waste material properties and regulatory information"
|
|
1661
|
-
});
|
|
1662
|
-
var EventAttributeFormatSchema = z.enum(["KILOGRAM", "DATE", "CURRENCY", "PERCENTAGE", "COORDINATE"]).meta({
|
|
1663
|
-
title: "Event Attribute Format",
|
|
1664
|
-
description: "Data format hint for proper display",
|
|
1665
|
-
examples: ["KILOGRAM", "DATE", "PERCENTAGE"]
|
|
1666
|
-
});
|
|
1667
|
-
var EventAttributeSchema = z.strictObject({
|
|
1668
|
-
name: NonEmptyStringSchema.max(100).meta({
|
|
1669
|
-
title: "Attribute Name",
|
|
1670
|
-
description: "Event attribute name",
|
|
1671
|
-
examples: [
|
|
1672
|
-
"temperature",
|
|
1673
|
-
"humidity",
|
|
1674
|
-
"contamination_percentage",
|
|
1675
|
-
"quality_grade",
|
|
1676
|
-
"batch_number",
|
|
1677
|
-
"operator_id",
|
|
1678
|
-
"equipment_used",
|
|
1679
|
-
"processing_cost"
|
|
1680
|
-
]
|
|
1681
|
-
}),
|
|
1682
|
-
value: z.union([z.string(), z.number(), z.boolean()]).optional().meta({
|
|
1683
|
-
title: "Attribute Value",
|
|
1684
|
-
description: "Event attribute value",
|
|
1685
|
-
examples: [
|
|
1686
|
-
25.5,
|
|
1687
|
-
"Grade A",
|
|
1688
|
-
true,
|
|
1689
|
-
"BATCH-2024-001",
|
|
1690
|
-
12.75,
|
|
1691
|
-
"Shredder-X200",
|
|
1692
|
-
false,
|
|
1693
|
-
"OP-456"
|
|
1694
|
-
]
|
|
1695
|
-
}),
|
|
1696
|
-
preserved_sensitivity: z.boolean().optional().meta({
|
|
1697
|
-
title: "Preserved Sensitivity",
|
|
1698
|
-
description: "Indicates if the attribute contains sensitive information that was preserved"
|
|
1699
|
-
}),
|
|
1700
|
-
format: EventAttributeFormatSchema.optional()
|
|
1701
|
-
}).meta({
|
|
1702
|
-
title: "Event Attribute",
|
|
1703
|
-
description: "Additional attribute specific to an event"
|
|
1704
|
-
});
|
|
1705
|
-
var EventAttachmentSchema = z.strictObject({
|
|
1706
|
-
type: NonEmptyStringSchema.max(50).meta({
|
|
1707
|
-
title: "Attachment Type",
|
|
1708
|
-
description: "Type of supporting attachment",
|
|
1709
|
-
examples: [
|
|
1710
|
-
"Waste Transfer Note",
|
|
1711
|
-
"Certificate of Disposal",
|
|
1712
|
-
"Certificate of Final Destination",
|
|
1713
|
-
"Quality Assessment Report",
|
|
1714
|
-
"Transport Manifest",
|
|
1715
|
-
"Processing Receipt",
|
|
1716
|
-
"Environmental Permit",
|
|
1717
|
-
"Invoice"
|
|
1718
|
-
]
|
|
1719
|
-
}),
|
|
1720
|
-
document_number: NonEmptyStringSchema.max(50).optional().meta({
|
|
1721
|
-
title: "Document Number",
|
|
1722
|
-
description: "Official document number if applicable",
|
|
1723
|
-
examples: [
|
|
1724
|
-
"WTN-2024-001234",
|
|
1725
|
-
"CD-ENV-456789",
|
|
1726
|
-
"INV-2024-QTR1-789",
|
|
1727
|
-
"PERMIT-EPA-2024-001",
|
|
1728
|
-
"MANIFEST-DOT-567890"
|
|
1729
|
-
]
|
|
1730
|
-
}),
|
|
1731
|
-
reference: NonEmptyStringSchema.meta({
|
|
1732
|
-
title: "Attachment Reference",
|
|
1733
|
-
description: "Reference to attachment (IPFS hash, file name, or external URL)",
|
|
1734
|
-
examples: [
|
|
1735
|
-
"QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o",
|
|
1736
|
-
"waste_transfer_note_2024_001.pdf",
|
|
1737
|
-
"https://docs.example.com/certificates/disposal_cert_456.pdf",
|
|
1738
|
-
"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
|
|
1739
|
-
"processing_receipt_20240315.jpg"
|
|
1740
|
-
]
|
|
1741
|
-
}),
|
|
1742
|
-
issue_timestamp: UnixTimestampSchema.optional().meta({
|
|
1743
|
-
title: "Issue Timestamp",
|
|
1744
|
-
description: "Unix timestamp in milliseconds when the attachment was issued",
|
|
1745
|
-
examples: [17105184e5, 17040672e5, 17152704e5]
|
|
1746
|
-
}),
|
|
1747
|
-
issuer: NonEmptyStringSchema.max(100).optional().meta({
|
|
1748
|
-
title: "Attachment Issuer",
|
|
1749
|
-
description: "Entity that issued the attachment",
|
|
1750
|
-
examples: [
|
|
1751
|
-
"Environmental Protection Agency",
|
|
1752
|
-
"Waste Management Solutions Ltd",
|
|
1753
|
-
"Green Recycling Corp",
|
|
1754
|
-
"City Waste Authority",
|
|
1755
|
-
"EcoProcess Industries",
|
|
1756
|
-
"Regional Environmental Office"
|
|
1757
|
-
]
|
|
1758
|
-
})
|
|
1759
|
-
}).meta({
|
|
1760
|
-
title: "Event Attachment",
|
|
1761
|
-
description: "Supporting event attachment"
|
|
1762
|
-
});
|
|
1763
|
-
var MassIDChainOfCustodyEventSchema = z.strictObject({
|
|
1764
|
-
event_id: UuidSchema.meta({
|
|
1765
|
-
title: "Event ID",
|
|
1766
|
-
description: "Unique event identifier"
|
|
1767
|
-
}),
|
|
1768
|
-
event_name: NonEmptyStringSchema.max(50).meta({
|
|
1769
|
-
title: "Event Name",
|
|
1770
|
-
description: "Name of custody or processing event",
|
|
1771
|
-
examples: ["Sorting", "Processing", "Recycling", "Weighing"]
|
|
1772
|
-
}),
|
|
1773
|
-
description: NonEmptyStringSchema.max(200).optional().meta({
|
|
1774
|
-
title: "Event Description",
|
|
1775
|
-
description: "Detailed description of what happened during this event",
|
|
1776
|
-
examples: [
|
|
1777
|
-
"Waste collected from residential area using collection truck",
|
|
1778
|
-
"Material sorted into recyclable and non-recyclable fractions",
|
|
1779
|
-
"Plastic waste processed through shredding and washing",
|
|
1780
|
-
"Waste transferred to authorized recycling facility",
|
|
1781
|
-
"Final disposal at licensed landfill site",
|
|
1782
|
-
"Quality inspection and contamination assessment completed"
|
|
1783
|
-
]
|
|
1784
|
-
}),
|
|
1785
|
-
timestamp: UnixTimestampSchema.meta({
|
|
1786
|
-
title: "Event Timestamp",
|
|
1787
|
-
description: "Unix timestamp in milliseconds when the event occurred",
|
|
1788
|
-
examples: [17105184e5, 17040672e5, 17152704e5]
|
|
1789
|
-
}),
|
|
1790
|
-
participant_id_hash: Sha256HashSchema.meta({
|
|
1791
|
-
title: "Participant ID Hash",
|
|
1792
|
-
description: "Reference to participant in the participants array"
|
|
1793
|
-
}),
|
|
1794
|
-
location_id_hash: Sha256HashSchema.meta({
|
|
1795
|
-
title: "Location ID Hash",
|
|
1796
|
-
description: "Reference to location in the locations array"
|
|
1797
|
-
}),
|
|
1798
|
-
weight: NonNegativeFloatSchema.optional().meta({
|
|
1799
|
-
title: "Event Weight",
|
|
1800
|
-
description: "Mass weight after this event"
|
|
1801
|
-
}),
|
|
1802
|
-
attributes: z.array(EventAttributeSchema).optional().meta({
|
|
1803
|
-
title: "Event Attributes",
|
|
1804
|
-
description: "Additional attributes specific to this event"
|
|
1805
|
-
}),
|
|
1806
|
-
attachments: z.array(EventAttachmentSchema).optional().meta({
|
|
1807
|
-
title: "Event Attachments",
|
|
1808
|
-
description: "Associated attachments for this event"
|
|
1809
|
-
})
|
|
1810
|
-
}).meta({
|
|
1811
|
-
title: "Chain of Custody Event",
|
|
1812
|
-
description: "Chain of custody event"
|
|
1813
|
-
});
|
|
1814
|
-
var MassIDChainOfCustodySchema = z.strictObject({
|
|
1815
|
-
events: z.array(MassIDChainOfCustodyEventSchema).min(1).meta({
|
|
1816
|
-
title: "Custody Events",
|
|
1817
|
-
description: "Chronological sequence of custody transfer and processing events"
|
|
1818
|
-
}),
|
|
1819
|
-
total_duration_minutes: MinutesSchema.meta({
|
|
1820
|
-
title: "Total Duration (minutes)",
|
|
1821
|
-
description: "Total time from first to last event in minutes"
|
|
1822
|
-
})
|
|
1823
|
-
}).meta({
|
|
1824
|
-
title: "Chain of Custody",
|
|
1825
|
-
description: "Complete chain of custody tracking from waste generation to final processing"
|
|
1826
|
-
});
|
|
1827
|
-
var MassIDGeographicDataSchema = z.strictObject({
|
|
1828
|
-
from_location_id_hash: Sha256HashSchema.meta({
|
|
1829
|
-
title: "From Location ID Hash",
|
|
1830
|
-
description: "Reference hash of the location where the waste started movement"
|
|
1831
|
-
}),
|
|
1832
|
-
to_location_id_hash: Sha256HashSchema.meta({
|
|
1833
|
-
title: "To Location ID Hash",
|
|
1834
|
-
description: "Reference hash of the location where the waste ended movement"
|
|
1835
|
-
}),
|
|
1836
|
-
first_reported_timestamp: UnixTimestampSchema.meta({
|
|
1837
|
-
title: "First Reported Timestamp",
|
|
1838
|
-
description: "Unix timestamp in milliseconds when the waste was first reported/collected at the origin location",
|
|
1839
|
-
examples: [17105184e5, 17040672e5, 17152704e5]
|
|
1840
|
-
}),
|
|
1841
|
-
last_reported_timestamp: UnixTimestampSchema.meta({
|
|
1842
|
-
title: "Last Reported Timestamp",
|
|
1843
|
-
description: "Unix timestamp in milliseconds when the waste was last reported/processed at the destination location",
|
|
1844
|
-
examples: [17106048e5, 17041536e5, 17153568e5]
|
|
1845
|
-
})
|
|
1846
|
-
}).refine((data) => {
|
|
1847
|
-
return data.first_reported_timestamp <= data.last_reported_timestamp;
|
|
1848
|
-
}, "first_reported_timestamp must be before or equal to last_reported_timestamp").meta({
|
|
1849
|
-
title: "Geographic Data",
|
|
1850
|
-
description: "Simplified geographic information tracking waste movement from origin to destination with temporal bounds"
|
|
1851
|
-
});
|
|
1852
|
-
var MassIDDataSchema = z.strictObject({
|
|
1853
|
-
waste_properties: MassIDWastePropertiesSchema,
|
|
1854
|
-
locations: uniqueBy(
|
|
1855
|
-
LocationSchema,
|
|
1856
|
-
(loc) => loc.id_hash,
|
|
1857
|
-
"Location ID hashes must be unique"
|
|
1858
|
-
).min(1).meta({
|
|
1859
|
-
title: "Locations",
|
|
1860
|
-
description: "All locations referenced in this MassID, indexed by ID"
|
|
1861
|
-
}),
|
|
1862
|
-
participants: uniqueBy(
|
|
1863
|
-
ParticipantSchema,
|
|
1864
|
-
(p) => p.id_hash,
|
|
1865
|
-
"Participant ID hashes must be unique"
|
|
1866
|
-
).min(1).meta({
|
|
1867
|
-
title: "Participants",
|
|
1868
|
-
description: "All participants referenced in this MassID, indexed by ID"
|
|
1869
|
-
}),
|
|
1870
|
-
chain_of_custody: MassIDChainOfCustodySchema,
|
|
1871
|
-
geographic_data: MassIDGeographicDataSchema
|
|
1872
|
-
}).refine((data) => {
|
|
1873
|
-
const participantIdSet = new Set(
|
|
1874
|
-
data.participants.map((participant) => participant.id_hash)
|
|
1875
|
-
);
|
|
1876
|
-
const eventParticipantIds = data.chain_of_custody.events.map(
|
|
1877
|
-
(event) => event.participant_id_hash
|
|
1878
|
-
);
|
|
1879
|
-
const allEventParticipantsExist = eventParticipantIds.every(
|
|
1880
|
-
(participantId) => participantIdSet.has(participantId)
|
|
1881
|
-
);
|
|
1882
|
-
return allEventParticipantsExist;
|
|
1883
|
-
}, "All participant ID hashes in chain of custody events must exist in participants array").refine((data) => {
|
|
1884
|
-
const locationIdSet = new Set(
|
|
1885
|
-
data.locations.map((location) => location.id_hash)
|
|
1886
|
-
);
|
|
1887
|
-
const eventLocationIds = data.chain_of_custody.events.map(
|
|
1888
|
-
(event) => event.location_id_hash
|
|
1889
|
-
);
|
|
1890
|
-
const allEventLocationsExist = eventLocationIds.every(
|
|
1891
|
-
(locationId) => locationIdSet.has(locationId)
|
|
1892
|
-
);
|
|
1893
|
-
return allEventLocationsExist;
|
|
1894
|
-
}, "All location ID hashes in chain of custody events must exist in locations array").meta({
|
|
1895
|
-
title: "MassID Data",
|
|
1896
|
-
description: "MassID data containing waste tracking and chain of custody information"
|
|
1819
|
+
description: "MassID NFT attributes array. Provide the canonical set covering waste (type, subtype, net weight), origin (country, municipality, administrative division), logistics (vehicle, manifests, weighing method/scale), and lifecycle timestamps (pick-up, drop-off, recycling). Length is validated; specific composition is producer-controlled."
|
|
1897
1820
|
});
|
|
1821
|
+
var isPickUpEvent = (event) => event.event_name === "Pick-up";
|
|
1822
|
+
var isWeighingEvent = (event) => event.event_name === "Weighing";
|
|
1898
1823
|
var MassIDIpfsSchemaMeta = {
|
|
1899
1824
|
title: "MassID NFT IPFS Record",
|
|
1900
1825
|
description: "Complete MassID NFT IPFS record including fixed attributes and detailed waste tracking data",
|
|
@@ -1910,6 +1835,148 @@ var MassIDIpfsSchema = NftIpfsSchema.safeExtend({
|
|
|
1910
1835
|
}),
|
|
1911
1836
|
attributes: MassIDAttributesSchema,
|
|
1912
1837
|
data: MassIDDataSchema
|
|
1838
|
+
}).superRefine((record, ctx) => {
|
|
1839
|
+
const { data, attributes } = record;
|
|
1840
|
+
const findAttribute = (traitType) => {
|
|
1841
|
+
const index = attributes.findIndex(
|
|
1842
|
+
(attribute) => attribute.trait_type === traitType
|
|
1843
|
+
);
|
|
1844
|
+
return {
|
|
1845
|
+
attribute: index >= 0 ? attributes[index] : void 0,
|
|
1846
|
+
index
|
|
1847
|
+
};
|
|
1848
|
+
};
|
|
1849
|
+
const assertAttributeMatches = (traitType, expectedValue, sourceDescription) => {
|
|
1850
|
+
const { attribute, index } = findAttribute(traitType);
|
|
1851
|
+
if (expectedValue === void 0 || expectedValue === null) {
|
|
1852
|
+
if (attribute) {
|
|
1853
|
+
ctx.addIssue({
|
|
1854
|
+
code: "custom",
|
|
1855
|
+
path: ["attributes", index],
|
|
1856
|
+
message: `${traitType} attribute must be omitted when ${sourceDescription} is not provided`
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
if (!attribute) {
|
|
1862
|
+
ctx.addIssue({
|
|
1863
|
+
code: "custom",
|
|
1864
|
+
path: ["attributes"],
|
|
1865
|
+
message: `${traitType} attribute must be present and match ${sourceDescription}`
|
|
1866
|
+
});
|
|
1867
|
+
return;
|
|
1868
|
+
}
|
|
1869
|
+
if (attribute.value !== expectedValue) {
|
|
1870
|
+
ctx.addIssue({
|
|
1871
|
+
code: "custom",
|
|
1872
|
+
path: ["attributes", index, "value"],
|
|
1873
|
+
message: `${traitType} attribute must equal ${sourceDescription}`
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
const assertTimestampAttributeMatches = (traitType, isoTimestamp, sourceDescription) => {
|
|
1878
|
+
if (!isoTimestamp) {
|
|
1879
|
+
assertAttributeMatches(traitType, void 0, sourceDescription);
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const timestamp = Date.parse(isoTimestamp);
|
|
1883
|
+
if (Number.isNaN(timestamp)) {
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
assertAttributeMatches(traitType, timestamp, sourceDescription);
|
|
1887
|
+
};
|
|
1888
|
+
assertAttributeMatches(
|
|
1889
|
+
"Waste Type",
|
|
1890
|
+
data.waste_properties.type,
|
|
1891
|
+
"waste_properties.type"
|
|
1892
|
+
);
|
|
1893
|
+
assertAttributeMatches(
|
|
1894
|
+
"Waste Subtype",
|
|
1895
|
+
data.waste_properties.subtype,
|
|
1896
|
+
"waste_properties.subtype"
|
|
1897
|
+
);
|
|
1898
|
+
assertAttributeMatches(
|
|
1899
|
+
"Weight (kg)",
|
|
1900
|
+
data.waste_properties.net_weight,
|
|
1901
|
+
"waste_properties.net_weight"
|
|
1902
|
+
);
|
|
1903
|
+
assertAttributeMatches(
|
|
1904
|
+
"Local Waste Classification ID",
|
|
1905
|
+
data.waste_properties.local_classification?.code,
|
|
1906
|
+
"waste_properties.local_classification.code"
|
|
1907
|
+
);
|
|
1908
|
+
const pickUpEvent = data.events.find(isPickUpEvent);
|
|
1909
|
+
const pickUpLocation = pickUpEvent ? data.locations.find(
|
|
1910
|
+
(location) => location.id_hash === pickUpEvent.location_id_hash
|
|
1911
|
+
) : void 0;
|
|
1912
|
+
assertAttributeMatches(
|
|
1913
|
+
"Origin Country",
|
|
1914
|
+
pickUpLocation?.country,
|
|
1915
|
+
"Pick-up event location.country"
|
|
1916
|
+
);
|
|
1917
|
+
assertAttributeMatches(
|
|
1918
|
+
"Origin Municipality",
|
|
1919
|
+
pickUpLocation?.municipality,
|
|
1920
|
+
"Pick-up event location.municipality"
|
|
1921
|
+
);
|
|
1922
|
+
assertAttributeMatches(
|
|
1923
|
+
"Origin Administrative Division",
|
|
1924
|
+
pickUpLocation?.administrative_division,
|
|
1925
|
+
"Pick-up event location.administrative_division"
|
|
1926
|
+
);
|
|
1927
|
+
assertTimestampAttributeMatches(
|
|
1928
|
+
"Pick-up Date",
|
|
1929
|
+
pickUpEvent?.timestamp,
|
|
1930
|
+
"Pick-up event timestamp"
|
|
1931
|
+
);
|
|
1932
|
+
assertAttributeMatches(
|
|
1933
|
+
"Pick-up Vehicle Type",
|
|
1934
|
+
pickUpEvent?.data?.vehicle_type,
|
|
1935
|
+
"Pick-up event vehicle_type"
|
|
1936
|
+
);
|
|
1937
|
+
const dropOffEvent = data.events.find(
|
|
1938
|
+
(event) => event.event_name === "Drop-off"
|
|
1939
|
+
);
|
|
1940
|
+
assertTimestampAttributeMatches(
|
|
1941
|
+
"Drop-off Date",
|
|
1942
|
+
dropOffEvent?.timestamp,
|
|
1943
|
+
"Drop-off event timestamp"
|
|
1944
|
+
);
|
|
1945
|
+
const recyclingEvent = data.events.find(
|
|
1946
|
+
(event) => event.event_name === "Recycling"
|
|
1947
|
+
);
|
|
1948
|
+
assertTimestampAttributeMatches(
|
|
1949
|
+
"Recycling Date",
|
|
1950
|
+
recyclingEvent?.timestamp,
|
|
1951
|
+
"Recycling event timestamp"
|
|
1952
|
+
);
|
|
1953
|
+
const weighingEvent = data.events.find(isWeighingEvent);
|
|
1954
|
+
assertAttributeMatches(
|
|
1955
|
+
"Weighing Capture Method",
|
|
1956
|
+
weighingEvent?.data?.weighing_capture_method,
|
|
1957
|
+
"Weighing event weighing_capture_method"
|
|
1958
|
+
);
|
|
1959
|
+
assertAttributeMatches(
|
|
1960
|
+
"Scale Type",
|
|
1961
|
+
weighingEvent?.data?.scale_type,
|
|
1962
|
+
"Weighing event scale_type"
|
|
1963
|
+
);
|
|
1964
|
+
const recyclingManifest = data.attachments?.find(
|
|
1965
|
+
(attachment) => attachment.type === "Recycling Manifest" && attachment.document_number
|
|
1966
|
+
);
|
|
1967
|
+
assertAttributeMatches(
|
|
1968
|
+
"Recycling Manifest Number",
|
|
1969
|
+
recyclingManifest?.document_number,
|
|
1970
|
+
"Recycling Manifest attachment document_number"
|
|
1971
|
+
);
|
|
1972
|
+
const transportManifest = data.attachments?.find(
|
|
1973
|
+
(attachment) => attachment.type === "Transport Manifest" && attachment.document_number
|
|
1974
|
+
);
|
|
1975
|
+
assertAttributeMatches(
|
|
1976
|
+
"Transport Manifest Number",
|
|
1977
|
+
transportManifest?.document_number,
|
|
1978
|
+
"Transport Manifest attachment document_number"
|
|
1979
|
+
);
|
|
1913
1980
|
}).meta(MassIDIpfsSchemaMeta);
|
|
1914
1981
|
var GasIDAttributeMethodologySchema = MethodologyAttributeSchema;
|
|
1915
1982
|
var GasIDAttributeGasTypeSchema = NftAttributeSchema.safeExtend({
|
|
@@ -3390,6 +3457,6 @@ var MassIDAuditSchema = BaseIpfsSchema.safeExtend({
|
|
|
3390
3457
|
data: MassIDAuditDataSchema
|
|
3391
3458
|
}).meta(MassIDAuditSchemaMeta);
|
|
3392
3459
|
|
|
3393
|
-
export { AccreditedParticipantSchema, AccreditedParticipantsSchema, AdministrativeDivisionSchema, AuditReferenceSchema, AuditRuleDefinitionSchema, AuditRuleDefinitionsSchema, AuditRuleExecutionResultSchema, AuditRuleExecutionResultsSchema, BaseIpfsSchema, BlockchainChainIdSchema, BlockchainNetworkNameSchema, CollectionNameSchema, CollectionSchema, CollectionSchemaMeta, CollectionSlugSchema, CoordinatesSchema, CountryNameSchema, CreditAmountAttributeSchema, CreditAmountSchema, CreditPurchaseReceiptAttributesSchema, CreditPurchaseReceiptDataSchema, CreditPurchaseReceiptIpfsSchema, CreditPurchaseReceiptIpfsSchemaMeta, CreditPurchaseReceiptSummarySchema, CreditRetirementReceiptAttributesSchema, CreditRetirementReceiptDataSchema, CreditRetirementReceiptIpfsSchema, CreditRetirementReceiptIpfsSchemaMeta, CreditRetirementReceiptSummarySchema, CreditSchema, CreditSchemaMeta, CreditTokenSymbolSchema, CreditTypeAttributeSchema, CreditTypeSchema, DistributionNotesSchema, EPSILON, EthereumAddressSchema, ExternalIdSchema, ExternalUrlSchema,
|
|
3460
|
+
export { AccreditedParticipantSchema, AccreditedParticipantsSchema, AdministrativeDivisionSchema, AuditReferenceSchema, AuditRuleDefinitionSchema, AuditRuleDefinitionsSchema, AuditRuleExecutionResultSchema, AuditRuleExecutionResultsSchema, BaseIpfsSchema, BlockchainChainIdSchema, BlockchainNetworkNameSchema, CollectionNameSchema, CollectionSchema, CollectionSchemaMeta, CollectionSlugSchema, CoordinatesSchema, CountryNameSchema, CreditAmountAttributeSchema, CreditAmountSchema, CreditPurchaseReceiptAttributesSchema, CreditPurchaseReceiptDataSchema, CreditPurchaseReceiptIpfsSchema, CreditPurchaseReceiptIpfsSchemaMeta, CreditPurchaseReceiptSummarySchema, CreditRetirementReceiptAttributesSchema, CreditRetirementReceiptDataSchema, CreditRetirementReceiptIpfsSchema, CreditRetirementReceiptIpfsSchemaMeta, CreditRetirementReceiptSummarySchema, CreditSchema, CreditSchemaMeta, CreditTokenSymbolSchema, CreditTypeAttributeSchema, CreditTypeSchema, DistributionNotesSchema, EPSILON, EthereumAddressSchema, ExternalIdSchema, ExternalUrlSchema, GasIDAttributesSchema, GasIDDataSchema, GasIDIpfsSchema, GasIDIpfsSchemaMeta, GasIDReferenceSchema, HexColorSchema, HoursSchema, IbamaWasteClassificationSchema, IpfsUriSchema, IsoAdministrativeDivisionCodeSchema, IsoCountryCodeSchema, IsoDateSchema, IsoTimestampSchema, LatitudeSchema, LocationSchema, LongitudeSchema, MassIDAttributesSchema, MassIDAuditDataSchema, MassIDAuditSchema, MassIDAuditSchemaMeta, MassIDDataSchema, MassIDIpfsSchema, MassIDIpfsSchemaMeta, MassIDRecyclingDateAttributeSchema, MassIDReferenceSchema, MassIDTokenIdAttributeSchema, MassIdReferenceWithContractSchema, MethodologyAttributeSchema, MethodologyComplianceSchema, MethodologyDataSchema, MethodologyNameSchema, MethodologyReferenceSchema, MethodologySchema, MethodologySchemaMeta, MinutesSchema, MunicipalitySchema, NftAttributeSchema, NftIpfsSchema, NonEmptyStringSchema, NonNegativeFloatSchema, NonNegativeIntegerSchema, OriginCountryAttributeSchema, OriginMunicipalityAttributeSchema, ParticipantNameSchema, ParticipantRewardsSchema, ParticipantRoleSchema, ParticipantSchema, PercentageSchema, PositiveIntegerSchema, ReceiptIdentitySchema, RecordEnvironmentSchema, RecordSchemaTypeSchema, RecycledIDAttributesSchema, RecycledIDDataSchema, RecycledIDIpfsSchema, RecycledIDIpfsSchemaMeta, RecyclerAttributeSchema, RewardAllocationSchema, SemanticVersionSchema, Sha256HashSchema, SlugSchema, SmartContractAddressSchema, SmartContractSchema, SourceWasteTypeAttributeSchema, SourceWeightAttributeSchema, StringifiedTokenIdSchema, TokenIdSchema, TokenSymbolSchema, UnixTimestampSchema, UuidSchema, WasteClassificationSchema, WasteSubtypeSchema, WasteTypeSchema, WeightKgSchema, buildSchemaUrl, createAttributeMap, createReceiptCertificateSchema, createReceiptCollectionSchema, createReceiptCreditSchema, getSchemaBaseUrl, getSchemaVersionOrDefault, nearlyEqual, uniqueArrayItems, uniqueBy, validateAttributeValue, validateAttributesForItems, validateCountMatches, validateDateAttribute, validateSummaryListMatchesData, validateTotalMatches };
|
|
3394
3461
|
//# sourceMappingURL=index.js.map
|
|
3395
3462
|
//# sourceMappingURL=index.js.map
|