@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.
- package/CHANGELOG.md +24329 -0
- package/LICENSE +61 -0
- package/README.md +441 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +7737 -0
- package/dist/capture.js +53 -0
- package/dist/catalog.d.ts +63 -0
- package/dist/catalog.js +5 -0
- package/dist/cmsCatalog.d.ts +95 -0
- package/dist/cmsCatalog.js +80 -0
- package/dist/components.d.ts +247 -0
- package/dist/components.js +321 -0
- package/dist/crafting.d.ts +211 -0
- package/dist/crafting.js +193 -0
- package/dist/declarationFixtures.js +66 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +22 -0
- package/dist/index.d.ts +576 -0
- package/dist/index.js +8 -0
- package/dist/inventoryPort.fixture.js +66 -0
- package/dist/inventoryPresentation.js +109 -0
- package/dist/inventoryStore.js +1576 -0
- package/dist/inventoryUiCopy.js +63 -0
- package/dist/item.d.ts +73 -0
- package/dist/item.js +105 -0
- package/dist/plugin.js +407 -0
- package/dist/port.js +5 -0
- package/dist/reservation.js +85 -0
- package/dist/rpc.d.ts +145 -0
- package/dist/rpc.js +135 -0
- package/dist/server.d.ts +816 -0
- package/dist/server.js +4 -0
- package/dist/sqlCatalog.js +185 -0
- package/dist/strategies.d.ts +64 -0
- package/dist/strategies.js +47 -0
- package/dist/systemFixtures.js +172 -0
- package/dist/tables.entity.js +164 -0
- package/dist/testing.d.ts +448 -0
- package/dist/testing.js +4 -0
- package/dist/web.d.ts +60 -0
- package/dist/web.js +7 -0
- package/package.json +104 -4
package/dist/capture.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { inventoryError as e } from "./errors.js";
|
|
2
|
+
//#region src/capture.ts
|
|
3
|
+
var t = (t, n) => {
|
|
4
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw e("invalid_input");
|
|
5
|
+
let r = Object.getPrototypeOf(t);
|
|
6
|
+
if (r !== Object.prototype && r !== null) throw e("invalid_input");
|
|
7
|
+
let i = Object.getOwnPropertyDescriptors(t), a = Object.create(null);
|
|
8
|
+
for (let t of Reflect.ownKeys(i)) {
|
|
9
|
+
if (typeof t != "string" || n && !n.includes(t)) throw e("invalid_input");
|
|
10
|
+
let r = i[t];
|
|
11
|
+
if (!r || !("value" in r) || !r.enumerable) throw e("invalid_input");
|
|
12
|
+
a[t] = r.value;
|
|
13
|
+
}
|
|
14
|
+
return Object.freeze(a);
|
|
15
|
+
}, n = (t) => {
|
|
16
|
+
if (typeof t != "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/.test(t)) throw e("invalid_input");
|
|
17
|
+
return t;
|
|
18
|
+
}, r = (t, n, r) => {
|
|
19
|
+
if (typeof t != "number" || !Number.isSafeInteger(t) || Object.is(t, -0) || t < n || t > r) throw e("invalid_input");
|
|
20
|
+
return t;
|
|
21
|
+
}, i = (t, n) => {
|
|
22
|
+
if (!Array.isArray(t) || t.length > n) throw e("invalid_input");
|
|
23
|
+
let r = Object.getOwnPropertyDescriptors(t);
|
|
24
|
+
if (Reflect.ownKeys(r).length !== t.length + 1) throw e("invalid_input");
|
|
25
|
+
return Object.freeze(Array.from({ length: t.length }, (t, n) => {
|
|
26
|
+
let i = r[String(n)];
|
|
27
|
+
if (!i || !("value" in i) || !i.enumerable) throw e("invalid_input");
|
|
28
|
+
return i.value;
|
|
29
|
+
}));
|
|
30
|
+
}, a = (n) => {
|
|
31
|
+
let r = 0, a = 0, o = (n, s) => {
|
|
32
|
+
if (++r > 4096 || s > 16) throw e("limit_exceeded");
|
|
33
|
+
if (n === null || typeof n == "boolean") return n;
|
|
34
|
+
if (typeof n == "string") {
|
|
35
|
+
if (a += n.length * 3, a > 65536) throw e("limit_exceeded");
|
|
36
|
+
return n;
|
|
37
|
+
}
|
|
38
|
+
if (typeof n == "number") {
|
|
39
|
+
if (!Number.isFinite(n) || Object.is(n, -0)) throw e("invalid_attributes");
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(n)) return Object.freeze(i(n, 4096).map((e) => o(e, s + 1)));
|
|
43
|
+
let c = t(n), l = Object.create(null);
|
|
44
|
+
for (let t of Object.keys(c).sort()) {
|
|
45
|
+
if (a += t.length * 3, a > 65536 || t.length > 120) throw e("limit_exceeded");
|
|
46
|
+
l[t] = o(c[t], s + 1);
|
|
47
|
+
}
|
|
48
|
+
return Object.freeze(l);
|
|
49
|
+
};
|
|
50
|
+
return o(n, 0);
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { n as identifier, r as integer, a as jsonData, i as list, t as object };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { Schema } from 'effect';
|
|
4
|
+
import { YieldableError } from 'effect/Cause';
|
|
5
|
+
|
|
6
|
+
/** Serializable content uses a declared item's version, never a stored Schema object. */
|
|
7
|
+
declare interface CatalogItem {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly schemaVersion: number;
|
|
10
|
+
readonly kind: ItemKind;
|
|
11
|
+
readonly stackable: boolean;
|
|
12
|
+
readonly maxStack: number;
|
|
13
|
+
readonly tradable: boolean;
|
|
14
|
+
readonly rarity: string;
|
|
15
|
+
readonly tags: readonly string[];
|
|
16
|
+
readonly equipSlot: string | null;
|
|
17
|
+
readonly expiresAfter: number | null;
|
|
18
|
+
readonly display: {
|
|
19
|
+
readonly nameKey: string;
|
|
20
|
+
readonly icon: string | null;
|
|
21
|
+
};
|
|
22
|
+
readonly attributes: JsonValue;
|
|
23
|
+
readonly instanceDefaults: JsonValue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export declare interface CatalogScope {
|
|
27
|
+
readonly tenantId: string;
|
|
28
|
+
readonly channel: string;
|
|
29
|
+
readonly locale: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export declare interface CatalogSnapshot {
|
|
33
|
+
readonly revision: string;
|
|
34
|
+
readonly items: readonly CatalogItem[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare class CatalogSource extends CatalogSource_base {
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare const CatalogSource_base: Context.ServiceClass<CatalogSource, "@voltro/CatalogSource", CatalogSourceService>;
|
|
41
|
+
|
|
42
|
+
/** Read only. Call at join/workflow boundaries, never from a room tick. */
|
|
43
|
+
export declare interface CatalogSourceService {
|
|
44
|
+
readonly read: (scope: CatalogScope) => Effect.Effect<CatalogSnapshot, InventoryError>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Public errors carry codes, never subjects, catalog values or provider causes. */
|
|
48
|
+
declare class InventoryError extends InventoryError_base {
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare const InventoryError_base: Schema.Class<InventoryError, Schema.TaggedStruct<"InventoryError", {
|
|
52
|
+
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"]>;
|
|
53
|
+
}>, YieldableError>;
|
|
54
|
+
|
|
55
|
+
declare const ITEM_KINDS: readonly ["consumable", "equipment", "cosmetic", "currencyBundle", "key", "mod"];
|
|
56
|
+
|
|
57
|
+
declare type ItemKind = typeof ITEM_KINDS[number];
|
|
58
|
+
|
|
59
|
+
declare type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
60
|
+
readonly [key: string]: JsonValue;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export { }
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ContentEntities } from '@voltro/cms';
|
|
2
|
+
import { ContentType } from '@voltro/cms';
|
|
3
|
+
import { DataStore } from '@voltro/database';
|
|
4
|
+
import { Effect } from 'effect';
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
import { YieldableError } from 'effect/Cause';
|
|
7
|
+
|
|
8
|
+
/** Serializable content uses a declared item's version, never a stored Schema object. */
|
|
9
|
+
declare interface CatalogItem {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly schemaVersion: number;
|
|
12
|
+
readonly kind: ItemKind;
|
|
13
|
+
readonly stackable: boolean;
|
|
14
|
+
readonly maxStack: number;
|
|
15
|
+
readonly tradable: boolean;
|
|
16
|
+
readonly rarity: string;
|
|
17
|
+
readonly tags: readonly string[];
|
|
18
|
+
readonly equipSlot: string | null;
|
|
19
|
+
readonly expiresAfter: number | null;
|
|
20
|
+
readonly display: {
|
|
21
|
+
readonly nameKey: string;
|
|
22
|
+
readonly icon: string | null;
|
|
23
|
+
};
|
|
24
|
+
readonly attributes: JsonValue;
|
|
25
|
+
readonly instanceDefaults: JsonValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare interface CatalogScope {
|
|
29
|
+
readonly tenantId: string;
|
|
30
|
+
readonly channel: string;
|
|
31
|
+
readonly locale: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare interface CatalogSnapshot {
|
|
35
|
+
readonly revision: string;
|
|
36
|
+
readonly items: readonly CatalogItem[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Read only. Call at join/workflow boundaries, never from a room tick. */
|
|
40
|
+
declare interface CatalogSourceService {
|
|
41
|
+
readonly read: (scope: CatalogScope) => Effect.Effect<CatalogSnapshot, InventoryError>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export declare interface CmsCatalogOptions {
|
|
45
|
+
readonly items: readonly ItemDefinition[];
|
|
46
|
+
readonly site: string;
|
|
47
|
+
/** Explicit channel-to-CMS-environment binding. No guessed live/staging environment. */
|
|
48
|
+
readonly environments: Readonly<Record<string, string>>;
|
|
49
|
+
readonly maxCatalogItems?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export declare const cmsCatalogSource: (store: DataStore, input: CmsCatalogOptions) => CatalogSourceService;
|
|
53
|
+
|
|
54
|
+
/** Public errors carry codes, never subjects, catalog values or provider causes. */
|
|
55
|
+
declare class InventoryError extends InventoryError_base {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare const InventoryError_base: Schema.Class<InventoryError, Schema.TaggedStruct<"InventoryError", {
|
|
59
|
+
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"]>;
|
|
60
|
+
}>, YieldableError>;
|
|
61
|
+
|
|
62
|
+
export declare const inventoryItemContentTables: ContentEntities;
|
|
63
|
+
|
|
64
|
+
/** CMS owns drafts, releases and immutable revisions. Gameplay only reads published rows. */
|
|
65
|
+
export declare const inventoryItemContentType: ContentType;
|
|
66
|
+
|
|
67
|
+
declare const ITEM_KINDS: readonly ["consumable", "equipment", "cosmetic", "currencyBundle", "key", "mod"];
|
|
68
|
+
|
|
69
|
+
declare interface ItemDefinition {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
readonly kind: ItemKind;
|
|
72
|
+
readonly schemaVersion?: number;
|
|
73
|
+
readonly stackable: boolean;
|
|
74
|
+
readonly maxStack: number;
|
|
75
|
+
readonly tradable: boolean;
|
|
76
|
+
readonly rarity: string;
|
|
77
|
+
readonly tags: readonly string[];
|
|
78
|
+
readonly attributes: Schema.Top;
|
|
79
|
+
readonly instanceAttributes: Schema.Top;
|
|
80
|
+
readonly equipSlot?: string | null;
|
|
81
|
+
/** Milliseconds; resolved on grant, never by a tick. */
|
|
82
|
+
readonly expiresAfter?: number | null;
|
|
83
|
+
readonly display: {
|
|
84
|
+
readonly nameKey: string;
|
|
85
|
+
readonly icon?: string | null;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
declare type ItemKind = typeof ITEM_KINDS[number];
|
|
90
|
+
|
|
91
|
+
declare type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
92
|
+
readonly [key: string]: JsonValue;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { InventoryError as e, inventoryError as t } from "./errors.js";
|
|
2
|
+
import { integer as n, object as r } from "./capture.js";
|
|
3
|
+
import { captureCatalogItem as i, captureItemContracts as a } from "./item.js";
|
|
4
|
+
import { catalogScope as o, inventoryHash as s, inventoryIo as c } from "./sqlCatalog.js";
|
|
5
|
+
import { Effect as l } from "effect";
|
|
6
|
+
import { Schema as u, cmsContext as d, contentTypeToEntities as f, defineContentType as p } from "@voltro/cms";
|
|
7
|
+
//#region src/cmsCatalog.ts
|
|
8
|
+
var m = p({
|
|
9
|
+
name: "item",
|
|
10
|
+
displayName: "Game item",
|
|
11
|
+
pluralName: "Game items",
|
|
12
|
+
fields: {
|
|
13
|
+
itemId: u.String.pipe(u.maxLength(120), u.pattern(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/), u.unique()),
|
|
14
|
+
schemaVersion: u.Number,
|
|
15
|
+
definitionJson: u.String.pipe(u.maxLength(65536))
|
|
16
|
+
},
|
|
17
|
+
list: {
|
|
18
|
+
columns: ["itemId", "schemaVersion"],
|
|
19
|
+
defaultSort: {
|
|
20
|
+
field: "itemId",
|
|
21
|
+
dir: "asc"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}), h = f(m), g = (u, f) => {
|
|
25
|
+
let p = r(f, [
|
|
26
|
+
"items",
|
|
27
|
+
"site",
|
|
28
|
+
"environments",
|
|
29
|
+
"maxCatalogItems"
|
|
30
|
+
]), h = a(p.items), g = r(p.environments), _ = p.site, v = n(p.maxCatalogItems ?? 1e4, 1, 1e4), y = (e) => {
|
|
31
|
+
if (typeof e != "string" || e.length < 1 || e.length > 64 || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(e)) throw t("invalid_input");
|
|
32
|
+
return e;
|
|
33
|
+
}, b = y(_), x = Object.freeze(Object.fromEntries(Object.entries(g).map(([e, t]) => [o({
|
|
34
|
+
tenantId: "validation",
|
|
35
|
+
channel: e,
|
|
36
|
+
locale: "en"
|
|
37
|
+
}).channel, y(t)])));
|
|
38
|
+
if (Object.keys(x).length < 1 || Object.keys(x).length > 32) throw t("invalid_input");
|
|
39
|
+
return Object.freeze({ read: (n) => {
|
|
40
|
+
try {
|
|
41
|
+
let e = o(n), r = x[e.channel];
|
|
42
|
+
if (r === void 0) throw t("not_found");
|
|
43
|
+
let a = Object.freeze({
|
|
44
|
+
site: b,
|
|
45
|
+
environment: r,
|
|
46
|
+
locale: y(e.locale)
|
|
47
|
+
});
|
|
48
|
+
return c(async () => {
|
|
49
|
+
let n = await d(u, [m], { scope: a }).contentType("item").where("tenantId", "=", e.tenantId).orderBy("itemId", "asc").limit(v + 1).all();
|
|
50
|
+
if (n.length > v) throw t("limit_exceeded");
|
|
51
|
+
let o = Object.freeze(n.map((n) => {
|
|
52
|
+
if (n.tenantId !== e.tenantId || n.site !== b || n.environment !== r || n.locale !== e.locale || n.status !== "published" || typeof n.definitionJson != "string" || n.definitionJson.length > 65536) throw t("invalid_record");
|
|
53
|
+
let a;
|
|
54
|
+
try {
|
|
55
|
+
a = JSON.parse(n.definitionJson);
|
|
56
|
+
} catch {
|
|
57
|
+
throw t("invalid_record");
|
|
58
|
+
}
|
|
59
|
+
let o = i(a, h);
|
|
60
|
+
if (o.id !== n.itemId || o.schemaVersion !== n.schemaVersion) throw t("invalid_record");
|
|
61
|
+
return o;
|
|
62
|
+
}).sort((e, t) => e.id < t.id ? -1 : +(e.id > t.id)));
|
|
63
|
+
if (new Set(o.map((e) => e.id)).size !== o.length) throw t("conflict");
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
revision: s({
|
|
66
|
+
site: b,
|
|
67
|
+
environment: r,
|
|
68
|
+
locale: e.locale,
|
|
69
|
+
items: o
|
|
70
|
+
}),
|
|
71
|
+
items: o
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
} catch (n) {
|
|
75
|
+
return l.fail(n instanceof e ? n : t("invalid_input"));
|
|
76
|
+
}
|
|
77
|
+
} });
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { g as cmsCatalogSource, h as inventoryItemContentTables, m as inventoryItemContentType };
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
|
|
4
|
+
/** Detached wire admission; no author Schema, storage, URL resolver or policy runs here. */
|
|
5
|
+
export declare const captureInventoryPresentation: (instances: unknown, snapshot: unknown, equipped: unknown, at: number) => InventoryPresentation;
|
|
6
|
+
|
|
7
|
+
/** Serializable content uses a declared item's version, never a stored Schema object. */
|
|
8
|
+
declare interface CatalogItem {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly schemaVersion: number;
|
|
11
|
+
readonly kind: ItemKind;
|
|
12
|
+
readonly stackable: boolean;
|
|
13
|
+
readonly maxStack: number;
|
|
14
|
+
readonly tradable: boolean;
|
|
15
|
+
readonly rarity: string;
|
|
16
|
+
readonly tags: readonly string[];
|
|
17
|
+
readonly equipSlot: string | null;
|
|
18
|
+
readonly expiresAfter: number | null;
|
|
19
|
+
readonly display: {
|
|
20
|
+
readonly nameKey: string;
|
|
21
|
+
readonly icon: string | null;
|
|
22
|
+
};
|
|
23
|
+
readonly attributes: JsonValue;
|
|
24
|
+
readonly instanceDefaults: JsonValue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare interface CatalogSnapshot {
|
|
28
|
+
readonly revision: string;
|
|
29
|
+
readonly items: readonly CatalogItem[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare const CatalogSnapshotSchema: Schema.Struct<{
|
|
33
|
+
readonly revision: Schema.String;
|
|
34
|
+
readonly items: Schema.$Array<Schema.Struct<{
|
|
35
|
+
readonly id: Schema.String;
|
|
36
|
+
readonly schemaVersion: Schema.Number;
|
|
37
|
+
readonly kind: Schema.Literals<readonly ["consumable", "equipment", "cosmetic", "currencyBundle", "key", "mod"]>;
|
|
38
|
+
readonly stackable: Schema.Boolean;
|
|
39
|
+
readonly maxStack: Schema.Number;
|
|
40
|
+
readonly tradable: Schema.Boolean;
|
|
41
|
+
readonly rarity: Schema.String;
|
|
42
|
+
readonly tags: Schema.$Array<Schema.String>;
|
|
43
|
+
readonly equipSlot: Schema.NullOr<Schema.String>;
|
|
44
|
+
readonly expiresAfter: Schema.NullOr<Schema.Number>;
|
|
45
|
+
readonly display: Schema.Struct<{
|
|
46
|
+
readonly nameKey: Schema.String;
|
|
47
|
+
readonly icon: Schema.NullOr<Schema.String>;
|
|
48
|
+
}>;
|
|
49
|
+
readonly attributes: Schema.Unknown;
|
|
50
|
+
readonly instanceDefaults: Schema.Unknown;
|
|
51
|
+
}>>;
|
|
52
|
+
}>;
|
|
53
|
+
|
|
54
|
+
declare type CopyProps = {
|
|
55
|
+
readonly locale?: 'en' | 'de' | undefined;
|
|
56
|
+
readonly copy?: InventoryUiCopy | undefined;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** Read-only default; an app may supply its own authorized intention control. No craft RPC is invented. */
|
|
60
|
+
export declare const CraftingPanel: (props: CraftingPanelProps) => ReactNode;
|
|
61
|
+
|
|
62
|
+
export declare interface CraftingPanelProps extends CopyProps {
|
|
63
|
+
readonly view: InventoryPresentation;
|
|
64
|
+
readonly recipes: readonly Recipe[];
|
|
65
|
+
readonly at: number;
|
|
66
|
+
readonly title: (itemId: string) => string;
|
|
67
|
+
readonly currencyLabel?: ((currency: string) => string) | undefined;
|
|
68
|
+
readonly renderAction?: ((recipe: Recipe, batches: number, materialsAvailable: boolean) => ReactNode) | undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export declare const inventoryCanEquip: (item: InventoryDisplayItem, slot: string) => boolean;
|
|
72
|
+
|
|
73
|
+
export declare interface InventoryDisplayItem {
|
|
74
|
+
readonly instance: InventoryInstance;
|
|
75
|
+
readonly content: CatalogItem | undefined;
|
|
76
|
+
readonly equipped: boolean;
|
|
77
|
+
readonly expired: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
declare interface InventoryEquip {
|
|
81
|
+
readonly slotSet: string;
|
|
82
|
+
readonly slot: string;
|
|
83
|
+
readonly instanceId: string | null;
|
|
84
|
+
readonly requestId: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Fixed-height rows, overscan and a retained focused row. All-items mode is available for traversal. */
|
|
88
|
+
export declare const InventoryGrid: (props: InventoryGridProps) => ReactNode;
|
|
89
|
+
|
|
90
|
+
export declare interface InventoryGridProps extends CopyProps, ItemContentProps {
|
|
91
|
+
readonly source: InventoryObservation<readonly (typeof InventoryInstanceSchema.Type)[]>;
|
|
92
|
+
readonly catalog: InventoryObservation<typeof CatalogSnapshotSchema.Type>;
|
|
93
|
+
readonly at: number;
|
|
94
|
+
readonly onSelect?: ItemCardProps['onSelect'];
|
|
95
|
+
readonly busy?: boolean | undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
declare interface InventoryInstance {
|
|
99
|
+
readonly id: string;
|
|
100
|
+
readonly itemId: string;
|
|
101
|
+
readonly schemaVersion: number;
|
|
102
|
+
readonly qty: number;
|
|
103
|
+
readonly attributes: JsonValue;
|
|
104
|
+
readonly acquiredAt: number;
|
|
105
|
+
readonly expiresAt: number | null;
|
|
106
|
+
readonly locked: boolean;
|
|
107
|
+
readonly source: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare const InventoryInstanceSchema: Schema.Struct<{
|
|
111
|
+
readonly id: Schema.String;
|
|
112
|
+
readonly itemId: Schema.String;
|
|
113
|
+
readonly schemaVersion: Schema.Number;
|
|
114
|
+
readonly qty: Schema.Number;
|
|
115
|
+
readonly attributes: Schema.Unknown;
|
|
116
|
+
readonly acquiredAt: Schema.Number;
|
|
117
|
+
readonly expiresAt: Schema.NullOr<Schema.Number>;
|
|
118
|
+
readonly locked: Schema.Boolean;
|
|
119
|
+
readonly source: Schema.String;
|
|
120
|
+
}>;
|
|
121
|
+
|
|
122
|
+
declare interface InventoryLoadout {
|
|
123
|
+
readonly slotSet: string;
|
|
124
|
+
readonly slot: string;
|
|
125
|
+
readonly instanceId: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export declare interface InventoryObservation<A> {
|
|
129
|
+
readonly data: A | undefined;
|
|
130
|
+
readonly loading: boolean;
|
|
131
|
+
readonly error: unknown;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export declare interface InventoryPresentation {
|
|
135
|
+
readonly items: readonly InventoryDisplayItem[];
|
|
136
|
+
readonly loadout: readonly InventoryLoadout[];
|
|
137
|
+
readonly catalog: CatalogSnapshot;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Calls the actual conserved selection rule; materials do not prove wallet affordability. */
|
|
141
|
+
export declare const inventoryRecipePreview: (view: InventoryPresentation, original: Recipe, batches: number, at: number) => RecipePreview;
|
|
142
|
+
|
|
143
|
+
export declare interface InventoryUiCopy {
|
|
144
|
+
readonly inventory: string;
|
|
145
|
+
readonly loading: string;
|
|
146
|
+
readonly unavailable: string;
|
|
147
|
+
readonly empty: string;
|
|
148
|
+
readonly noMatches: string;
|
|
149
|
+
readonly search: string;
|
|
150
|
+
readonly tag: string;
|
|
151
|
+
readonly allTags: string;
|
|
152
|
+
readonly showAll: string;
|
|
153
|
+
readonly virtualize: string;
|
|
154
|
+
readonly equipped: string;
|
|
155
|
+
readonly locked: string;
|
|
156
|
+
readonly expired: string;
|
|
157
|
+
readonly unknown: string;
|
|
158
|
+
readonly select: string;
|
|
159
|
+
readonly loadout: string;
|
|
160
|
+
readonly unequipped: string;
|
|
161
|
+
readonly recipes: string;
|
|
162
|
+
readonly batches: string;
|
|
163
|
+
readonly materials: string;
|
|
164
|
+
readonly materialsReady: string;
|
|
165
|
+
readonly materialsMissing: string;
|
|
166
|
+
readonly currencyCost: string;
|
|
167
|
+
readonly freeCost: string;
|
|
168
|
+
readonly serverCraft: string;
|
|
169
|
+
readonly count: (shown: number, total: number) => string;
|
|
170
|
+
readonly quantity: (amount: number) => string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export declare const inventoryUiCopy: Readonly<Readonly<Record<"en" | "de", InventoryUiCopy>>>;
|
|
174
|
+
|
|
175
|
+
declare const ITEM_KINDS: readonly ["consumable", "equipment", "cosmetic", "currencyBundle", "key", "mod"];
|
|
176
|
+
|
|
177
|
+
/** The grid supplies an admitted detached view. Icons resolve only in the app-owned slot. */
|
|
178
|
+
export declare const ItemCard: (props: ItemCardProps) => ReactNode;
|
|
179
|
+
|
|
180
|
+
export declare interface ItemCardProps extends CopyProps, ItemContentProps {
|
|
181
|
+
readonly item: InventoryDisplayItem;
|
|
182
|
+
readonly onSelect?: ((instanceId: string) => void) | undefined;
|
|
183
|
+
readonly busy?: boolean | undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
declare type ItemContentProps = {
|
|
187
|
+
readonly title: (key: string) => string;
|
|
188
|
+
readonly renderIcon?: ((item: InventoryDisplayItem) => ReactNode) | undefined;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
declare type ItemKind = typeof ITEM_KINDS[number];
|
|
192
|
+
|
|
193
|
+
declare type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
194
|
+
readonly [key: string]: JsonValue;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/** Controlled by the server observation; never patches local item/loadout values. */
|
|
198
|
+
export declare const LoadoutEditor: (props: LoadoutEditorProps) => ReactNode;
|
|
199
|
+
|
|
200
|
+
export declare interface LoadoutEditorProps extends CopyProps, ItemContentProps {
|
|
201
|
+
readonly source: InventoryObservation<readonly (typeof InventoryInstanceSchema.Type)[]>;
|
|
202
|
+
readonly catalog: InventoryObservation<typeof CatalogSnapshotSchema.Type>;
|
|
203
|
+
readonly loadout: InventoryObservation<readonly InventoryLoadout[]>;
|
|
204
|
+
readonly slotSet: string;
|
|
205
|
+
readonly slots: readonly string[];
|
|
206
|
+
readonly at: number;
|
|
207
|
+
readonly busy: boolean;
|
|
208
|
+
readonly requestId: () => string;
|
|
209
|
+
readonly onEquip: (intention: InventoryEquip) => void;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare interface Recipe {
|
|
213
|
+
readonly id: string;
|
|
214
|
+
readonly version: number;
|
|
215
|
+
readonly inputs: readonly RecipeIngredient[];
|
|
216
|
+
readonly outputs: readonly RecipeOutput[];
|
|
217
|
+
readonly maxBatches: number;
|
|
218
|
+
readonly cost: RecipeCurrencyCost | null;
|
|
219
|
+
readonly timeMs: 0;
|
|
220
|
+
readonly requires: null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
declare interface RecipeCurrencyCost {
|
|
224
|
+
readonly currency: string;
|
|
225
|
+
readonly amount: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
declare interface RecipeIngredient {
|
|
229
|
+
readonly itemId: string;
|
|
230
|
+
readonly qty: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
declare interface RecipeOutput extends RecipeIngredient {
|
|
234
|
+
readonly attributes?: JsonValue;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export declare interface RecipePreview {
|
|
238
|
+
readonly recipe: Recipe;
|
|
239
|
+
readonly batches: number;
|
|
240
|
+
readonly materialsAvailable: boolean;
|
|
241
|
+
readonly currencyCost: {
|
|
242
|
+
readonly currency: string;
|
|
243
|
+
readonly amount: string;
|
|
244
|
+
} | null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export { }
|