@classytic/primitives 0.26.3 → 0.27.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/CHANGELOG.md +38 -0
- package/dist/address.d.mts +2 -2
- package/dist/address.mjs +2 -1
- package/dist/csv.d.mts +36 -0
- package/dist/csv.mjs +50 -0
- package/dist/price-basis.d.mts +31 -0
- package/dist/price-basis.mjs +51 -0
- package/dist/rounded-div-BWJb98Ws.mjs +13 -0
- package/dist/unit-cost-rate.d.mts +9 -3
- package/dist/unit-cost-rate.mjs +1 -14
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,44 @@
|
|
|
3
3
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
4
|
adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
5
|
|
|
6
|
+
## 0.27.0
|
|
7
|
+
|
|
8
|
+
### Added — `./csv` subpath: one CSV cell escaper for the whole fleet
|
|
9
|
+
|
|
10
|
+
`escapeCsvCell(value)` and `neutralizeCsvFormula(value)`. Six CSV producers
|
|
11
|
+
across ledger, the spine and the hosts each hand-rolled RFC 4180 quoting, and
|
|
12
|
+
not one neutralized a leading `= + - @ \t \r` — so a customer-supplied payment
|
|
13
|
+
reference or party name reached the accountant's spreadsheet as a live formula.
|
|
14
|
+
Quoting does not help: a spreadsheet strips the quotes and evaluates what is
|
|
15
|
+
left, which is why the two defences ship as one module.
|
|
16
|
+
|
|
17
|
+
The two functions are separable on purpose. A consumer holding a real CSV
|
|
18
|
+
writer (`csv-stringify`) takes `neutralizeCsvFormula` only, so its quoting is
|
|
19
|
+
not done twice; a hand-rolled `rows.map(...).join(',')` takes `escapeCsvCell`.
|
|
20
|
+
|
|
21
|
+
**Well-formed numbers are exempt.** Prefixing `-1500` would make every negative
|
|
22
|
+
amount text and break `SUM` in every finance export — a fix that quietly
|
|
23
|
+
corrupts the product is worse than the hole. The exemption requires the WHOLE
|
|
24
|
+
cell to be a number, so `-2+3+cmd|'/c calc'!A0` is still neutralized.
|
|
25
|
+
|
|
26
|
+
Not for a machine-to-machine upload contract with a fixed column spec (a
|
|
27
|
+
courier's bulk-import CSV): there the receiver is a parser, not a spreadsheet,
|
|
28
|
+
and an added `'` corrupts the payload.
|
|
29
|
+
|
|
30
|
+
## 0.26.4
|
|
31
|
+
|
|
32
|
+
### Added — `./price-basis` subpath: measured pricing across physical dimensions
|
|
33
|
+
|
|
34
|
+
New `PriceBasis` type (`FixedPriceBasis | MeasuredPriceBasis`) models how a quoted price spans a sellable quantity — flat fixed or per-unit-of-measure (mass, duration, volume, length, area). Factory functions `fixedPriceBasis()` and `measuredPriceBasis(dimension, qtyUnit, priceUnit, qtyPerPriceUnit)` construct the two shapes; `isPriceBasis()` is a structural guard for DB/wire boundaries. `resolvePriceBasisTotal(unitPriceMinor, quantity, basis?)` converts a minor-unit price × integer quantity to a final minor-unit total using half-even rounding (`roundedDiv` internally) and throws `PriceBasisError` on unsafe inputs or overflow.
|
|
35
|
+
|
|
36
|
+
### Added — `./unit-cost-rate` re-exports `RoundingMode`
|
|
37
|
+
|
|
38
|
+
`RoundingMode` (`'half-even' | 'half-up'`) is now defined in the new internal `rounded-div.ts` and re-exported from `unit-cost-rate`. No breaking change — existing consumers who import `RoundingMode` from `@classytic/primitives/unit-cost-rate` continue to work.
|
|
39
|
+
|
|
40
|
+
### Changed — `validateAddress` / `isAddressValid` accept `Address` directly
|
|
41
|
+
|
|
42
|
+
Both functions now accept `Address | PartialAddress | null | undefined`, removing the need for a cast when validating a fully-typed value object.
|
|
43
|
+
|
|
6
44
|
## 0.26.3
|
|
7
45
|
|
|
8
46
|
### Added — `PaymentProviderPort.wantsRawBody`
|
package/dist/address.d.mts
CHANGED
|
@@ -298,9 +298,9 @@ interface AddressFieldError {
|
|
|
298
298
|
* `' '` satisfies a naive truthiness check and then prints as a blank line on
|
|
299
299
|
* a courier label. Required means a value, not a character.
|
|
300
300
|
*/
|
|
301
|
-
declare function validateAddress(address: PartialAddress | null | undefined, format: AddressFormat): AddressFieldError[];
|
|
301
|
+
declare function validateAddress(address: Address | PartialAddress | null | undefined, format: AddressFormat): AddressFieldError[];
|
|
302
302
|
/** Convenience for a submit gate. */
|
|
303
|
-
declare function isAddressValid(address: PartialAddress | null | undefined, format: AddressFormat): boolean;
|
|
303
|
+
declare function isAddressValid(address: Address | PartialAddress | null | undefined, format: AddressFormat): boolean;
|
|
304
304
|
/** A readable default message, in the country's own vocabulary. */
|
|
305
305
|
declare function describeAddressError(error: AddressFieldError): string;
|
|
306
306
|
//#endregion
|
package/dist/address.mjs
CHANGED
|
@@ -162,7 +162,8 @@ function supportedCountries(registry) {
|
|
|
162
162
|
*/
|
|
163
163
|
function validateAddress(address, format) {
|
|
164
164
|
const errors = [];
|
|
165
|
-
const
|
|
165
|
+
const values = address;
|
|
166
|
+
const value = (k) => String(values?.[k] ?? "").trim();
|
|
166
167
|
/**
|
|
167
168
|
* Canonical and extension fields are checked IDENTICALLY, keyed by
|
|
168
169
|
* `fieldName`. A required Delivery Area is enforced exactly as a required
|
package/dist/csv.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/serialization/csv.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `@classytic/primitives/csv` — make one value safe to put in a CSV cell.
|
|
4
|
+
*
|
|
5
|
+
* Two defences, deliberately separable because a consumer that already has a
|
|
6
|
+
* real CSV writer must NOT get its quoting done twice:
|
|
7
|
+
*
|
|
8
|
+
* - `neutralizeCsvFormula` — stops the cell being executed as a formula when
|
|
9
|
+
* the file is opened in Excel / Sheets / LibreOffice. Use this when a
|
|
10
|
+
* library (`csv-stringify`, `papaparse`, …) is doing the quoting.
|
|
11
|
+
* - `escapeCsvCell` — neutralize + RFC 4180 quoting. Use this in a
|
|
12
|
+
* hand-rolled `rows.map(...).join(',')` serializer.
|
|
13
|
+
*
|
|
14
|
+
* WHY quoting is not enough: a spreadsheet strips the quotes first and
|
|
15
|
+
* evaluates what is left, so `"=cmd|'/c calc'!A1"` still executes. Only
|
|
16
|
+
* changing the LEADING character stops it, which is why these are one module
|
|
17
|
+
* and not a quoting helper someone can use alone.
|
|
18
|
+
*
|
|
19
|
+
* Well-formed numbers are exempt. Prefixing `-1500` would make every negative
|
|
20
|
+
* amount text and break the reader's `SUM` — a fix that quietly corrupts every
|
|
21
|
+
* finance export is worse than the hole. The exemption is the WHOLE cell
|
|
22
|
+
* matching a number, so `-2+3+cmd|'/c calc'!A0` is still neutralized.
|
|
23
|
+
*
|
|
24
|
+
* NOT for a machine-to-machine upload contract with a fixed column spec (a
|
|
25
|
+
* courier's bulk-import CSV, say) — there the receiver is a parser, not a
|
|
26
|
+
* spreadsheet, and an added `'` corrupts the payload.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Prefix `'` when the cell would otherwise be evaluated as a formula.
|
|
30
|
+
* `null`/`undefined` become `''`. Numbers are returned unchanged.
|
|
31
|
+
*/
|
|
32
|
+
declare function neutralizeCsvFormula(value: unknown): string;
|
|
33
|
+
/** `neutralizeCsvFormula` + RFC 4180 quoting. The one-call form. */
|
|
34
|
+
declare function escapeCsvCell(value: unknown): string;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { escapeCsvCell, neutralizeCsvFormula };
|
package/dist/csv.mjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/serialization/csv.ts
|
|
2
|
+
/**
|
|
3
|
+
* `@classytic/primitives/csv` — make one value safe to put in a CSV cell.
|
|
4
|
+
*
|
|
5
|
+
* Two defences, deliberately separable because a consumer that already has a
|
|
6
|
+
* real CSV writer must NOT get its quoting done twice:
|
|
7
|
+
*
|
|
8
|
+
* - `neutralizeCsvFormula` — stops the cell being executed as a formula when
|
|
9
|
+
* the file is opened in Excel / Sheets / LibreOffice. Use this when a
|
|
10
|
+
* library (`csv-stringify`, `papaparse`, …) is doing the quoting.
|
|
11
|
+
* - `escapeCsvCell` — neutralize + RFC 4180 quoting. Use this in a
|
|
12
|
+
* hand-rolled `rows.map(...).join(',')` serializer.
|
|
13
|
+
*
|
|
14
|
+
* WHY quoting is not enough: a spreadsheet strips the quotes first and
|
|
15
|
+
* evaluates what is left, so `"=cmd|'/c calc'!A1"` still executes. Only
|
|
16
|
+
* changing the LEADING character stops it, which is why these are one module
|
|
17
|
+
* and not a quoting helper someone can use alone.
|
|
18
|
+
*
|
|
19
|
+
* Well-formed numbers are exempt. Prefixing `-1500` would make every negative
|
|
20
|
+
* amount text and break the reader's `SUM` — a fix that quietly corrupts every
|
|
21
|
+
* finance export is worse than the hole. The exemption is the WHOLE cell
|
|
22
|
+
* matching a number, so `-2+3+cmd|'/c calc'!A0` is still neutralized.
|
|
23
|
+
*
|
|
24
|
+
* NOT for a machine-to-machine upload contract with a fixed column spec (a
|
|
25
|
+
* courier's bulk-import CSV, say) — there the receiver is a parser, not a
|
|
26
|
+
* spreadsheet, and an added `'` corrupts the payload.
|
|
27
|
+
*/
|
|
28
|
+
/** Leading characters a spreadsheet may treat as the start of a formula or DDE call. */
|
|
29
|
+
const FORMULA_LEAD = /^[=+\-@\t\r]/;
|
|
30
|
+
/** The WHOLE cell is a plain number — no separators, no currency symbol. */
|
|
31
|
+
const WHOLE_NUMBER = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?$/;
|
|
32
|
+
/** Characters that force RFC 4180 quoting. */
|
|
33
|
+
const NEEDS_QUOTING = /[",\r\n]/;
|
|
34
|
+
/**
|
|
35
|
+
* Prefix `'` when the cell would otherwise be evaluated as a formula.
|
|
36
|
+
* `null`/`undefined` become `''`. Numbers are returned unchanged.
|
|
37
|
+
*/
|
|
38
|
+
function neutralizeCsvFormula(value) {
|
|
39
|
+
const text = value == null ? "" : String(value);
|
|
40
|
+
if (!FORMULA_LEAD.test(text)) return text;
|
|
41
|
+
if (WHOLE_NUMBER.test(text)) return text;
|
|
42
|
+
return `'${text}`;
|
|
43
|
+
}
|
|
44
|
+
/** `neutralizeCsvFormula` + RFC 4180 quoting. The one-call form. */
|
|
45
|
+
function escapeCsvCell(value) {
|
|
46
|
+
const text = neutralizeCsvFormula(value);
|
|
47
|
+
return NEEDS_QUOTING.test(text) ? `"${text.replace(/"/g, "\"\"")}"` : text;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { escapeCsvCell, neutralizeCsvFormula };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/money/price-basis.d.ts
|
|
2
|
+
/** How a quoted price extends across a sellable quantity. */
|
|
3
|
+
type PriceBasis = FixedPriceBasis | MeasuredPriceBasis;
|
|
4
|
+
interface FixedPriceBasis {
|
|
5
|
+
readonly kind: 'fixed';
|
|
6
|
+
}
|
|
7
|
+
type MeasureDimension = 'mass' | 'duration' | 'volume' | 'length' | 'area';
|
|
8
|
+
interface MeasuredPriceBasis {
|
|
9
|
+
readonly kind: 'measured';
|
|
10
|
+
readonly dimension: MeasureDimension;
|
|
11
|
+
/** Integer unit carried by the line quantity, such as `gram` or `minute`. */
|
|
12
|
+
readonly quantityUnit: string;
|
|
13
|
+
/** Unit named by the quoted price, such as `kilogram` or `hour`. */
|
|
14
|
+
readonly priceUnit: string;
|
|
15
|
+
/** Number of quantity units represented by one quoted price unit. */
|
|
16
|
+
readonly quantityPerPriceUnit: number;
|
|
17
|
+
}
|
|
18
|
+
type PriceBasisErrorCode = 'INVALID_PRICE' | 'INVALID_QUANTITY' | 'INVALID_DENOMINATOR' | 'INVALID_UNIT' | 'UNSAFE_TOTAL';
|
|
19
|
+
declare class PriceBasisError extends Error {
|
|
20
|
+
readonly name = "PriceBasisError";
|
|
21
|
+
readonly code: PriceBasisErrorCode;
|
|
22
|
+
constructor(code: PriceBasisErrorCode, message: string);
|
|
23
|
+
}
|
|
24
|
+
declare function fixedPriceBasis(): FixedPriceBasis;
|
|
25
|
+
declare function measuredPriceBasis(dimension: MeasureDimension, quantityUnit: string, priceUnit: string, quantityPerPriceUnit: number): MeasuredPriceBasis;
|
|
26
|
+
/** Structural guard for database and wire boundaries. */
|
|
27
|
+
declare function isPriceBasis(value: unknown): value is PriceBasis;
|
|
28
|
+
/** Extend a minor-unit price using integer quantity and exact half-even rounding. */
|
|
29
|
+
declare function resolvePriceBasisTotal(unitPriceMinor: number, quantity: number, basis?: PriceBasis): number;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { FixedPriceBasis, MeasureDimension, MeasuredPriceBasis, PriceBasis, PriceBasisError, PriceBasisErrorCode, fixedPriceBasis, isPriceBasis, measuredPriceBasis, resolvePriceBasisTotal };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t as roundedDiv } from "./rounded-div-BWJb98Ws.mjs";
|
|
2
|
+
//#region src/money/price-basis.ts
|
|
3
|
+
var PriceBasisError = class extends Error {
|
|
4
|
+
name = "PriceBasisError";
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
function fixedPriceBasis() {
|
|
12
|
+
return { kind: "fixed" };
|
|
13
|
+
}
|
|
14
|
+
function measuredPriceBasis(dimension, quantityUnit, priceUnit, quantityPerPriceUnit) {
|
|
15
|
+
if (quantityUnit.trim() === "" || priceUnit.trim() === "") throw new PriceBasisError("INVALID_UNIT", "quantityUnit and priceUnit must not be empty");
|
|
16
|
+
if (!Number.isSafeInteger(quantityPerPriceUnit) || quantityPerPriceUnit <= 0) throw new PriceBasisError("INVALID_DENOMINATOR", "quantityPerPriceUnit must be a positive safe integer");
|
|
17
|
+
return {
|
|
18
|
+
kind: "measured",
|
|
19
|
+
dimension,
|
|
20
|
+
quantityUnit,
|
|
21
|
+
priceUnit,
|
|
22
|
+
quantityPerPriceUnit
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const MEASURE_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
26
|
+
"mass",
|
|
27
|
+
"duration",
|
|
28
|
+
"volume",
|
|
29
|
+
"length",
|
|
30
|
+
"area"
|
|
31
|
+
]);
|
|
32
|
+
/** Structural guard for database and wire boundaries. */
|
|
33
|
+
function isPriceBasis(value) {
|
|
34
|
+
if (typeof value !== "object" || value === null) return false;
|
|
35
|
+
const candidate = value;
|
|
36
|
+
if (candidate.kind === "fixed") return true;
|
|
37
|
+
return candidate.kind === "measured" && MEASURE_DIMENSIONS.has(candidate.dimension) && typeof candidate.quantityUnit === "string" && candidate.quantityUnit.trim() !== "" && typeof candidate.priceUnit === "string" && candidate.priceUnit.trim() !== "" && typeof candidate.quantityPerPriceUnit === "number" && Number.isSafeInteger(candidate.quantityPerPriceUnit) && candidate.quantityPerPriceUnit > 0;
|
|
38
|
+
}
|
|
39
|
+
/** Extend a minor-unit price using integer quantity and exact half-even rounding. */
|
|
40
|
+
function resolvePriceBasisTotal(unitPriceMinor, quantity, basis = fixedPriceBasis()) {
|
|
41
|
+
if (!Number.isSafeInteger(unitPriceMinor) || unitPriceMinor < 0) throw new PriceBasisError("INVALID_PRICE", "unitPriceMinor must be a non-negative safe integer");
|
|
42
|
+
if (!Number.isSafeInteger(quantity) || quantity < 0) throw new PriceBasisError("INVALID_QUANTITY", "quantity must be a non-negative safe integer");
|
|
43
|
+
const numerator = BigInt(unitPriceMinor) * BigInt(quantity);
|
|
44
|
+
const denominator = basis.kind === "measured" ? BigInt(basis.quantityPerPriceUnit) : 1n;
|
|
45
|
+
const rounded = roundedDiv(numerator, denominator, "half-even");
|
|
46
|
+
const total = Number(rounded);
|
|
47
|
+
if (!Number.isSafeInteger(total)) throw new PriceBasisError("UNSAFE_TOTAL", "resolved total exceeds Number.MAX_SAFE_INTEGER");
|
|
48
|
+
return total;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { PriceBasisError, fixedPriceBasis, isPriceBasis, measuredPriceBasis, resolvePriceBasisTotal };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/money/rounded-div.ts
|
|
2
|
+
/** Exact signed integer division rounded at the rational boundary. */
|
|
3
|
+
function roundedDiv(numerator, denominator, mode) {
|
|
4
|
+
if (denominator <= 0n) throw new RangeError("denominator must be positive");
|
|
5
|
+
const negative = numerator < 0n;
|
|
6
|
+
const magnitude = negative ? -numerator : numerator;
|
|
7
|
+
const quotient = magnitude / denominator;
|
|
8
|
+
const twiceRemainder = magnitude % denominator * 2n;
|
|
9
|
+
const rounded = twiceRemainder > denominator || twiceRemainder === denominator && (mode === "half-up" || quotient % 2n !== 0n) ? quotient + 1n : quotient;
|
|
10
|
+
return negative ? -rounded : rounded;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { roundedDiv as t };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { t as MinorUnits, w as CurrencyCode } from "./money-CfAvfNiM.mjs";
|
|
2
|
+
//#region src/money/rounded-div.d.ts
|
|
3
|
+
type RoundingMode = 'half-even' | 'half-up';
|
|
4
|
+
//#endregion
|
|
2
5
|
//#region src/money/unit-cost-rate.d.ts
|
|
3
6
|
/** Fixed, ecosystem-wide rate scale: 6 decimal places below the minor unit. */
|
|
4
7
|
declare const RATE_SCALE = 1000000;
|
|
5
|
-
/** Half-to-even (banker's) is the default; half-up available for legacy parity. */
|
|
6
|
-
type RoundingMode = 'half-even' | 'half-up';
|
|
7
8
|
/**
|
|
8
9
|
* Minor units per unit, stored as an integer scaled by {@link RATE_SCALE}.
|
|
9
10
|
* `scale` is carried so a value is self-describing on the wire even if
|
|
@@ -67,5 +68,10 @@ declare function weightedAverageScaledRate(onHandQuantity: number, onHandScaledR
|
|
|
67
68
|
declare function rateMinorPerUnit(rate: UnitCostRate): number;
|
|
68
69
|
/** Structural guard. */
|
|
69
70
|
declare function isUnitCostRate(value: unknown): value is UnitCostRate;
|
|
71
|
+
/**
|
|
72
|
+
* Rounded integer division of two bigints, `numerator / denominator`
|
|
73
|
+
* (`denominator > 0`), honouring the rounding mode at the exact half.
|
|
74
|
+
* Sign-safe for negative numerators.
|
|
75
|
+
*/
|
|
70
76
|
//#endregion
|
|
71
|
-
export { RATE_SCALE, RoundingMode, UnitCostRate, UnitCostRateError, UnitCostRateErrorCode, extendedAmount, isUnitCostRate, rateMinorPerUnit, unitCostRate, unitCostRateFromTotal, weightedAverageScaledRate };
|
|
77
|
+
export { RATE_SCALE, type RoundingMode, UnitCostRate, UnitCostRateError, UnitCostRateErrorCode, extendedAmount, isUnitCostRate, rateMinorPerUnit, unitCostRate, unitCostRateFromTotal, weightedAverageScaledRate };
|
package/dist/unit-cost-rate.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MinorUnits } from "./money.mjs";
|
|
2
|
+
import { t as roundedDiv } from "./rounded-div-BWJb98Ws.mjs";
|
|
2
3
|
//#region src/money/unit-cost-rate.ts
|
|
3
4
|
/** Fixed, ecosystem-wide rate scale: 6 decimal places below the minor unit. */
|
|
4
5
|
const RATE_SCALE = 1e6;
|
|
@@ -127,19 +128,5 @@ function isUnitCostRate(value) {
|
|
|
127
128
|
* (`denominator > 0`), honouring the rounding mode at the exact half.
|
|
128
129
|
* Sign-safe for negative numerators.
|
|
129
130
|
*/
|
|
130
|
-
function roundedDiv(numerator, denominator, mode) {
|
|
131
|
-
const neg = numerator < 0n;
|
|
132
|
-
const n = neg ? -numerator : numerator;
|
|
133
|
-
const q = n / denominator;
|
|
134
|
-
const remainder = n - q * denominator;
|
|
135
|
-
if (remainder === 0n) return neg ? -q : q;
|
|
136
|
-
const twiceRem = remainder * 2n;
|
|
137
|
-
let up;
|
|
138
|
-
if (twiceRem > denominator) up = true;
|
|
139
|
-
else if (twiceRem < denominator) up = false;
|
|
140
|
-
else up = mode === "half-up" ? true : q % 2n !== 0n;
|
|
141
|
-
const result = up ? q + 1n : q;
|
|
142
|
-
return neg ? -result : result;
|
|
143
|
-
}
|
|
144
131
|
//#endregion
|
|
145
132
|
export { RATE_SCALE, UnitCostRateError, extendedAmount, isUnitCostRate, rateMinorPerUnit, unitCostRate, unitCostRateFromTotal, weightedAverageScaledRate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Framework-agnostic TypeScript primitives shared across Classytic packages — Money, events, pagination, tenant config, and other building blocks.",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
"types": "./dist/unit-cost-rate.d.mts",
|
|
34
34
|
"default": "./dist/unit-cost-rate.mjs"
|
|
35
35
|
},
|
|
36
|
+
"./price-basis": {
|
|
37
|
+
"types": "./dist/price-basis.d.mts",
|
|
38
|
+
"default": "./dist/price-basis.mjs"
|
|
39
|
+
},
|
|
36
40
|
"./address": {
|
|
37
41
|
"types": "./dist/address.d.mts",
|
|
38
42
|
"default": "./dist/address.mjs"
|
|
@@ -201,6 +205,10 @@
|
|
|
201
205
|
"types": "./dist/canonical.d.mts",
|
|
202
206
|
"default": "./dist/canonical.mjs"
|
|
203
207
|
},
|
|
208
|
+
"./csv": {
|
|
209
|
+
"types": "./dist/csv.d.mts",
|
|
210
|
+
"default": "./dist/csv.mjs"
|
|
211
|
+
},
|
|
204
212
|
"./package.json": "./package.json",
|
|
205
213
|
"./state-diagram": {
|
|
206
214
|
"types": "./dist/state-diagram.d.mts",
|