@classytic/primitives 0.1.0 → 0.1.1

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 CHANGED
@@ -3,6 +3,26 @@
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.1.1]
7
+
8
+ ### Added
9
+
10
+ - **`MinorUnits<C>` branded type on `/money`** — wire-format monetary amount
11
+ (integer minor units, branded with phantom currency) for HTTP/JSON fields
12
+ where a full `Money` struct is overkill. Erases at runtime; `MinorUnits<'BDT'>`
13
+ vs `MinorUnits<'USD'>` collide at compile time. Pair with structured `Money`
14
+ for in-process arithmetic. Constructor: `MinorUnits(amount, currency?)`.
15
+
16
+ ### Changed
17
+
18
+ - **`/tenant` `contextKey` cascade default** — `resolveTenantConfig({ tenantField: 'branchId' })`
19
+ now defaults `contextKey` to `'branchId'` instead of `'organizationId'`.
20
+ When a host renames `tenantField`, their `OperationContext` carries the id
21
+ under the same key in the overwhelming majority of cases; mirroring the
22
+ rename is the least-surprise default. Explicit `contextKey` still overrides
23
+ (set when the doc field and context key genuinely diverge). Existing call
24
+ sites that supplied both `tenantField` and `contextKey` are unaffected.
25
+
6
26
  ## [0.1.0]
7
27
 
8
28
  Initial release. Framework-agnostic TypeScript primitives shared across
package/dist/money.d.mts CHANGED
@@ -1,6 +1,38 @@
1
1
  import { CurrencyCode } from "./currency.mjs";
2
2
 
3
3
  //#region src/money.d.ts
4
+ /**
5
+ * Wire-format monetary amount: integer minor units, branded with a phantom
6
+ * currency type so calls like `formatBdt(usdValue)` fail at compile time.
7
+ *
8
+ * Use this for HTTP/JSON fields where transmitting a `Money` struct would be
9
+ * overkill: `interface Order { grandTotal: MinorUnits<'BDT'>; ... }`. Pair
10
+ * with the structured {@link Money} for in-process arithmetic.
11
+ *
12
+ * Erases at runtime — branded types have zero cost.
13
+ *
14
+ * @example
15
+ * type Paisa = MinorUnits<'BDT'>;
16
+ * type UsdCents = MinorUnits<'USD'>;
17
+ * const p: Paisa = MinorUnits(489900, 'BDT');
18
+ * const c: UsdCents = p; // ❌ type error: BDT vs USD
19
+ */
20
+ declare const __unitBrand: unique symbol;
21
+ declare const __currencyBrand: unique symbol;
22
+ type MinorUnits<C extends string = string> = number & {
23
+ readonly [__unitBrand]: 'minor';
24
+ readonly [__currencyBrand]: C;
25
+ };
26
+ /**
27
+ * Cast a raw number to {@link MinorUnits}. Pass the currency as the second
28
+ * argument to fix the phantom type. With no second arg, `MinorUnits<string>`
29
+ * — useful for generic SDK boundaries that don't know the currency yet.
30
+ *
31
+ * @example
32
+ * MinorUnits(489900, 'BDT') // typed MinorUnits<'BDT'>
33
+ * MinorUnits(199, 'USD') // typed MinorUnits<'USD'>
34
+ */
35
+ declare function MinorUnits<C extends string = string>(amount: number, _currency?: C): MinorUnits<C>;
4
36
  /**
5
37
  * A monetary amount stored as an integer in the currency's minor unit.
6
38
  *
@@ -75,4 +107,4 @@ declare function absMoney(m: Money): Money;
75
107
  /** Structural type guard. */
76
108
  declare function isMoney(value: unknown): value is Money;
77
109
  //#endregion
78
- export { CurrencyMismatchError, Money, absMoney, addMoney, compareMoney, equalsMoney, fromMajor, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, money, multiplyMoney, negateMoney, subtractMoney, sumMoney, toMajor };
110
+ export { CurrencyMismatchError, MinorUnits, Money, absMoney, addMoney, compareMoney, equalsMoney, fromMajor, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, money, multiplyMoney, negateMoney, subtractMoney, sumMoney, toMajor };
package/dist/money.mjs CHANGED
@@ -1,5 +1,17 @@
1
1
  import { minorUnitFactor } from "./currency.mjs";
2
2
  //#region src/money.ts
3
+ /**
4
+ * Cast a raw number to {@link MinorUnits}. Pass the currency as the second
5
+ * argument to fix the phantom type. With no second arg, `MinorUnits<string>`
6
+ * — useful for generic SDK boundaries that don't know the currency yet.
7
+ *
8
+ * @example
9
+ * MinorUnits(489900, 'BDT') // typed MinorUnits<'BDT'>
10
+ * MinorUnits(199, 'USD') // typed MinorUnits<'USD'>
11
+ */
12
+ function MinorUnits(amount, _currency) {
13
+ return amount;
14
+ }
3
15
  var CurrencyMismatchError = class extends Error {
4
16
  name = "CurrencyMismatchError";
5
17
  left;
@@ -128,4 +140,4 @@ function isMoney(value) {
128
140
  return typeof value === "object" && value !== null && typeof value.amount === "number" && Number.isInteger(value.amount) && typeof value.currency === "string";
129
141
  }
130
142
  //#endregion
131
- export { CurrencyMismatchError, absMoney, addMoney, compareMoney, equalsMoney, fromMajor, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, money, multiplyMoney, negateMoney, subtractMoney, sumMoney, toMajor };
143
+ export { CurrencyMismatchError, MinorUnits, absMoney, addMoney, compareMoney, equalsMoney, fromMajor, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, money, multiplyMoney, negateMoney, subtractMoney, sumMoney, toMajor };
package/dist/tenant.d.mts CHANGED
@@ -71,7 +71,14 @@ interface TenantConfig {
71
71
  /**
72
72
  * Which key on `OperationContext` to read the tenant id from.
73
73
  *
74
- * @default 'organizationId'
74
+ * Defaults cascade: if omitted, falls back to the caller's `tenantField`
75
+ * (if supplied), else to `'organizationId'`. Rationale: when a host renames
76
+ * `tenantField` to e.g. `'branchId'`, their `OperationContext` almost always
77
+ * carries the value under the same key — so mirroring `tenantField` is the
78
+ * least-surprise behavior. Override explicitly if the context key diverges
79
+ * from the document field (e.g. `tenantField: 'branchId'`, `contextKey: 'organizationId'`).
80
+ *
81
+ * @default tenantField ?? 'organizationId'
75
82
  */
76
83
  contextKey?: string;
77
84
  /**
package/dist/tenant.mjs CHANGED
@@ -26,9 +26,11 @@ function resolveTenantConfig(config) {
26
26
  };
27
27
  if (config === true || config === void 0) return { ...DEFAULT_TENANT_CONFIG };
28
28
  const strategy = config.strategy ?? (config.enabled === false ? "none" : "field");
29
+ const contextKey = config.contextKey ?? config.tenantField ?? DEFAULT_TENANT_CONFIG.contextKey;
29
30
  if (strategy === "none") return {
30
31
  ...DEFAULT_TENANT_CONFIG,
31
32
  ...config,
33
+ contextKey,
32
34
  strategy: "none",
33
35
  enabled: false,
34
36
  required: false
@@ -38,6 +40,7 @@ function resolveTenantConfig(config) {
38
40
  return {
39
41
  ...DEFAULT_TENANT_CONFIG,
40
42
  ...config,
43
+ contextKey,
41
44
  strategy: "custom",
42
45
  enabled: config.enabled ?? true,
43
46
  resolve: config.resolve
@@ -46,6 +49,7 @@ function resolveTenantConfig(config) {
46
49
  return {
47
50
  ...DEFAULT_TENANT_CONFIG,
48
51
  ...config,
52
+ contextKey,
49
53
  strategy: "field",
50
54
  enabled: config.enabled ?? true
51
55
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/primitives",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",
@@ -117,11 +117,13 @@
117
117
  "test:all": "vitest run",
118
118
  "test:watch": "vitest --project unit --project integration",
119
119
  "test:smoke": "node tests/smoke/smoke.mjs",
120
+ "push": "classytic-push",
120
121
  "prepublishOnly": "npm run typecheck && npm run test && npm run build && npm run test:smoke",
121
122
  "release": "npm run build && npm run typecheck && npm publish --access public"
122
123
  },
123
124
  "devDependencies": {
124
125
  "@biomejs/biome": "^2.4.9",
126
+ "@classytic/dev-tools": "^0.2.0",
125
127
  "@types/node": "^25.5.0",
126
128
  "tsdown": "^0.21.7",
127
129
  "typescript": "^5.7.0",