cs2-inventory-resolver 0.1.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,2 @@
1
+ import type { InventoryData } from './types.js';
2
+ export declare function getData(): InventoryData;
@@ -0,0 +1,9 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+ let data = null;
4
+ export function getData() {
5
+ if (!data) {
6
+ data = require('../data/inventory.json');
7
+ }
8
+ return data;
9
+ }
@@ -0,0 +1,2 @@
1
+ export { resolveItem, getAttributeUint32 } from './resolver.js';
2
+ export type { ItemCategory, ResolvedItemData, GcItemInput } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { resolveItem, getAttributeUint32 } from './resolver.js';
@@ -0,0 +1,45 @@
1
+ import type { GcItemInput, ResolvedItemData } from './types.js';
2
+ /**
3
+ * Resolve a raw GC item into a name, image, and category.
4
+ *
5
+ * Resolution priority:
6
+ * 1. Skins (by `def_index` + `paint_index`)
7
+ * 2. Music kits (by attribute 166)
8
+ * 3. Keychains (by attribute 299)
9
+ * 4. Graffiti (by `stickers[0].sticker_id` + attribute 233)
10
+ * 5. Crates / cases / keys (by `def_index`)
11
+ * 6. Collectibles (by `def_index`)
12
+ * 7. Stickers / patches (by `stickers[0].sticker_id`)
13
+ *
14
+ * @param gcItem - The raw GC item to resolve.
15
+ * @returns The resolved item data, or `null` if the item could not be identified.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const result = resolveItem({ def_index: 7, paint_index: 282 });
20
+ * // => { name: "AK-47 | Redline", image: "https://...", category: "skin" }
21
+ * ```
22
+ */
23
+ export declare function resolveItem(gcItem: GcItemInput): ResolvedItemData | null;
24
+ /**
25
+ * Read a uint32 value from a raw GC item's attribute[] array.
26
+ *
27
+ * Each attribute has a `def_index` identifying which attribute it is, and
28
+ * `value_bytes` containing the raw little-endian bytes.
29
+ *
30
+ * @param item - An object with an optional `attribute` array (typically a {@link GcItemInput}).
31
+ * @param attrDefIndex - The attribute definition index to look up.
32
+ * @returns The decoded uint32 value, or `undefined` if the attribute is missing or too short.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const musicIndex = getAttributeUint32(gcItem, 166);
37
+ * if (musicIndex) console.log("Music kit ID:", musicIndex);
38
+ * ```
39
+ */
40
+ export declare function getAttributeUint32(item: {
41
+ attribute?: {
42
+ def_index: number;
43
+ value_bytes?: Buffer;
44
+ }[];
45
+ }, attrDefIndex: number): number | undefined;
@@ -0,0 +1,105 @@
1
+ import { getData } from './data-loader.js';
2
+ /**
3
+ * Resolve a raw GC item into a name, image, and category.
4
+ *
5
+ * Resolution priority:
6
+ * 1. Skins (by `def_index` + `paint_index`)
7
+ * 2. Music kits (by attribute 166)
8
+ * 3. Keychains (by attribute 299)
9
+ * 4. Graffiti (by `stickers[0].sticker_id` + attribute 233)
10
+ * 5. Crates / cases / keys (by `def_index`)
11
+ * 6. Collectibles (by `def_index`)
12
+ * 7. Stickers / patches (by `stickers[0].sticker_id`)
13
+ *
14
+ * @param gcItem - The raw GC item to resolve.
15
+ * @returns The resolved item data, or `null` if the item could not be identified.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const result = resolveItem({ def_index: 7, paint_index: 282 });
20
+ * // => { name: "AK-47 | Redline", image: "https://...", category: "skin" }
21
+ * ```
22
+ */
23
+ export function resolveItem(gcItem) {
24
+ const data = getData();
25
+ if (!data)
26
+ return null;
27
+ const defIdx = String(gcItem.def_index);
28
+ const musicIndex = getAttributeUint32(gcItem, 166);
29
+ const graffitiTint = getAttributeUint32(gcItem, 233);
30
+ const keychainIndex = getAttributeUint32(gcItem, 299);
31
+ // 1. Skins: def_index + paint_index
32
+ if (gcItem.paint_index && gcItem.paint_index > 0) {
33
+ const weapon = data.skins[defIdx];
34
+ if (weapon) {
35
+ const skin = weapon[String(gcItem.paint_index)];
36
+ if (skin)
37
+ return { name: skin.name, image: skin.image, category: 'skin' };
38
+ }
39
+ }
40
+ // 2. Music kits: music_index (attribute 166)
41
+ if (musicIndex && musicIndex > 0) {
42
+ const kit = data.music_kits[String(musicIndex)];
43
+ if (kit)
44
+ return { name: kit.name, image: kit.image, category: 'music_kit' };
45
+ }
46
+ // 3. Keychains (charms): keychain_index (attribute 299)
47
+ if (keychainIndex && keychainIndex > 0) {
48
+ const keychain = data.keychains[String(keychainIndex)];
49
+ if (keychain)
50
+ return { name: keychain.name, image: keychain.image, category: 'keychain' };
51
+ }
52
+ // 4. Graffiti: stickers[0].sticker_id + graffiti_tint (attribute 233)
53
+ if (graffitiTint !== undefined && gcItem.stickers?.length) {
54
+ const stickerId = gcItem.stickers[0].sticker_id;
55
+ if (stickerId) {
56
+ const tintedKey = `${stickerId}_${graffitiTint}`;
57
+ const tinted = data.graffiti[tintedKey];
58
+ if (tinted)
59
+ return { name: tinted.name, image: tinted.image, category: 'graffiti' };
60
+ const mono = data.graffiti[String(stickerId)];
61
+ if (mono)
62
+ return { name: mono.name, image: mono.image, category: 'graffiti' };
63
+ }
64
+ }
65
+ // 5. Crates / cases / keys
66
+ const crate = data.crates[defIdx];
67
+ if (crate)
68
+ return { name: crate.name, image: crate.image, category: 'crate' };
69
+ // 6. Collectibles (coins, pins, etc.)
70
+ const collectible = data.collectibles[defIdx];
71
+ if (collectible)
72
+ return { name: collectible.name, image: collectible.image, category: 'collectible' };
73
+ // 7. Stickers/patches as items: use stickers[0].sticker_id
74
+ if (gcItem.stickers?.length) {
75
+ const stickerId = gcItem.stickers[0].sticker_id;
76
+ if (stickerId) {
77
+ const sticker = data.stickers[String(stickerId)];
78
+ if (sticker)
79
+ return { name: sticker.name, image: sticker.image, category: 'sticker' };
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+ /**
85
+ * Read a uint32 value from a raw GC item's attribute[] array.
86
+ *
87
+ * Each attribute has a `def_index` identifying which attribute it is, and
88
+ * `value_bytes` containing the raw little-endian bytes.
89
+ *
90
+ * @param item - An object with an optional `attribute` array (typically a {@link GcItemInput}).
91
+ * @param attrDefIndex - The attribute definition index to look up.
92
+ * @returns The decoded uint32 value, or `undefined` if the attribute is missing or too short.
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * const musicIndex = getAttributeUint32(gcItem, 166);
97
+ * if (musicIndex) console.log("Music kit ID:", musicIndex);
98
+ * ```
99
+ */
100
+ export function getAttributeUint32(item, attrDefIndex) {
101
+ const attrib = (item.attribute || []).find(a => a.def_index === attrDefIndex);
102
+ if (!attrib?.value_bytes || attrib.value_bytes.length < 4)
103
+ return undefined;
104
+ return attrib.value_bytes.readUInt32LE(0);
105
+ }
@@ -0,0 +1,52 @@
1
+ /** Possible CS2 item categories returned by {@link resolveItem}. */
2
+ export type ItemCategory = 'skin' | 'music_kit' | 'keychain' | 'graffiti' | 'crate' | 'collectible' | 'sticker';
3
+ /** The resolved information for a CS2 inventory item. */
4
+ export interface ResolvedItemData {
5
+ /** The human-readable item name (e.g. `"AK-47 | Redline"`). */
6
+ name: string;
7
+ /** URL to the item's image. */
8
+ image: string;
9
+ /** The resolved item category. */
10
+ category: ItemCategory;
11
+ }
12
+ /**
13
+ * Raw GC (Game Coordinator) item input accepted by {@link resolveItem}.
14
+ *
15
+ * This mirrors the relevant fields from the CS2 GC protobuf `CSOEconItem` message.
16
+ */
17
+ export interface GcItemInput {
18
+ /** The item definition index from the GC protobuf message. */
19
+ def_index: number;
20
+ /** The paint/skin index. Non-zero for weapon skins. */
21
+ paint_index?: number;
22
+ /** Sticker slots array. Also used for graffiti and sticker/patch items via `sticker_id`. */
23
+ stickers?: {
24
+ sticker_id?: number;
25
+ }[];
26
+ /**
27
+ * Raw attribute array from the GC message.
28
+ *
29
+ * Used to extract `music_index` (def_index 166), `graffiti_tint` (def_index 233),
30
+ * and `keychain_index` (def_index 299) via {@link getAttributeUint32}.
31
+ */
32
+ attribute?: {
33
+ def_index: number;
34
+ value_bytes?: Buffer;
35
+ }[];
36
+ }
37
+ /** A single entry in the inventory lookup tables. */
38
+ export interface ItemEntry {
39
+ name: string;
40
+ image: string;
41
+ }
42
+ /** The full shape of inventory.json from the API. */
43
+ export interface InventoryData {
44
+ skins: Record<string, Record<string, ItemEntry>>;
45
+ crates: Record<string, ItemEntry>;
46
+ collectibles: Record<string, ItemEntry>;
47
+ stickers: Record<string, ItemEntry>;
48
+ graffiti: Record<string, ItemEntry>;
49
+ music_kits: Record<string, ItemEntry>;
50
+ keychains: Record<string, ItemEntry>;
51
+ highlights: Record<string, ItemEntry>;
52
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "cs2-inventory-resolver",
3
+ "version": "0.1.0",
4
+ "description": "Resolve CS2 Game Coordinator protobuf items into human-readable names, images, and categories",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/",
16
+ "data/"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.0.0",
23
+ "typescript": "^5.9.3"
24
+ }
25
+ }