@csfloat/cs2-inspect-serializer 1.0.1 → 1.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CS2 Inspect Link Serializer
2
2
 
3
- Lightweight serializer for CS2 inspect links. Fork of the package
3
+ Lightweight serializer and decoder for CS2 inspect links. Fork of the package
4
4
  [cs2-inspect-create](https://github.com/candyboyz/cs2-inspect-create).
5
5
 
6
6
  # Installation
@@ -13,6 +13,26 @@ npm i @csfloat/cs2-inspect-serializer
13
13
 
14
14
  See the [tests](tests/gen.test.ts) for examples.
15
15
 
16
+ ```ts
17
+ import { decodeHex, decodeLink, generateHex, generateLink } from "@csfloat/cs2-inspect-serializer";
18
+
19
+ const props = {
20
+ defindex: 7,
21
+ paintindex: 474,
22
+ paintseed: 306,
23
+ paintwear: 0.6336590647697449,
24
+ rarity: 6,
25
+ stickers: [],
26
+ keychains: [],
27
+ };
28
+
29
+ const hex = generateHex(props);
30
+ const link = generateLink(props);
31
+
32
+ decodeHex(hex);
33
+ decodeLink(link);
34
+ ```
35
+
16
36
  # Development
17
37
 
18
38
  ```bash
package/dist/index.d.mts CHANGED
@@ -149,6 +149,9 @@ interface CEconItemPreviewDataBlock_Sticker {
149
149
  */
150
150
  declare const CEconItemPreviewDataBlock_Sticker: CEconItemPreviewDataBlock_Sticker$Type;
151
151
 
152
+ declare const decodeHex: (hex: string) => CEconItemPreviewDataBlock;
153
+ declare const decodeLink: (link: string) => CEconItemPreviewDataBlock;
154
+
152
155
  declare const previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
153
156
  /**
154
157
  * Creates the hex representation of the inspect data
@@ -163,4 +166,4 @@ declare const generateHex: ({ paintwear, ...props }: CEconItemPreviewDataBlock)
163
166
  */
164
167
  declare const generateLink: (props: CEconItemPreviewDataBlock) => string;
165
168
 
166
- export { generateHex, generateLink, previewLink };
169
+ export { CEconItemPreviewDataBlock, decodeHex, decodeLink, generateHex, generateLink, previewLink };
package/dist/index.d.ts CHANGED
@@ -149,6 +149,9 @@ interface CEconItemPreviewDataBlock_Sticker {
149
149
  */
150
150
  declare const CEconItemPreviewDataBlock_Sticker: CEconItemPreviewDataBlock_Sticker$Type;
151
151
 
152
+ declare const decodeHex: (hex: string) => CEconItemPreviewDataBlock;
153
+ declare const decodeLink: (link: string) => CEconItemPreviewDataBlock;
154
+
152
155
  declare const previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
153
156
  /**
154
157
  * Creates the hex representation of the inspect data
@@ -163,4 +166,4 @@ declare const generateHex: ({ paintwear, ...props }: CEconItemPreviewDataBlock)
163
166
  */
164
167
  declare const generateLink: (props: CEconItemPreviewDataBlock) => string;
165
168
 
166
- export { generateHex, generateLink, previewLink };
169
+ export { CEconItemPreviewDataBlock, decodeHex, decodeLink, generateHex, generateLink, previewLink };
package/dist/index.js CHANGED
@@ -30,6 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ CEconItemPreviewDataBlock: () => CEconItemPreviewDataBlock,
34
+ decodeHex: () => decodeHex,
35
+ decodeLink: () => decodeLink,
33
36
  generateHex: () => generateHex,
34
37
  generateLink: () => generateLink,
35
38
  previewLink: () => previewLink
@@ -289,27 +292,125 @@ var CEconItemPreviewDataBlock_Sticker$Type = class extends import_runtime.Messag
289
292
  var CEconItemPreviewDataBlock_Sticker = new CEconItemPreviewDataBlock_Sticker$Type();
290
293
 
291
294
  // src/index.ts
295
+ var import_buffer3 = require("buffer");
296
+
297
+ // src/decode.ts
298
+ var import_buffer2 = require("buffer");
299
+
300
+ // src/inspect-payload.ts
292
301
  var import_crc_32 = __toESM(require("crc-32"));
293
302
  var import_buffer = require("buffer");
294
- var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
295
303
  var floatToBytes = (floatValue) => {
296
- const floatArray = new Float32Array(1);
297
- floatArray[0] = floatValue;
298
- const byteArray = new Uint32Array(floatArray.buffer);
299
- return byteArray[0];
304
+ const buffer = new ArrayBuffer(4);
305
+ const view = new DataView(buffer);
306
+ view.setFloat32(0, floatValue, true);
307
+ return view.getUint32(0, true);
308
+ };
309
+ var bytesToFloat = (uintValue) => {
310
+ const buffer = new ArrayBuffer(4);
311
+ const view = new DataView(buffer);
312
+ view.setUint32(0, uintValue, true);
313
+ return view.getFloat32(0, true);
314
+ };
315
+ var getChecksum = (payload) => {
316
+ const bufferPayload = import_buffer.Buffer.concat([Uint8Array.from([0]), payload]);
317
+ const crc = import_crc_32.default.buf(bufferPayload);
318
+ const x_crc = crc & 65535 ^ payload.byteLength * crc;
319
+ return (x_crc & 4294967295) >>> 0;
300
320
  };
321
+
322
+ // src/decode.ts
323
+ var normalizeDecodedEcon = (econ) => {
324
+ return {
325
+ ...econ,
326
+ paintwear: econ.paintwear === void 0 ? void 0 : bytesToFloat(econ.paintwear)
327
+ };
328
+ };
329
+ var hasDecodedInspectPayload = (econ) => {
330
+ return econ.itemid !== void 0 || econ.defindex !== void 0 || econ.paintindex !== void 0 || econ.paintseed !== void 0 || econ.stickers.length > 0 || econ.keychains.length > 0;
331
+ };
332
+ var assertValidHex = (hex) => {
333
+ if (!/^[0-9A-F]+$/i.test(hex) || hex.length % 2 !== 0) {
334
+ throw new Error("Invalid inspect hex payload");
335
+ }
336
+ };
337
+ var decodeURIComponentSafely = (value) => {
338
+ try {
339
+ return decodeURIComponent(value);
340
+ } catch {
341
+ return value;
342
+ }
343
+ };
344
+ var extractHexFromLink = (link) => {
345
+ const decodedLink = decodeURIComponentSafely(link.trim());
346
+ const linkMatch = decodedLink.match(
347
+ /^(?:steam:\/\/(?:run|rungame)\/730\/(?:76561202255233023\/)?\/?)?\+?csgo_econ_action_preview\s+([0-9A-F]+)$/i
348
+ );
349
+ if (linkMatch?.[1]) {
350
+ assertValidHex(linkMatch[1]);
351
+ return linkMatch[1];
352
+ }
353
+ throw new Error("Invalid inspect link");
354
+ };
355
+ var decodePayload = (payload, isValidPayload) => {
356
+ const econ = normalizeDecodedEcon(CEconItemPreviewDataBlock.fromBinary(payload));
357
+ if (!isValidPayload(econ)) {
358
+ throw new Error("Invalid inspect hex payload");
359
+ }
360
+ return econ;
361
+ };
362
+ var decodeWrappedBuffer = (buffer) => {
363
+ if (buffer.length < 5 || buffer[0] !== 0) {
364
+ throw new Error("Invalid inspect hex payload");
365
+ }
366
+ const payload = buffer.subarray(1, -4);
367
+ const expectedChecksum = buffer.readUInt32BE(buffer.length - 4);
368
+ const actualChecksum = getChecksum(payload);
369
+ if (expectedChecksum !== actualChecksum) {
370
+ throw new Error("Inspect hex checksum mismatch");
371
+ }
372
+ return decodePayload(payload, hasDecodedInspectPayload);
373
+ };
374
+ var isDecodedMaskedInspectPayload = (econ) => {
375
+ return econ.itemid !== void 0 && econ.defindex !== void 0 && econ.paintindex !== void 0 && econ.inventory !== void 0 && econ.origin !== void 0;
376
+ };
377
+ var decodeMaskedBuffer = (buffer) => {
378
+ if (buffer.length < 5) {
379
+ throw new Error("Invalid inspect hex payload");
380
+ }
381
+ const unmaskedBuffer = xorMaskBuffer(buffer, buffer[0]);
382
+ if (unmaskedBuffer[0] !== 0) {
383
+ throw new Error("Invalid inspect hex payload");
384
+ }
385
+ return decodePayload(unmaskedBuffer.subarray(1, -4), isDecodedMaskedInspectPayload);
386
+ };
387
+ var xorMaskBuffer = (buffer, key) => {
388
+ return import_buffer2.Buffer.from(buffer.map((byte) => byte ^ key));
389
+ };
390
+ var decodeHex = (hex) => {
391
+ const normalizedHex = hex.trim();
392
+ assertValidHex(normalizedHex);
393
+ const buffer = import_buffer2.Buffer.from(normalizedHex, "hex");
394
+ if (buffer[0] === 0) {
395
+ return decodeWrappedBuffer(buffer);
396
+ }
397
+ return decodeMaskedBuffer(buffer);
398
+ };
399
+ var decodeLink = (link) => {
400
+ return decodeHex(extractHexFromLink(link));
401
+ };
402
+
403
+ // src/index.ts
404
+ var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
301
405
  var generateHex = ({ paintwear = 1e-3, ...props }) => {
302
406
  const econ = {
303
407
  ...props,
304
408
  paintwear: floatToBytes(paintwear)
305
409
  };
306
410
  const payload = CEconItemPreviewDataBlock.toBinary(econ);
307
- const bufferPayload = import_buffer.Buffer.concat([Uint8Array.from([0]), payload]);
308
- const crc = import_crc_32.default.buf(bufferPayload);
309
- const x_crc = crc & 65535 ^ payload.byteLength * crc;
310
- const crcBuffer = import_buffer.Buffer.alloc(4);
311
- crcBuffer.writeUInt32BE((x_crc & 4294967295) >>> 0, 0);
312
- return import_buffer.Buffer.concat([bufferPayload, crcBuffer]).toString("hex").toUpperCase();
411
+ const crcBuffer = import_buffer3.Buffer.alloc(4);
412
+ crcBuffer.writeUInt32BE(getChecksum(payload), 0);
413
+ return import_buffer3.Buffer.concat([Uint8Array.from([0]), payload, crcBuffer]).toString("hex").toUpperCase();
313
414
  };
314
415
  var generateLink = (props) => {
315
416
  const hex = generateHex(props);
@@ -317,6 +418,9 @@ var generateLink = (props) => {
317
418
  };
318
419
  // Annotate the CommonJS export names for ESM import in node:
319
420
  0 && (module.exports = {
421
+ CEconItemPreviewDataBlock,
422
+ decodeHex,
423
+ decodeLink,
320
424
  generateHex,
321
425
  generateLink,
322
426
  previewLink
package/dist/index.mjs CHANGED
@@ -251,33 +251,134 @@ var CEconItemPreviewDataBlock_Sticker$Type = class extends MessageType {
251
251
  var CEconItemPreviewDataBlock_Sticker = new CEconItemPreviewDataBlock_Sticker$Type();
252
252
 
253
253
  // src/index.ts
254
+ import { Buffer as Buffer3 } from "buffer";
255
+
256
+ // src/decode.ts
257
+ import { Buffer as Buffer2 } from "buffer";
258
+
259
+ // src/inspect-payload.ts
254
260
  import CRC32 from "crc-32";
255
261
  import { Buffer } from "buffer";
256
- var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
257
262
  var floatToBytes = (floatValue) => {
258
- const floatArray = new Float32Array(1);
259
- floatArray[0] = floatValue;
260
- const byteArray = new Uint32Array(floatArray.buffer);
261
- return byteArray[0];
263
+ const buffer = new ArrayBuffer(4);
264
+ const view = new DataView(buffer);
265
+ view.setFloat32(0, floatValue, true);
266
+ return view.getUint32(0, true);
267
+ };
268
+ var bytesToFloat = (uintValue) => {
269
+ const buffer = new ArrayBuffer(4);
270
+ const view = new DataView(buffer);
271
+ view.setUint32(0, uintValue, true);
272
+ return view.getFloat32(0, true);
273
+ };
274
+ var getChecksum = (payload) => {
275
+ const bufferPayload = Buffer.concat([Uint8Array.from([0]), payload]);
276
+ const crc = CRC32.buf(bufferPayload);
277
+ const x_crc = crc & 65535 ^ payload.byteLength * crc;
278
+ return (x_crc & 4294967295) >>> 0;
262
279
  };
280
+
281
+ // src/decode.ts
282
+ var normalizeDecodedEcon = (econ) => {
283
+ return {
284
+ ...econ,
285
+ paintwear: econ.paintwear === void 0 ? void 0 : bytesToFloat(econ.paintwear)
286
+ };
287
+ };
288
+ var hasDecodedInspectPayload = (econ) => {
289
+ return econ.itemid !== void 0 || econ.defindex !== void 0 || econ.paintindex !== void 0 || econ.paintseed !== void 0 || econ.stickers.length > 0 || econ.keychains.length > 0;
290
+ };
291
+ var assertValidHex = (hex) => {
292
+ if (!/^[0-9A-F]+$/i.test(hex) || hex.length % 2 !== 0) {
293
+ throw new Error("Invalid inspect hex payload");
294
+ }
295
+ };
296
+ var decodeURIComponentSafely = (value) => {
297
+ try {
298
+ return decodeURIComponent(value);
299
+ } catch {
300
+ return value;
301
+ }
302
+ };
303
+ var extractHexFromLink = (link) => {
304
+ const decodedLink = decodeURIComponentSafely(link.trim());
305
+ const linkMatch = decodedLink.match(
306
+ /^(?:steam:\/\/(?:run|rungame)\/730\/(?:76561202255233023\/)?\/?)?\+?csgo_econ_action_preview\s+([0-9A-F]+)$/i
307
+ );
308
+ if (linkMatch?.[1]) {
309
+ assertValidHex(linkMatch[1]);
310
+ return linkMatch[1];
311
+ }
312
+ throw new Error("Invalid inspect link");
313
+ };
314
+ var decodePayload = (payload, isValidPayload) => {
315
+ const econ = normalizeDecodedEcon(CEconItemPreviewDataBlock.fromBinary(payload));
316
+ if (!isValidPayload(econ)) {
317
+ throw new Error("Invalid inspect hex payload");
318
+ }
319
+ return econ;
320
+ };
321
+ var decodeWrappedBuffer = (buffer) => {
322
+ if (buffer.length < 5 || buffer[0] !== 0) {
323
+ throw new Error("Invalid inspect hex payload");
324
+ }
325
+ const payload = buffer.subarray(1, -4);
326
+ const expectedChecksum = buffer.readUInt32BE(buffer.length - 4);
327
+ const actualChecksum = getChecksum(payload);
328
+ if (expectedChecksum !== actualChecksum) {
329
+ throw new Error("Inspect hex checksum mismatch");
330
+ }
331
+ return decodePayload(payload, hasDecodedInspectPayload);
332
+ };
333
+ var isDecodedMaskedInspectPayload = (econ) => {
334
+ return econ.itemid !== void 0 && econ.defindex !== void 0 && econ.paintindex !== void 0 && econ.inventory !== void 0 && econ.origin !== void 0;
335
+ };
336
+ var decodeMaskedBuffer = (buffer) => {
337
+ if (buffer.length < 5) {
338
+ throw new Error("Invalid inspect hex payload");
339
+ }
340
+ const unmaskedBuffer = xorMaskBuffer(buffer, buffer[0]);
341
+ if (unmaskedBuffer[0] !== 0) {
342
+ throw new Error("Invalid inspect hex payload");
343
+ }
344
+ return decodePayload(unmaskedBuffer.subarray(1, -4), isDecodedMaskedInspectPayload);
345
+ };
346
+ var xorMaskBuffer = (buffer, key) => {
347
+ return Buffer2.from(buffer.map((byte) => byte ^ key));
348
+ };
349
+ var decodeHex = (hex) => {
350
+ const normalizedHex = hex.trim();
351
+ assertValidHex(normalizedHex);
352
+ const buffer = Buffer2.from(normalizedHex, "hex");
353
+ if (buffer[0] === 0) {
354
+ return decodeWrappedBuffer(buffer);
355
+ }
356
+ return decodeMaskedBuffer(buffer);
357
+ };
358
+ var decodeLink = (link) => {
359
+ return decodeHex(extractHexFromLink(link));
360
+ };
361
+
362
+ // src/index.ts
363
+ var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
263
364
  var generateHex = ({ paintwear = 1e-3, ...props }) => {
264
365
  const econ = {
265
366
  ...props,
266
367
  paintwear: floatToBytes(paintwear)
267
368
  };
268
369
  const payload = CEconItemPreviewDataBlock.toBinary(econ);
269
- const bufferPayload = Buffer.concat([Uint8Array.from([0]), payload]);
270
- const crc = CRC32.buf(bufferPayload);
271
- const x_crc = crc & 65535 ^ payload.byteLength * crc;
272
- const crcBuffer = Buffer.alloc(4);
273
- crcBuffer.writeUInt32BE((x_crc & 4294967295) >>> 0, 0);
274
- return Buffer.concat([bufferPayload, crcBuffer]).toString("hex").toUpperCase();
370
+ const crcBuffer = Buffer3.alloc(4);
371
+ crcBuffer.writeUInt32BE(getChecksum(payload), 0);
372
+ return Buffer3.concat([Uint8Array.from([0]), payload, crcBuffer]).toString("hex").toUpperCase();
275
373
  };
276
374
  var generateLink = (props) => {
277
375
  const hex = generateHex(props);
278
376
  return `${previewLink} ${hex}`;
279
377
  };
280
378
  export {
379
+ CEconItemPreviewDataBlock,
380
+ decodeHex,
381
+ decodeLink,
281
382
  generateHex,
282
383
  generateLink,
283
384
  previewLink
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csfloat/cs2-inspect-serializer",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Lightweight serializer for CS2 inspect links",
5
5
  "homepage": "https://github.com/csfloat/cs2-inspect-serializer",
6
6
  "bugs": {