@lacspace/inventory 1.0.0 → 1.0.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 +4 -3
- 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/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
**A stock-tracking engine that prevents overselling — reserve, commit & restock over a plain state object.**
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@lacspace/inventory)
|
|
8
|
+
[](https://packagephobia.com/result?p=@lacspace/inventory)
|
|
8
9
|
[](https://bundlephobia.com/package/@lacspace/inventory)
|
|
9
10
|
[](https://www.npmjs.com/package/@lacspace/inventory)
|
|
10
11
|
[](https://github.com/lacspace/npm-packages/blob/main/LICENSE)
|
|
@@ -84,7 +85,7 @@ stock = release(stock, 18); // cart abandoned → put them back
|
|
|
84
85
|
|
|
85
86
|
## Licensing
|
|
86
87
|
|
|
87
|
-
This package is **free** under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — permissive freedoms. Use it in personal and commercial projects at no cost; just keep the notice.
|
|
88
|
+
This package is **free** under the **[Lacspace Free Licence](https://developer.lacspace.com/licenses/lacspace-free-1.0)** — permissive freedoms. Use it in personal and commercial projects at no cost; just keep the notice.
|
|
88
89
|
|
|
89
90
|
Not every Lacspace package is free. We also offer **Commercial** (paid), **Client-specific**, and **Private** (proprietary) packages under separate terms. See the full **[Lacspace Licence Centre](https://lacspace.com/licenses)**.
|
|
90
91
|
|
|
@@ -94,7 +95,7 @@ Not every Lacspace package is free. We also offer **Commercial** (paid), **Clien
|
|
|
94
95
|
|
|
95
96
|
## The Lacspace Developer Platform
|
|
96
97
|
|
|
97
|
-
`@lacspace/inventory` is part of **
|
|
98
|
+
`@lacspace/inventory` is part of **80+ zero-dependency, isomorphic TypeScript packages**. Explore the ecosystem:
|
|
98
99
|
|
|
99
100
|
- 🗂️ **All packages** — https://developer.lacspace.com/packages
|
|
100
101
|
- 🧭 **Developer handbook** — https://developer.lacspace.com/handbook
|
|
@@ -102,4 +103,4 @@ Not every Lacspace package is free. We also offer **Commercial** (paid), **Clien
|
|
|
102
103
|
- 🖥️ **Finished app templates** — https://templates.lacspace.com
|
|
103
104
|
- 🚀 **Scaffold a full app** — `npm create lacspace-app@latest`
|
|
104
105
|
|
|
105
|
-
Free under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — a permissive, free-to-use licence.
|
|
106
|
+
Free under the **[Lacspace Free Licence](https://developer.lacspace.com/licenses/lacspace-free-1.0)** — a permissive, free-to-use licence.
|
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.2",
|
|
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",
|