@lacspace/inventory 1.0.0 → 1.0.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/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,11 @@ function commit(stock, qty) {
|
|
|
46
46
|
`Cannot commit ${q}: only ${stock.reserved} reserved`
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
+
if (q > stock.onHand) {
|
|
50
|
+
throw new InventoryError(
|
|
51
|
+
`Cannot commit ${q}: only ${stock.onHand} in stock`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
49
54
|
return { onHand: stock.onHand - q, reserved: stock.reserved - q };
|
|
50
55
|
}
|
|
51
56
|
function restock(stock, qty) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAoBO,IAAM,cAAA,GAAN,MAAM,eAAA,SAAuB,KAAA,CAAM;AAAA,EACxC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AAEZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,eAAA,CAAe,SAAS,CAAA;AAAA,EACtD;AACF;AAEA,SAAS,OAAA,CAAQ,GAAW,KAAA,EAAuB;AACjD,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACtB,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,QAAS,IAAI,cAAA,CAAe,CAAA,EAAG,KAAK,CAAA,wBAAA,CAA0B,CAAA;AACpF,EAAA,OAAO,CAAA;AACT;AAGA,SAAS,WAAW,GAAA,EAAqB;AACvC,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,EAAK,KAAK,CAAA;AAC5B,EAAA,IAAI,CAAA,GAAI,CAAA,EAAG,MAAM,IAAI,eAAe,kBAAkB,CAAA;AACtD,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,WAAA,CAAY,SAAS,CAAA,EAAU;AAC7C,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,MAAA,EAAQ,QAAQ,CAAA;AAClC,EAAA,IAAI,CAAA,GAAI,CAAA,EAAG,MAAM,IAAI,eAAe,qBAAqB,CAAA;AACzD,EAAA,OAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,QAAA,EAAU,CAAA,EAAE;AAClC;AAGO,SAAS,UAAU,KAAA,EAAsB;AAC9C,EAAA,OAAO,KAAA,CAAM,SAAS,KAAA,CAAM,QAAA;AAC9B;AAOO,SAAS,OAAA,CAAQ,OAAc,GAAA,EAAoB;AACxD,EAAA,MAAM,CAAA,GAAI,WAAW,GAAG,CAAA;AACxB,EAAA,IAAI,CAAA,GAAI,SAAA,CAAU,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,IAAI,cAAA;AAAA,MACR,CAAA,eAAA,EAAkB,CAAC,CAAA,OAAA,EAAU,SAAA,CAAU,KAAK,CAAC,CAAA,UAAA;AAAA,KAC/C;AAAA,EACF;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,CAAM,QAAQ,QAAA,EAAU,KAAA,CAAM,WAAW,CAAA,EAAE;AAC9D;AAMO,SAAS,OAAA,CAAQ,OAAc,GAAA,EAAoB;AACxD,EAAA,MAAM,CAAA,GAAI,WAAW,GAAG,CAAA;AACxB,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,KAAA,CAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,CAAM,QAAQ,CAAA,EAAE;AACxF;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/inventory — a stock-tracking engine that prevents overselling.\n *\n * Bring-your-own-store: this package is a set of pure, immutable functions over\n * a plain `Stock` state object `{ onHand, reserved }`. You decide where the\n * state lives (a database row, a cache, a signal); this decides the maths.\n *\n * The core guarantee: you can never reserve or fulfil more than is available,\n * so a race between two checkouts fails loudly instead of overselling.\n */\n\n/** Stock state for a single SKU. Both fields are non-negative integers. */\nexport interface Stock {\n /** Physical units in the warehouse. */\n onHand: number;\n /** Units held for pending orders (not yet shipped). */\n reserved: number;\n}\n\n/** Thrown when an operation would oversell or is otherwise invalid. */\nexport class InventoryError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InventoryError\";\n // Restore the prototype chain for instanceof across transpile targets.\n Object.setPrototypeOf(this, InventoryError.prototype);\n }\n}\n\nfunction toCount(n: number, label: string): number {\n const v = Math.trunc(n);\n if (!Number.isFinite(v)) throw new InventoryError(`${label} must be a finite number`);\n return v;\n}\n\n/** Require a non-negative quantity for an operation. */\nfunction requireQty(qty: number): number {\n const q = toCount(qty, \"qty\");\n if (q < 0) throw new InventoryError(\"qty must be >= 0\");\n return q;\n}\n\n/** Create a new stock state with the given quantity on hand (default `0`). */\nexport function createStock(onHand = 0): Stock {\n const n = toCount(onHand, \"onHand\");\n if (n < 0) throw new InventoryError(\"onHand must be >= 0\");\n return { onHand: n, reserved: 0 };\n}\n\n/** Units that can still be reserved: `onHand - reserved`. */\nexport function available(stock: Stock): number {\n return stock.onHand - stock.reserved;\n}\n\n/**\n * Reserve `qty` units for a pending order. Increases `reserved`.\n *\n * @throws {InventoryError} if `qty` exceeds {@link available} (would oversell).\n */\nexport function reserve(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n if (q > available(stock)) {\n throw new InventoryError(\n `Cannot reserve ${q}: only ${available(stock)} available`,\n );\n }\n return { onHand: stock.onHand, reserved: stock.reserved + q };\n}\n\n/**\n * Release a previously-held reservation (e.g. an abandoned cart). Never drops\n * `reserved` below `0` — it releases at most what is currently reserved.\n */\nexport function release(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n return { onHand: stock.onHand, reserved: stock.reserved - Math.min(q, stock.reserved) };\n}\n\n/**\n * Fulfil (ship) `qty` reserved units: decrements both `onHand` and `reserved`.\n *\n * @throws {InventoryError} if `qty` exceeds the currently reserved amount, or\n * exceeds the physical units on hand (which can happen when {@link adjust} has\n * shrunk `onHand` below the reserved count) — committing further would drive\n * `onHand` negative, so it fails loudly instead.\n */\nexport function commit(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n if (q > stock.reserved) {\n throw new InventoryError(\n `Cannot commit ${q}: only ${stock.reserved} reserved`,\n );\n }\n if (q > stock.onHand) {\n throw new InventoryError(\n `Cannot commit ${q}: only ${stock.onHand} in stock`,\n );\n }\n return { onHand: stock.onHand - q, reserved: stock.reserved - q };\n}\n\n/** Add `qty` units to `onHand` (a delivery / restock). */\nexport function restock(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n return { onHand: stock.onHand + q, reserved: stock.reserved };\n}\n\n/**\n * Apply a signed correction to `onHand` (stock-take, shrinkage, returns).\n * `onHand` is clamped at `0`; `reserved` is left untouched.\n */\nexport function adjust(stock: Stock, delta: number): Stock {\n const d = toCount(delta, \"delta\");\n return { onHand: Math.max(0, stock.onHand + d), reserved: stock.reserved };\n}\n\n/** `true` when {@link available} is at or below `threshold`. */\nexport function isLow(stock: Stock, threshold: number): boolean {\n return available(stock) <= toCount(threshold, \"threshold\");\n}\n\n/** `true` when nothing is available to reserve (`available <= 0`). */\nexport function isOutOfStock(stock: Stock): boolean {\n return available(stock) <= 0;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -37,7 +37,10 @@ declare function release(stock: Stock, qty: number): Stock;
|
|
|
37
37
|
/**
|
|
38
38
|
* Fulfil (ship) `qty` reserved units: decrements both `onHand` and `reserved`.
|
|
39
39
|
*
|
|
40
|
-
* @throws {InventoryError} if `qty` exceeds the currently reserved amount
|
|
40
|
+
* @throws {InventoryError} if `qty` exceeds the currently reserved amount, or
|
|
41
|
+
* exceeds the physical units on hand (which can happen when {@link adjust} has
|
|
42
|
+
* shrunk `onHand` below the reserved count) — committing further would drive
|
|
43
|
+
* `onHand` negative, so it fails loudly instead.
|
|
41
44
|
*/
|
|
42
45
|
declare function commit(stock: Stock, qty: number): Stock;
|
|
43
46
|
/** Add `qty` units to `onHand` (a delivery / restock). */
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,10 @@ declare function release(stock: Stock, qty: number): Stock;
|
|
|
37
37
|
/**
|
|
38
38
|
* Fulfil (ship) `qty` reserved units: decrements both `onHand` and `reserved`.
|
|
39
39
|
*
|
|
40
|
-
* @throws {InventoryError} if `qty` exceeds the currently reserved amount
|
|
40
|
+
* @throws {InventoryError} if `qty` exceeds the currently reserved amount, or
|
|
41
|
+
* exceeds the physical units on hand (which can happen when {@link adjust} has
|
|
42
|
+
* shrunk `onHand` below the reserved count) — committing further would drive
|
|
43
|
+
* `onHand` negative, so it fails loudly instead.
|
|
41
44
|
*/
|
|
42
45
|
declare function commit(stock: Stock, qty: number): Stock;
|
|
43
46
|
/** Add `qty` units to `onHand` (a delivery / restock). */
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,11 @@ function commit(stock, qty) {
|
|
|
44
44
|
`Cannot commit ${q}: only ${stock.reserved} reserved`
|
|
45
45
|
);
|
|
46
46
|
}
|
|
47
|
+
if (q > stock.onHand) {
|
|
48
|
+
throw new InventoryError(
|
|
49
|
+
`Cannot commit ${q}: only ${stock.onHand} in stock`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
47
52
|
return { onHand: stock.onHand - q, reserved: stock.reserved - q };
|
|
48
53
|
}
|
|
49
54
|
function restock(stock, qty) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAoBO,IAAM,cAAA,GAAN,MAAM,eAAA,SAAuB,KAAA,CAAM;AAAA,EACxC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AAEZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,eAAA,CAAe,SAAS,CAAA;AAAA,EACtD;AACF;AAEA,SAAS,OAAA,CAAQ,GAAW,KAAA,EAAuB;AACjD,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACtB,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,QAAS,IAAI,cAAA,CAAe,CAAA,EAAG,KAAK,CAAA,wBAAA,CAA0B,CAAA;AACpF,EAAA,OAAO,CAAA;AACT;AAGA,SAAS,WAAW,GAAA,EAAqB;AACvC,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,EAAK,KAAK,CAAA;AAC5B,EAAA,IAAI,CAAA,GAAI,CAAA,EAAG,MAAM,IAAI,eAAe,kBAAkB,CAAA;AACtD,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,WAAA,CAAY,SAAS,CAAA,EAAU;AAC7C,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,MAAA,EAAQ,QAAQ,CAAA;AAClC,EAAA,IAAI,CAAA,GAAI,CAAA,EAAG,MAAM,IAAI,eAAe,qBAAqB,CAAA;AACzD,EAAA,OAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,QAAA,EAAU,CAAA,EAAE;AAClC;AAGO,SAAS,UAAU,KAAA,EAAsB;AAC9C,EAAA,OAAO,KAAA,CAAM,SAAS,KAAA,CAAM,QAAA;AAC9B;AAOO,SAAS,OAAA,CAAQ,OAAc,GAAA,EAAoB;AACxD,EAAA,MAAM,CAAA,GAAI,WAAW,GAAG,CAAA;AACxB,EAAA,IAAI,CAAA,GAAI,SAAA,CAAU,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,IAAI,cAAA;AAAA,MACR,CAAA,eAAA,EAAkB,CAAC,CAAA,OAAA,EAAU,SAAA,CAAU,KAAK,CAAC,CAAA,UAAA;AAAA,KAC/C;AAAA,EACF;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,CAAM,QAAQ,QAAA,EAAU,KAAA,CAAM,WAAW,CAAA,EAAE;AAC9D;AAMO,SAAS,OAAA,CAAQ,OAAc,GAAA,EAAoB;AACxD,EAAA,MAAM,CAAA,GAAI,WAAW,GAAG,CAAA;AACxB,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,KAAA,CAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,CAAM,QAAQ,CAAA,EAAE;AACxF;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/inventory — a stock-tracking engine that prevents overselling.\n *\n * Bring-your-own-store: this package is a set of pure, immutable functions over\n * a plain `Stock` state object `{ onHand, reserved }`. You decide where the\n * state lives (a database row, a cache, a signal); this decides the maths.\n *\n * The core guarantee: you can never reserve or fulfil more than is available,\n * so a race between two checkouts fails loudly instead of overselling.\n */\n\n/** Stock state for a single SKU. Both fields are non-negative integers. */\nexport interface Stock {\n /** Physical units in the warehouse. */\n onHand: number;\n /** Units held for pending orders (not yet shipped). */\n reserved: number;\n}\n\n/** Thrown when an operation would oversell or is otherwise invalid. */\nexport class InventoryError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InventoryError\";\n // Restore the prototype chain for instanceof across transpile targets.\n Object.setPrototypeOf(this, InventoryError.prototype);\n }\n}\n\nfunction toCount(n: number, label: string): number {\n const v = Math.trunc(n);\n if (!Number.isFinite(v)) throw new InventoryError(`${label} must be a finite number`);\n return v;\n}\n\n/** Require a non-negative quantity for an operation. */\nfunction requireQty(qty: number): number {\n const q = toCount(qty, \"qty\");\n if (q < 0) throw new InventoryError(\"qty must be >= 0\");\n return q;\n}\n\n/** Create a new stock state with the given quantity on hand (default `0`). */\nexport function createStock(onHand = 0): Stock {\n const n = toCount(onHand, \"onHand\");\n if (n < 0) throw new InventoryError(\"onHand must be >= 0\");\n return { onHand: n, reserved: 0 };\n}\n\n/** Units that can still be reserved: `onHand - reserved`. */\nexport function available(stock: Stock): number {\n return stock.onHand - stock.reserved;\n}\n\n/**\n * Reserve `qty` units for a pending order. Increases `reserved`.\n *\n * @throws {InventoryError} if `qty` exceeds {@link available} (would oversell).\n */\nexport function reserve(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n if (q > available(stock)) {\n throw new InventoryError(\n `Cannot reserve ${q}: only ${available(stock)} available`,\n );\n }\n return { onHand: stock.onHand, reserved: stock.reserved + q };\n}\n\n/**\n * Release a previously-held reservation (e.g. an abandoned cart). Never drops\n * `reserved` below `0` — it releases at most what is currently reserved.\n */\nexport function release(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n return { onHand: stock.onHand, reserved: stock.reserved - Math.min(q, stock.reserved) };\n}\n\n/**\n * Fulfil (ship) `qty` reserved units: decrements both `onHand` and `reserved`.\n *\n * @throws {InventoryError} if `qty` exceeds the currently reserved amount, or\n * exceeds the physical units on hand (which can happen when {@link adjust} has\n * shrunk `onHand` below the reserved count) — committing further would drive\n * `onHand` negative, so it fails loudly instead.\n */\nexport function commit(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n if (q > stock.reserved) {\n throw new InventoryError(\n `Cannot commit ${q}: only ${stock.reserved} reserved`,\n );\n }\n if (q > stock.onHand) {\n throw new InventoryError(\n `Cannot commit ${q}: only ${stock.onHand} in stock`,\n );\n }\n return { onHand: stock.onHand - q, reserved: stock.reserved - q };\n}\n\n/** Add `qty` units to `onHand` (a delivery / restock). */\nexport function restock(stock: Stock, qty: number): Stock {\n const q = requireQty(qty);\n return { onHand: stock.onHand + q, reserved: stock.reserved };\n}\n\n/**\n * Apply a signed correction to `onHand` (stock-take, shrinkage, returns).\n * `onHand` is clamped at `0`; `reserved` is left untouched.\n */\nexport function adjust(stock: Stock, delta: number): Stock {\n const d = toCount(delta, \"delta\");\n return { onHand: Math.max(0, stock.onHand + d), reserved: stock.reserved };\n}\n\n/** `true` when {@link available} is at or below `threshold`. */\nexport function isLow(stock: Stock, threshold: number): boolean {\n return available(stock) <= toCount(threshold, \"threshold\");\n}\n\n/** `true` when nothing is available to reserve (`available <= 0`). */\nexport function isOutOfStock(stock: Stock): boolean {\n return available(stock) <= 0;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lacspace/inventory",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Stock-tracking engine that prevents overselling — reserve, release, commit & restock over a plain { onHand, reserved } state. Immutable, bring-your-own-store, throws before it oversells. Isomorphic (Node, edge, browser).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|