@vlydev/cs2-masked-inspect-ts 1.0.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/cjs/InspectLink.d.ts +45 -0
  4. package/dist/cjs/InspectLink.d.ts.map +1 -0
  5. package/dist/cjs/InspectLink.js +368 -0
  6. package/dist/cjs/ItemPreviewData.d.ts +59 -0
  7. package/dist/cjs/ItemPreviewData.d.ts.map +1 -0
  8. package/dist/cjs/ItemPreviewData.js +28 -0
  9. package/dist/cjs/Sticker.d.ts +34 -0
  10. package/dist/cjs/Sticker.d.ts.map +1 -0
  11. package/dist/cjs/Sticker.js +19 -0
  12. package/dist/cjs/crc32.d.ts +9 -0
  13. package/dist/cjs/crc32.d.ts.map +1 -0
  14. package/dist/cjs/crc32.js +28 -0
  15. package/dist/cjs/index.d.ts +10 -0
  16. package/dist/cjs/index.d.ts.map +1 -0
  17. package/dist/cjs/index.js +15 -0
  18. package/dist/cjs/proto/reader.d.ts +42 -0
  19. package/dist/cjs/proto/reader.d.ts.map +1 -0
  20. package/dist/cjs/proto/reader.js +105 -0
  21. package/dist/cjs/proto/writer.d.ts +31 -0
  22. package/dist/cjs/proto/writer.d.ts.map +1 -0
  23. package/dist/cjs/proto/writer.js +105 -0
  24. package/dist/esm/InspectLink.d.ts +45 -0
  25. package/dist/esm/InspectLink.d.ts.map +1 -0
  26. package/dist/esm/InspectLink.js +364 -0
  27. package/dist/esm/ItemPreviewData.d.ts +59 -0
  28. package/dist/esm/ItemPreviewData.d.ts.map +1 -0
  29. package/dist/esm/ItemPreviewData.js +24 -0
  30. package/dist/esm/Sticker.d.ts +34 -0
  31. package/dist/esm/Sticker.d.ts.map +1 -0
  32. package/dist/esm/Sticker.js +15 -0
  33. package/dist/esm/crc32.d.ts +9 -0
  34. package/dist/esm/crc32.d.ts.map +1 -0
  35. package/dist/esm/crc32.js +25 -0
  36. package/dist/esm/index.d.ts +10 -0
  37. package/dist/esm/index.d.ts.map +1 -0
  38. package/dist/esm/index.js +6 -0
  39. package/dist/esm/proto/reader.d.ts +42 -0
  40. package/dist/esm/proto/reader.d.ts.map +1 -0
  41. package/dist/esm/proto/reader.js +101 -0
  42. package/dist/esm/proto/writer.d.ts +31 -0
  43. package/dist/esm/proto/writer.d.ts.map +1 -0
  44. package/dist/esm/proto/writer.js +101 -0
  45. package/package.json +43 -0
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Encodes and decodes CS2 masked inspect links.
3
+ *
4
+ * Binary format:
5
+ * [key_byte] [proto_bytes XOR'd with key] [4-byte checksum XOR'd with key]
6
+ *
7
+ * For tool-generated links key_byte = 0x00 (no XOR needed).
8
+ * For native CS2 links key_byte != 0x00 — every byte must be XOR'd before parsing.
9
+ *
10
+ * Checksum:
11
+ * buffer = [0x00] + proto_bytes
12
+ * crc = crc32(buffer)
13
+ * xored = (crc & 0xffff) ^ (len(proto_bytes) * crc) [unsigned 32-bit]
14
+ * checksum = big-endian uint32 of (xored & 0xFFFFFFFF)
15
+ */
16
+ import { ItemPreviewData } from "./ItemPreviewData.js";
17
+ import { Sticker } from "./Sticker.js";
18
+ import { ProtoReader } from "./proto/reader.js";
19
+ import { ProtoWriter } from "./proto/writer.js";
20
+ import { crc32 } from "./crc32.js";
21
+ // ------------------------------------------------------------------
22
+ // Checksum helpers
23
+ // ------------------------------------------------------------------
24
+ /**
25
+ * Compute checksum over [0x00] + proto_bytes.
26
+ * Returns a 4-byte big-endian Uint8Array.
27
+ */
28
+ function computeChecksum(buffer, protoLen) {
29
+ const crcVal = crc32(buffer);
30
+ const val = BigInt(((crcVal & 0xFFFF) ^ (protoLen * crcVal)) >>> 0) & 0xffffffffn;
31
+ const result = new Uint8Array(4);
32
+ const dv = new DataView(result.buffer);
33
+ dv.setUint32(0, Number(val), false); // big-endian
34
+ return result;
35
+ }
36
+ // ------------------------------------------------------------------
37
+ // float32 <-> uint32 reinterpretation
38
+ // ------------------------------------------------------------------
39
+ function float32ToUint32(f) {
40
+ const dv = new DataView(new ArrayBuffer(4));
41
+ dv.setFloat32(0, f, true); // little-endian
42
+ return dv.getUint32(0, true);
43
+ }
44
+ function uint32ToFloat32(u) {
45
+ const dv = new DataView(new ArrayBuffer(4));
46
+ dv.setUint32(0, u >>> 0, true);
47
+ return dv.getFloat32(0, true);
48
+ }
49
+ // ------------------------------------------------------------------
50
+ // Hex encoding / decoding helpers
51
+ // ------------------------------------------------------------------
52
+ function hexToBytes(hex) {
53
+ const bytes = new Uint8Array(hex.length / 2);
54
+ for (let i = 0; i < bytes.length; i++) {
55
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
56
+ }
57
+ return bytes;
58
+ }
59
+ function bytesToHex(bytes) {
60
+ return Array.from(bytes)
61
+ .map(b => b.toString(16).padStart(2, '0'))
62
+ .join('')
63
+ .toUpperCase();
64
+ }
65
+ function concatBytes(...arrays) {
66
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
67
+ const result = new Uint8Array(totalLength);
68
+ let offset = 0;
69
+ for (const arr of arrays) {
70
+ result.set(arr, offset);
71
+ offset += arr.length;
72
+ }
73
+ return result;
74
+ }
75
+ // ------------------------------------------------------------------
76
+ // URL extraction
77
+ // ------------------------------------------------------------------
78
+ const INSPECT_URL_RE = /(?:%20|\s|\+)A([0-9A-Fa-f]+)/i;
79
+ const HYBRID_URL_RE = /S\d+A\d+D([0-9A-Fa-f]+)$/i;
80
+ const CLASSIC_URL_RE = /csgo_econ_action_preview(?:%20|\s)[SM]\d+A\d+D\d+$/i;
81
+ const MASKED_URL_RE = /csgo_econ_action_preview(?:%20|\s)[0-9A-Fa-f]{10,}$/i;
82
+ function extractHex(input) {
83
+ const stripped = input.trim();
84
+ // Hybrid format: S\d+A\d+D<hexproto>
85
+ const mh = stripped.match(HYBRID_URL_RE);
86
+ if (mh && /[A-Fa-f]/.test(mh[1]))
87
+ return mh[1];
88
+ // Classic/market URL: A<hex> preceded by %20, space, or + (A is a prefix marker, not hex).
89
+ // If stripping A yields odd-length hex, A is actually the first byte of the payload —
90
+ // fall through to the pure-masked check below which captures it with A included.
91
+ const m = stripped.match(INSPECT_URL_RE);
92
+ if (m && m[1].length % 2 === 0)
93
+ return m[1];
94
+ // Pure masked format: csgo_econ_action_preview%20<hexblob> (no S/A/M prefix).
95
+ // Also handles payloads whose first hex character happens to be A.
96
+ const mm = stripped.match(/csgo_econ_action_preview(?:%20|\s|\+)([0-9A-Fa-f]{10,})$/i);
97
+ if (mm)
98
+ return mm[1];
99
+ // Bare hex — strip whitespace
100
+ return stripped.replace(/\s+/g, '');
101
+ }
102
+ // ------------------------------------------------------------------
103
+ // Sticker encode / decode
104
+ // ------------------------------------------------------------------
105
+ function encodeSticker(s) {
106
+ const w = new ProtoWriter();
107
+ w.writeUint32(1, s.slot);
108
+ w.writeUint32(2, s.stickerId);
109
+ if (s.wear !== null)
110
+ w.writeFloat32Fixed(3, s.wear);
111
+ if (s.scale !== null)
112
+ w.writeFloat32Fixed(4, s.scale);
113
+ if (s.rotation !== null)
114
+ w.writeFloat32Fixed(5, s.rotation);
115
+ w.writeUint32(6, s.tintId);
116
+ if (s.offsetX !== null)
117
+ w.writeFloat32Fixed(7, s.offsetX);
118
+ if (s.offsetY !== null)
119
+ w.writeFloat32Fixed(8, s.offsetY);
120
+ if (s.offsetZ !== null)
121
+ w.writeFloat32Fixed(9, s.offsetZ);
122
+ w.writeUint32(10, s.pattern);
123
+ if (s.highlightReel != null)
124
+ w.writeUint32(11, s.highlightReel);
125
+ return w.toBytes();
126
+ }
127
+ function decodeSticker(data) {
128
+ const reader = new ProtoReader(data);
129
+ const s = new Sticker();
130
+ for (const f of reader.readAllFields()) {
131
+ switch (f.field) {
132
+ case 1:
133
+ s.slot = Number(f.value);
134
+ break;
135
+ case 2:
136
+ s.stickerId = Number(f.value);
137
+ break;
138
+ case 3: {
139
+ const bytes = f.value;
140
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
141
+ s.wear = dv.getFloat32(0, true);
142
+ break;
143
+ }
144
+ case 4: {
145
+ const bytes = f.value;
146
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
147
+ s.scale = dv.getFloat32(0, true);
148
+ break;
149
+ }
150
+ case 5: {
151
+ const bytes = f.value;
152
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
153
+ s.rotation = dv.getFloat32(0, true);
154
+ break;
155
+ }
156
+ case 6:
157
+ s.tintId = Number(f.value);
158
+ break;
159
+ case 7: {
160
+ const bytes = f.value;
161
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
162
+ s.offsetX = dv.getFloat32(0, true);
163
+ break;
164
+ }
165
+ case 8: {
166
+ const bytes = f.value;
167
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
168
+ s.offsetY = dv.getFloat32(0, true);
169
+ break;
170
+ }
171
+ case 9: {
172
+ const bytes = f.value;
173
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
174
+ s.offsetZ = dv.getFloat32(0, true);
175
+ break;
176
+ }
177
+ case 10:
178
+ s.pattern = Number(f.value);
179
+ break;
180
+ case 11:
181
+ s.highlightReel = Number(f.value);
182
+ break;
183
+ default: break;
184
+ }
185
+ }
186
+ return s;
187
+ }
188
+ // ------------------------------------------------------------------
189
+ // ItemPreviewData encode / decode
190
+ // ------------------------------------------------------------------
191
+ function encodeItem(item) {
192
+ const w = new ProtoWriter();
193
+ w.writeUint32(1, item.accountId);
194
+ w.writeUint64(2, item.itemId);
195
+ w.writeUint32(3, item.defIndex);
196
+ w.writeUint32(4, item.paintIndex);
197
+ w.writeUint32(5, item.rarity);
198
+ w.writeUint32(6, item.quality);
199
+ // paintWear: float32 reinterpreted as uint32 varint
200
+ if (item.paintWear != null) {
201
+ w.writeUint32(7, float32ToUint32(item.paintWear));
202
+ }
203
+ w.writeUint32(8, item.paintSeed);
204
+ w.writeUint32(9, item.killEaterScoreType);
205
+ w.writeUint32(10, item.killEaterValue);
206
+ w.writeString(11, item.customName);
207
+ for (const sticker of item.stickers) {
208
+ w.writeRawBytes(12, encodeSticker(sticker));
209
+ }
210
+ w.writeUint32(13, item.inventory);
211
+ w.writeUint32(14, item.origin);
212
+ w.writeUint32(15, item.questId);
213
+ w.writeUint32(16, item.dropReason);
214
+ w.writeUint32(17, item.musicIndex);
215
+ w.writeInt32(18, item.entIndex);
216
+ w.writeUint32(19, item.petIndex);
217
+ for (const kc of item.keychains) {
218
+ w.writeRawBytes(20, encodeSticker(kc));
219
+ }
220
+ return w.toBytes();
221
+ }
222
+ function decodeItem(data) {
223
+ const reader = new ProtoReader(data);
224
+ const item = new ItemPreviewData();
225
+ for (const f of reader.readAllFields()) {
226
+ switch (f.field) {
227
+ case 1:
228
+ item.accountId = Number(f.value);
229
+ break;
230
+ case 2:
231
+ item.itemId = Number(f.value);
232
+ break;
233
+ case 3:
234
+ item.defIndex = Number(f.value);
235
+ break;
236
+ case 4:
237
+ item.paintIndex = Number(f.value);
238
+ break;
239
+ case 5:
240
+ item.rarity = Number(f.value);
241
+ break;
242
+ case 6:
243
+ item.quality = Number(f.value);
244
+ break;
245
+ case 7:
246
+ item.paintWear = uint32ToFloat32(Number(f.value));
247
+ break;
248
+ case 8:
249
+ item.paintSeed = Number(f.value);
250
+ break;
251
+ case 9:
252
+ item.killEaterScoreType = Number(f.value);
253
+ break;
254
+ case 10:
255
+ item.killEaterValue = Number(f.value);
256
+ break;
257
+ case 11:
258
+ item.customName = new TextDecoder().decode(f.value);
259
+ break;
260
+ case 12:
261
+ item.stickers.push(decodeSticker(f.value));
262
+ break;
263
+ case 13:
264
+ item.inventory = Number(f.value);
265
+ break;
266
+ case 14:
267
+ item.origin = Number(f.value);
268
+ break;
269
+ case 15:
270
+ item.questId = Number(f.value);
271
+ break;
272
+ case 16:
273
+ item.dropReason = Number(f.value);
274
+ break;
275
+ case 17:
276
+ item.musicIndex = Number(f.value);
277
+ break;
278
+ case 18:
279
+ item.entIndex = Number(f.value);
280
+ break;
281
+ case 19:
282
+ item.petIndex = Number(f.value);
283
+ break;
284
+ case 20:
285
+ item.keychains.push(decodeSticker(f.value));
286
+ break;
287
+ default: break;
288
+ }
289
+ }
290
+ return item;
291
+ }
292
+ // ------------------------------------------------------------------
293
+ // Public API
294
+ // ------------------------------------------------------------------
295
+ export class InspectLink {
296
+ /**
297
+ * Encode an ItemPreviewData to an uppercase hex inspect-link payload.
298
+ *
299
+ * The returned string can be appended to a steam:// inspect URL or used
300
+ * standalone. The key_byte is always 0x00 (no XOR applied).
301
+ */
302
+ static serialize(data) {
303
+ if (data.paintWear != null && (data.paintWear < 0.0 || data.paintWear > 1.0)) {
304
+ throw new RangeError(`paintwear must be in [0.0, 1.0], got ${data.paintWear}`);
305
+ }
306
+ if (data.customName != null && data.customName.length > 100) {
307
+ throw new RangeError(`customname must not exceed 100 characters, got ${data.customName.length}`);
308
+ }
309
+ const protoBytes = encodeItem(data);
310
+ const buffer = concatBytes(new Uint8Array([0x00]), protoBytes);
311
+ const checksum = computeChecksum(buffer, protoBytes.length);
312
+ return bytesToHex(concatBytes(buffer, checksum));
313
+ }
314
+ /**
315
+ * Returns true if the link contains a decodable protobuf payload (can be decoded offline).
316
+ */
317
+ static isMasked(link) {
318
+ const s = link.trim();
319
+ if (MASKED_URL_RE.test(s))
320
+ return true;
321
+ const m = s.match(HYBRID_URL_RE);
322
+ return !!(m && /[A-Fa-f]/.test(m[1]));
323
+ }
324
+ /**
325
+ * Returns true if the link is a classic S/A/D inspect URL with decimal did.
326
+ */
327
+ static isClassic(link) {
328
+ return CLASSIC_URL_RE.test(link.trim());
329
+ }
330
+ /**
331
+ * Decode an inspect-link hex payload (or full URL) into an ItemPreviewData.
332
+ *
333
+ * Accepts:
334
+ * - A raw uppercase or lowercase hex string
335
+ * - A full steam://rungame/... inspect URL
336
+ * - A CS2-style csgo://rungame/... URL
337
+ *
338
+ * Handles the XOR obfuscation used in native CS2 links.
339
+ */
340
+ static deserialize(input) {
341
+ const hex = extractHex(input);
342
+ if (hex.length > 4096) {
343
+ throw new RangeError(`Payload too long (max 4096 hex chars): "${input.slice(0, 64)}..."`);
344
+ }
345
+ const raw = hexToBytes(hex);
346
+ if (raw.length < 6) {
347
+ throw new TypeError(`Payload too short or invalid hex: "${input}"`);
348
+ }
349
+ const key = raw[0];
350
+ let decrypted;
351
+ if (key === 0) {
352
+ decrypted = raw;
353
+ }
354
+ else {
355
+ decrypted = new Uint8Array(raw.length);
356
+ for (let i = 0; i < raw.length; i++) {
357
+ decrypted[i] = raw[i] ^ key;
358
+ }
359
+ }
360
+ // Layout: [key_byte] [proto_bytes] [4-byte checksum]
361
+ const protoBytes = decrypted.slice(1, decrypted.length - 4);
362
+ return decodeItem(protoBytes);
363
+ }
364
+ }
@@ -0,0 +1,59 @@
1
+ import { Sticker } from './Sticker.ts';
2
+ /**
3
+ * Represents a CS2 item as encoded in an inspect link.
4
+ *
5
+ * Fields map directly to the CEconItemPreviewDataBlock protobuf message
6
+ * used by the CS2 game coordinator.
7
+ *
8
+ * paintWear is stored as a float32 (IEEE 754). On the wire it is reinterpreted
9
+ * as a uint32 — this class always exposes it as a JavaScript number for convenience.
10
+ *
11
+ * accountId and itemId may be large integers; they are stored as number but
12
+ * can also accept bigint for construction (values > 2^53 should use bigint).
13
+ */
14
+ export interface ItemPreviewDataInit {
15
+ accountId?: number | bigint;
16
+ itemId?: number | bigint;
17
+ defIndex?: number;
18
+ paintIndex?: number;
19
+ rarity?: number;
20
+ quality?: number;
21
+ paintWear?: number | null;
22
+ paintSeed?: number;
23
+ killEaterScoreType?: number;
24
+ killEaterValue?: number;
25
+ customName?: string;
26
+ stickers?: Sticker[];
27
+ inventory?: number;
28
+ origin?: number;
29
+ questId?: number;
30
+ dropReason?: number;
31
+ musicIndex?: number;
32
+ entIndex?: number;
33
+ petIndex?: number;
34
+ keychains?: Sticker[];
35
+ }
36
+ export declare class ItemPreviewData {
37
+ accountId: number | bigint;
38
+ itemId: number | bigint;
39
+ defIndex: number;
40
+ paintIndex: number;
41
+ rarity: number;
42
+ quality: number;
43
+ paintWear: number | null;
44
+ paintSeed: number;
45
+ killEaterScoreType: number;
46
+ killEaterValue: number;
47
+ customName: string;
48
+ stickers: Sticker[];
49
+ inventory: number;
50
+ origin: number;
51
+ questId: number;
52
+ dropReason: number;
53
+ musicIndex: number;
54
+ entIndex: number;
55
+ petIndex: number;
56
+ keychains: Sticker[];
57
+ constructor({ accountId, itemId, defIndex, paintIndex, rarity, quality, paintWear, paintSeed, killEaterScoreType, killEaterValue, customName, stickers, inventory, origin, questId, dropReason, musicIndex, entIndex, petIndex, keychains, }?: ItemPreviewDataInit);
58
+ }
59
+ //# sourceMappingURL=ItemPreviewData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemPreviewData.d.ts","sourceRoot":"","sources":["../../src/ItemPreviewData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;CACvB;AAED,qBAAa,eAAe;IAC1B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,EAAE,CAAC;gBAET,EACV,SAAa,EACb,MAAU,EACV,QAAY,EACZ,UAAc,EACd,MAAU,EACV,OAAW,EACX,SAAgB,EAChB,SAAa,EACb,kBAAsB,EACtB,cAAkB,EAClB,UAAe,EACf,QAAa,EACb,SAAa,EACb,MAAU,EACV,OAAW,EACX,UAAc,EACd,UAAc,EACd,QAAY,EACZ,QAAY,EACZ,SAAc,GACf,GAAE,mBAAwB;CAsB5B"}
@@ -0,0 +1,24 @@
1
+ export class ItemPreviewData {
2
+ constructor({ accountId = 0, itemId = 0, defIndex = 0, paintIndex = 0, rarity = 0, quality = 0, paintWear = null, paintSeed = 0, killEaterScoreType = 0, killEaterValue = 0, customName = '', stickers = [], inventory = 0, origin = 0, questId = 0, dropReason = 0, musicIndex = 0, entIndex = 0, petIndex = 0, keychains = [], } = {}) {
3
+ this.accountId = accountId;
4
+ this.itemId = itemId;
5
+ this.defIndex = defIndex;
6
+ this.paintIndex = paintIndex;
7
+ this.rarity = rarity;
8
+ this.quality = quality;
9
+ this.paintWear = paintWear;
10
+ this.paintSeed = paintSeed;
11
+ this.killEaterScoreType = killEaterScoreType;
12
+ this.killEaterValue = killEaterValue;
13
+ this.customName = customName;
14
+ this.stickers = stickers;
15
+ this.inventory = inventory;
16
+ this.origin = origin;
17
+ this.questId = questId;
18
+ this.dropReason = dropReason;
19
+ this.musicIndex = musicIndex;
20
+ this.entIndex = entIndex;
21
+ this.petIndex = petIndex;
22
+ this.keychains = keychains;
23
+ }
24
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Represents a sticker or keychain applied to a CS2 item.
3
+ *
4
+ * Maps to the Sticker protobuf message nested inside CEconItemPreviewDataBlock.
5
+ * The same message is used for both stickers (field 12) and keychains (field 20).
6
+ */
7
+ export interface StickerInit {
8
+ slot?: number;
9
+ stickerId?: number;
10
+ wear?: number | null;
11
+ scale?: number | null;
12
+ rotation?: number | null;
13
+ tintId?: number;
14
+ offsetX?: number | null;
15
+ offsetY?: number | null;
16
+ offsetZ?: number | null;
17
+ pattern?: number;
18
+ highlightReel?: number | null;
19
+ }
20
+ export declare class Sticker {
21
+ slot: number;
22
+ stickerId: number;
23
+ wear: number | null;
24
+ scale: number | null;
25
+ rotation: number | null;
26
+ tintId: number;
27
+ offsetX: number | null;
28
+ offsetY: number | null;
29
+ offsetZ: number | null;
30
+ pattern: number;
31
+ highlightReel: number | null;
32
+ constructor({ slot, stickerId, wear, scale, rotation, tintId, offsetX, offsetY, offsetZ, pattern, highlightReel, }?: StickerInit);
33
+ }
34
+ //# sourceMappingURL=Sticker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sticker.d.ts","sourceRoot":"","sources":["../../src/Sticker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,OAAO;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;gBAEjB,EACV,IAAQ,EACR,SAAa,EACb,IAAW,EACX,KAAY,EACZ,QAAe,EACf,MAAU,EACV,OAAc,EACd,OAAc,EACd,OAAc,EACd,OAAW,EACX,aAAoB,GACrB,GAAE,WAAgB;CAapB"}
@@ -0,0 +1,15 @@
1
+ export class Sticker {
2
+ constructor({ slot = 0, stickerId = 0, wear = null, scale = null, rotation = null, tintId = 0, offsetX = null, offsetY = null, offsetZ = null, pattern = 0, highlightReel = null, } = {}) {
3
+ this.slot = slot;
4
+ this.stickerId = stickerId;
5
+ this.wear = wear;
6
+ this.scale = scale;
7
+ this.rotation = rotation;
8
+ this.tintId = tintId;
9
+ this.offsetX = offsetX;
10
+ this.offsetY = offsetY;
11
+ this.offsetZ = offsetZ;
12
+ this.pattern = pattern;
13
+ this.highlightReel = highlightReel;
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CRC32 implementation using standard polynomial 0xEDB88320 (same as zlib/PHP crc32).
3
+ */
4
+ /**
5
+ * Compute CRC32 of a Uint8Array.
6
+ * @returns unsigned 32-bit CRC32
7
+ */
8
+ export declare function crc32(buf: Uint8Array): number;
9
+ //# sourceMappingURL=crc32.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crc32.d.ts","sourceRoot":"","sources":["../../src/crc32.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAM7C"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * CRC32 implementation using standard polynomial 0xEDB88320 (same as zlib/PHP crc32).
3
+ */
4
+ const CRC32_TABLE = (() => {
5
+ const table = new Uint32Array(256);
6
+ for (let i = 0; i < 256; i++) {
7
+ let c = i;
8
+ for (let j = 0; j < 8; j++) {
9
+ c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
10
+ }
11
+ table[i] = c;
12
+ }
13
+ return table;
14
+ })();
15
+ /**
16
+ * Compute CRC32 of a Uint8Array.
17
+ * @returns unsigned 32-bit CRC32
18
+ */
19
+ export function crc32(buf) {
20
+ let crc = 0xFFFFFFFF;
21
+ for (let i = 0; i < buf.length; i++) {
22
+ crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ buf[i]) & 0xFF];
23
+ }
24
+ return (crc ^ 0xFFFFFFFF) >>> 0;
25
+ }
@@ -0,0 +1,10 @@
1
+ export { InspectLink } from './InspectLink.ts';
2
+ export { ItemPreviewData } from './ItemPreviewData.ts';
3
+ export type { ItemPreviewDataInit } from './ItemPreviewData.ts';
4
+ export { Sticker } from './Sticker.ts';
5
+ export type { StickerInit } from './Sticker.ts';
6
+ export { crc32 } from './crc32.ts';
7
+ export { ProtoReader } from './proto/reader.ts';
8
+ export type { ProtoField } from './proto/reader.ts';
9
+ export { ProtoWriter } from './proto/writer.ts';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { InspectLink } from "./InspectLink.js";
2
+ export { ItemPreviewData } from "./ItemPreviewData.js";
3
+ export { Sticker } from "./Sticker.js";
4
+ export { crc32 } from "./crc32.js";
5
+ export { ProtoReader } from "./proto/reader.js";
6
+ export { ProtoWriter } from "./proto/writer.js";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pure TypeScript protobuf binary reader.
3
+ *
4
+ * Implements the subset of wire types needed for CEconItemPreviewDataBlock:
5
+ * - Wire type 0: varint (uint32, uint64, int32)
6
+ * - Wire type 2: length-delimited (string, bytes, nested messages)
7
+ * - Wire type 5: 32-bit fixed (float32)
8
+ */
9
+ export declare const WIRE_VARINT = 0;
10
+ export declare const WIRE_64BIT = 1;
11
+ export declare const WIRE_LEN = 2;
12
+ export declare const WIRE_32BIT = 5;
13
+ export interface ProtoField {
14
+ field: number;
15
+ wire: number;
16
+ value: bigint | Uint8Array;
17
+ }
18
+ export declare class ProtoReader {
19
+ private readonly _data;
20
+ private _pos;
21
+ constructor(data: Uint8Array);
22
+ get pos(): number;
23
+ remaining(): number;
24
+ readByte(): number;
25
+ readBytes(n: number): Uint8Array;
26
+ /**
27
+ * Read a base-128 varint.
28
+ * Returns a BigInt for 64-bit range safety; callers convert as needed.
29
+ */
30
+ readVarint(): bigint;
31
+ /**
32
+ * Read tag and return [fieldNumber, wireType].
33
+ */
34
+ readTag(): [number, number];
35
+ readLengthDelimited(): Uint8Array;
36
+ /**
37
+ * Read all fields until EOF.
38
+ * Max 100 fields enforced.
39
+ */
40
+ readAllFields(): ProtoField[];
41
+ }
42
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../src/proto/reader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAK,CAAC;AAC7B,eAAO,MAAM,QAAQ,IAAO,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAK,CAAC;AAE7B,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;CAC5B;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,IAAI,CAAS;gBAET,IAAI,EAAE,UAAU;IAK5B,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,SAAS,IAAI,MAAM;IAInB,QAAQ,IAAI,MAAM;IAOlB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU;IAWhC;;;OAGG;IACH,UAAU,IAAI,MAAM;IAiBpB;;OAEG;IACH,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IAK3B,mBAAmB,IAAI,UAAU;IAKjC;;;OAGG;IACH,aAAa,IAAI,UAAU,EAAE;CAmC9B"}