@voltro/plugin-inventory 0.0.0-stage → 0.87.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.
@@ -0,0 +1,193 @@
1
+ import { inventoryError as e } from "./errors.js";
2
+ import { identifier as t, integer as n, jsonData as r, list as i, object as a } from "./capture.js";
3
+ import { Context as o } from "effect";
4
+ //#region src/crafting.ts
5
+ var s = (o) => {
6
+ let s = a(o, [
7
+ "id",
8
+ "version",
9
+ "inputs",
10
+ "outputs",
11
+ "maxBatches",
12
+ "cost",
13
+ "timeMs",
14
+ "requires"
15
+ ]);
16
+ if (s.timeMs !== void 0 && s.timeMs !== 0 || s.requires !== void 0 && s.requires !== null) throw e("invalid_input");
17
+ let c = (o, s) => {
18
+ let c = i(o, 64).map((e) => {
19
+ let i = a(e, s ? [
20
+ "itemId",
21
+ "qty",
22
+ "attributes"
23
+ ] : ["itemId", "qty"]);
24
+ return Object.freeze({
25
+ itemId: t(i.itemId),
26
+ qty: n(i.qty, 1, 1e6),
27
+ ...i.attributes === void 0 ? {} : { attributes: r(i.attributes) }
28
+ });
29
+ });
30
+ if (!c.length || new Set(c.map((e) => e.itemId)).size !== c.length) throw e("invalid_input");
31
+ return Object.freeze(c);
32
+ }, l = c(s.inputs, !1), u = c(s.outputs, !0), d = n(s.maxBatches ?? 1e3, 1, 1e3);
33
+ if ([...l, ...u].some((e) => e.qty * d > 1e6)) throw e("limit_exceeded");
34
+ let f = null;
35
+ if (s.cost != null) {
36
+ let n = a(s.cost, ["currency", "amount"]);
37
+ if (typeof n.amount != "string" || n.amount.length > 19 || !/^[1-9][0-9]*$/.test(n.amount) || BigInt(n.amount) * BigInt(d) > 9223372036854775807n) throw e("invalid_input");
38
+ f = Object.freeze({
39
+ currency: t(n.currency),
40
+ amount: n.amount
41
+ });
42
+ }
43
+ return Object.freeze({
44
+ id: t(s.id),
45
+ version: n(s.version ?? 1, 1, 1e6),
46
+ inputs: l,
47
+ outputs: u,
48
+ maxBatches: d,
49
+ cost: f,
50
+ timeMs: 0,
51
+ requires: null
52
+ });
53
+ }, c = (t) => {
54
+ let n = [];
55
+ for (let r of t.recipe.inputs) {
56
+ let i = r.qty * t.batches, a = t.available.filter((e) => e.itemId === r.itemId && !e.locked && !t.excludedIds.includes(e.id) && (e.expiresAt === null || e.expiresAt > t.at)).slice().sort((e, t) => e.acquiredAt - t.acquiredAt || (e.id < t.id ? -1 : +(e.id > t.id)));
57
+ for (let e of a) {
58
+ let t = Math.min(i, e.qty);
59
+ if (t && (n.push(Object.freeze({
60
+ instanceId: e.id,
61
+ qty: t
62
+ })), i -= t), !i) break;
63
+ }
64
+ if (i) throw e("insufficient_items");
65
+ }
66
+ return Object.freeze({
67
+ consume: Object.freeze(n),
68
+ outputs: Object.freeze(t.recipe.outputs.map((e) => Object.freeze({
69
+ ...e,
70
+ qty: e.qty * t.batches
71
+ })))
72
+ });
73
+ }, l = (o, l = c) => {
74
+ let d = a(o, [
75
+ "recipe",
76
+ "batches",
77
+ "at",
78
+ "available",
79
+ "excludedIds"
80
+ ]), f = s(d.recipe), p = n(d.batches, 1, f.maxBatches), m = n(d.at, 0, 864e13), h = Object.freeze(i(d.excludedIds, 2048).map(t));
81
+ if (typeof l != "function" || new Set(h).size !== h.length) throw e("invalid_input");
82
+ let g = Object.freeze(i(d.available, 1e4).map((i) => {
83
+ let o = a(i, [
84
+ "id",
85
+ "itemId",
86
+ "schemaVersion",
87
+ "qty",
88
+ "attributes",
89
+ "acquiredAt",
90
+ "expiresAt",
91
+ "locked",
92
+ "source"
93
+ ]), s = n(o.acquiredAt, 0, m), c = o.expiresAt === null ? null : n(o.expiresAt, s + 1, 864e13);
94
+ if (typeof o.locked != "boolean") throw e("invalid_input");
95
+ return Object.freeze({
96
+ id: t(o.id),
97
+ itemId: t(o.itemId),
98
+ schemaVersion: n(o.schemaVersion, 1, 1e6),
99
+ qty: n(o.qty, 1, 1e6),
100
+ attributes: r(o.attributes),
101
+ acquiredAt: s,
102
+ expiresAt: c,
103
+ locked: o.locked,
104
+ source: t(o.source)
105
+ });
106
+ }));
107
+ if (new Set(g.map((e) => e.id)).size !== g.length || h.some((e) => !g.some((t) => t.id === e))) throw e("invalid_input");
108
+ let _ = Object.freeze({
109
+ recipe: f,
110
+ batches: p,
111
+ at: m,
112
+ available: g,
113
+ excludedIds: h
114
+ });
115
+ return u(l(_), _);
116
+ }, u = (o, s) => {
117
+ let c = a(o, ["consume", "outputs"]), l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Map(), d = Object.freeze(i(c.consume, 1e4).map((r) => {
118
+ let i = a(r, ["instanceId", "qty"]), o = t(i.instanceId), c = s.available.find((e) => e.id === o), d = n(i.qty, 1, 1e6);
119
+ if (!c || l.has(o) || d > c.qty || c.locked || s.excludedIds.includes(o) || c.expiresAt !== null && c.expiresAt <= s.at || !s.recipe.inputs.some((e) => e.itemId === c.itemId)) throw e("conflict");
120
+ return l.add(o), u.set(c.itemId, (u.get(c.itemId) ?? 0) + d), Object.freeze({
121
+ instanceId: o,
122
+ qty: d
123
+ });
124
+ }));
125
+ if (s.recipe.inputs.some((e) => u.get(e.itemId) !== e.qty * s.batches)) throw e("conflict");
126
+ let f = Object.freeze(i(c.outputs, 64).map((e) => {
127
+ let i = a(e, [
128
+ "itemId",
129
+ "qty",
130
+ "attributes"
131
+ ]);
132
+ return Object.freeze({
133
+ itemId: t(i.itemId),
134
+ qty: n(i.qty, 1, 1e6),
135
+ ...i.attributes === void 0 ? {} : { attributes: r(i.attributes) }
136
+ });
137
+ }));
138
+ if (f.length !== s.recipe.outputs.length || new Set(f.map((e) => e.itemId)).size !== f.length || s.recipe.outputs.some((e) => f.find((t) => t.itemId === e.itemId)?.qty !== e.qty * s.batches)) throw e("conflict");
139
+ return Object.freeze({
140
+ consume: d,
141
+ outputs: f
142
+ });
143
+ }, d = class extends o.Service()("@voltro/CraftingPort") {}, f = (n) => {
144
+ let r = a(n, [
145
+ "recipes",
146
+ "craftResolver",
147
+ "version",
148
+ "service",
149
+ "economy",
150
+ "systemAccount"
151
+ ]), o = Object.freeze(i(r.recipes, 256).map((e) => s(e))), l = r.craftResolver ?? c, u = t(r.version ?? "default.v1");
152
+ if (!o.length || new Set(o.map((e) => e.id)).size !== o.length || typeof l != "function" || l !== c && u === "default.v1") throw e("invalid_input");
153
+ let d = [
154
+ "craft",
155
+ "recipes",
156
+ "exportSubject",
157
+ "eraseSubject"
158
+ ], f = r.service === void 0 ? void 0 : a(r.service);
159
+ if (f && d.some((e) => typeof f[e] != "function")) throw e("invalid_input");
160
+ let p = f ? Object.freeze(Object.fromEntries(d.map((e) => [e, f[e].bind(r.service)]))) : void 0;
161
+ if (p && (r.economy !== void 0 || r.systemAccount !== void 0)) throw e("invalid_input");
162
+ let m = r.economy === void 0 ? void 0 : a(r.economy);
163
+ if (m && typeof m.prepareTransfer != "function" || !p && o.some((e) => e.cost !== null) && !m || !m && r.systemAccount !== void 0) throw e("invalid_input");
164
+ let h = m ? Object.freeze({ prepareTransfer: m.prepareTransfer.bind(r.economy) }) : void 0, g = h ? t(r.systemAccount ?? "crafting") : void 0;
165
+ return Object.freeze({
166
+ economy: h,
167
+ systemAccount: g,
168
+ recipes: o,
169
+ craftResolver: l,
170
+ version: u,
171
+ service: p
172
+ });
173
+ }, p = (r, i, o) => {
174
+ if (i.cost === null) {
175
+ if (r !== null) throw e("invalid_record");
176
+ return null;
177
+ }
178
+ let s = a(r, [
179
+ "txId",
180
+ "currency",
181
+ "amount",
182
+ "at"
183
+ ]), c = (BigInt(i.cost.amount) * BigInt(n(o, 1, i.maxBatches))).toString();
184
+ if (s.currency !== i.cost.currency || s.amount !== c) throw e("invalid_record");
185
+ return Object.freeze({
186
+ txId: t(s.txId),
187
+ currency: i.cost.currency,
188
+ amount: c,
189
+ at: n(s.at, 0, 864e13)
190
+ });
191
+ };
192
+ //#endregion
193
+ export { d as CraftingPort, p as captureCraftPayment, u as captureCraftPlan, c as defaultCraftResolver, s as defineRecipe, l as resolveCraftPlan, f as resolveCraftingOptions };
@@ -0,0 +1,66 @@
1
+ import { defineRecipe as e } from "./crafting.js";
2
+ import { defineItem as t, itemContent as n } from "./item.js";
3
+ import { Schema as r } from "effect";
4
+ //#region src/declarationFixtures.ts
5
+ var i = () => {
6
+ let e = t({
7
+ id: "test.potion",
8
+ kind: "consumable",
9
+ stackable: !0,
10
+ maxStack: 10,
11
+ tradable: !1,
12
+ rarity: "common",
13
+ tags: ["test"],
14
+ attributes: r.Struct({ potency: r.Number }),
15
+ instanceAttributes: r.Struct({}),
16
+ display: { nameKey: "test.potion.name" }
17
+ });
18
+ return Object.freeze({
19
+ item: e,
20
+ content: n(e, { potency: 1 }, {}),
21
+ stack: Object.freeze({
22
+ item: n(e, { potency: 1 }, {}),
23
+ quantity: 12,
24
+ available: Object.freeze([{
25
+ id: "test.stack",
26
+ quantity: 8
27
+ }])
28
+ }),
29
+ expiry: Object.freeze({
30
+ item: n(e, { potency: 1 }, {}),
31
+ acquiredAt: Date.UTC(2026, 9, 10)
32
+ })
33
+ });
34
+ }, a = () => {
35
+ let t = e({
36
+ id: "distill",
37
+ inputs: [{
38
+ itemId: "test.potion",
39
+ qty: 2
40
+ }],
41
+ outputs: [{
42
+ itemId: "test.potion",
43
+ qty: 1
44
+ }],
45
+ maxBatches: 10
46
+ }), n = Date.UTC(2026, 9, 10);
47
+ return Object.freeze({
48
+ recipe: t,
49
+ batches: 1,
50
+ at: n,
51
+ available: Object.freeze([Object.freeze({
52
+ id: "fixture.potion",
53
+ itemId: "test.potion",
54
+ schemaVersion: 1,
55
+ qty: 6,
56
+ attributes: Object.freeze({}),
57
+ acquiredAt: n,
58
+ expiresAt: null,
59
+ locked: !1,
60
+ source: "fixture"
61
+ })]),
62
+ excludedIds: Object.freeze([])
63
+ });
64
+ };
65
+ //#endregion
66
+ export { a as craftFixture, i as inventoryFixture };
@@ -0,0 +1,14 @@
1
+ import { Schema } from 'effect';
2
+ import { YieldableError } from 'effect/Cause';
3
+
4
+ /** Public errors carry codes, never subjects, catalog values or provider causes. */
5
+ export declare class InventoryError extends InventoryError_base {
6
+ }
7
+
8
+ export declare const inventoryError: (code: InventoryError["code"]) => InventoryError;
9
+
10
+ declare const InventoryError_base: Schema.Class<InventoryError, Schema.TaggedStruct<"InventoryError", {
11
+ readonly code: Schema.Literals<readonly ["invalid_input", "invalid_record", "invalid_item", "invalid_attributes", "conflict", "forbidden", "not_found", "unavailable", "limit_exceeded", "erased", "insufficient_items", "insufficient_funds", "payment_refused", "locked", "expired", "invalid_slot"]>;
12
+ }>, YieldableError>;
13
+
14
+ export { }
package/dist/errors.js ADDED
@@ -0,0 +1,22 @@
1
+ import { Schema as e } from "effect";
2
+ //#region src/errors.ts
3
+ var t = class extends e.TaggedError()("InventoryError", { code: e.Literals([
4
+ "invalid_input",
5
+ "invalid_record",
6
+ "invalid_item",
7
+ "invalid_attributes",
8
+ "conflict",
9
+ "forbidden",
10
+ "not_found",
11
+ "unavailable",
12
+ "limit_exceeded",
13
+ "erased",
14
+ "insufficient_items",
15
+ "insufficient_funds",
16
+ "payment_refused",
17
+ "locked",
18
+ "expired",
19
+ "invalid_slot"
20
+ ]) }) {}, n = (e) => new t({ code: e });
21
+ //#endregion
22
+ export { t as InventoryError, n as inventoryError };