@marteye/studiojs 1.1.41 → 1.1.43

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/dist/index.esm.js CHANGED
@@ -43,6 +43,9 @@ function SimpleHttpClient(baseUrl, apiKey, fetch, defaultTimeout, debug = false)
43
43
  console.log(`[SimpleHttpClient] ${method} ${path} response: ${response.status}`);
44
44
  }
45
45
  if (response.ok) {
46
+ if (response.status === 204) {
47
+ return undefined;
48
+ }
46
49
  return response.json();
47
50
  }
48
51
  if (response.status === 404) {
@@ -157,8 +160,8 @@ function create$m(httpClient) {
157
160
  list: async (marketId) => {
158
161
  return httpClient.get(`/${marketId}/adjustments`);
159
162
  },
160
- get: async (marketId, id) => {
161
- return httpClient.get(`/${marketId}/adjustments/${id}`);
163
+ get: async (marketId, id, options) => {
164
+ return httpClient.get(`/${marketId}/adjustments/${id}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
162
165
  },
163
166
  create: async (marketId, data) => {
164
167
  return httpClient.post(`/${marketId}/adjustments`, data);
@@ -274,6 +277,23 @@ function create$j(httpClient) {
274
277
  reject: async (marketId, applicationId, notes) => {
275
278
  return httpClient.post(`/${marketId}/applications/${applicationId}/reject`, { notes });
276
279
  },
280
+ /**
281
+ * Unlink an application from its customer/contact
282
+ * @param marketId - ID of the market
283
+ * @param applicationId - ID of the application to unlink
284
+ * @returns The unlinked application (reset to pending)
285
+ */
286
+ unlink: async (marketId, applicationId) => {
287
+ return httpClient.post(`/${marketId}/applications/${applicationId}/unlink`, {});
288
+ },
289
+ /**
290
+ * Delete an application
291
+ * @param marketId - ID of the market
292
+ * @param applicationId - ID of the application to delete
293
+ */
294
+ delete: async (marketId, applicationId) => {
295
+ return httpClient.delete(`/${marketId}/applications/${applicationId}`);
296
+ },
277
297
  };
278
298
  return applications;
279
299
  }
@@ -288,8 +308,8 @@ function create$i(httpClient) {
288
308
  }
289
309
  return httpClient.get(`/${marketId}/customers`, params);
290
310
  },
291
- get: async (marketId, customerId) => {
292
- return httpClient.get(`/${marketId}/customers/${customerId}`);
311
+ get: async (marketId, customerId, options) => {
312
+ return httpClient.get(`/${marketId}/customers/${customerId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
293
313
  },
294
314
  avatar: async (marketId, customerId) => {
295
315
  return httpClient.get(`/${marketId}/customers/${customerId}/avatar`);
@@ -5152,8 +5172,8 @@ function create$g(httpClient) {
5152
5172
  * @param invoiceId - ID of the invoice to fetch
5153
5173
  * @returns The invoice details
5154
5174
  */
5155
- get: async (marketId, invoiceId) => {
5156
- return httpClient.get(`/${marketId}/invoices/${invoiceId}`);
5175
+ get: async (marketId, invoiceId, options) => {
5176
+ return httpClient.get(`/${marketId}/invoices/${invoiceId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5157
5177
  },
5158
5178
  };
5159
5179
  return invoices;
@@ -5178,8 +5198,8 @@ function create$f(httpClient) {
5178
5198
  */
5179
5199
  function create$e(httpClient) {
5180
5200
  return {
5181
- get: async (marketId, saleId, lotId) => {
5182
- return httpClient.get(`/${marketId}/sales/${saleId}/lots/${lotId}`);
5201
+ get: async (marketId, saleId, lotId, options) => {
5202
+ return httpClient.get(`/${marketId}/sales/${saleId}/lots/${lotId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5183
5203
  },
5184
5204
  list: async (marketId, saleId, filters) => {
5185
5205
  return httpClient.get(`/${marketId}/sales/${saleId}/lots`, filters);
@@ -5198,8 +5218,8 @@ function create$e(httpClient) {
5198
5218
 
5199
5219
  function create$d(httpClient) {
5200
5220
  const markets = {
5201
- get: async (marketId) => {
5202
- return httpClient.get(`/${marketId}`);
5221
+ get: async (marketId, options) => {
5222
+ return httpClient.get(`/${marketId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5203
5223
  },
5204
5224
  // update: async (marketId: string, market: Partial<Market>) => {
5205
5225
  // // return httpClient.put<Market>(`/${marketId}`, market);
@@ -5321,8 +5341,8 @@ function create$9(httpClient) {
5321
5341
  list: async (marketId) => {
5322
5342
  return httpClient.get(`/${marketId}/product-codes`);
5323
5343
  },
5324
- get: async (marketId, id) => {
5325
- return httpClient.get(`/${marketId}/product-codes/${id}`);
5344
+ get: async (marketId, id, options) => {
5345
+ return httpClient.get(`/${marketId}/product-codes/${id}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5326
5346
  },
5327
5347
  create: async (marketId, data) => {
5328
5348
  return httpClient.post(`/${marketId}/product-codes`, data);
@@ -5335,8 +5355,8 @@ function create$9(httpClient) {
5335
5355
 
5336
5356
  function create$8(httpClient) {
5337
5357
  return {
5338
- get: async (marketId, saleId) => {
5339
- return httpClient.get(`/${marketId}/sales/${saleId}`);
5358
+ get: async (marketId, saleId, options) => {
5359
+ return httpClient.get(`/${marketId}/sales/${saleId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5340
5360
  },
5341
5361
  list: async (marketId, opts) => {
5342
5362
  return httpClient.get(`/${marketId}/sales`, opts);
@@ -5387,8 +5407,8 @@ function create$6(httpClient) {
5387
5407
 
5388
5408
  function create$5(httpClient) {
5389
5409
  return {
5390
- get: async (marketId) => {
5391
- return httpClient.get(`/${marketId}/settings`);
5410
+ get: async (marketId, options) => {
5411
+ return httpClient.get(`/${marketId}/settings`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5392
5412
  },
5393
5413
  };
5394
5414
  }
@@ -5513,13 +5533,19 @@ function create(httpClient) {
5513
5533
  * @returns List of transactions with pagination info
5514
5534
  */
5515
5535
  listTransactions: async (marketId, params) => {
5516
- let queryParams = {
5517
- account: params.account,
5518
- dateFrom: params.dateFrom,
5519
- dateTo: params.dateTo,
5520
- limit: params.limit,
5521
- cursor: params.cursor,
5522
- };
5536
+ let queryParams = {};
5537
+ if (params.account)
5538
+ queryParams.account = params.account;
5539
+ if (params.referenceGroupKey)
5540
+ queryParams.referenceGroupKey = params.referenceGroupKey;
5541
+ if (params.dateFrom)
5542
+ queryParams.dateFrom = params.dateFrom;
5543
+ if (params.dateTo)
5544
+ queryParams.dateTo = params.dateTo;
5545
+ if (params.limit)
5546
+ queryParams.limit = params.limit;
5547
+ if (params.cursor)
5548
+ queryParams.cursor = params.cursor;
5523
5549
  return httpClient.get(`/${marketId}/ledger/transactions`, queryParams);
5524
5550
  },
5525
5551
  };
@@ -5788,6 +5814,15 @@ class EarTag {
5788
5814
  parsedCountryCode = match11[1];
5789
5815
  parsedNationalIdentifier = `${match11[3]}${match11[4]}`;
5790
5816
  }
5817
+ else {
5818
+ // 10-digit national ID (e.g. DE, FR imported tags)
5819
+ const regex10 = new RegExp(`^[0-9]{0,7}(${countryPattern})([0-9]{5})([0-9]{5})`);
5820
+ let match10 = regex10.exec(workingInput);
5821
+ if (match10) {
5822
+ parsedCountryCode = match10[1];
5823
+ parsedNationalIdentifier = `${match10[3]}${match10[4]}`;
5824
+ }
5825
+ }
5791
5826
  }
5792
5827
  // Part 2: If no country code parsed yet, try fallback
5793
5828
  if (!parsedCountryCode && fallbackCountryCode) {
@@ -5795,7 +5830,7 @@ class EarTag {
5795
5830
  if (numericFallback) {
5796
5831
  // `workingInput` at this point is the original input (cleaned, no recognized country code)
5797
5832
  // Assume `workingInput` is the national identifier part (must be 11 or 12 digits)
5798
- if (workingInput.length === 12 || workingInput.length === 11) {
5833
+ if (workingInput.length >= 10 && workingInput.length <= 12) {
5799
5834
  parsedCountryCode = numericFallback;
5800
5835
  parsedNationalIdentifier = workingInput;
5801
5836
  // Update _raw to reflect the tag as if it had the country code
@@ -5806,7 +5841,11 @@ class EarTag {
5806
5841
  // Part 3: Finalize and set properties
5807
5842
  if (parsedCountryCode && parsedNationalIdentifier) {
5808
5843
  this._isoCountryCode = parsedCountryCode;
5809
- if (parsedNationalIdentifier.length === 11) {
5844
+ if (parsedNationalIdentifier.length === 10) {
5845
+ // 10-digit national ID (e.g. DE, FR imported tags) — store as-is
5846
+ this._nationalIdentifier = parsedNationalIdentifier;
5847
+ }
5848
+ else if (parsedNationalIdentifier.length === 11) {
5810
5849
  // Pad 11-digit national ID to 12-digits by prepending "0"
5811
5850
  this._nationalIdentifier = "0" + parsedNationalIdentifier;
5812
5851
  }
@@ -5814,7 +5853,6 @@ class EarTag {
5814
5853
  this._nationalIdentifier = parsedNationalIdentifier;
5815
5854
  }
5816
5855
  else {
5817
- // This case should ideally not be reached if lengths are checked properly before.
5818
5856
  this._isEartag = false;
5819
5857
  return;
5820
5858
  }
@@ -5838,7 +5876,14 @@ class EarTag {
5838
5876
  if (!this._isEartag) {
5839
5877
  return "Invalid EarTag";
5840
5878
  }
5841
- return `${EarTag.countryCodesByNumber[this.isoCountryCode]} ${this.nationalIdentifier.slice(0, 7)} ${this.nationalIdentifier.slice(7)}`;
5879
+ let country = EarTag.countryCodesByNumber[this.isoCountryCode];
5880
+ let id = this.nationalIdentifier;
5881
+ // 10-digit national IDs (DE, FR imports) format as 5+5
5882
+ // 12-digit national IDs (UK, IE, etc.) format as 7+5
5883
+ if (id.length === 10) {
5884
+ return `${country} ${id.slice(0, 5)} ${id.slice(5)}`;
5885
+ }
5886
+ return `${country} ${id.slice(0, 7)} ${id.slice(7)}`;
5842
5887
  }
5843
5888
  isISO24631() {
5844
5889
  return EarTag.regexISO24631.test(this._raw);
@@ -5863,6 +5908,124 @@ EarTag.countryCodes = {
5863
5908
  BE: "056",
5864
5909
  };
5865
5910
 
5911
+ /**
5912
+ * Parses the bottom barcode on a UK cattle passport.
5913
+ *
5914
+ * The barcode is a 30-character fixed-width positional format:
5915
+ * [0-13] Eartag — 2 alpha country code + 12 char national ID (space-padded for shorter foreign tags)
5916
+ * [14-21] Date of birth — ddMMyyyy
5917
+ * [22] Sex — F or M
5918
+ * [23-27] Breed code — left-justified, space-padded to 5 chars
5919
+ * [28-29] Passport version — 2 digits
5920
+ *
5921
+ * UK animals fill all 12 digits of the national ID. Imported animals (DE, FR, BE, etc.)
5922
+ * have shorter national IDs so the field is right-padded with spaces.
5923
+ *
5924
+ * Examples:
5925
+ * UK12345671004215032023MHER 01 ← UK tag, breed HER
5926
+ * UK98765430018722112022FLIMX 01 ← UK tag, breed LIMX
5927
+ * DE04821 9315614092018FHF 01 ← German import, 10-digit national ID
5928
+ * FR72341 6850203052020FHF 01 ← French import, 10-digit national ID
5929
+ */
5930
+ class CattlePassport {
5931
+ constructor(raw, earTag, dateOfBirth, sex, breed, passportVersion) {
5932
+ this._raw = raw;
5933
+ this._earTag = earTag;
5934
+ this._dateOfBirth = dateOfBirth;
5935
+ this._sex = sex;
5936
+ this._breed = breed;
5937
+ this._passportVersion = passportVersion;
5938
+ }
5939
+ static parse(code) {
5940
+ let raw = code;
5941
+ let trimmed = code.trim();
5942
+ if (trimmed.length !== CattlePassport.BARCODE_LENGTH)
5943
+ return null;
5944
+ // Extract fixed-width fields
5945
+ let earTagField = trimmed.slice(0, 14);
5946
+ let dobField = trimmed.slice(14, 22);
5947
+ let sexChar = trimmed.charAt(22);
5948
+ let breedField = trimmed.slice(23, 28);
5949
+ let versionField = trimmed.slice(28, 30);
5950
+ // Country code: 2 alpha chars
5951
+ let countryCode = earTagField.slice(0, 2);
5952
+ if (!/^[A-Z]{2}$/.test(countryCode))
5953
+ return null;
5954
+ // National ID: strip spaces (padding for shorter foreign tags)
5955
+ let nationalId = earTagField.slice(2).replace(/\s/g, "");
5956
+ if (!/^\d+$/.test(nationalId) || nationalId.length === 0)
5957
+ return null;
5958
+ let earTag = countryCode + nationalId;
5959
+ // DOB: ddMMyyyy
5960
+ if (!/^\d{8}$/.test(dobField))
5961
+ return null;
5962
+ let day = dobField.slice(0, 2);
5963
+ let month = dobField.slice(2, 4);
5964
+ let year = dobField.slice(4, 8);
5965
+ let d = new Date(`${year}-${month}-${day}T00:00:00Z`);
5966
+ if (isNaN(d.getTime()))
5967
+ return null;
5968
+ // Sex
5969
+ if (sexChar !== "F" && sexChar !== "M")
5970
+ return null;
5971
+ let sex = sexChar === "M" ? "Male" : "Female";
5972
+ // Breed: trimmed, alpha only
5973
+ let breed = breedField.trim();
5974
+ if (!breed || !/^[A-Z]+$/.test(breed))
5975
+ return null;
5976
+ // Passport version
5977
+ if (!/^\d{2}$/.test(versionField))
5978
+ return null;
5979
+ let passportVersion = parseInt(versionField);
5980
+ return new CattlePassport(raw, earTag, d, sex, breed, passportVersion);
5981
+ }
5982
+ /** The original raw barcode string */
5983
+ get raw() {
5984
+ return this._raw;
5985
+ }
5986
+ /** The eartag extracted from the barcode, e.g. "UK705946601313" or "DE0359581730" */
5987
+ get earTag() {
5988
+ return this._earTag;
5989
+ }
5990
+ /** Date of birth (UTC) */
5991
+ get dateOfBirth() {
5992
+ return this._dateOfBirth;
5993
+ }
5994
+ /** Male or Female */
5995
+ get sex() {
5996
+ return this._sex;
5997
+ }
5998
+ /** Breed code, e.g. "AA", "HF", "LIMX" */
5999
+ get breed() {
6000
+ return this._breed;
6001
+ }
6002
+ /** Passport version number */
6003
+ get passportVersion() {
6004
+ return this._passportVersion;
6005
+ }
6006
+ /** 2-letter country code, e.g. "UK", "DE", "FR" */
6007
+ get countryCode() {
6008
+ return this._earTag.slice(0, 2);
6009
+ }
6010
+ /** Format the eartag via the EarTag class. Falls back to the raw tag string. */
6011
+ get formattedEarTag() {
6012
+ let formatted = EarTag.format(this._earTag);
6013
+ return formatted !== null && formatted !== void 0 ? formatted : this._earTag;
6014
+ }
6015
+ /** Date of birth as DD/MM/YYYY */
6016
+ get formattedDateOfBirth() {
6017
+ let d = this._dateOfBirth;
6018
+ let day = String(d.getUTCDate()).padStart(2, "0");
6019
+ let month = String(d.getUTCMonth() + 1).padStart(2, "0");
6020
+ let year = d.getUTCFullYear();
6021
+ return `${day}/${month}/${year}`;
6022
+ }
6023
+ toString() {
6024
+ return `${this.formattedEarTag} | ${this.formattedDateOfBirth} | ${this._sex} | ${this._breed} | v${this._passportVersion}`;
6025
+ }
6026
+ }
6027
+ CattlePassport.BARCODE_LENGTH = 30;
6028
+
5866
6029
  /**
5867
6030
  * Extract the smallest lot number for sorting purposes.
5868
6031
  * Handles formats:
@@ -6024,4 +6187,4 @@ function incrementAlphaSequence(alpha) {
6024
6187
  return chars.join("");
6025
6188
  }
6026
6189
 
6027
- export { EarTag, Studio, StudioHeaders, types as StudioTypes, createAppManifest, Studio as default, lotComparator, nextLotNumber, sortByLotNumber };
6190
+ export { CattlePassport, EarTag, Studio, StudioHeaders, types as StudioTypes, createAppManifest, Studio as default, lotComparator, nextLotNumber, sortByLotNumber };
package/dist/index.js CHANGED
@@ -47,6 +47,9 @@ function SimpleHttpClient(baseUrl, apiKey, fetch, defaultTimeout, debug = false)
47
47
  console.log(`[SimpleHttpClient] ${method} ${path} response: ${response.status}`);
48
48
  }
49
49
  if (response.ok) {
50
+ if (response.status === 204) {
51
+ return undefined;
52
+ }
50
53
  return response.json();
51
54
  }
52
55
  if (response.status === 404) {
@@ -161,8 +164,8 @@ function create$m(httpClient) {
161
164
  list: async (marketId) => {
162
165
  return httpClient.get(`/${marketId}/adjustments`);
163
166
  },
164
- get: async (marketId, id) => {
165
- return httpClient.get(`/${marketId}/adjustments/${id}`);
167
+ get: async (marketId, id, options) => {
168
+ return httpClient.get(`/${marketId}/adjustments/${id}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
166
169
  },
167
170
  create: async (marketId, data) => {
168
171
  return httpClient.post(`/${marketId}/adjustments`, data);
@@ -278,6 +281,23 @@ function create$j(httpClient) {
278
281
  reject: async (marketId, applicationId, notes) => {
279
282
  return httpClient.post(`/${marketId}/applications/${applicationId}/reject`, { notes });
280
283
  },
284
+ /**
285
+ * Unlink an application from its customer/contact
286
+ * @param marketId - ID of the market
287
+ * @param applicationId - ID of the application to unlink
288
+ * @returns The unlinked application (reset to pending)
289
+ */
290
+ unlink: async (marketId, applicationId) => {
291
+ return httpClient.post(`/${marketId}/applications/${applicationId}/unlink`, {});
292
+ },
293
+ /**
294
+ * Delete an application
295
+ * @param marketId - ID of the market
296
+ * @param applicationId - ID of the application to delete
297
+ */
298
+ delete: async (marketId, applicationId) => {
299
+ return httpClient.delete(`/${marketId}/applications/${applicationId}`);
300
+ },
281
301
  };
282
302
  return applications;
283
303
  }
@@ -292,8 +312,8 @@ function create$i(httpClient) {
292
312
  }
293
313
  return httpClient.get(`/${marketId}/customers`, params);
294
314
  },
295
- get: async (marketId, customerId) => {
296
- return httpClient.get(`/${marketId}/customers/${customerId}`);
315
+ get: async (marketId, customerId, options) => {
316
+ return httpClient.get(`/${marketId}/customers/${customerId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
297
317
  },
298
318
  avatar: async (marketId, customerId) => {
299
319
  return httpClient.get(`/${marketId}/customers/${customerId}/avatar`);
@@ -5156,8 +5176,8 @@ function create$g(httpClient) {
5156
5176
  * @param invoiceId - ID of the invoice to fetch
5157
5177
  * @returns The invoice details
5158
5178
  */
5159
- get: async (marketId, invoiceId) => {
5160
- return httpClient.get(`/${marketId}/invoices/${invoiceId}`);
5179
+ get: async (marketId, invoiceId, options) => {
5180
+ return httpClient.get(`/${marketId}/invoices/${invoiceId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5161
5181
  },
5162
5182
  };
5163
5183
  return invoices;
@@ -5182,8 +5202,8 @@ function create$f(httpClient) {
5182
5202
  */
5183
5203
  function create$e(httpClient) {
5184
5204
  return {
5185
- get: async (marketId, saleId, lotId) => {
5186
- return httpClient.get(`/${marketId}/sales/${saleId}/lots/${lotId}`);
5205
+ get: async (marketId, saleId, lotId, options) => {
5206
+ return httpClient.get(`/${marketId}/sales/${saleId}/lots/${lotId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5187
5207
  },
5188
5208
  list: async (marketId, saleId, filters) => {
5189
5209
  return httpClient.get(`/${marketId}/sales/${saleId}/lots`, filters);
@@ -5202,8 +5222,8 @@ function create$e(httpClient) {
5202
5222
 
5203
5223
  function create$d(httpClient) {
5204
5224
  const markets = {
5205
- get: async (marketId) => {
5206
- return httpClient.get(`/${marketId}`);
5225
+ get: async (marketId, options) => {
5226
+ return httpClient.get(`/${marketId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5207
5227
  },
5208
5228
  // update: async (marketId: string, market: Partial<Market>) => {
5209
5229
  // // return httpClient.put<Market>(`/${marketId}`, market);
@@ -5325,8 +5345,8 @@ function create$9(httpClient) {
5325
5345
  list: async (marketId) => {
5326
5346
  return httpClient.get(`/${marketId}/product-codes`);
5327
5347
  },
5328
- get: async (marketId, id) => {
5329
- return httpClient.get(`/${marketId}/product-codes/${id}`);
5348
+ get: async (marketId, id, options) => {
5349
+ return httpClient.get(`/${marketId}/product-codes/${id}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5330
5350
  },
5331
5351
  create: async (marketId, data) => {
5332
5352
  return httpClient.post(`/${marketId}/product-codes`, data);
@@ -5339,8 +5359,8 @@ function create$9(httpClient) {
5339
5359
 
5340
5360
  function create$8(httpClient) {
5341
5361
  return {
5342
- get: async (marketId, saleId) => {
5343
- return httpClient.get(`/${marketId}/sales/${saleId}`);
5362
+ get: async (marketId, saleId, options) => {
5363
+ return httpClient.get(`/${marketId}/sales/${saleId}`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5344
5364
  },
5345
5365
  list: async (marketId, opts) => {
5346
5366
  return httpClient.get(`/${marketId}/sales`, opts);
@@ -5391,8 +5411,8 @@ function create$6(httpClient) {
5391
5411
 
5392
5412
  function create$5(httpClient) {
5393
5413
  return {
5394
- get: async (marketId) => {
5395
- return httpClient.get(`/${marketId}/settings`);
5414
+ get: async (marketId, options) => {
5415
+ return httpClient.get(`/${marketId}/settings`, (options === null || options === void 0 ? void 0 : options.at) ? { at: options.at } : undefined);
5396
5416
  },
5397
5417
  };
5398
5418
  }
@@ -5517,13 +5537,19 @@ function create(httpClient) {
5517
5537
  * @returns List of transactions with pagination info
5518
5538
  */
5519
5539
  listTransactions: async (marketId, params) => {
5520
- let queryParams = {
5521
- account: params.account,
5522
- dateFrom: params.dateFrom,
5523
- dateTo: params.dateTo,
5524
- limit: params.limit,
5525
- cursor: params.cursor,
5526
- };
5540
+ let queryParams = {};
5541
+ if (params.account)
5542
+ queryParams.account = params.account;
5543
+ if (params.referenceGroupKey)
5544
+ queryParams.referenceGroupKey = params.referenceGroupKey;
5545
+ if (params.dateFrom)
5546
+ queryParams.dateFrom = params.dateFrom;
5547
+ if (params.dateTo)
5548
+ queryParams.dateTo = params.dateTo;
5549
+ if (params.limit)
5550
+ queryParams.limit = params.limit;
5551
+ if (params.cursor)
5552
+ queryParams.cursor = params.cursor;
5527
5553
  return httpClient.get(`/${marketId}/ledger/transactions`, queryParams);
5528
5554
  },
5529
5555
  };
@@ -5792,6 +5818,15 @@ class EarTag {
5792
5818
  parsedCountryCode = match11[1];
5793
5819
  parsedNationalIdentifier = `${match11[3]}${match11[4]}`;
5794
5820
  }
5821
+ else {
5822
+ // 10-digit national ID (e.g. DE, FR imported tags)
5823
+ const regex10 = new RegExp(`^[0-9]{0,7}(${countryPattern})([0-9]{5})([0-9]{5})`);
5824
+ let match10 = regex10.exec(workingInput);
5825
+ if (match10) {
5826
+ parsedCountryCode = match10[1];
5827
+ parsedNationalIdentifier = `${match10[3]}${match10[4]}`;
5828
+ }
5829
+ }
5795
5830
  }
5796
5831
  // Part 2: If no country code parsed yet, try fallback
5797
5832
  if (!parsedCountryCode && fallbackCountryCode) {
@@ -5799,7 +5834,7 @@ class EarTag {
5799
5834
  if (numericFallback) {
5800
5835
  // `workingInput` at this point is the original input (cleaned, no recognized country code)
5801
5836
  // Assume `workingInput` is the national identifier part (must be 11 or 12 digits)
5802
- if (workingInput.length === 12 || workingInput.length === 11) {
5837
+ if (workingInput.length >= 10 && workingInput.length <= 12) {
5803
5838
  parsedCountryCode = numericFallback;
5804
5839
  parsedNationalIdentifier = workingInput;
5805
5840
  // Update _raw to reflect the tag as if it had the country code
@@ -5810,7 +5845,11 @@ class EarTag {
5810
5845
  // Part 3: Finalize and set properties
5811
5846
  if (parsedCountryCode && parsedNationalIdentifier) {
5812
5847
  this._isoCountryCode = parsedCountryCode;
5813
- if (parsedNationalIdentifier.length === 11) {
5848
+ if (parsedNationalIdentifier.length === 10) {
5849
+ // 10-digit national ID (e.g. DE, FR imported tags) — store as-is
5850
+ this._nationalIdentifier = parsedNationalIdentifier;
5851
+ }
5852
+ else if (parsedNationalIdentifier.length === 11) {
5814
5853
  // Pad 11-digit national ID to 12-digits by prepending "0"
5815
5854
  this._nationalIdentifier = "0" + parsedNationalIdentifier;
5816
5855
  }
@@ -5818,7 +5857,6 @@ class EarTag {
5818
5857
  this._nationalIdentifier = parsedNationalIdentifier;
5819
5858
  }
5820
5859
  else {
5821
- // This case should ideally not be reached if lengths are checked properly before.
5822
5860
  this._isEartag = false;
5823
5861
  return;
5824
5862
  }
@@ -5842,7 +5880,14 @@ class EarTag {
5842
5880
  if (!this._isEartag) {
5843
5881
  return "Invalid EarTag";
5844
5882
  }
5845
- return `${EarTag.countryCodesByNumber[this.isoCountryCode]} ${this.nationalIdentifier.slice(0, 7)} ${this.nationalIdentifier.slice(7)}`;
5883
+ let country = EarTag.countryCodesByNumber[this.isoCountryCode];
5884
+ let id = this.nationalIdentifier;
5885
+ // 10-digit national IDs (DE, FR imports) format as 5+5
5886
+ // 12-digit national IDs (UK, IE, etc.) format as 7+5
5887
+ if (id.length === 10) {
5888
+ return `${country} ${id.slice(0, 5)} ${id.slice(5)}`;
5889
+ }
5890
+ return `${country} ${id.slice(0, 7)} ${id.slice(7)}`;
5846
5891
  }
5847
5892
  isISO24631() {
5848
5893
  return EarTag.regexISO24631.test(this._raw);
@@ -5867,6 +5912,124 @@ EarTag.countryCodes = {
5867
5912
  BE: "056",
5868
5913
  };
5869
5914
 
5915
+ /**
5916
+ * Parses the bottom barcode on a UK cattle passport.
5917
+ *
5918
+ * The barcode is a 30-character fixed-width positional format:
5919
+ * [0-13] Eartag — 2 alpha country code + 12 char national ID (space-padded for shorter foreign tags)
5920
+ * [14-21] Date of birth — ddMMyyyy
5921
+ * [22] Sex — F or M
5922
+ * [23-27] Breed code — left-justified, space-padded to 5 chars
5923
+ * [28-29] Passport version — 2 digits
5924
+ *
5925
+ * UK animals fill all 12 digits of the national ID. Imported animals (DE, FR, BE, etc.)
5926
+ * have shorter national IDs so the field is right-padded with spaces.
5927
+ *
5928
+ * Examples:
5929
+ * UK12345671004215032023MHER 01 ← UK tag, breed HER
5930
+ * UK98765430018722112022FLIMX 01 ← UK tag, breed LIMX
5931
+ * DE04821 9315614092018FHF 01 ← German import, 10-digit national ID
5932
+ * FR72341 6850203052020FHF 01 ← French import, 10-digit national ID
5933
+ */
5934
+ class CattlePassport {
5935
+ constructor(raw, earTag, dateOfBirth, sex, breed, passportVersion) {
5936
+ this._raw = raw;
5937
+ this._earTag = earTag;
5938
+ this._dateOfBirth = dateOfBirth;
5939
+ this._sex = sex;
5940
+ this._breed = breed;
5941
+ this._passportVersion = passportVersion;
5942
+ }
5943
+ static parse(code) {
5944
+ let raw = code;
5945
+ let trimmed = code.trim();
5946
+ if (trimmed.length !== CattlePassport.BARCODE_LENGTH)
5947
+ return null;
5948
+ // Extract fixed-width fields
5949
+ let earTagField = trimmed.slice(0, 14);
5950
+ let dobField = trimmed.slice(14, 22);
5951
+ let sexChar = trimmed.charAt(22);
5952
+ let breedField = trimmed.slice(23, 28);
5953
+ let versionField = trimmed.slice(28, 30);
5954
+ // Country code: 2 alpha chars
5955
+ let countryCode = earTagField.slice(0, 2);
5956
+ if (!/^[A-Z]{2}$/.test(countryCode))
5957
+ return null;
5958
+ // National ID: strip spaces (padding for shorter foreign tags)
5959
+ let nationalId = earTagField.slice(2).replace(/\s/g, "");
5960
+ if (!/^\d+$/.test(nationalId) || nationalId.length === 0)
5961
+ return null;
5962
+ let earTag = countryCode + nationalId;
5963
+ // DOB: ddMMyyyy
5964
+ if (!/^\d{8}$/.test(dobField))
5965
+ return null;
5966
+ let day = dobField.slice(0, 2);
5967
+ let month = dobField.slice(2, 4);
5968
+ let year = dobField.slice(4, 8);
5969
+ let d = new Date(`${year}-${month}-${day}T00:00:00Z`);
5970
+ if (isNaN(d.getTime()))
5971
+ return null;
5972
+ // Sex
5973
+ if (sexChar !== "F" && sexChar !== "M")
5974
+ return null;
5975
+ let sex = sexChar === "M" ? "Male" : "Female";
5976
+ // Breed: trimmed, alpha only
5977
+ let breed = breedField.trim();
5978
+ if (!breed || !/^[A-Z]+$/.test(breed))
5979
+ return null;
5980
+ // Passport version
5981
+ if (!/^\d{2}$/.test(versionField))
5982
+ return null;
5983
+ let passportVersion = parseInt(versionField);
5984
+ return new CattlePassport(raw, earTag, d, sex, breed, passportVersion);
5985
+ }
5986
+ /** The original raw barcode string */
5987
+ get raw() {
5988
+ return this._raw;
5989
+ }
5990
+ /** The eartag extracted from the barcode, e.g. "UK705946601313" or "DE0359581730" */
5991
+ get earTag() {
5992
+ return this._earTag;
5993
+ }
5994
+ /** Date of birth (UTC) */
5995
+ get dateOfBirth() {
5996
+ return this._dateOfBirth;
5997
+ }
5998
+ /** Male or Female */
5999
+ get sex() {
6000
+ return this._sex;
6001
+ }
6002
+ /** Breed code, e.g. "AA", "HF", "LIMX" */
6003
+ get breed() {
6004
+ return this._breed;
6005
+ }
6006
+ /** Passport version number */
6007
+ get passportVersion() {
6008
+ return this._passportVersion;
6009
+ }
6010
+ /** 2-letter country code, e.g. "UK", "DE", "FR" */
6011
+ get countryCode() {
6012
+ return this._earTag.slice(0, 2);
6013
+ }
6014
+ /** Format the eartag via the EarTag class. Falls back to the raw tag string. */
6015
+ get formattedEarTag() {
6016
+ let formatted = EarTag.format(this._earTag);
6017
+ return formatted !== null && formatted !== void 0 ? formatted : this._earTag;
6018
+ }
6019
+ /** Date of birth as DD/MM/YYYY */
6020
+ get formattedDateOfBirth() {
6021
+ let d = this._dateOfBirth;
6022
+ let day = String(d.getUTCDate()).padStart(2, "0");
6023
+ let month = String(d.getUTCMonth() + 1).padStart(2, "0");
6024
+ let year = d.getUTCFullYear();
6025
+ return `${day}/${month}/${year}`;
6026
+ }
6027
+ toString() {
6028
+ return `${this.formattedEarTag} | ${this.formattedDateOfBirth} | ${this._sex} | ${this._breed} | v${this._passportVersion}`;
6029
+ }
6030
+ }
6031
+ CattlePassport.BARCODE_LENGTH = 30;
6032
+
5870
6033
  /**
5871
6034
  * Extract the smallest lot number for sorting purposes.
5872
6035
  * Handles formats:
@@ -6028,6 +6191,7 @@ function incrementAlphaSequence(alpha) {
6028
6191
  return chars.join("");
6029
6192
  }
6030
6193
 
6194
+ exports.CattlePassport = CattlePassport;
6031
6195
  exports.EarTag = EarTag;
6032
6196
  exports.Studio = Studio;
6033
6197
  exports.StudioHeaders = StudioHeaders;