@carrot-foundation/schemas 1.0.0 → 2.0.0

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.d.cts CHANGED
@@ -2013,6 +2013,7 @@ declare const CreditPurchaseReceiptCertificateSchema: z.ZodObject<{
2013
2013
  "carbon-methane": "carbon-methane";
2014
2014
  biowaste: "biowaste";
2015
2015
  }>;
2016
+ purchased_amount: z.ZodNumber;
2016
2017
  collections: z.ZodArray<z.ZodObject<{
2017
2018
  slug: z.ZodEnum<{
2018
2019
  "bold-innovators": "bold-innovators";
@@ -2102,6 +2103,7 @@ declare const CreditPurchaseReceiptDataSchema: z.ZodObject<{
2102
2103
  "carbon-methane": "carbon-methane";
2103
2104
  biowaste: "biowaste";
2104
2105
  }>;
2106
+ purchased_amount: z.ZodNumber;
2105
2107
  collections: z.ZodArray<z.ZodObject<{
2106
2108
  slug: z.ZodEnum<{
2107
2109
  "bold-innovators": "bold-innovators";
@@ -2125,7 +2127,7 @@ type CreditPurchaseReceiptData = z.infer<typeof CreditPurchaseReceiptDataSchema>
2125
2127
 
2126
2128
  declare const CreditPurchaseReceiptIpfsSchemaMeta: {
2127
2129
  readonly title: "CreditPurchaseReceipt NFT IPFS Record";
2128
- readonly description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes";
2130
+ readonly description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.";
2129
2131
  readonly $id: string;
2130
2132
  readonly version: string;
2131
2133
  };
@@ -2260,6 +2262,7 @@ declare const CreditPurchaseReceiptIpfsSchema: z.ZodObject<{
2260
2262
  "carbon-methane": "carbon-methane";
2261
2263
  biowaste: "biowaste";
2262
2264
  }>;
2265
+ purchased_amount: z.ZodNumber;
2263
2266
  collections: z.ZodArray<z.ZodObject<{
2264
2267
  slug: z.ZodEnum<{
2265
2268
  "bold-innovators": "bold-innovators";
@@ -2518,7 +2521,7 @@ type CreditRetirementReceiptData = z.infer<typeof CreditRetirementReceiptDataSch
2518
2521
 
2519
2522
  declare const CreditRetirementReceiptIpfsSchemaMeta: {
2520
2523
  readonly title: "CreditRetirementReceipt NFT IPFS Record";
2521
- readonly description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes";
2524
+ readonly description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.";
2522
2525
  readonly $id: string;
2523
2526
  readonly version: string;
2524
2527
  };
package/dist/index.d.ts CHANGED
@@ -2013,6 +2013,7 @@ declare const CreditPurchaseReceiptCertificateSchema: z.ZodObject<{
2013
2013
  "carbon-methane": "carbon-methane";
2014
2014
  biowaste: "biowaste";
2015
2015
  }>;
2016
+ purchased_amount: z.ZodNumber;
2016
2017
  collections: z.ZodArray<z.ZodObject<{
2017
2018
  slug: z.ZodEnum<{
2018
2019
  "bold-innovators": "bold-innovators";
@@ -2102,6 +2103,7 @@ declare const CreditPurchaseReceiptDataSchema: z.ZodObject<{
2102
2103
  "carbon-methane": "carbon-methane";
2103
2104
  biowaste: "biowaste";
2104
2105
  }>;
2106
+ purchased_amount: z.ZodNumber;
2105
2107
  collections: z.ZodArray<z.ZodObject<{
2106
2108
  slug: z.ZodEnum<{
2107
2109
  "bold-innovators": "bold-innovators";
@@ -2125,7 +2127,7 @@ type CreditPurchaseReceiptData = z.infer<typeof CreditPurchaseReceiptDataSchema>
2125
2127
 
2126
2128
  declare const CreditPurchaseReceiptIpfsSchemaMeta: {
2127
2129
  readonly title: "CreditPurchaseReceipt NFT IPFS Record";
2128
- readonly description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes";
2130
+ readonly description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.";
2129
2131
  readonly $id: string;
2130
2132
  readonly version: string;
2131
2133
  };
@@ -2260,6 +2262,7 @@ declare const CreditPurchaseReceiptIpfsSchema: z.ZodObject<{
2260
2262
  "carbon-methane": "carbon-methane";
2261
2263
  biowaste: "biowaste";
2262
2264
  }>;
2265
+ purchased_amount: z.ZodNumber;
2263
2266
  collections: z.ZodArray<z.ZodObject<{
2264
2267
  slug: z.ZodEnum<{
2265
2268
  "bold-innovators": "bold-innovators";
@@ -2518,7 +2521,7 @@ type CreditRetirementReceiptData = z.infer<typeof CreditRetirementReceiptDataSch
2518
2521
 
2519
2522
  declare const CreditRetirementReceiptIpfsSchemaMeta: {
2520
2523
  readonly title: "CreditRetirementReceipt NFT IPFS Record";
2521
- readonly description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes";
2524
+ readonly description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.";
2522
2525
  readonly $id: string;
2523
2526
  readonly version: string;
2524
2527
  };
package/dist/index.js CHANGED
@@ -29382,9 +29382,9 @@ var CreditPurchaseReceiptSummarySchema = SummaryBaseSchema.safeExtend({
29382
29382
  title: "Total Amount (USDC)",
29383
29383
  description: "Total amount paid in USDC stablecoin for the credit purchase"
29384
29384
  }),
29385
- total_credits: CreditAmountSchema.meta({
29385
+ total_credits: CreditAmountSchema.gt(0).meta({
29386
29386
  title: "Total Credits",
29387
- description: "Total number of environmental impact credits purchased in this transaction"
29387
+ description: "Total number of environmental impact credits purchased in this transaction. Must be greater than 0."
29388
29388
  }),
29389
29389
  purchased_at: IsoDateTimeSchema.meta({
29390
29390
  title: "Purchased At",
@@ -29395,9 +29395,9 @@ var CreditPurchaseReceiptSummarySchema = SummaryBaseSchema.safeExtend({
29395
29395
  description: "Summary totals for the credit purchase including payment amount, credit quantity, certificate count, and timestamp"
29396
29396
  });
29397
29397
  var CreditRetirementReceiptSummarySchema = SummaryBaseSchema.safeExtend({
29398
- total_credits_retired: CreditAmountSchema.meta({
29398
+ total_credits_retired: CreditAmountSchema.gt(0).meta({
29399
29399
  title: "Total Credits Retired",
29400
- description: "Total number of environmental impact credits permanently retired (removed from circulation)"
29400
+ description: "Total number of environmental impact credits permanently retired (removed from circulation). Must be greater than 0."
29401
29401
  }),
29402
29402
  retired_at: IsoDateTimeSchema.meta({
29403
29403
  title: "Retired At",
@@ -29484,7 +29484,7 @@ function buildSchemaUrl(schemaPath) {
29484
29484
  return `${getSchemaBaseUrl()}/${cleanPath}`;
29485
29485
  }
29486
29486
  function getSchemaVersionOrDefault() {
29487
- return "1.0.0";
29487
+ return "2.0.0";
29488
29488
  }
29489
29489
 
29490
29490
  // src/shared/schema-validation.ts
@@ -31106,13 +31106,17 @@ var CreditPurchaseReceiptCertificateSchema = CertificateReferenceBaseSchema.safe
31106
31106
  credit_slug: CreditTokenSlugSchema.meta({
31107
31107
  description: "Slug of the credit type for this certificate"
31108
31108
  }),
31109
+ purchased_amount: CreditAmountSchema.meta({
31110
+ title: "Certificate Purchased Amount",
31111
+ description: "Total credits purchased from this certificate. Authoritative source for receipt totals; cross-checked against sum(collections[].purchased_amount) when collections are non-empty."
31112
+ }),
31109
31113
  collections: uniqueBy(
31110
31114
  CertificateCollectionItemPurchaseSchema,
31111
31115
  (item) => item.slug,
31112
31116
  "Collection slugs within certificate collections must be unique"
31113
- ).min(1).meta({
31117
+ ).meta({
31114
31118
  title: "Certificate Collections",
31115
- description: "Collections associated with this certificate, each with purchased and retired amounts"
31119
+ description: "Collections associated with this certificate, each with purchased and retired amounts. May be empty when this certificate is not assigned to any collection."
31116
31120
  })
31117
31121
  }).meta({
31118
31122
  title: "Certificate",
@@ -31126,9 +31130,9 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31126
31130
  CreditPurchaseReceiptCollectionSchema,
31127
31131
  (collection) => collection.slug,
31128
31132
  "Collection slugs must be unique"
31129
- ).min(1).meta({
31133
+ ).meta({
31130
31134
  title: "Collections",
31131
- description: "Impact collections referenced by this purchase, each identified by a unique slug"
31135
+ description: "Impact collections referenced by this purchase, each identified by a unique slug. May be empty when no certificate is assigned to a collection."
31132
31136
  }),
31133
31137
  credits: uniqueBy(
31134
31138
  CreditPurchaseReceiptCreditSchema,
@@ -31158,12 +31162,10 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31158
31162
  const collectionSlugs = new Set(
31159
31163
  data.collections.map((collection) => String(collection.slug))
31160
31164
  );
31165
+ const referencedCollectionSlugs = /* @__PURE__ */ new Set();
31161
31166
  const creditSlugs = new Set(
31162
31167
  data.credits.map((credit) => String(credit.slug))
31163
31168
  );
31164
- const creditPurchaseTotalsBySlug = /* @__PURE__ */ new Map();
31165
- const creditRetiredTotalsBySlug = /* @__PURE__ */ new Map();
31166
- const collectionPurchasedTotalsBySlug = /* @__PURE__ */ new Map();
31167
31169
  const collectionRetiredTotalsBySlug = /* @__PURE__ */ new Map();
31168
31170
  let totalCreditsFromCertificates = 0;
31169
31171
  data.certificates.forEach((certificate, index) => {
@@ -31174,7 +31176,6 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31174
31176
  path: ["certificates", index, "credit_slug"]
31175
31177
  });
31176
31178
  let certificatePurchasedTotal = 0;
31177
- let certificateRetiredTotal = 0;
31178
31179
  validateCertificateCollectionSlugs({
31179
31180
  ctx,
31180
31181
  certificateCollections: certificate.collections,
@@ -31182,6 +31183,7 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31182
31183
  certificateIndex: index
31183
31184
  });
31184
31185
  certificate.collections.forEach((collectionItem, collectionIndex) => {
31186
+ referencedCollectionSlugs.add(String(collectionItem.slug));
31185
31187
  if (collectionItem.retired_amount > collectionItem.purchased_amount) {
31186
31188
  ctx.addIssue({
31187
31189
  code: "custom",
@@ -31196,42 +31198,45 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31196
31198
  });
31197
31199
  }
31198
31200
  certificatePurchasedTotal += Number(collectionItem.purchased_amount);
31199
- certificateRetiredTotal += Number(collectionItem.retired_amount);
31200
- collectionPurchasedTotalsBySlug.set(
31201
- collectionItem.slug,
31202
- (collectionPurchasedTotalsBySlug.get(collectionItem.slug) ?? 0) + Number(collectionItem.purchased_amount)
31203
- );
31204
31201
  collectionRetiredTotalsBySlug.set(
31205
31202
  collectionItem.slug,
31206
31203
  (collectionRetiredTotalsBySlug.get(collectionItem.slug) ?? 0) + Number(collectionItem.retired_amount)
31207
31204
  );
31208
31205
  });
31209
- if (certificatePurchasedTotal > certificate.total_amount) {
31206
+ if (certificate.purchased_amount > certificate.total_amount) {
31210
31207
  ctx.addIssue({
31211
31208
  code: "custom",
31212
- message: "Sum of certificate.collections[].purchased_amount cannot exceed certificate.total_amount",
31213
- path: ["certificates", index]
31209
+ message: "certificate.purchased_amount cannot exceed certificate.total_amount",
31210
+ path: ["certificates", index, "purchased_amount"]
31214
31211
  });
31215
31212
  }
31216
- totalCreditsFromCertificates += certificatePurchasedTotal;
31217
- creditPurchaseTotalsBySlug.set(
31218
- String(certificate.credit_slug),
31219
- (creditPurchaseTotalsBySlug.get(certificate.credit_slug) ?? 0) + certificatePurchasedTotal
31220
- );
31221
- creditRetiredTotalsBySlug.set(
31222
- String(certificate.credit_slug),
31223
- (creditRetiredTotalsBySlug.get(certificate.credit_slug) ?? 0) + certificateRetiredTotal
31224
- );
31213
+ if (certificate.collections.length > 0 && !nearlyEqual(certificatePurchasedTotal, certificate.purchased_amount)) {
31214
+ ctx.addIssue({
31215
+ code: "custom",
31216
+ message: "certificate.purchased_amount must equal sum of collections[].purchased_amount when collections are present",
31217
+ path: ["certificates", index, "purchased_amount"]
31218
+ });
31219
+ }
31220
+ totalCreditsFromCertificates += Number(certificate.purchased_amount);
31225
31221
  });
31226
31222
  const certificateCollectionRetiredTotal = Array.from(
31227
31223
  collectionRetiredTotalsBySlug.values()
31228
31224
  ).reduce((sum, amount) => sum + amount, 0);
31225
+ data.collections.forEach((collection, collectionIndex) => {
31226
+ if (!referencedCollectionSlugs.has(String(collection.slug))) {
31227
+ ctx.addIssue({
31228
+ code: "custom",
31229
+ message: "collections must only include slugs referenced by certificates[].collections",
31230
+ path: ["collections", collectionIndex, "slug"]
31231
+ });
31232
+ }
31233
+ });
31229
31234
  validateTotalMatches({
31230
31235
  ctx,
31231
31236
  actualTotal: totalCreditsFromCertificates,
31232
31237
  expectedTotal: data.summary.total_credits,
31233
31238
  path: ["summary", "total_credits"],
31234
- message: "summary.total_credits must equal sum of certificate.collections[].purchased_amount"
31239
+ message: "summary.total_credits must equal sum of certificates[].purchased_amount"
31235
31240
  });
31236
31241
  validateRetirementReceiptRequirement({
31237
31242
  ctx,
@@ -31244,7 +31249,7 @@ var CreditPurchaseReceiptDataSchema = z.strictObject({
31244
31249
  });
31245
31250
  var CreditPurchaseReceiptIpfsSchemaMeta = {
31246
31251
  title: "CreditPurchaseReceipt NFT IPFS Record",
31247
- description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes",
31252
+ description: "Complete CreditPurchaseReceipt NFT IPFS record including purchase summary, buyer details, credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.",
31248
31253
  $id: buildSchemaUrl(
31249
31254
  "credit-purchase-receipt/credit-purchase-receipt.schema.json"
31250
31255
  ),
@@ -31382,14 +31387,10 @@ var CreditPurchaseReceiptIpfsSchema = NftIpfsSchema.safeExtend({
31382
31387
  });
31383
31388
  return;
31384
31389
  }
31385
- const certificatePurchasedTotal = certificate.collections.reduce(
31386
- (sum, collection) => sum + Number(collection.purchased_amount),
31387
- 0
31388
- );
31389
31390
  const currentTotal = creditTotalsBySymbol.get(credit.symbol) ?? 0;
31390
31391
  creditTotalsBySymbol.set(
31391
31392
  credit.symbol,
31392
- currentTotal + certificatePurchasedTotal
31393
+ currentTotal + Number(certificate.purchased_amount)
31393
31394
  );
31394
31395
  });
31395
31396
  data.credits.forEach((credit) => {
@@ -31404,7 +31405,7 @@ var CreditPurchaseReceiptIpfsSchema = NftIpfsSchema.safeExtend({
31404
31405
  } else if (Number(attribute.value) !== expectedTotal) {
31405
31406
  ctx.addIssue({
31406
31407
  code: "custom",
31407
- message: `Attribute for credit symbol ${credit.symbol} must match sum of certificate.collections[].purchased_amount for the credit symbol`,
31408
+ message: `Attribute for credit symbol ${credit.symbol} must match sum of certificates[].purchased_amount for the credit symbol`,
31408
31409
  path: ["attributes"]
31409
31410
  });
31410
31411
  }
@@ -31571,9 +31572,9 @@ var CreditRetirementReceiptCertificateSchema = CertificateReferenceBaseSchema.sa
31571
31572
  CertificateCollectionItemRetirementSchema,
31572
31573
  (item) => item.slug,
31573
31574
  "Collection slugs within certificate collections must be unique"
31574
- ).min(1).meta({
31575
+ ).meta({
31575
31576
  title: "Certificate Collections",
31576
- description: "Collections associated with this certificate, each with retired amounts"
31577
+ description: "Collections associated with this certificate, each with retired amounts. May be empty when this certificate is not assigned to any collection."
31577
31578
  }),
31578
31579
  credits_retired: uniqueBy(
31579
31580
  CreditRetirementReceiptCertificateCreditSchema,
@@ -31595,9 +31596,9 @@ var CreditRetirementReceiptDataSchema = z.strictObject({
31595
31596
  CreditRetirementReceiptCollectionSchema,
31596
31597
  (collection) => collection.slug,
31597
31598
  "Collection slugs must be unique"
31598
- ).min(1).meta({
31599
+ ).meta({
31599
31600
  title: "Collections",
31600
- description: "Impact collections referenced by this retirement, each identified by a unique slug"
31601
+ description: "Impact collections referenced by this retirement, each identified by a unique slug. May be empty when no certificate is assigned to a collection."
31601
31602
  }),
31602
31603
  credits: uniqueBy(
31603
31604
  CreditRetirementReceiptCreditSchema,
@@ -31651,6 +31652,17 @@ var CreditRetirementReceiptDataSchema = z.strictObject({
31651
31652
  path: ["certificates", index]
31652
31653
  });
31653
31654
  }
31655
+ const creditsRetiredTotal = certificate.credits_retired.reduce(
31656
+ (sum, credit) => sum + Number(credit.amount),
31657
+ 0
31658
+ );
31659
+ if (creditsRetiredTotal > certificate.total_amount) {
31660
+ ctx.addIssue({
31661
+ code: "custom",
31662
+ message: "Sum of certificate.credits_retired[].amount cannot exceed certificate.total_amount",
31663
+ path: ["certificates", index, "credits_retired"]
31664
+ });
31665
+ }
31654
31666
  validateCertificateCollectionSlugs({
31655
31667
  ctx,
31656
31668
  certificateCollections: certificate.collections,
@@ -31663,11 +31675,7 @@ var CreditRetirementReceiptDataSchema = z.strictObject({
31663
31675
  (collectionRetiredTotalsBySlug.get(collectionItem.slug) ?? 0) + Number(collectionItem.retired_amount)
31664
31676
  );
31665
31677
  });
31666
- const creditsRetiredTotal = certificate.credits_retired.reduce(
31667
- (sum, credit) => sum + Number(credit.amount),
31668
- 0
31669
- );
31670
- if (!nearlyEqual(creditsRetiredTotal, certificateCollectionRetiredTotal)) {
31678
+ if (certificate.collections.length > 0 && !nearlyEqual(creditsRetiredTotal, certificateCollectionRetiredTotal)) {
31671
31679
  ctx.addIssue({
31672
31680
  code: "custom",
31673
31681
  message: "certificates.credits_retired amounts must sum to certificate.collections[].retired_amount",
@@ -31718,27 +31726,29 @@ var CreditRetirementReceiptDataSchema = z.strictObject({
31718
31726
  (creditTotalsBySymbol.get(credit.credit_symbol) ?? 0) + credit.amount
31719
31727
  );
31720
31728
  });
31721
- totalRetiredFromCertificates += certificateCollectionRetiredTotal;
31729
+ totalRetiredFromCertificates += creditsRetiredTotal;
31722
31730
  });
31723
31731
  validateTotalMatches({
31724
31732
  ctx,
31725
31733
  actualTotal: totalRetiredFromCertificates,
31726
31734
  expectedTotal: data.summary.total_credits_retired,
31727
31735
  path: ["summary", "total_credits_retired"],
31728
- message: "summary.total_credits_retired must equal sum of certificate.collections[].retired_amount"
31729
- });
31730
- validateCollectionsHaveRetiredAmounts({
31731
- ctx,
31732
- collections: data.collections,
31733
- retiredTotalsBySlug: collectionRetiredTotalsBySlug
31736
+ message: "summary.total_credits_retired must equal sum of certificates[].credits_retired[].amount"
31734
31737
  });
31738
+ if (data.collections.length > 0) {
31739
+ validateCollectionsHaveRetiredAmounts({
31740
+ ctx,
31741
+ collections: data.collections,
31742
+ retiredTotalsBySlug: collectionRetiredTotalsBySlug
31743
+ });
31744
+ }
31735
31745
  }).meta({
31736
31746
  title: "Credit Retirement Receipt Data",
31737
31747
  description: "Complete data structure for a credit retirement receipt"
31738
31748
  });
31739
31749
  var CreditRetirementReceiptIpfsSchemaMeta = {
31740
31750
  title: "CreditRetirementReceipt NFT IPFS Record",
31741
- description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes",
31751
+ description: "Complete CreditRetirementReceipt NFT IPFS record including retirement summary, beneficiary and credit holder details (identity optional), credit breakdowns, certificate allocations, and NFT display attributes. Supports both collection-assigned and no-collection variants.",
31742
31752
  $id: buildSchemaUrl(
31743
31753
  "credit-retirement-receipt/credit-retirement-receipt.schema.json"
31744
31754
  ),