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