@oods/component-contracts 0.3.1 → 0.3.2

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/README.md CHANGED
@@ -21,7 +21,7 @@ console.log(componentContracts.Button.accessibility);
21
21
 
22
22
  Use the contract when writing a component adapter. The `componentCapabilityBaseline` export and `@oods/component-contracts/registry/capabilities` contain the retained capability ledger. Its evidence is scoped to the recorded component scenarios; a declared obligation is not evidence that an arbitrary implementation meets it.
23
23
 
24
- Forge's mapped-component reports distinguish met, unmet and not-checked obligations. Read their reasons and source identities before using a report as evidence. The package does not certify an application, a third-party library or every possible component state.
24
+ OODS Foundry's mapped-component reports distinguish met, unmet and not-checked obligations. Read their reasons and source identities before using a report as evidence. The package does not certify an application, a third-party library or every possible component state.
25
25
 
26
26
  ## Limits
27
27
 
@@ -29,4 +29,4 @@ Use matching versions of the OODS packages. These packages are separate from the
29
29
 
30
30
  ## License
31
31
 
32
- Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE). Generated output belongs to its user; installed package dependencies retain their own licenses.
32
+ Apache License 2.0. See [LICENSE](https://cdn.jsdelivr.net/npm/@oods/component-contracts@0.3.2/LICENSE) and [NOTICE](https://cdn.jsdelivr.net/npm/@oods/component-contracts@0.3.2/NOTICE). Generated output belongs to its user; installed package dependencies retain their own licenses.
package/dist/index.cjs CHANGED
@@ -15373,7 +15373,7 @@ var authoredContracts = {
15373
15373
  states: ["subtle", "solid"],
15374
15374
  tokenRoles: ["badge.background", "badge.border", "badge.text"],
15375
15375
  accessibility: ["false remains visible", "archive is the badge variant"],
15376
- compatibility: "Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean false and true remain literal scalar labels/status metadata; absent flags remain absent and authored labels or children win. field binds isArchived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action."
15376
+ compatibility: "Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean flags read Not archived / Archived while preserving their recorded status; absent flags remain absent and authored labels or children win. field binds isArchived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action."
15377
15377
  },
15378
15378
  ArchiveSummary: {
15379
15379
  id: "ArchiveSummary",
@@ -15959,7 +15959,7 @@ var authoredContracts = {
15959
15959
  states: ["populated", "empty"],
15960
15960
  tokenRoles: ["meta.text", "meta.label"],
15961
15961
  accessibility: ["model and interval have literal inline labels", "price metadata is noninteractive"],
15962
- compatibility: "Mirrors renderPriceCardMeta over renderMetaInline: title/label/heading/name (default Price), Model model/pricingModel and Interval interval/billingInterval inline terms. Children replace the entire body including its title. modelField and intervalField lower to their runtime keys. amountField, currencyField and minorUnitsParameter are consumed unbound because this HTML metadata renderer has no amount or currency term. Noninteractive."
15962
+ compatibility: "Mirrors renderPriceCardMeta over renderMetaInline: title/label/heading/name (default Price), Model model/pricingModel and Interval interval/billingInterval inline terms, their codes read as PriceSummary reads them (formatPriceCode: one_time reads One Time). Children replace the entire body including its title. modelField and intervalField lower to their runtime keys. amountField, currencyField and minorUnitsParameter are consumed unbound because this HTML metadata renderer has no amount or currency term. Noninteractive."
15963
15963
  },
15964
15964
  PriceSummary: {
15965
15965
  id: "PriceSummary",
@@ -16396,7 +16396,7 @@ var authoredScenarios = [
16396
16396
  { id: "address-editor-fields-and-change", oodsComponentId: "AddressEditor", props: { title: "Shipping address", street: "1 Main St", city: "Springfield", region: "IL", postalCode: "62701" }, slots: {}, initialState: { street: "1 Main St" }, renderExpectation: { name: "change", trigger: "type into the City input", expected: "change emitted with the current street/city/region/postalCode record" }, assertions: ["title is a real h2 heading", "four labelled inputs are prefilled", "change carries the whole address record", "submitting is a no-op"] },
16397
16397
  { id: "address-summary-badge-role", oodsComponentId: "AddressSummaryBadge", props: { label: "Billing address", role: "billing" }, slots: {}, initialState: { status: "billing" }, renderExpectation: { name: "render", trigger: "mount", expected: "visible Billing address label with data-badge-status billing and the address variant" }, assertions: ["label is visible text", "data-badge-status is billing", "data-badge-variant is address", "badge is noninteractive"] },
16398
16398
  { id: "address-validation-timeline-events", oodsComponentId: "AddressValidationTimeline", props: { title: "Address checks", validations: [{ label: "Postal code verified", timestamp: "2026-09-05T12:00:00Z", detail: "Matched carrier database" }, "Geocoded"] }, slots: {}, initialState: { events: 2 }, renderExpectation: { name: "render", trigger: "mount", expected: "a log region titled Address checks with two ordered events, the first timestamped and detailed" }, assertions: ["region has role log and an h2 title", "events are ordered list items", "the timestamp is a time element", "scalar entries render as text"] },
16399
- { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "false remains visible; archive is the badge variant" }, assertions: ["false remains visible", "archive is the badge variant"] },
16399
+ { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "Not archived remains visible; machine status remains false; archive is the badge variant" }, assertions: ["Not archived remains visible; machine status remains false", "archive is the badge variant"] },
16400
16400
  { id: "archive-summary-false-and-reason", oodsComponentId: "ArchiveSummary", props: { "isArchived": false, "archivedAt": "2026-09-05T12:00:00Z", "reason": "Retention policy" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "No remains visible in its named term; archive date and reason remain associated terms" }, assertions: ["No remains visible in its named term", "archive date and reason remain associated terms"] },
16401
16401
  { id: "archived-row-presentation", oodsComponentId: "ArchivedRowOverlay", props: { "isArchived": true, "showBadge": true, "separateTab": true, "tabLabel": "Archived", "label": "Team subscription" }, slots: {}, initialState: {}, renderExpectation: { name: "render", trigger: "mount", expected: "Archived row stays accessible and its badge and tab label agree" }, assertions: ["Archived row stays accessible and its badge and tab label agree"] },
16402
16402
  { id: "audit-event-type-and-timestamp", oodsComponentId: "AuditEvent", props: { event: "user.updated", timestamp: "2026-09-05T12:00:00Z", detail: "Display name changed" }, slots: {}, initialState: { timestamped: true }, renderExpectation: { name: "render", trigger: "mount", expected: "one audit article with a machine-readable time, the event label and the detail" }, assertions: ["article carries data-event-type audit", "time element has a datetime", "label and detail are visible text"] },
@@ -16608,6 +16608,28 @@ function billingCycle(values) {
16608
16608
  const announcement = `${percent === void 0 ? "Progress unavailable" : `${percent}% complete`} \xB7 ${remainingDays === void 0 ? "Remaining days unavailable" : `${remainingDays} ${remainingDays === 1 ? "day" : "days"} remaining`}`;
16609
16609
  return { percent, remainingDays, announcement, ended };
16610
16610
  }
16611
+ var PERIOD_MONTHS = { monthly: 1, quarterly: 3, yearly: 12, annual: 12 };
16612
+ function billingPeriodEnd(start, interval) {
16613
+ const date = new Date(start);
16614
+ if (!Number.isFinite(date.getTime())) return void 0;
16615
+ if (interval === "weekly") return new Date(date.getTime() + 7 * 864e5).toISOString();
16616
+ const months = interval ? PERIOD_MONTHS[interval] : void 0;
16617
+ if (!months) return void 0;
16618
+ const end = new Date(date);
16619
+ end.setUTCDate(1);
16620
+ end.setUTCMonth(end.getUTCMonth() + months);
16621
+ end.setUTCDate(Math.min(date.getUTCDate(), new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth() + 1, 0)).getUTCDate()));
16622
+ return end.toISOString();
16623
+ }
16624
+ function restartedBillingPeriod(at, interval) {
16625
+ return {
16626
+ current_period_start: at,
16627
+ current_period_end: billingPeriodEnd(at, interval),
16628
+ current_period_progress: void 0,
16629
+ next_payment_due_at: at,
16630
+ payment_status: "pending"
16631
+ };
16632
+ }
16611
16633
  var NO_NEXT_PAYMENT = "No payment scheduled";
16612
16634
  var NO_LAST_PAYMENT = "No previous payment";
16613
16635
  function billingDate(value) {
@@ -16667,9 +16689,13 @@ function recordCollectionEvents(record2, options = {}) {
16667
16689
  if (typeof at !== "string" || typeof state !== "string") return [];
16668
16690
  return [{ id: "state-" + index, title: String(entry.title ?? state.split(/[_-]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ")), at, description: String(entry.reason ?? ""), kind: "state" }];
16669
16691
  }) : [];
16692
+ const recorded = Array.isArray(record2.payment_history) ? record2.payment_history : [];
16670
16693
  for (const source2 of options.payments ?? []) {
16671
16694
  const at = record2[source2.field];
16672
- if (typeof at === "string") events.push({ id: "payment-" + source2.field, title: source2.title, at, description: billingSummary(Number(record2.amount), String(record2.currency), options.minorUnits ?? 100, String(record2.billing_interval)), kind: "payment" });
16695
+ if (typeof at !== "string") continue;
16696
+ const paid = recorded.find((row) => row && typeof row === "object" && Date.parse(row.at) === Date.parse(at) && typeof row.amount === "number");
16697
+ const description = paid ? formatBillingAmount(paid.amount, String(paid.currency ?? record2.currency), options.minorUnits ?? 100) : billingSummary(Number(record2.amount), String(record2.currency), options.minorUnits ?? 100, String(record2.billing_interval));
16698
+ events.push({ id: "payment-" + source2.field, title: source2.title, at, description, kind: "payment" });
16673
16699
  }
16674
16700
  for (const source2 of [{ field: "created_at", title: "Created" }, { field: "last_event_at", title: String(record2.last_event ?? "Updated").replaceAll("_", " ") }, { field: "issued_at", title: "Issued" }, { field: "period_start", title: "Period started" }, { field: "ownership_transferred_at", title: "Ownership transferred" }]) {
16675
16701
  const at = record2[source2.field];
@@ -17031,6 +17057,7 @@ exports.billingDate = billingDate;
17031
17057
  exports.billingIntervalMessage = billingIntervalMessage;
17032
17058
  exports.billingPaymentRows = billingPaymentRows;
17033
17059
  exports.billingPaymentSummary = billingPaymentSummary;
17060
+ exports.billingPeriodEnd = billingPeriodEnd;
17034
17061
  exports.billingSummary = billingSummary;
17035
17062
  exports.chronologicalEvents = chronologicalEvents;
17036
17063
  exports.componentBehaviors = componentBehaviors;
@@ -17063,6 +17090,7 @@ exports.portedComponentContracts = portedComponentContracts;
17063
17090
  exports.portedScenarios = portedScenarios;
17064
17091
  exports.recipeItemLabels = recipeItemLabels;
17065
17092
  exports.recordCollectionEvents = recordCollectionEvents;
17093
+ exports.restartedBillingPeriod = restartedBillingPeriod;
17066
17094
  exports.sharedScenarios = sharedScenarios;
17067
17095
  exports.substitutionContractReport = substitutionContractReport;
17068
17096
  exports.summarizeSubstitutionReport = summarizeSubstitutionReport;
package/dist/index.d.cts CHANGED
@@ -177,6 +177,25 @@ declare function billingCycle(values: BillingCycleValues): {
177
177
  announcement: string;
178
178
  ended: boolean;
179
179
  };
180
+ /**
181
+ * The end of a billing period that starts at `start` and lasts one `interval` (UTC). A month keeps the start's day, or
182
+ * the month's last day when it is shorter. An interval with no fixed length has no computable end: undefined.
183
+ */
184
+ declare function billingPeriodEnd(start: string, interval: string | undefined): string | undefined;
185
+ /**
186
+ * s220-m01 (#2461): Billable's billing-anchor reset (traits/financial/Billable.trait.yaml). When the terms an active
187
+ * record is billed at change (price, currency or interval), a new billing period starts at the change. Billable charges
188
+ * at a period's start (prepaid), so the new period's payment is due at once, and nothing has collected it: pending.
189
+ * Progress is left to the clock the period is measured by. Recorded payments are history and keep their own amounts.
190
+ * Before it, an edit to "€19.99 · yearly" kept the monthly period (77% complete, 7 days remaining, next payment in a month).
191
+ */
192
+ declare function restartedBillingPeriod(at: string, interval: string | undefined): {
193
+ current_period_start: string;
194
+ current_period_end: string | undefined;
195
+ current_period_progress: undefined;
196
+ next_payment_due_at: string;
197
+ payment_status: "pending";
198
+ };
180
199
  interface BillingPaymentValues {
181
200
  lastPayment?: string;
182
201
  nextPayment?: string;
@@ -3021,4 +3040,4 @@ declare function getBaselineCapability(componentId: string): {
3021
3040
  };
3022
3041
  } | undefined;
3023
3042
 
3024
- export { type AuditSummaryValues, BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, type BillingAmountResult, type BillingCycleValues, type BillingPaymentValues, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, type CollectionEvent, type ComponentBehavior, type ComponentClassification, type ComponentContract, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, type EmissionEligibilityEvidence, type EmissionEligibilityEvidenceClass, type EvidenceResult, type EvidenceStatus, FOUNDATION_V1_EVIDENCE_CLASSES, type FoundationV1Evidence, type FoundationV1EvidenceClass, GOVERNED_DEFINITION, GOVERNED_SURFACES, type GeoFieldMappingValue, type GovernedComponentId, type GovernedLedgerRow, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, type NucleusComponentId, type ObligationStatus, PORTED_COMPONENT_IDS, type PortedComponentId, RESULT_STATES, RESULT_STATE_TONE, type ResultState, SEVERITY_TONES, type ScenarioTrigger, type SharedScenario, type SortIndicatorValues, type SortState, type SubstitutionContractReport, type SubstitutionObligation, type TraitEventKind, type TraitEventValues, UI_WORKFLOW_STATES, type UiWorkflowState, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, type VizChannel, type VizChartType, type VizColorBinding, type VizControlField, type VizControlId, type VizFieldBinding, type VizIntentFragment, type VizScale, type VizSummaryId, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
3043
+ export { type AuditSummaryValues, BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, type BillingAmountResult, type BillingCycleValues, type BillingPaymentValues, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, type CollectionEvent, type ComponentBehavior, type ComponentClassification, type ComponentContract, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, type EmissionEligibilityEvidence, type EmissionEligibilityEvidenceClass, type EvidenceResult, type EvidenceStatus, FOUNDATION_V1_EVIDENCE_CLASSES, type FoundationV1Evidence, type FoundationV1EvidenceClass, GOVERNED_DEFINITION, GOVERNED_SURFACES, type GeoFieldMappingValue, type GovernedComponentId, type GovernedLedgerRow, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, type NucleusComponentId, type ObligationStatus, PORTED_COMPONENT_IDS, type PortedComponentId, RESULT_STATES, RESULT_STATE_TONE, type ResultState, SEVERITY_TONES, type ScenarioTrigger, type SharedScenario, type SortIndicatorValues, type SortState, type SubstitutionContractReport, type SubstitutionObligation, type TraitEventKind, type TraitEventValues, UI_WORKFLOW_STATES, type UiWorkflowState, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, type VizChannel, type VizChartType, type VizColorBinding, type VizControlField, type VizControlId, type VizFieldBinding, type VizIntentFragment, type VizScale, type VizSummaryId, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingPeriodEnd, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, restartedBillingPeriod, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
package/dist/index.d.ts CHANGED
@@ -177,6 +177,25 @@ declare function billingCycle(values: BillingCycleValues): {
177
177
  announcement: string;
178
178
  ended: boolean;
179
179
  };
180
+ /**
181
+ * The end of a billing period that starts at `start` and lasts one `interval` (UTC). A month keeps the start's day, or
182
+ * the month's last day when it is shorter. An interval with no fixed length has no computable end: undefined.
183
+ */
184
+ declare function billingPeriodEnd(start: string, interval: string | undefined): string | undefined;
185
+ /**
186
+ * s220-m01 (#2461): Billable's billing-anchor reset (traits/financial/Billable.trait.yaml). When the terms an active
187
+ * record is billed at change (price, currency or interval), a new billing period starts at the change. Billable charges
188
+ * at a period's start (prepaid), so the new period's payment is due at once, and nothing has collected it: pending.
189
+ * Progress is left to the clock the period is measured by. Recorded payments are history and keep their own amounts.
190
+ * Before it, an edit to "€19.99 · yearly" kept the monthly period (77% complete, 7 days remaining, next payment in a month).
191
+ */
192
+ declare function restartedBillingPeriod(at: string, interval: string | undefined): {
193
+ current_period_start: string;
194
+ current_period_end: string | undefined;
195
+ current_period_progress: undefined;
196
+ next_payment_due_at: string;
197
+ payment_status: "pending";
198
+ };
180
199
  interface BillingPaymentValues {
181
200
  lastPayment?: string;
182
201
  nextPayment?: string;
@@ -3021,4 +3040,4 @@ declare function getBaselineCapability(componentId: string): {
3021
3040
  };
3022
3041
  } | undefined;
3023
3042
 
3024
- export { type AuditSummaryValues, BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, type BillingAmountResult, type BillingCycleValues, type BillingPaymentValues, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, type CollectionEvent, type ComponentBehavior, type ComponentClassification, type ComponentContract, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, type EmissionEligibilityEvidence, type EmissionEligibilityEvidenceClass, type EvidenceResult, type EvidenceStatus, FOUNDATION_V1_EVIDENCE_CLASSES, type FoundationV1Evidence, type FoundationV1EvidenceClass, GOVERNED_DEFINITION, GOVERNED_SURFACES, type GeoFieldMappingValue, type GovernedComponentId, type GovernedLedgerRow, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, type NucleusComponentId, type ObligationStatus, PORTED_COMPONENT_IDS, type PortedComponentId, RESULT_STATES, RESULT_STATE_TONE, type ResultState, SEVERITY_TONES, type ScenarioTrigger, type SharedScenario, type SortIndicatorValues, type SortState, type SubstitutionContractReport, type SubstitutionObligation, type TraitEventKind, type TraitEventValues, UI_WORKFLOW_STATES, type UiWorkflowState, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, type VizChannel, type VizChartType, type VizColorBinding, type VizControlField, type VizControlId, type VizFieldBinding, type VizIntentFragment, type VizScale, type VizSummaryId, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
3043
+ export { type AuditSummaryValues, BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, type BillingAmountResult, type BillingCycleValues, type BillingPaymentValues, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, type CollectionEvent, type ComponentBehavior, type ComponentClassification, type ComponentContract, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, type EmissionEligibilityEvidence, type EmissionEligibilityEvidenceClass, type EvidenceResult, type EvidenceStatus, FOUNDATION_V1_EVIDENCE_CLASSES, type FoundationV1Evidence, type FoundationV1EvidenceClass, GOVERNED_DEFINITION, GOVERNED_SURFACES, type GeoFieldMappingValue, type GovernedComponentId, type GovernedLedgerRow, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, type NucleusComponentId, type ObligationStatus, PORTED_COMPONENT_IDS, type PortedComponentId, RESULT_STATES, RESULT_STATE_TONE, type ResultState, SEVERITY_TONES, type ScenarioTrigger, type SharedScenario, type SortIndicatorValues, type SortState, type SubstitutionContractReport, type SubstitutionObligation, type TraitEventKind, type TraitEventValues, UI_WORKFLOW_STATES, type UiWorkflowState, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, type VizChannel, type VizChartType, type VizColorBinding, type VizControlField, type VizControlId, type VizFieldBinding, type VizIntentFragment, type VizScale, type VizSummaryId, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingPeriodEnd, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, restartedBillingPeriod, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
package/dist/index.js CHANGED
@@ -15371,7 +15371,7 @@ var authoredContracts = {
15371
15371
  states: ["subtle", "solid"],
15372
15372
  tokenRoles: ["badge.background", "badge.border", "badge.text"],
15373
15373
  accessibility: ["false remains visible", "archive is the badge variant"],
15374
- compatibility: "Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean false and true remain literal scalar labels/status metadata; absent flags remain absent and authored labels or children win. field binds isArchived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action."
15374
+ compatibility: "Mirrors renderArchivePill over renderBadgePrimitive: label/text/status/state/isArchived/value label precedence, status/state/isArchived/value status precedence, Archive fallback and archive variant. Boolean flags read Not archived / Archived while preserving their recorded status; absent flags remain absent and authored labels or children win. field binds isArchived. archivedAtField is consumed unbound because the HTML pill has no date term. Noninteractive; no archive or restore action."
15375
15375
  },
15376
15376
  ArchiveSummary: {
15377
15377
  id: "ArchiveSummary",
@@ -15957,7 +15957,7 @@ var authoredContracts = {
15957
15957
  states: ["populated", "empty"],
15958
15958
  tokenRoles: ["meta.text", "meta.label"],
15959
15959
  accessibility: ["model and interval have literal inline labels", "price metadata is noninteractive"],
15960
- compatibility: "Mirrors renderPriceCardMeta over renderMetaInline: title/label/heading/name (default Price), Model model/pricingModel and Interval interval/billingInterval inline terms. Children replace the entire body including its title. modelField and intervalField lower to their runtime keys. amountField, currencyField and minorUnitsParameter are consumed unbound because this HTML metadata renderer has no amount or currency term. Noninteractive."
15960
+ compatibility: "Mirrors renderPriceCardMeta over renderMetaInline: title/label/heading/name (default Price), Model model/pricingModel and Interval interval/billingInterval inline terms, their codes read as PriceSummary reads them (formatPriceCode: one_time reads One Time). Children replace the entire body including its title. modelField and intervalField lower to their runtime keys. amountField, currencyField and minorUnitsParameter are consumed unbound because this HTML metadata renderer has no amount or currency term. Noninteractive."
15961
15961
  },
15962
15962
  PriceSummary: {
15963
15963
  id: "PriceSummary",
@@ -16394,7 +16394,7 @@ var authoredScenarios = [
16394
16394
  { id: "address-editor-fields-and-change", oodsComponentId: "AddressEditor", props: { title: "Shipping address", street: "1 Main St", city: "Springfield", region: "IL", postalCode: "62701" }, slots: {}, initialState: { street: "1 Main St" }, renderExpectation: { name: "change", trigger: "type into the City input", expected: "change emitted with the current street/city/region/postalCode record" }, assertions: ["title is a real h2 heading", "four labelled inputs are prefilled", "change carries the whole address record", "submitting is a no-op"] },
16395
16395
  { id: "address-summary-badge-role", oodsComponentId: "AddressSummaryBadge", props: { label: "Billing address", role: "billing" }, slots: {}, initialState: { status: "billing" }, renderExpectation: { name: "render", trigger: "mount", expected: "visible Billing address label with data-badge-status billing and the address variant" }, assertions: ["label is visible text", "data-badge-status is billing", "data-badge-variant is address", "badge is noninteractive"] },
16396
16396
  { id: "address-validation-timeline-events", oodsComponentId: "AddressValidationTimeline", props: { title: "Address checks", validations: [{ label: "Postal code verified", timestamp: "2026-09-05T12:00:00Z", detail: "Matched carrier database" }, "Geocoded"] }, slots: {}, initialState: { events: 2 }, renderExpectation: { name: "render", trigger: "mount", expected: "a log region titled Address checks with two ordered events, the first timestamped and detailed" }, assertions: ["region has role log and an h2 title", "events are ordered list items", "the timestamp is a time element", "scalar entries render as text"] },
16397
- { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "false remains visible; archive is the badge variant" }, assertions: ["false remains visible", "archive is the badge variant"] },
16397
+ { id: "archive-pill-false", oodsComponentId: "ArchivePill", props: { "isArchived": false }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "Not archived remains visible; machine status remains false; archive is the badge variant" }, assertions: ["Not archived remains visible; machine status remains false", "archive is the badge variant"] },
16398
16398
  { id: "archive-summary-false-and-reason", oodsComponentId: "ArchiveSummary", props: { "isArchived": false, "archivedAt": "2026-09-05T12:00:00Z", "reason": "Retention policy" }, slots: {}, initialState: { content: "populated" }, renderExpectation: { name: "render", trigger: "mount", expected: "No remains visible in its named term; archive date and reason remain associated terms" }, assertions: ["No remains visible in its named term", "archive date and reason remain associated terms"] },
16399
16399
  { id: "archived-row-presentation", oodsComponentId: "ArchivedRowOverlay", props: { "isArchived": true, "showBadge": true, "separateTab": true, "tabLabel": "Archived", "label": "Team subscription" }, slots: {}, initialState: {}, renderExpectation: { name: "render", trigger: "mount", expected: "Archived row stays accessible and its badge and tab label agree" }, assertions: ["Archived row stays accessible and its badge and tab label agree"] },
16400
16400
  { id: "audit-event-type-and-timestamp", oodsComponentId: "AuditEvent", props: { event: "user.updated", timestamp: "2026-09-05T12:00:00Z", detail: "Display name changed" }, slots: {}, initialState: { timestamped: true }, renderExpectation: { name: "render", trigger: "mount", expected: "one audit article with a machine-readable time, the event label and the detail" }, assertions: ["article carries data-event-type audit", "time element has a datetime", "label and detail are visible text"] },
@@ -16606,6 +16606,28 @@ function billingCycle(values) {
16606
16606
  const announcement = `${percent === void 0 ? "Progress unavailable" : `${percent}% complete`} \xB7 ${remainingDays === void 0 ? "Remaining days unavailable" : `${remainingDays} ${remainingDays === 1 ? "day" : "days"} remaining`}`;
16607
16607
  return { percent, remainingDays, announcement, ended };
16608
16608
  }
16609
+ var PERIOD_MONTHS = { monthly: 1, quarterly: 3, yearly: 12, annual: 12 };
16610
+ function billingPeriodEnd(start, interval) {
16611
+ const date = new Date(start);
16612
+ if (!Number.isFinite(date.getTime())) return void 0;
16613
+ if (interval === "weekly") return new Date(date.getTime() + 7 * 864e5).toISOString();
16614
+ const months = interval ? PERIOD_MONTHS[interval] : void 0;
16615
+ if (!months) return void 0;
16616
+ const end = new Date(date);
16617
+ end.setUTCDate(1);
16618
+ end.setUTCMonth(end.getUTCMonth() + months);
16619
+ end.setUTCDate(Math.min(date.getUTCDate(), new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth() + 1, 0)).getUTCDate()));
16620
+ return end.toISOString();
16621
+ }
16622
+ function restartedBillingPeriod(at, interval) {
16623
+ return {
16624
+ current_period_start: at,
16625
+ current_period_end: billingPeriodEnd(at, interval),
16626
+ current_period_progress: void 0,
16627
+ next_payment_due_at: at,
16628
+ payment_status: "pending"
16629
+ };
16630
+ }
16609
16631
  var NO_NEXT_PAYMENT = "No payment scheduled";
16610
16632
  var NO_LAST_PAYMENT = "No previous payment";
16611
16633
  function billingDate(value) {
@@ -16665,9 +16687,13 @@ function recordCollectionEvents(record2, options = {}) {
16665
16687
  if (typeof at !== "string" || typeof state !== "string") return [];
16666
16688
  return [{ id: "state-" + index, title: String(entry.title ?? state.split(/[_-]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ")), at, description: String(entry.reason ?? ""), kind: "state" }];
16667
16689
  }) : [];
16690
+ const recorded = Array.isArray(record2.payment_history) ? record2.payment_history : [];
16668
16691
  for (const source2 of options.payments ?? []) {
16669
16692
  const at = record2[source2.field];
16670
- if (typeof at === "string") events.push({ id: "payment-" + source2.field, title: source2.title, at, description: billingSummary(Number(record2.amount), String(record2.currency), options.minorUnits ?? 100, String(record2.billing_interval)), kind: "payment" });
16693
+ if (typeof at !== "string") continue;
16694
+ const paid = recorded.find((row) => row && typeof row === "object" && Date.parse(row.at) === Date.parse(at) && typeof row.amount === "number");
16695
+ const description = paid ? formatBillingAmount(paid.amount, String(paid.currency ?? record2.currency), options.minorUnits ?? 100) : billingSummary(Number(record2.amount), String(record2.currency), options.minorUnits ?? 100, String(record2.billing_interval));
16696
+ events.push({ id: "payment-" + source2.field, title: source2.title, at, description, kind: "payment" });
16671
16697
  }
16672
16698
  for (const source2 of [{ field: "created_at", title: "Created" }, { field: "last_event_at", title: String(record2.last_event ?? "Updated").replaceAll("_", " ") }, { field: "issued_at", title: "Issued" }, { field: "period_start", title: "Period started" }, { field: "ownership_transferred_at", title: "Ownership transferred" }]) {
16673
16699
  const at = record2[source2.field];
@@ -16995,4 +17021,4 @@ function getBaselineCapability(componentId) {
16995
17021
  return componentCapabilityBaseline.rows.find((row) => row.id === componentId);
16996
17022
  }
16997
17023
 
16998
- export { BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, FOUNDATION_V1_EVIDENCE_CLASSES, GOVERNED_DEFINITION, GOVERNED_SURFACES, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, PORTED_COMPONENT_IDS, RESULT_STATES, RESULT_STATE_TONE, SEVERITY_TONES, UI_WORKFLOW_STATES, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
17024
+ export { BILLING_AMOUNT_ERROR, BILLING_INTERVALS, BILLING_INTERVAL_ERROR, BILLING_MINOR_UNITS, COMPONENT_CLASSIFICATIONS, COMPONENT_CONTRACT_VERSION, COMPONENT_CONTRACT_VERSION_1_1, DEFAULT_COLOR_STATES, EMISSION_ELIGIBILITY_EVIDENCE_CLASSES, FOUNDATION_V1_EVIDENCE_CLASSES, GOVERNED_DEFINITION, GOVERNED_SURFACES, NO_LAST_PAYMENT, NO_NEXT_PAYMENT, NUCLEUS_COMPONENT_IDS, PORTED_COMPONENT_IDS, RESULT_STATES, RESULT_STATE_TONE, SEVERITY_TONES, UI_WORKFLOW_STATES, VIZ_CONTROL_IDS, VIZ_CONTROL_TITLES, VIZ_PREVIEW_TYPES, VIZ_SUMMARY_IDS, ariaSort, assertStaticSvg, auditSummary, billingAmountMessage, billingAmountText, billingCycle, billingDate, billingIntervalMessage, billingPaymentRows, billingPaymentSummary, billingPeriodEnd, billingSummary, chronologicalEvents, componentBehaviors, componentCapabilityBaseline, componentContracts, componentIntake, componentReconciliationProposal, currencyMinorUnits, dateTimeInputValue, defaultVizIntent, deriveStartingComponentCount, editVizIntent, evaluateEmissionEligibility, evaluateFoundationV1, formatBillingAmount, formatDateTime, formatPriceAmount, formatPriceCode, formatReadOnlyValue, formatRecordLabel, formatReferenceLabel, geoFieldMapping, getBaselineCapability, initialSort, isGovernedComponent, isVizIntentFragment, nextSort, parseBillingAmount, portedComponentContracts, portedScenarios, recipeItemLabels, recordCollectionEvents, restartedBillingPeriod, sharedScenarios, substitutionContractReport, summarizeSubstitutionReport, summaryValue, svgCarriesTitle, traitEventRows, validMinorUnits, validateComponentIntakeDocument, vizControlFields, vizFieldValue, vizSummaryRows };
package/package.json CHANGED
@@ -1,11 +1,22 @@
1
1
  {
2
2
  "name": "@oods/component-contracts",
3
- "version": "0.3.1",
4
- "description": "Versioned OODS component identities, semantic contracts, shared scenarios, and readiness predicates.",
3
+ "version": "0.3.2",
4
+ "description": "Component contracts for OODS Foundry: each component's identity, props, events, states, token roles and accessibility obligations, with shared formatting helpers.",
5
+ "homepage": "https://oods-foundry.com/",
6
+ "bugs": {
7
+ "email": "derek@derekn.com"
8
+ },
9
+ "keywords": [
10
+ "oods",
11
+ "oods-foundry",
12
+ "component-contracts",
13
+ "design-system",
14
+ "accessibility"
15
+ ],
5
16
  "type": "module",
6
17
  "license": "Apache-2.0",
7
18
  "engines": {
8
- "node": ">=20.11.1"
19
+ "node": ">=22.0.0"
9
20
  },
10
21
  "files": [
11
22
  "dist",