cs2-inventory-resolver 0.3.8 → 0.4.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/LICENSE +21 -21
- package/README.md +91 -78
- package/data/inventory.json +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/resolver.js +26 -0
- package/dist/resolver.test.js +28 -0
- package/dist/types.d.ts +23 -1
- package/package.json +39 -39
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { resolveItem, getAttributeUint32 } from './resolver.js';
|
|
2
|
-
export type { ItemEntity, ResolvedItemData, GcItemInput, ItemEntry, InventoryData } from './types.js';
|
|
2
|
+
export type { ItemEntity, TradeStatus, ResolvedItemData, GcItemInput, ItemEntry, InventoryData } from './types.js';
|
package/dist/resolver.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
import { getData } from './data-loader.js';
|
|
2
|
+
/** The `trade_protected_escrow_date` attribute def_index. */
|
|
3
|
+
const TRADE_PROTECTED_ESCROW_DATE = 312;
|
|
4
|
+
/**
|
|
5
|
+
* Derive the trade state of an item instance from attribute 312
|
|
6
|
+
* (`trade_protected_escrow_date`).
|
|
7
|
+
*
|
|
8
|
+
* - Attribute absent → `'tradable'`.
|
|
9
|
+
* - Attribute present and `0` → `'market_listed'` (listed on the Steam
|
|
10
|
+
* Community Market, kept in inventory until it sells; no clear date).
|
|
11
|
+
* - Attribute present and a future timestamp → `'trade_hold'`, with the escrow
|
|
12
|
+
* expiry returned as an ISO 8601 string.
|
|
13
|
+
*/
|
|
14
|
+
function resolveTradeStatus(gcItem) {
|
|
15
|
+
const escrow = getAttributeUint32(gcItem, TRADE_PROTECTED_ESCROW_DATE);
|
|
16
|
+
if (escrow === undefined)
|
|
17
|
+
return { status: 'tradable', trade_hold_expires: null };
|
|
18
|
+
if (escrow === 0)
|
|
19
|
+
return { status: 'market_listed', trade_hold_expires: null };
|
|
20
|
+
return {
|
|
21
|
+
status: 'trade_hold',
|
|
22
|
+
trade_hold_expires: new Date(escrow * 1000).toISOString(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
2
25
|
/**
|
|
3
26
|
* Return the wear tier name for a given paint wear float.
|
|
4
27
|
*
|
|
@@ -51,12 +74,15 @@ function buildSkinName(name, gcItem) {
|
|
|
51
74
|
}
|
|
52
75
|
/** Build a {@link ResolvedItemData} from a matched inventory entry. */
|
|
53
76
|
function makeResult(entry, gcItem, entity) {
|
|
77
|
+
const { status, trade_hold_expires } = resolveTradeStatus(gcItem);
|
|
54
78
|
return {
|
|
55
79
|
name: entity === 'skin' ? buildSkinName(entry.name, gcItem) : entry.name,
|
|
56
80
|
image: entry.image,
|
|
57
81
|
entity,
|
|
58
82
|
rarity: entry.rarity,
|
|
59
83
|
marketable: entry.marketable,
|
|
84
|
+
status,
|
|
85
|
+
trade_hold_expires,
|
|
60
86
|
};
|
|
61
87
|
}
|
|
62
88
|
/**
|
package/dist/resolver.test.js
CHANGED
|
@@ -345,6 +345,34 @@ describe('resolveItem — wear-name boundaries', () => {
|
|
|
345
345
|
});
|
|
346
346
|
});
|
|
347
347
|
// ---------------------------------------------------------------------------
|
|
348
|
+
// Trade status (attribute 312 — trade_protected_escrow_date)
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
describe('resolveItem — trade status', () => {
|
|
351
|
+
const skin = { def_index: 7, paint_index: 282 };
|
|
352
|
+
it('is "tradable" when attribute 312 is absent', () => {
|
|
353
|
+
const result = resolveItem({ ...skin });
|
|
354
|
+
expect(result.status).toBe('tradable');
|
|
355
|
+
expect(result.trade_hold_expires).toBeNull();
|
|
356
|
+
});
|
|
357
|
+
it('is "market_listed" when attribute 312 is 0', () => {
|
|
358
|
+
const result = resolveItem({ ...skin, attribute: [makeAttr(312, 0)] });
|
|
359
|
+
expect(result.status).toBe('market_listed');
|
|
360
|
+
expect(result.trade_hold_expires).toBeNull();
|
|
361
|
+
});
|
|
362
|
+
it('is "trade_hold" with an ISO expiry when attribute 312 is a future date', () => {
|
|
363
|
+
// 1781161200 = 2026-06-11T07:00:00.000Z
|
|
364
|
+
const result = resolveItem({ ...skin, attribute: [makeAttr(312, 1781161200)] });
|
|
365
|
+
expect(result.status).toBe('trade_hold');
|
|
366
|
+
expect(result.trade_hold_expires).toBe('2026-06-11T07:00:00.000Z');
|
|
367
|
+
});
|
|
368
|
+
it('resolves trade status for non-skin entities too', () => {
|
|
369
|
+
const crateId = firstKey(data.crates);
|
|
370
|
+
const result = resolveItem({ def_index: crateId, attribute: [makeAttr(312, 0)] });
|
|
371
|
+
expect(result.entity).toBe('crate');
|
|
372
|
+
expect(result.status).toBe('market_listed');
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
348
376
|
// Numeric edge cases
|
|
349
377
|
// ---------------------------------------------------------------------------
|
|
350
378
|
describe('resolveItem — numeric edge cases', () => {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
/** Possible CS2 item entity types returned by {@link resolveItem}. */
|
|
2
2
|
export type ItemEntity = 'skin' | 'music_kit' | 'highlight' | 'keychain' | 'graffiti' | 'crate' | 'key' | 'collectible' | 'agent' | 'tool' | 'patch' | 'sticker';
|
|
3
|
+
/**
|
|
4
|
+
* Current trade state of a specific item instance, derived from attribute 312
|
|
5
|
+
* (`trade_protected_escrow_date`).
|
|
6
|
+
*
|
|
7
|
+
* - `'tradable'` — no hold; the item can be freely traded and moved to/from storage.
|
|
8
|
+
* - `'market_listed'` — listed on the Steam Community Market and kept in the
|
|
9
|
+
* inventory until it sells (escrow date is `0`).
|
|
10
|
+
* - `'trade_hold'` — under a trade-protection / escrow hold (escrow date is a
|
|
11
|
+
* future timestamp).
|
|
12
|
+
*
|
|
13
|
+
* Items that are `'market_listed'` or `'trade_hold'` cannot be moved into or out
|
|
14
|
+
* of a storage unit.
|
|
15
|
+
*/
|
|
16
|
+
export type TradeStatus = 'tradable' | 'market_listed' | 'trade_hold';
|
|
3
17
|
/** The resolved information for a CS2 inventory item. */
|
|
4
18
|
export interface ResolvedItemData {
|
|
5
19
|
/** The human-readable item name (e.g. `"AK-47 | Redline"`). */
|
|
@@ -16,6 +30,13 @@ export interface ResolvedItemData {
|
|
|
16
30
|
} | null;
|
|
17
31
|
/** Whether the item is marketable on the Steam Community Market. */
|
|
18
32
|
marketable: boolean;
|
|
33
|
+
/** Current trade state of this specific item instance. See {@link TradeStatus}. */
|
|
34
|
+
status: TradeStatus;
|
|
35
|
+
/**
|
|
36
|
+
* When a trade hold expires, as an ISO 8601 string, or `null`.
|
|
37
|
+
* Always `null` for `'tradable'` and `'market_listed'` (held until sold).
|
|
38
|
+
*/
|
|
39
|
+
trade_hold_expires: string | null;
|
|
19
40
|
}
|
|
20
41
|
/**
|
|
21
42
|
* Raw GC (Game Coordinator) item input accepted by {@link resolveItem}.
|
|
@@ -39,7 +60,8 @@ export interface GcItemInput {
|
|
|
39
60
|
* Raw attribute array from the GC message.
|
|
40
61
|
*
|
|
41
62
|
* Used to extract `music_index` (def_index 166), `graffiti_tint` (def_index 233),
|
|
42
|
-
* `keychain_index` (def_index 299),
|
|
63
|
+
* `keychain_index` (def_index 299), `highlight_index` (def_index 314), and the
|
|
64
|
+
* `trade_protected_escrow_date` (def_index 312) via {@link getAttributeUint32}.
|
|
43
65
|
*/
|
|
44
66
|
attribute?: {
|
|
45
67
|
def_index: number;
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cs2-inventory-resolver",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Resolve CS2 Game Coordinator protobuf items into human-readable names, images, and categories",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"cs2",
|
|
7
|
-
"csgo",
|
|
8
|
-
"counter-strike",
|
|
9
|
-
"steam",
|
|
10
|
-
"inventory",
|
|
11
|
-
"skins",
|
|
12
|
-
"game-coordinator",
|
|
13
|
-
"protobuf",
|
|
14
|
-
"resolver",
|
|
15
|
-
"valve"
|
|
16
|
-
],
|
|
17
|
-
"type": "module",
|
|
18
|
-
"main": "./dist/index.js",
|
|
19
|
-
"types": "./dist/index.d.ts",
|
|
20
|
-
"exports": {
|
|
21
|
-
".": {
|
|
22
|
-
"types": "./dist/index.d.ts",
|
|
23
|
-
"default": "./dist/index.js"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"dist/",
|
|
28
|
-
"data/"
|
|
29
|
-
],
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "tsc",
|
|
32
|
-
"test": "vitest run"
|
|
33
|
-
},
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@types/node": "^22.0.0",
|
|
36
|
-
"typescript": "^5.9.3",
|
|
37
|
-
"vitest": "^3.0.0"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "cs2-inventory-resolver",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Resolve CS2 Game Coordinator protobuf items into human-readable names, images, and categories",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cs2",
|
|
7
|
+
"csgo",
|
|
8
|
+
"counter-strike",
|
|
9
|
+
"steam",
|
|
10
|
+
"inventory",
|
|
11
|
+
"skins",
|
|
12
|
+
"game-coordinator",
|
|
13
|
+
"protobuf",
|
|
14
|
+
"resolver",
|
|
15
|
+
"valve"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/",
|
|
28
|
+
"data/"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"test": "vitest run"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.0.0",
|
|
36
|
+
"typescript": "^5.9.3",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|