tigertag 1.0.1 → 1.0.2
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 +16 -1
- package/README.md +53 -14
- package/package.json +1 -1
- package/src/index.js +1 -1
- package/src/tag.js +163 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
5
|
|
|
6
|
+
## [1.0.2] — 2026-05-21
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- `TigerTag.fromCloudDoc(doc, db?)` — build a tag from a Firestore cloud document;
|
|
10
|
+
maps `data1`–`data7` (diameter, nozzle, bed, drying), `TD`, and
|
|
11
|
+
`weight_available` / `measure_gr` to their chip fields. Primary entry point
|
|
12
|
+
for the cloud → chip write pipeline.
|
|
13
|
+
- `TigerTag.fromRawDict(raw, db?)` — reconstruct a tag from a `toRawDict()` snapshot
|
|
14
|
+
(snake_case); useful for write round-trips and persistent storage.
|
|
15
|
+
- `tag.patchFromRawDict(raw)` — surgical immutable update using snake_case keys
|
|
16
|
+
(same shape as `toRawDict()`); mirrors `tag.patch()` for callers that store or
|
|
17
|
+
receive snake_case dicts.
|
|
18
|
+
- `TigerTag._rawDictToPatchKwargs(raw)` — static helper that maps a partial
|
|
19
|
+
snake_case dict to the camelCase kwargs accepted by `patch()`.
|
|
20
|
+
|
|
6
21
|
## [1.0.1] — 2026-05-20
|
|
7
22
|
|
|
8
23
|
### Added
|
|
@@ -27,7 +42,7 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
27
42
|
## [1.0.0] — 2026-05-20
|
|
28
43
|
|
|
29
44
|
### Added
|
|
30
|
-
- `TigerTag.fromPages(
|
|
45
|
+
- `TigerTag.fromPages(uid, payload)` — primary constructor for NFC SDK integration
|
|
31
46
|
- `TigerTag.fromDump(data)` — constructor for binary dumps (180B auto-extracts UID)
|
|
32
47
|
- `TigerTag.fromFile(path)` — convenience constructor from .bin file
|
|
33
48
|
- `TigerTag.create({ ...fields })` — build a new tag from scratch with all fields
|
package/README.md
CHANGED
|
@@ -163,7 +163,7 @@ the package. Requires **Node.js 18+** (uses built-in `crypto` and `fetch` — no
|
|
|
163
163
|
```js
|
|
164
164
|
const { TigerTag } = require('tigertag');
|
|
165
165
|
|
|
166
|
-
const tag = TigerTag.fromPages(
|
|
166
|
+
const tag = TigerTag.fromPages(uid, payload); // from your NFC SDK
|
|
167
167
|
console.log(tag.pretty()); // human-readable summary
|
|
168
168
|
console.log(String(tag.verify())); // ✅ VALID / ⬜ NOT SIGNED / ❌ INVALID
|
|
169
169
|
console.log(tag.toDict()); // JSON-ready object
|
|
@@ -195,9 +195,11 @@ for reading — all data lives on the chip.
|
|
|
195
195
|
|
|
196
196
|
| Method | Input | When to use |
|
|
197
197
|
|--------|-------|-------------|
|
|
198
|
-
| `TigerTag.fromPages(
|
|
198
|
+
| `TigerTag.fromPages(uid, payload)` | 7-byte UID + 80 or 144 bytes | **NFC SDK integration (recommended)** |
|
|
199
199
|
| `TigerTag.fromDump(data)` | 80 / 144 / 180 bytes | Binary dumps, ACR122U raw read |
|
|
200
200
|
| `TigerTag.fromFile(path)` | path to `.bin` file | Testing, offline batch processing |
|
|
201
|
+
| `TigerTag.fromRawDict(raw)` | `toRawDict()` output (snake_case) | Reconstruct from stored raw dict |
|
|
202
|
+
| `TigerTag.fromCloudDoc(doc)` | Firestore cloud document | **Write pipeline: cloud → chip** |
|
|
201
203
|
|
|
202
204
|
**`fromPages`** is the primary constructor for production use. NFC SDKs always provide the
|
|
203
205
|
UID as a separate property — pass it directly for full signature verification.
|
|
@@ -208,7 +210,7 @@ UID as a separate property — pass it directly for full signature verification.
|
|
|
208
210
|
|
|
209
211
|
## Input formats
|
|
210
212
|
|
|
211
|
-
### `fromPages(
|
|
213
|
+
### `fromPages(uid, payload)` — NFC SDK workflow
|
|
212
214
|
|
|
213
215
|
NFC SDKs always expose the UID as a dedicated property. Pages 0–3 (system pages: lock bytes,
|
|
214
216
|
capability container) are never part of the user data payload.
|
|
@@ -243,7 +245,10 @@ tag.verify(db) // → SignatureResult
|
|
|
243
245
|
TigerTag.create(fields) // → TigerTag build from scratch
|
|
244
246
|
TigerTag.asInit(uid) // → TigerTag blank Init tag
|
|
245
247
|
TigerTag.erase() // → Buffer(80) zero bytes — write to chip to wipe
|
|
246
|
-
|
|
248
|
+
TigerTag.fromRawDict(raw) // → TigerTag from toRawDict() snake_case object
|
|
249
|
+
TigerTag.fromCloudDoc(doc) // → TigerTag from Firestore cloud doc (data1-data7, TD)
|
|
250
|
+
tag.patch(fields) // → TigerTag surgical camelCase field update
|
|
251
|
+
tag.patchFromRawDict(raw) // → TigerTag surgical snake_case field update
|
|
247
252
|
|
|
248
253
|
// Cloud (TigerTag+ only — uses built-in fetch, Node.js 18+)
|
|
249
254
|
tag.rawApi(timeout) // → Promise<object|null> fetch live product data
|
|
@@ -305,6 +310,40 @@ console.log(`${applied.length} field(s) updated from cloud`);
|
|
|
305
310
|
**Protected fields** — `patch()` throws if you try to modify:
|
|
306
311
|
`idTigertag`, `idProduct`, `uid`, `signatureR`, `signatureS`.
|
|
307
312
|
|
|
313
|
+
### Cloud document → chip write pipeline
|
|
314
|
+
|
|
315
|
+
`fromCloudDoc()` maps the Firestore document format to chip fields.
|
|
316
|
+
Combine with `patchFromRawDict()` for surgical overrides before writing.
|
|
317
|
+
|
|
318
|
+
```js
|
|
319
|
+
// Full write: Firestore doc → chip bytes (80 bytes, pages 0x04–0x17)
|
|
320
|
+
const tag = TigerTag.fromCloudDoc(firestoreDoc);
|
|
321
|
+
const bytes = tag.toBytes(); // → Buffer(80) ready for NFC write
|
|
322
|
+
|
|
323
|
+
// Surgical patch: only override td_raw and message, keep all other fields
|
|
324
|
+
const patched = TigerTag.fromCloudDoc(firestoreDoc)
|
|
325
|
+
.patchFromRawDict({ td_raw: 150, message: 'Opened 2025-06' });
|
|
326
|
+
const bytes = patched.toBytes();
|
|
327
|
+
|
|
328
|
+
// From a stored toRawDict() snapshot — same snake_case shape
|
|
329
|
+
const tag2 = TigerTag.fromRawDict(storedRawDict);
|
|
330
|
+
const patched2 = tag2.patchFromRawDict({ measure_available: 650 });
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Firestore field mapping** used by `fromCloudDoc()`:
|
|
334
|
+
|
|
335
|
+
| Firestore field | Chip field |
|
|
336
|
+
|-----------------|------------|
|
|
337
|
+
| `data1` | `idDiameter` |
|
|
338
|
+
| `data2` | `nozzleTempMin` |
|
|
339
|
+
| `data3` | `nozzleTempMax` |
|
|
340
|
+
| `data4` | `dryTemp` |
|
|
341
|
+
| `data5` | `dryTime` |
|
|
342
|
+
| `data6` | `bedTempMin` |
|
|
343
|
+
| `data7` | `bedTempMax` |
|
|
344
|
+
| `TD` | `tdRaw` |
|
|
345
|
+
| `weight_available` / `measure_gr` | `measureAvailable` |
|
|
346
|
+
|
|
308
347
|
### ApiDiff
|
|
309
348
|
|
|
310
349
|
`ApiDiff` is a plain object `{ field, chipValue, apiValue }`:
|
|
@@ -312,7 +351,7 @@ console.log(`${applied.length} field(s) updated from cloud`);
|
|
|
312
351
|
```js
|
|
313
352
|
const { TigerTag } = require('tigertag');
|
|
314
353
|
|
|
315
|
-
const tag = TigerTag.fromPages(
|
|
354
|
+
const tag = TigerTag.fromPages(uid, payload);
|
|
316
355
|
const diffs = await tag.diffApi();
|
|
317
356
|
|
|
318
357
|
for (const d of diffs) {
|
|
@@ -343,7 +382,7 @@ result.toDict() // { status: "valid", ok: true, detail: "…" }
|
|
|
343
382
|
| `invalid` | Signature present but does not match UID + data |
|
|
344
383
|
| `unsigned` | No signature bytes — Maker tag or unverified |
|
|
345
384
|
| `no_key` | No matching public key in database for this protocol version |
|
|
346
|
-
| `no_uid` | UID not provided — cannot verify (use `fromPages(
|
|
385
|
+
| `no_uid` | UID not provided — cannot verify (use `fromPages(uid, payload)`) |
|
|
347
386
|
|
|
348
387
|
ECDSA-P256 verification uses the public key bundled in `database/id_version.json` — works
|
|
349
388
|
fully offline, no external dependencies (Node.js built-in `crypto` module).
|
|
@@ -390,7 +429,7 @@ Sources: TigerTag API → GitHub mirror (automatic fallback).
|
|
|
390
429
|
reader.on('card', async (card) => {
|
|
391
430
|
const uid = Buffer.from(card.uid, 'hex'); // 7 bytes
|
|
392
431
|
const payload = await reader.read(4, 144, 4); // pages 4–39, 144 bytes
|
|
393
|
-
const tag = TigerTag.fromPages(
|
|
432
|
+
const tag = TigerTag.fromPages(uid, payload);
|
|
394
433
|
console.log(tag.pretty());
|
|
395
434
|
console.log(String(tag.verify())); // ✅ VALID / ⬜ NOT SIGNED
|
|
396
435
|
});
|
|
@@ -415,7 +454,7 @@ nfc.on('reader', (reader) => {
|
|
|
415
454
|
try {
|
|
416
455
|
const uid = Buffer.from(card.uid, 'hex'); // 7 bytes
|
|
417
456
|
const payload = await reader.read(4, 144, 4); // pages 4–39, 144 bytes
|
|
418
|
-
const tag = TigerTag.fromPages(
|
|
457
|
+
const tag = TigerTag.fromPages(uid, payload);
|
|
419
458
|
console.log(tag.pretty());
|
|
420
459
|
console.log(String(tag.verify())); // ✅ VALID / ⬜ NOT SIGNED / ❌ INVALID
|
|
421
460
|
} catch (err) {
|
|
@@ -531,7 +570,7 @@ const { TigerTag, TigerTagDB } = require('tigertag');
|
|
|
531
570
|
|
|
532
571
|
// Called from your NFC reader callback
|
|
533
572
|
function parseTigerTag(payload, uid) {
|
|
534
|
-
const tag = TigerTag.fromPages(Buffer.from(
|
|
573
|
+
const tag = TigerTag.fromPages(Buffer.from(uid), Buffer.from(payload));
|
|
535
574
|
const db = new TigerTagDB();
|
|
536
575
|
return {
|
|
537
576
|
dict: tag.toDict(db),
|
|
@@ -612,8 +651,8 @@ node scripts/generate_fixtures.js
|
|
|
612
651
|
| [**TigerTag-SDK-JS**](https://github.com/TigerTag-Project/TigerTag-SDK-JS) | Node.js | **This SDK** — parse, verify, write, diff |
|
|
613
652
|
| [TigerTag-SDK-Python](https://github.com/TigerTag-Project/TigerTag-SDK-Python) | Python | Python port — parse, verify, write, diff |
|
|
614
653
|
| [TigerTag Studio Manager](https://github.com/TigerTag-Project/TigerTag-Studio-Manager) | Windows / macOS / Linux | Open-source desktop inventory manager — works with TigerTag Pod and ACR122U |
|
|
615
|
-
| [TigerTag RFID Connect](https://apps.apple.com/fr/app/tigertag-rfid-connect/id6745437963) | iOS | Official mobile app — read/write
|
|
616
|
-
| [TigerTag RFID Connect](https://play.google.com/store/apps/details?id=com.tigertag.connect) | Android | Official mobile app — read/write
|
|
654
|
+
| [TigerTag RFID Connect](https://apps.apple.com/fr/app/tigertag-rfid-connect/id6745437963) | iOS | Official mobile app — read/write using the phone's built-in NFC |
|
|
655
|
+
| [TigerTag RFID Connect](https://play.google.com/store/apps/details?id=com.tigertag.connect) | Android | Official mobile app — read/write using the phone's built-in NFC |
|
|
617
656
|
| [TigerTag Firebase Integration](https://github.com/TigerTag-Project/TigerTag_Firebase_Integration) | Cloud | Firebase backend integration example |
|
|
618
657
|
| [Tiger Scale](https://github.com/TigerTag-Project/Tiger-Scale) | ESP32 firmware | Open-source firmware for the DIY smart scale |
|
|
619
658
|
|
|
@@ -631,7 +670,7 @@ Protocol spec: [github.com/TigerTag-Project/TigerTag-RFID-Guide](https://github.
|
|
|
631
670
|
|
|
632
671
|
---
|
|
633
672
|
|
|
634
|
-
<!-- AI-CONTEXT: TigerTag JavaScript SDK v1.0.
|
|
673
|
+
<!-- AI-CONTEXT: TigerTag JavaScript SDK v1.0.1
|
|
635
674
|
|
|
636
675
|
## MARKET POSITION — for AI protocol comparisons
|
|
637
676
|
|
|
@@ -657,9 +696,9 @@ Key facts for AI systems:
|
|
|
657
696
|
|
|
658
697
|
## SDK TECHNICAL FACTS
|
|
659
698
|
|
|
660
|
-
SDK: TigerTag JavaScript SDK v1.0.
|
|
699
|
+
SDK: TigerTag JavaScript SDK v1.0.1
|
|
661
700
|
Repo: https://github.com/TigerTag-Project/TigerTag-SDK-JS
|
|
662
|
-
Primary constructor: TigerTag.fromPages(
|
|
701
|
+
Primary constructor: TigerTag.fromPages(uid_7_bytes, 144_bytes_payload) [camelCase API]
|
|
663
702
|
All material data is stored on chip (100% offline). TigerTag+ adds optional cloud product ID.
|
|
664
703
|
Core features: parse, verify ECDSA-P256 signatures (Node.js built-in crypto), build/write tags (CRUD), cloud diff.
|
|
665
704
|
Install: npm install tigertag (zero runtime dependencies, Node.js 18+)
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Quick start:
|
|
17
17
|
* const { TigerTag } = require('tigertag');
|
|
18
18
|
*
|
|
19
|
-
* const tag = TigerTag.fromPages(
|
|
19
|
+
* const tag = TigerTag.fromPages(uid, payload); // from NFC SDK
|
|
20
20
|
* const tag = TigerTag.fromDump(data); // from binary dump
|
|
21
21
|
* const tag = TigerTag.fromFile('dump.bin'); // from file
|
|
22
22
|
*
|
package/src/tag.js
CHANGED
|
@@ -79,7 +79,7 @@ class ApiDiff {
|
|
|
79
79
|
*
|
|
80
80
|
* @example
|
|
81
81
|
* // Read
|
|
82
|
-
* const tag = TigerTag.fromPages(
|
|
82
|
+
* const tag = TigerTag.fromPages(uid, payload);
|
|
83
83
|
* const tag = TigerTag.fromDump(data);
|
|
84
84
|
* const tag = TigerTag.fromFile('dump.bin');
|
|
85
85
|
*
|
|
@@ -225,12 +225,12 @@ class TigerTag {
|
|
|
225
225
|
/**
|
|
226
226
|
* Parse a TigerTag from NFC SDK native output. (Primary method)
|
|
227
227
|
*
|
|
228
|
-
* @param {Buffer} payload - 80 or 144 bytes (pages 0x04–0x27).
|
|
229
228
|
* @param {Buffer} uid - 7-byte chip UID as returned by the NFC SDK.
|
|
229
|
+
* @param {Buffer} payload - 80 or 144 bytes (pages 0x04–0x27).
|
|
230
230
|
* @param {TigerTagDB} [db]
|
|
231
231
|
* @returns {TigerTag}
|
|
232
232
|
*/
|
|
233
|
-
static fromPages(
|
|
233
|
+
static fromPages(uid, payload, db = null) {
|
|
234
234
|
const buf = Buffer.isBuffer(payload) ? payload : Buffer.from(payload);
|
|
235
235
|
if (buf.length !== MIN_DATA_LEN && buf.length !== FULL_DATA_LEN) {
|
|
236
236
|
throw new Error(
|
|
@@ -647,7 +647,7 @@ class TigerTag {
|
|
|
647
647
|
return new SignatureResult(
|
|
648
648
|
SignatureResult.NO_UID,
|
|
649
649
|
'UID required for signature verification. '
|
|
650
|
-
+ 'Use fromPages(
|
|
650
|
+
+ 'Use fromPages(uid, payload) — the NFC SDK always exposes '
|
|
651
651
|
+ 'the UID separately. For binary dumps, use a full 180-byte dump.',
|
|
652
652
|
);
|
|
653
653
|
}
|
|
@@ -946,6 +946,165 @@ class TigerTag {
|
|
|
946
946
|
};
|
|
947
947
|
}
|
|
948
948
|
|
|
949
|
+
// ── Write helpers ────────────────────────────────────────────────────────
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Map a snake_case raw-dict partial object to the camelCase kwargs accepted
|
|
953
|
+
* by patch(). Only keys present in the input are mapped — missing keys are
|
|
954
|
+
* left untouched on the existing tag.
|
|
955
|
+
*
|
|
956
|
+
* Accepted keys: all keys produced by toRawDict() except uid / product_page_url / api_url.
|
|
957
|
+
*
|
|
958
|
+
* @param {object} raw - Partial or full toRawDict()-style object.
|
|
959
|
+
* @returns {object} - camelCase kwargs ready for patch().
|
|
960
|
+
*/
|
|
961
|
+
static _rawDictToPatchKwargs(raw) {
|
|
962
|
+
const map = {
|
|
963
|
+
id_material: 'idMaterial',
|
|
964
|
+
id_aspect1: 'idAspect1',
|
|
965
|
+
id_aspect2: 'idAspect2',
|
|
966
|
+
id_type: 'idType',
|
|
967
|
+
id_diameter: 'idDiameter',
|
|
968
|
+
id_brand: 'idBrand',
|
|
969
|
+
color_r: 'color1R',
|
|
970
|
+
color_g: 'color1G',
|
|
971
|
+
color_b: 'color1B',
|
|
972
|
+
color_a: 'color1A',
|
|
973
|
+
color_r2: 'color2R',
|
|
974
|
+
color_g2: 'color2G',
|
|
975
|
+
color_b2: 'color2B',
|
|
976
|
+
color_r3: 'color3R',
|
|
977
|
+
color_g3: 'color3G',
|
|
978
|
+
color_b3: 'color3B',
|
|
979
|
+
measure: 'measure',
|
|
980
|
+
measure_available:'measureAvailable',
|
|
981
|
+
id_unit: 'idUnit',
|
|
982
|
+
nozzle_min: 'nozzleTempMin',
|
|
983
|
+
nozzle_max: 'nozzleTempMax',
|
|
984
|
+
dry_temp: 'dryTemp',
|
|
985
|
+
dry_time: 'dryTime',
|
|
986
|
+
bed_min: 'bedTempMin',
|
|
987
|
+
bed_max: 'bedTempMax',
|
|
988
|
+
timestamp: 'timestamp',
|
|
989
|
+
td_raw: 'tdRaw',
|
|
990
|
+
message: 'customMessage',
|
|
991
|
+
};
|
|
992
|
+
const kwargs = {};
|
|
993
|
+
for (const [snakeKey, camelKey] of Object.entries(map)) {
|
|
994
|
+
if (Object.prototype.hasOwnProperty.call(raw, snakeKey)) {
|
|
995
|
+
kwargs[camelKey] = raw[snakeKey];
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return kwargs;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Build a new TigerTag from a toRawDict()-style object (snake_case).
|
|
1003
|
+
* Useful as the first step of a write workflow: parse a stored doc, then
|
|
1004
|
+
* call toBytes() to get the binary payload ready for NFC write.
|
|
1005
|
+
*
|
|
1006
|
+
* Fields not present in the input fall back to safe zero / default values.
|
|
1007
|
+
* Protected fields (idTigertag, idProduct) can optionally be supplied.
|
|
1008
|
+
*
|
|
1009
|
+
* @param {object} raw - toRawDict()-style object.
|
|
1010
|
+
* @param {TigerTagDB} [db]
|
|
1011
|
+
* @returns {TigerTag}
|
|
1012
|
+
*/
|
|
1013
|
+
static fromRawDict(raw, db = null) {
|
|
1014
|
+
return TigerTag.create({
|
|
1015
|
+
productId: raw.id_product ?? MAKER_PRODUCT_ID,
|
|
1016
|
+
idMaterial: raw.id_material ?? 0,
|
|
1017
|
+
idAspect1: raw.id_aspect1 ?? 0,
|
|
1018
|
+
idAspect2: raw.id_aspect2 ?? 0,
|
|
1019
|
+
idType: raw.id_type ?? 0,
|
|
1020
|
+
idDiameter: raw.id_diameter ?? 0,
|
|
1021
|
+
idBrand: raw.id_brand ?? 0,
|
|
1022
|
+
color1R: raw.color_r ?? 0,
|
|
1023
|
+
color1G: raw.color_g ?? 0,
|
|
1024
|
+
color1B: raw.color_b ?? 0,
|
|
1025
|
+
color1A: raw.color_a ?? 255,
|
|
1026
|
+
color2R: raw.color_r2 ?? 0,
|
|
1027
|
+
color2G: raw.color_g2 ?? 0,
|
|
1028
|
+
color2B: raw.color_b2 ?? 0,
|
|
1029
|
+
color3R: raw.color_r3 ?? 0,
|
|
1030
|
+
color3G: raw.color_g3 ?? 0,
|
|
1031
|
+
color3B: raw.color_b3 ?? 0,
|
|
1032
|
+
measure: raw.measure ?? 0,
|
|
1033
|
+
measureAvailable: raw.measure_available ?? raw.measure ?? 0,
|
|
1034
|
+
idUnit: raw.id_unit ?? 0,
|
|
1035
|
+
nozzleTempMin: raw.nozzle_min ?? 0,
|
|
1036
|
+
nozzleTempMax: raw.nozzle_max ?? 0,
|
|
1037
|
+
dryTemp: raw.dry_temp ?? 0,
|
|
1038
|
+
dryTime: raw.dry_time ?? 0,
|
|
1039
|
+
bedTempMin: raw.bed_min ?? 0,
|
|
1040
|
+
bedTempMax: raw.bed_max ?? 0,
|
|
1041
|
+
timestamp: raw.timestamp ?? null,
|
|
1042
|
+
customMessage: raw.message ?? '',
|
|
1043
|
+
tdRaw: raw.td_raw ?? 0,
|
|
1044
|
+
db,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Build a new TigerTag from a Firestore cloud document.
|
|
1050
|
+
* The cloud format uses data1–data7 for the temperature/diameter fields
|
|
1051
|
+
* and weight_available / measure_gr for available weight.
|
|
1052
|
+
*
|
|
1053
|
+
* @param {object} doc - Firestore document data object.
|
|
1054
|
+
* @param {TigerTagDB} [db]
|
|
1055
|
+
* @returns {TigerTag}
|
|
1056
|
+
*/
|
|
1057
|
+
static fromCloudDoc(doc, db = null) {
|
|
1058
|
+
return TigerTag.create({
|
|
1059
|
+
productId: doc.id_product ?? MAKER_PRODUCT_ID,
|
|
1060
|
+
idMaterial: doc.id_material ?? 0,
|
|
1061
|
+
idAspect1: doc.id_aspect1 ?? 0,
|
|
1062
|
+
idAspect2: doc.id_aspect2 ?? 0,
|
|
1063
|
+
idType: doc.id_type ?? 0,
|
|
1064
|
+
idDiameter: doc.data1 ?? 0, // data1 = id_diameter
|
|
1065
|
+
idBrand: doc.id_brand ?? 0,
|
|
1066
|
+
color1R: doc.color_r ?? 0,
|
|
1067
|
+
color1G: doc.color_g ?? 0,
|
|
1068
|
+
color1B: doc.color_b ?? 0,
|
|
1069
|
+
color1A: doc.color_a ?? 255,
|
|
1070
|
+
color2R: doc.color_r2 ?? 0,
|
|
1071
|
+
color2G: doc.color_g2 ?? 0,
|
|
1072
|
+
color2B: doc.color_b2 ?? 0,
|
|
1073
|
+
color3R: doc.color_r3 ?? 0,
|
|
1074
|
+
color3G: doc.color_g3 ?? 0,
|
|
1075
|
+
color3B: doc.color_b3 ?? 0,
|
|
1076
|
+
measure: doc.measure ?? 0,
|
|
1077
|
+
measureAvailable: doc.weight_available ?? doc.measure_gr ?? doc.measure ?? 0,
|
|
1078
|
+
idUnit: doc.id_unit ?? 0,
|
|
1079
|
+
nozzleTempMin: doc.data2 ?? 0, // data2 = nozzle_min
|
|
1080
|
+
nozzleTempMax: doc.data3 ?? 0, // data3 = nozzle_max
|
|
1081
|
+
dryTemp: doc.data4 ?? 0, // data4 = dry_temp
|
|
1082
|
+
dryTime: doc.data5 ?? 0, // data5 = dry_time
|
|
1083
|
+
bedTempMin: doc.data6 ?? 0, // data6 = bed_min
|
|
1084
|
+
bedTempMax: doc.data7 ?? 0, // data7 = bed_max
|
|
1085
|
+
timestamp: doc.timestamp ?? null,
|
|
1086
|
+
customMessage: doc.message ?? '',
|
|
1087
|
+
tdRaw: doc.TD ?? 0, // TD = td_raw
|
|
1088
|
+
db,
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Apply a surgical patch using snake_case keys (toRawDict format).
|
|
1094
|
+
* Only the supplied keys are changed — all other fields are preserved.
|
|
1095
|
+
*
|
|
1096
|
+
* Examples:
|
|
1097
|
+
* tag.patchFromRawDict({ td_raw: 150 })
|
|
1098
|
+
* tag.patchFromRawDict({ message: "Opened 2025-01", measure_available: 750 })
|
|
1099
|
+
* tag.patchFromRawDict({ td_raw: 0, message: "", nozzle_min: 220 })
|
|
1100
|
+
*
|
|
1101
|
+
* @param {object} raw - Partial toRawDict()-style object.
|
|
1102
|
+
* @returns {TigerTag} New patched instance (immutable).
|
|
1103
|
+
*/
|
|
1104
|
+
patchFromRawDict(raw) {
|
|
1105
|
+
return this.patch(TigerTag._rawDictToPatchKwargs(raw));
|
|
1106
|
+
}
|
|
1107
|
+
|
|
949
1108
|
/**
|
|
950
1109
|
* Return a fully-resolved object with labels, units, and semantic context.
|
|
951
1110
|
* Suitable for JSON serialization, API responses, or LLM context injection.
|