iobroker.parcelapp 0.2.8 → 0.2.10

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
@@ -11,13 +11,13 @@
11
11
 
12
12
  <img src="https://raw.githubusercontent.com/krobipd/ioBroker.parcelapp/main/admin/parcelapp.svg" width="100" />
13
13
 
14
- ioBroker adapter that connects to the [parcel.app](https://parcelapp.net) API and exposes package tracking data from 300+ carriers as ioBroker states — including delivery status, time windows, and tracking events.
14
+ ioBroker adapter that connects to the [parcel.app](https://parcelapp.net) API and exposes package tracking data from 400+ carriers as ioBroker states — including delivery status, time windows, and tracking events.
15
15
 
16
16
  ---
17
17
 
18
18
  ## Features
19
19
 
20
- - **300+ carriers** — DHL, FedEx, UPS, Amazon, Hermes, GLS, DPD, and many more via parcel.app
20
+ - **400+ carriers** — DHL, FedEx, UPS, Amazon, Hermes, GLS, DPD, and many more via parcel.app
21
21
  - **Per-package ioBroker states** — carrier, status, tracking number, delivery window, last event, last location
22
22
  - **Summary states** — active count, today count, combined delivery window
23
23
  - **Delivery time estimates** — today, tomorrow, in X days with combined time window
@@ -94,6 +94,13 @@ parcelapp.0.
94
94
 
95
95
  ## Changelog
96
96
 
97
+ ### 0.2.10 (2026-04-12)
98
+ - Fix test timezone bug, remove unused devDependencies, add `no-floating-promises` lint rule
99
+ - Remove redundant `actions/checkout` from CI workflow
100
+
101
+ ### 0.2.9 (2026-04-08)
102
+ - Add standard ioBroker test suite, optimize test build config
103
+
97
104
  ### 0.2.8 (2026-04-05)
98
105
  - Clean up empty parent folders after removing obsolete states
99
106
 
@@ -109,13 +116,7 @@ parcelapp.0.
109
116
  ### 0.2.4 (2026-04-03)
110
117
  - Modernize dev tooling (esbuild, TypeScript 5.9 pin, testing-action-check v2)
111
118
 
112
- ### 0.2.3 (2026-03-28)
113
- - Fix carrier name cache not retrying after initial failure
114
-
115
- ### 0.2.2 (2026-03-28)
116
- - Adapter-managed timers, CI on Windows/macOS, consistent i18n keys, full MIT license in README
117
-
118
- Older changelog: [CHANGELOG.md](CHANGELOG.md)
119
+ Older entries have been moved to [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
119
120
 
120
121
  ---
121
122
 
@@ -44,7 +44,7 @@ class StateManager {
44
44
  this.adapter = adapter;
45
45
  }
46
46
  /**
47
- * Sanitize a string for use as ioBroker object ID.
47
+ * Sanitize a string for use as ioBroker object ID (see adapter.FORBIDDEN_CHARS).
48
48
  *
49
49
  * @param name Raw string to sanitize
50
50
  */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/state-manager.ts"],
4
- "sourcesContent": ["import type { AdapterInstance } from \"@iobroker/adapter-core\";\nimport type { ParcelDelivery } from \"./types\";\nimport { STATUS_LABELS_DE, STATUS_LABELS_EN } from \"./types\";\n\n/** Status codes that have expected delivery date/time */\nconst TRACKABLE_STATUSES = new Set([2, 4, 8]);\n\nconst ESTIMATE_LABELS: Record<string, Record<string, string>> = {\n de: {\n overdue: \"\u00FCberf\u00E4llig\",\n today: \"heute\",\n tomorrow: \"morgen\",\n days: \"in %d Tagen\",\n },\n en: {\n overdue: \"overdue\",\n today: \"today\",\n tomorrow: \"tomorrow\",\n days: \"in %d days\",\n },\n};\n\n/** Manages ioBroker states for parcel deliveries */\nexport class StateManager {\n private adapter: AdapterInstance;\n\n /** @param adapter The ioBroker adapter instance */\n constructor(adapter: AdapterInstance) {\n this.adapter = adapter;\n }\n\n /**\n * Sanitize a string for use as ioBroker object ID.\n *\n * @param name Raw string to sanitize\n */\n sanitize(name: string): string {\n return (\n name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, 50) || \"unknown\"\n );\n }\n\n /**\n * Build a unique package ID from a delivery.\n *\n * @param delivery The delivery to build an ID for\n */\n packageId(delivery: ParcelDelivery): string {\n let id = this.sanitize(delivery.tracking_number);\n if (delivery.extra_information) {\n id += `_${this.sanitize(delivery.extra_information)}`;\n }\n return id;\n }\n\n /**\n * Update or create all states for a delivery.\n *\n * @param delivery The delivery data from API\n * @param carrierName Resolved carrier display name\n */\n async updateDelivery(\n delivery: ParcelDelivery,\n carrierName: string,\n ): Promise<void> {\n const pkgId = this.packageId(delivery);\n const devicePath = `deliveries.${pkgId}`;\n\n await this.adapter.extendObjectAsync(devicePath, {\n type: \"device\",\n common: {\n name: delivery.description || `Package ${delivery.tracking_number}`,\n },\n native: {},\n });\n\n const statusCode = parseInt(delivery.status_code, 10) || 0;\n const lang = this.adapter.config.language || \"de\";\n const labels = lang === \"de\" ? STATUS_LABELS_DE : STATUS_LABELS_EN;\n\n await Promise.all([\n this.createAndSet(\n `${devicePath}.carrier`,\n \"Carrier\",\n \"string\",\n \"text\",\n carrierName,\n ),\n this.createAndSet(\n `${devicePath}.status`,\n \"Status\",\n \"string\",\n \"text\",\n labels[statusCode] || `Unknown (${statusCode})`,\n ),\n this.createAndSet(\n `${devicePath}.statusCode`,\n \"Status Code\",\n \"number\",\n \"value\",\n statusCode,\n ),\n this.createAndSet(\n `${devicePath}.description`,\n \"Description\",\n \"string\",\n \"text\",\n delivery.description || \"\",\n ),\n this.createAndSet(\n `${devicePath}.trackingNumber`,\n \"Tracking Number\",\n \"string\",\n \"text\",\n delivery.tracking_number,\n ),\n this.createAndSet(\n `${devicePath}.extraInfo`,\n \"Extra Information\",\n \"string\",\n \"text\",\n delivery.extra_information || \"\",\n ),\n this.createAndSet(\n `${devicePath}.deliveryWindow`,\n \"Delivery Window\",\n \"string\",\n \"text\",\n this.calculateDeliveryWindow(delivery, statusCode),\n ),\n this.createAndSet(\n `${devicePath}.deliveryEstimate`,\n \"Delivery Estimate\",\n \"string\",\n \"text\",\n this.calculateDeliveryEstimate(delivery, statusCode),\n ),\n this.createAndSet(\n `${devicePath}.lastEvent`,\n \"Last Event\",\n \"string\",\n \"text\",\n this.formatLastEvent(delivery),\n ),\n this.createAndSet(\n `${devicePath}.lastLocation`,\n \"Last Location\",\n \"string\",\n \"text\",\n this.extractLastLocation(delivery),\n ),\n this.createAndSet(\n `${devicePath}.lastUpdated`,\n \"Last Updated\",\n \"string\",\n \"date\",\n new Date().toISOString(),\n ),\n ]);\n }\n\n /**\n * Update summary states. Expects already-filtered active deliveries.\n *\n * @param activeDeliveries Only active (non-delivered) deliveries\n */\n async updateSummary(activeDeliveries: ParcelDelivery[]): Promise<void> {\n await this.adapter.extendObjectAsync(\"summary\", {\n type: \"channel\",\n common: { name: \"Summary\" },\n native: {},\n });\n\n const todayDeliveries = activeDeliveries.filter((d) => {\n const statusCode = parseInt(d.status_code, 10) || 0;\n const estimate = this.calculateDeliveryEstimate(d, statusCode);\n return estimate === \"heute\" || estimate === \"today\";\n });\n\n await Promise.all([\n this.createAndSet(\n \"summary.activeCount\",\n \"Active Deliveries\",\n \"number\",\n \"value\",\n activeDeliveries.length,\n ),\n this.createAndSet(\n \"summary.todayCount\",\n \"Deliveries Today\",\n \"number\",\n \"value\",\n todayDeliveries.length,\n ),\n this.createAndSet(\n \"summary.deliveryWindow\",\n \"Combined Delivery Window\",\n \"string\",\n \"text\",\n this.calculateCombinedWindow(todayDeliveries),\n ),\n ]);\n }\n\n /**\n * Remove deliveries that are no longer active.\n *\n * @param activeIds List of currently active package IDs\n */\n async cleanupDeliveries(activeIds: string[]): Promise<void> {\n const activeSet = new Set(activeIds.map((id) => `deliveries.${id}`));\n\n const objects = await this.adapter.getObjectViewAsync(\"system\", \"device\", {\n startkey: `${this.adapter.namespace}.deliveries.`,\n endkey: `${this.adapter.namespace}.deliveries.\\u9999`,\n });\n\n for (const row of objects.rows) {\n const relativeId = row.id.replace(`${this.adapter.namespace}.`, \"\");\n if (relativeId.startsWith(\"deliveries.\") && !activeSet.has(relativeId)) {\n await this.adapter.delObjectAsync(relativeId, { recursive: true });\n this.adapter.log.debug(`Removed stale delivery: ${relativeId}`);\n }\n }\n }\n\n /**\n * Calculate delivery time window \u2014 only from Unix timestamps.\n *\n * @param delivery The delivery data\n * @param statusCode Pre-parsed status code\n */\n private calculateDeliveryWindow(\n delivery: ParcelDelivery,\n statusCode: number,\n ): string {\n if (!TRACKABLE_STATUSES.has(statusCode)) {\n return \"\";\n }\n\n const formatTime = (timestamp?: number): string | null => {\n if (!timestamp) {\n return null;\n }\n const d = new Date(timestamp * 1000);\n return `${d.getHours().toString().padStart(2, \"0\")}:${d.getMinutes().toString().padStart(2, \"0\")}`;\n };\n\n const start = formatTime(delivery.timestamp_expected);\n const end = formatTime(delivery.timestamp_expected_end);\n\n if (!start) {\n return \"\";\n }\n return end ? `${start} - ${end}` : start;\n }\n\n /**\n * Calculate human-readable delivery estimate.\n *\n * @param delivery The delivery data\n * @param statusCode Pre-parsed status code\n */\n private calculateDeliveryEstimate(\n delivery: ParcelDelivery,\n statusCode: number,\n ): string {\n if (!TRACKABLE_STATUSES.has(statusCode)) {\n return \"\";\n }\n\n let expectedDate: Date | null = null;\n if (delivery.timestamp_expected) {\n expectedDate = new Date(delivery.timestamp_expected * 1000);\n } else if (delivery.date_expected) {\n expectedDate = new Date(delivery.date_expected);\n }\n\n if (!expectedDate || isNaN(expectedDate.getTime())) {\n return \"\";\n }\n\n const now = new Date();\n const todayStart = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n );\n const expectedStart = new Date(\n expectedDate.getFullYear(),\n expectedDate.getMonth(),\n expectedDate.getDate(),\n );\n const diffDays = Math.round(\n (expectedStart.getTime() - todayStart.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n const lang = this.adapter.config.language || \"de\";\n const l = ESTIMATE_LABELS[lang] || ESTIMATE_LABELS.en;\n\n if (diffDays < 0) {\n return l.overdue;\n }\n if (diffDays === 0) {\n return l.today;\n }\n if (diffDays === 1) {\n return l.tomorrow;\n }\n return l.days.replace(\"%d\", String(diffDays));\n }\n\n /**\n * Format the latest tracking event.\n *\n * @param delivery The delivery data\n */\n private formatLastEvent(delivery: ParcelDelivery): string {\n if (!delivery.events || delivery.events.length === 0) {\n return \"\";\n }\n const latest = delivery.events[0];\n const parts: string[] = [];\n if (latest.event) {\n parts.push(latest.event);\n }\n if (latest.date) {\n parts.push(latest.date);\n }\n return parts.join(\" - \");\n }\n\n /**\n * Extract location from latest event.\n *\n * @param delivery The delivery data\n */\n private extractLastLocation(delivery: ParcelDelivery): string {\n if (!delivery.events || delivery.events.length === 0) {\n return \"\";\n }\n return delivery.events[0].location || \"\";\n }\n\n /**\n * Calculate combined delivery window for today's packages.\n *\n * @param todayDeliveries Deliveries expected today\n */\n private calculateCombinedWindow(todayDeliveries: ParcelDelivery[]): string {\n const windows = todayDeliveries\n .map((d) => {\n const sc = parseInt(d.status_code, 10) || 0;\n return this.calculateDeliveryWindow(d, sc);\n })\n .filter((w) => w.length > 0);\n\n if (windows.length === 0) {\n return \"\";\n }\n if (windows.length === 1) {\n return windows[0];\n }\n\n const times: {\n /** Window start */ start: string;\n /** Window end */ end: string;\n }[] = [];\n for (const w of windows) {\n const match = w.match(/(\\d{2}:\\d{2})(?:\\s*-\\s*(\\d{2}:\\d{2}))?/);\n if (match) {\n times.push({ start: match[1], end: match[2] || match[1] });\n }\n }\n\n if (times.length === 0) {\n return \"\";\n }\n\n times.sort((a, b) => a.start.localeCompare(b.start));\n return `${times[0].start} - ${times[times.length - 1].end}`;\n }\n\n /**\n * Create/extend a read-only state and set its value.\n *\n * @param id State ID relative to adapter namespace\n * @param name Display name\n * @param type Value type\n * @param role ioBroker role\n * @param val Value to set\n */\n private async createAndSet(\n id: string,\n name: string,\n type: ioBroker.CommonType,\n role: string,\n val: ioBroker.StateValue,\n ): Promise<void> {\n await this.adapter.extendObjectAsync(id, {\n type: \"state\",\n common: { name, type, role, read: true, write: false },\n native: {},\n });\n await this.adapter.setStateAsync(id, { val, ack: true });\n }\n}\n"],
4
+ "sourcesContent": ["import type { AdapterInstance } from \"@iobroker/adapter-core\";\nimport type { ParcelDelivery } from \"./types\";\nimport { STATUS_LABELS_DE, STATUS_LABELS_EN } from \"./types\";\n\n/** Status codes that have expected delivery date/time */\nconst TRACKABLE_STATUSES = new Set([2, 4, 8]);\n\nconst ESTIMATE_LABELS: Record<string, Record<string, string>> = {\n de: {\n overdue: \"\u00FCberf\u00E4llig\",\n today: \"heute\",\n tomorrow: \"morgen\",\n days: \"in %d Tagen\",\n },\n en: {\n overdue: \"overdue\",\n today: \"today\",\n tomorrow: \"tomorrow\",\n days: \"in %d days\",\n },\n};\n\n/** Manages ioBroker states for parcel deliveries */\nexport class StateManager {\n private adapter: AdapterInstance;\n\n /** @param adapter The ioBroker adapter instance */\n constructor(adapter: AdapterInstance) {\n this.adapter = adapter;\n }\n\n /**\n * Sanitize a string for use as ioBroker object ID (see adapter.FORBIDDEN_CHARS).\n *\n * @param name Raw string to sanitize\n */\n sanitize(name: string): string {\n return (\n name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, 50) || \"unknown\"\n );\n }\n\n /**\n * Build a unique package ID from a delivery.\n *\n * @param delivery The delivery to build an ID for\n */\n packageId(delivery: ParcelDelivery): string {\n let id = this.sanitize(delivery.tracking_number);\n if (delivery.extra_information) {\n id += `_${this.sanitize(delivery.extra_information)}`;\n }\n return id;\n }\n\n /**\n * Update or create all states for a delivery.\n *\n * @param delivery The delivery data from API\n * @param carrierName Resolved carrier display name\n */\n async updateDelivery(\n delivery: ParcelDelivery,\n carrierName: string,\n ): Promise<void> {\n const pkgId = this.packageId(delivery);\n const devicePath = `deliveries.${pkgId}`;\n\n await this.adapter.extendObjectAsync(devicePath, {\n type: \"device\",\n common: {\n name: delivery.description || `Package ${delivery.tracking_number}`,\n },\n native: {},\n });\n\n const statusCode = parseInt(delivery.status_code, 10) || 0;\n const lang = this.adapter.config.language || \"de\";\n const labels = lang === \"de\" ? STATUS_LABELS_DE : STATUS_LABELS_EN;\n\n await Promise.all([\n this.createAndSet(\n `${devicePath}.carrier`,\n \"Carrier\",\n \"string\",\n \"text\",\n carrierName,\n ),\n this.createAndSet(\n `${devicePath}.status`,\n \"Status\",\n \"string\",\n \"text\",\n labels[statusCode] || `Unknown (${statusCode})`,\n ),\n this.createAndSet(\n `${devicePath}.statusCode`,\n \"Status Code\",\n \"number\",\n \"value\",\n statusCode,\n ),\n this.createAndSet(\n `${devicePath}.description`,\n \"Description\",\n \"string\",\n \"text\",\n delivery.description || \"\",\n ),\n this.createAndSet(\n `${devicePath}.trackingNumber`,\n \"Tracking Number\",\n \"string\",\n \"text\",\n delivery.tracking_number,\n ),\n this.createAndSet(\n `${devicePath}.extraInfo`,\n \"Extra Information\",\n \"string\",\n \"text\",\n delivery.extra_information || \"\",\n ),\n this.createAndSet(\n `${devicePath}.deliveryWindow`,\n \"Delivery Window\",\n \"string\",\n \"text\",\n this.calculateDeliveryWindow(delivery, statusCode),\n ),\n this.createAndSet(\n `${devicePath}.deliveryEstimate`,\n \"Delivery Estimate\",\n \"string\",\n \"text\",\n this.calculateDeliveryEstimate(delivery, statusCode),\n ),\n this.createAndSet(\n `${devicePath}.lastEvent`,\n \"Last Event\",\n \"string\",\n \"text\",\n this.formatLastEvent(delivery),\n ),\n this.createAndSet(\n `${devicePath}.lastLocation`,\n \"Last Location\",\n \"string\",\n \"text\",\n this.extractLastLocation(delivery),\n ),\n this.createAndSet(\n `${devicePath}.lastUpdated`,\n \"Last Updated\",\n \"string\",\n \"date\",\n new Date().toISOString(),\n ),\n ]);\n }\n\n /**\n * Update summary states. Expects already-filtered active deliveries.\n *\n * @param activeDeliveries Only active (non-delivered) deliveries\n */\n async updateSummary(activeDeliveries: ParcelDelivery[]): Promise<void> {\n await this.adapter.extendObjectAsync(\"summary\", {\n type: \"channel\",\n common: { name: \"Summary\" },\n native: {},\n });\n\n const todayDeliveries = activeDeliveries.filter((d) => {\n const statusCode = parseInt(d.status_code, 10) || 0;\n const estimate = this.calculateDeliveryEstimate(d, statusCode);\n return estimate === \"heute\" || estimate === \"today\";\n });\n\n await Promise.all([\n this.createAndSet(\n \"summary.activeCount\",\n \"Active Deliveries\",\n \"number\",\n \"value\",\n activeDeliveries.length,\n ),\n this.createAndSet(\n \"summary.todayCount\",\n \"Deliveries Today\",\n \"number\",\n \"value\",\n todayDeliveries.length,\n ),\n this.createAndSet(\n \"summary.deliveryWindow\",\n \"Combined Delivery Window\",\n \"string\",\n \"text\",\n this.calculateCombinedWindow(todayDeliveries),\n ),\n ]);\n }\n\n /**\n * Remove deliveries that are no longer active.\n *\n * @param activeIds List of currently active package IDs\n */\n async cleanupDeliveries(activeIds: string[]): Promise<void> {\n const activeSet = new Set(activeIds.map((id) => `deliveries.${id}`));\n\n const objects = await this.adapter.getObjectViewAsync(\"system\", \"device\", {\n startkey: `${this.adapter.namespace}.deliveries.`,\n endkey: `${this.adapter.namespace}.deliveries.\\u9999`,\n });\n\n for (const row of objects.rows) {\n const relativeId = row.id.replace(`${this.adapter.namespace}.`, \"\");\n if (relativeId.startsWith(\"deliveries.\") && !activeSet.has(relativeId)) {\n await this.adapter.delObjectAsync(relativeId, { recursive: true });\n this.adapter.log.debug(`Removed stale delivery: ${relativeId}`);\n }\n }\n }\n\n /**\n * Calculate delivery time window \u2014 only from Unix timestamps.\n *\n * @param delivery The delivery data\n * @param statusCode Pre-parsed status code\n */\n private calculateDeliveryWindow(\n delivery: ParcelDelivery,\n statusCode: number,\n ): string {\n if (!TRACKABLE_STATUSES.has(statusCode)) {\n return \"\";\n }\n\n const formatTime = (timestamp?: number): string | null => {\n if (!timestamp) {\n return null;\n }\n const d = new Date(timestamp * 1000);\n return `${d.getHours().toString().padStart(2, \"0\")}:${d.getMinutes().toString().padStart(2, \"0\")}`;\n };\n\n const start = formatTime(delivery.timestamp_expected);\n const end = formatTime(delivery.timestamp_expected_end);\n\n if (!start) {\n return \"\";\n }\n return end ? `${start} - ${end}` : start;\n }\n\n /**\n * Calculate human-readable delivery estimate.\n *\n * @param delivery The delivery data\n * @param statusCode Pre-parsed status code\n */\n private calculateDeliveryEstimate(\n delivery: ParcelDelivery,\n statusCode: number,\n ): string {\n if (!TRACKABLE_STATUSES.has(statusCode)) {\n return \"\";\n }\n\n let expectedDate: Date | null = null;\n if (delivery.timestamp_expected) {\n expectedDate = new Date(delivery.timestamp_expected * 1000);\n } else if (delivery.date_expected) {\n expectedDate = new Date(delivery.date_expected);\n }\n\n if (!expectedDate || isNaN(expectedDate.getTime())) {\n return \"\";\n }\n\n const now = new Date();\n const todayStart = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n );\n const expectedStart = new Date(\n expectedDate.getFullYear(),\n expectedDate.getMonth(),\n expectedDate.getDate(),\n );\n const diffDays = Math.round(\n (expectedStart.getTime() - todayStart.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n const lang = this.adapter.config.language || \"de\";\n const l = ESTIMATE_LABELS[lang] || ESTIMATE_LABELS.en;\n\n if (diffDays < 0) {\n return l.overdue;\n }\n if (diffDays === 0) {\n return l.today;\n }\n if (diffDays === 1) {\n return l.tomorrow;\n }\n return l.days.replace(\"%d\", String(diffDays));\n }\n\n /**\n * Format the latest tracking event.\n *\n * @param delivery The delivery data\n */\n private formatLastEvent(delivery: ParcelDelivery): string {\n if (!delivery.events || delivery.events.length === 0) {\n return \"\";\n }\n const latest = delivery.events[0];\n const parts: string[] = [];\n if (latest.event) {\n parts.push(latest.event);\n }\n if (latest.date) {\n parts.push(latest.date);\n }\n return parts.join(\" - \");\n }\n\n /**\n * Extract location from latest event.\n *\n * @param delivery The delivery data\n */\n private extractLastLocation(delivery: ParcelDelivery): string {\n if (!delivery.events || delivery.events.length === 0) {\n return \"\";\n }\n return delivery.events[0].location || \"\";\n }\n\n /**\n * Calculate combined delivery window for today's packages.\n *\n * @param todayDeliveries Deliveries expected today\n */\n private calculateCombinedWindow(todayDeliveries: ParcelDelivery[]): string {\n const windows = todayDeliveries\n .map((d) => {\n const sc = parseInt(d.status_code, 10) || 0;\n return this.calculateDeliveryWindow(d, sc);\n })\n .filter((w) => w.length > 0);\n\n if (windows.length === 0) {\n return \"\";\n }\n if (windows.length === 1) {\n return windows[0];\n }\n\n const times: {\n /** Window start */ start: string;\n /** Window end */ end: string;\n }[] = [];\n for (const w of windows) {\n const match = w.match(/(\\d{2}:\\d{2})(?:\\s*-\\s*(\\d{2}:\\d{2}))?/);\n if (match) {\n times.push({ start: match[1], end: match[2] || match[1] });\n }\n }\n\n if (times.length === 0) {\n return \"\";\n }\n\n times.sort((a, b) => a.start.localeCompare(b.start));\n return `${times[0].start} - ${times[times.length - 1].end}`;\n }\n\n /**\n * Create/extend a read-only state and set its value.\n *\n * @param id State ID relative to adapter namespace\n * @param name Display name\n * @param type Value type\n * @param role ioBroker role\n * @param val Value to set\n */\n private async createAndSet(\n id: string,\n name: string,\n type: ioBroker.CommonType,\n role: string,\n val: ioBroker.StateValue,\n ): Promise<void> {\n await this.adapter.extendObjectAsync(id, {\n type: \"state\",\n common: { name, type, role, read: true, write: false },\n native: {},\n });\n await this.adapter.setStateAsync(id, { val, ack: true });\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "parcelapp",
4
- "version": "0.2.8",
4
+ "version": "0.2.10",
5
5
  "news": {
6
+ "0.2.10": {
7
+ "en": "Fix test timezone bug, remove unused devDependencies, add no-floating-promises lint rule",
8
+ "de": "Test-Zeitzonenfehler behoben, ungenutzte devDependencies entfernt, no-floating-promises Lint-Regel hinzugefügt",
9
+ "ru": "Исправлена ошибка часового пояса в тестах, удалены неиспользуемые devDependencies, добавлено правило линтинга no-floating-promises",
10
+ "pt": "Corrigido bug de fuso horário em testes, removidas devDependencies não utilizadas, adicionada regra de lint no-floating-promises",
11
+ "nl": "Tijdzonebug in tests opgelost, ongebruikte devDependencies verwijderd, no-floating-promises lintregel toegevoegd",
12
+ "fr": "Correction du bug de fuseau horaire dans les tests, suppression des devDependencies inutilisées, ajout de la règle de lint no-floating-promises",
13
+ "it": "Corretto bug fuso orario nei test, rimosse devDependencies inutilizzate, aggiunta regola lint no-floating-promises",
14
+ "es": "Corregido error de zona horaria en pruebas, eliminadas devDependencies no utilizadas, añadida regla de lint no-floating-promises",
15
+ "pl": "Naprawiono błąd strefy czasowej w testach, usunięto nieużywane devDependencies, dodano regułę lint no-floating-promises",
16
+ "uk": "Виправлено помилку часового поясу в тестах, видалено невикористані devDependencies, додано правило лінтингу no-floating-promises",
17
+ "zh-cn": "修复测试时区错误,移除未使用的开发依赖,添加 no-floating-promises 检查规则"
18
+ },
19
+ "0.2.9": {
20
+ "en": "Add standard ioBroker test suite, optimize test build config",
21
+ "de": "Standard-ioBroker-Testsuite hinzugefügt, Test-Build-Konfiguration optimiert",
22
+ "ru": "Добавлен стандартный набор тестов ioBroker, оптимизирована конфигурация сборки тестов",
23
+ "pt": "Adicionado conjunto de testes padrão do ioBroker, configuração de build de teste otimizada",
24
+ "nl": "Standaard ioBroker-testsuite toegevoegd, testbuild-configuratie geoptimaliseerd",
25
+ "fr": "Ajout de la suite de tests standard ioBroker, configuration de build de test optimisée",
26
+ "it": "Aggiunta suite di test standard ioBroker, configurazione build test ottimizzata",
27
+ "es": "Añadida suite de pruebas estándar de ioBroker, configuración de compilación de pruebas optimizada",
28
+ "pl": "Dodano standardowy zestaw testów ioBroker, zoptymalizowano konfigurację budowania testów",
29
+ "uk": "Додано стандартний набір тестів ioBroker, оптимізовано конфігурацію збірки тестів",
30
+ "zh-cn": "添加标准 ioBroker 测试套件,优化测试构建配置"
31
+ },
6
32
  "0.2.8": {
7
33
  "en": "Clean up empty parent folders after removing obsolete states",
8
34
  "de": "Leere Eltern-Ordner nach Entfernen obsoleter States löschen",
@@ -67,32 +93,6 @@
67
93
  "pl": "Modernizacja narzędzi programistycznych (esbuild, TypeScript 5.9, testing-action-check v2)",
68
94
  "uk": "Модернізація інструментів розробки (esbuild, TypeScript 5.9, testing-action-check v2)",
69
95
  "zh-cn": "开发工具现代化(esbuild、TypeScript 5.9 固定、testing-action-check v2)"
70
- },
71
- "0.2.3": {
72
- "en": "Fix carrier name cache not retrying after initial failure",
73
- "de": "Fix: Carrier-Namen-Cache versucht nach initialem Fehler erneut zu laden",
74
- "ru": "Исправление: кэш имен перевозчиков повторяет попытку после начального сбоя",
75
- "pt": "Correção: cache de nomes de transportadoras tenta novamente após falha inicial",
76
- "nl": "Fix: carrier naam cache probeert opnieuw na initiële fout",
77
- "fr": "Correction: le cache des noms de transporteurs réessaie après un échec initial",
78
- "it": "Fix: la cache dei nomi dei corrieri riprova dopo un errore iniziale",
79
- "es": "Corrección: la caché de nombres de transportistas reintenta tras fallo inicial",
80
- "pl": "Poprawka: pamięć podręczna nazw przewoźników ponawia próbę po początkowym błędzie",
81
- "uk": "Виправлення: кеш назв перевізників повторює спробу після початкової помилки",
82
- "zh-cn": "修复:运营商名称缓存在初次失败后重新尝试加载"
83
- },
84
- "0.2.2": {
85
- "en": "Adapter-managed timers, CI on Windows/macOS, consistent admin UI i18n keys, full MIT license in README",
86
- "de": "Adapter-verwaltete Timer, CI auf Windows/macOS, konsistente Admin-UI i18n-Keys, vollständige MIT-Lizenz in README",
87
- "ru": "Таймеры, управляемые адаптером, CI на Windows/macOS, согласованные ключи i18n в Admin UI, полная лицензия MIT в README",
88
- "pt": "Timers gerenciados pelo adaptador, CI no Windows/macOS, chaves i18n consistentes na UI admin, licença MIT completa no README",
89
- "nl": "Adapter-beheerde timers, CI op Windows/macOS, consistente admin-UI i18n-sleutels, volledige MIT-licentie in README",
90
- "fr": "Minuteries gérées par l adaptateur, CI sur Windows/macOS, clés i18n cohérentes dans l interface admin, licence MIT complète dans README",
91
- "it": "Timer gestiti dall adattatore, CI su Windows/macOS, chiavi i18n coerenti nell interfaccia admin, licenza MIT completa nel README",
92
- "es": "Temporizadores gestionados por el adaptador, CI en Windows/macOS, claves i18n consistentes en la UI de admin, licencia MIT completa en README",
93
- "pl": "Timery zarządzane przez adapter, CI na Windows/macOS, spójne klucze i18n w admin UI, pełna licencja MIT w README",
94
- "uk": "Таймери, керовані адаптером, CI на Windows/macOS, узгоджені ключі i18n в Admin UI, повна ліцензія MIT в README",
95
- "zh-cn": "适配器管理的定时器,Windows/macOS CI,一致的管理界面 i18n 键,README 中的完整 MIT 许可证"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -109,17 +109,17 @@
109
109
  "zh-cn": "包裹追踪"
110
110
  },
111
111
  "desc": {
112
- "en": "ioBroker adapter for parcel.app — track packages from 300+ carriers as ioBroker states",
113
- "de": "ioBroker-Adapter für parcel.app — Pakete von 300+ Versandunternehmen als ioBroker-States verfolgen",
114
- "ru": "Адаптер ioBroker для parcel.app — отслеживание посылок от 300+ перевозчиков как состояния ioBroker",
115
- "pt": "Adaptador ioBroker para parcel.app — rastreie pacotes de mais de 300 transportadoras como estados ioBroker",
116
- "nl": "ioBroker-adapter voor parcel.app — volg pakketten van 300+ vervoerders als ioBroker-states",
117
- "fr": "Adaptateur ioBroker pour parcel.app — suivez vos colis de plus de 300 transporteurs comme états ioBroker",
118
- "it": "Adattatore ioBroker per parcel.app — traccia pacchi da più di 300 corrieri come stati ioBroker",
119
- "es": "Adaptador ioBroker para parcel.app — rastrea paquetes de más de 300 transportistas como estados ioBroker",
120
- "pl": "Adapter ioBroker dla parcel.app — śledź przesyłki od 300+ przewoźników jako stany ioBroker",
121
- "uk": "Адаптер ioBroker для parcel.app — відстеження посилок від 300+ перевізників як стани ioBroker",
122
- "zh-cn": "parcel.app 的 ioBroker 适配器 — 将 300+ 快递公司的包裹追踪数据作为 ioBroker 状态"
112
+ "en": "ioBroker adapter for parcel.app — track packages from 400+ carriers as ioBroker states",
113
+ "de": "ioBroker-Adapter für parcel.app — Pakete von 400+ Versandunternehmen als ioBroker-States verfolgen",
114
+ "ru": "Адаптер ioBroker для parcel.app — отслеживание посылок от 400+ перевозчиков как состояния ioBroker",
115
+ "pt": "Adaptador ioBroker para parcel.app — rastreie pacotes de mais de 400 transportadoras como estados ioBroker",
116
+ "nl": "ioBroker-adapter voor parcel.app — volg pakketten van 400+ vervoerders als ioBroker-states",
117
+ "fr": "Adaptateur ioBroker pour parcel.app — suivez vos colis de plus de 400 transporteurs comme états ioBroker",
118
+ "it": "Adattatore ioBroker per parcel.app — traccia pacchi da più di 400 corrieri come stati ioBroker",
119
+ "es": "Adaptador ioBroker para parcel.app — rastrea paquetes de más de 400 transportistas como estados ioBroker",
120
+ "pl": "Adapter ioBroker dla parcel.app — śledź przesyłki od 400+ przewoźników jako stany ioBroker",
121
+ "uk": "Адаптер ioBroker для parcel.app — відстеження посилок від 400+ перевізників як стани ioBroker",
122
+ "zh-cn": "parcel.app 的 ioBroker 适配器 — 将 400+ 快递公司的包裹追踪数据作为 ioBroker 状态"
123
123
  },
124
124
  "authors": [
125
125
  "krobi <krobi@power-dreams.com>"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.parcelapp",
3
- "version": "0.2.8",
4
- "description": "ioBroker adapter for parcel.app — track packages from 300+ carriers",
3
+ "version": "0.2.10",
4
+ "description": "ioBroker adapter for parcel.app — track packages from 400+ carriers",
5
5
  "author": {
6
6
  "name": "krobi",
7
7
  "email": "krobi@power-dreams.com"
@@ -39,8 +39,6 @@
39
39
  "@types/iobroker": "npm:@iobroker/types@^7.1.0",
40
40
  "@types/node": "^25.5.0",
41
41
  "rimraf": "^6.1.3",
42
- "source-map-support": "^0.5.21",
43
- "ts-node": "^10.9.2",
44
42
  "typescript": "~5.9.3"
45
43
  },
46
44
  "files": [
@@ -56,10 +54,10 @@
56
54
  "build:test": "tsc -p tsconfig.test.json",
57
55
  "watch": "build-adapter ts --watch",
58
56
  "check": "tsc --noEmit",
59
- "test:package": "npm run build:test && mocha --exit \"build/test/testPackageFiles.js\"",
60
- "test:integration": "npm run build:test && mocha --exit \"build/test/**/*.js\"",
61
- "test": "npm run build:test && mocha --exit \"build/test/**/*.js\"",
62
- "test:ci": "npm run build:test && mocha --exit --reporter spec \"build/test/**/*.js\"",
57
+ "test:ts": "npm run build:test && mocha --exit \"build/test/test*.js\"",
58
+ "test:package": "mocha test/package --exit",
59
+ "test:integration": "mocha test/integration --exit",
60
+ "test": "npm run build && npm run test:ts && npm run test:package",
63
61
  "translate": "translate-adapter",
64
62
  "lint": "eslint",
65
63
  "lint:fix": "eslint --fix",