From 746f5a3aed5ef31062b9b69b43f02601d62cdaa6 Mon Sep 17 00:00:00 2001 From: Dave Meehan Date: Thu, 22 Jan 2026 15:03:41 +0000 Subject: [PATCH 1/3] Add vendor Wavetrend with initial support for SD01-L --- vendors/wavetrend/drivers/ONTOLOGY.md | 123 + vendors/wavetrend/drivers/README.md | 1200 +++++ .../wavetrend/drivers/sd01-l-v2/.npmignore | 12 + .../wavetrend/drivers/sd01-l-v2/driver.yaml | 18 + .../wavetrend/drivers/sd01-l-v2/examples.json | 400 ++ .../wavetrend/drivers/sd01-l-v2/metadata.json | 16 + .../drivers/sd01-l-v2/package-lock.json | 4695 +++++++++++++++++ .../wavetrend/drivers/sd01-l-v2/package.json | 18 + .../drivers/sd01-l-v2/run-driver-test.js | 20 + .../drivers/sd01-l-v2/src/downlink.js | 358 ++ .../wavetrend/drivers/sd01-l-v2/src/index.js | 2 + .../wavetrend/drivers/sd01-l-v2/src/uplink.js | 426 ++ .../drivers/sd01-l-v2/webpack.config.js | 14 + vendors/wavetrend/logo.png | Bin 0 -> 6821 bytes vendors/wavetrend/models/sd01-l-v2/logo.png | Bin 0 -> 33265 bytes vendors/wavetrend/models/sd01-l-v2/model.yaml | 64 + .../profiles/wavetrend_EU868_1.1_classA.yaml | 98 + vendors/wavetrend/vendor.yaml | 19 + 18 files changed, 7483 insertions(+) create mode 100644 vendors/wavetrend/drivers/ONTOLOGY.md create mode 100644 vendors/wavetrend/drivers/README.md create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/.npmignore create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/driver.yaml create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/examples.json create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/metadata.json create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/package-lock.json create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/package.json create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/run-driver-test.js create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/src/downlink.js create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/src/index.js create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/src/uplink.js create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js create mode 100644 vendors/wavetrend/logo.png create mode 100644 vendors/wavetrend/models/sd01-l-v2/logo.png create mode 100644 vendors/wavetrend/models/sd01-l-v2/model.yaml create mode 100644 vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml create mode 100644 vendors/wavetrend/vendor.yaml diff --git a/vendors/wavetrend/drivers/ONTOLOGY.md b/vendors/wavetrend/drivers/ONTOLOGY.md new file mode 100644 index 000000000..1842d35ef --- /dev/null +++ b/vendors/wavetrend/drivers/ONTOLOGY.md @@ -0,0 +1,123 @@ +# Ontology + +This is the ontology supported by Actility. You can define a sensor inside your model depending on this table. + +> Our ontology is based on [oBIX protocol](http://docs.oasis-open.org/obix/obix/v1.1/csprd01/obix-v1.1-csprd01.pdf) which provides an extensive database of predefined units that are represented in seven main dimensions. These seven dimensions are represented in SI respectively as kilogram (kg), meter (m), second (sec), Kelvin (K), ampere (A), mole (mol), and candela (cd). + +| Unit | unitId | type | symbol | fields | +|------|--------|------|--------|--------| +| acceleration compared to earth gravity | gravity | double | g | acceleration, vibration | +| ampere | A | double | A | current | +| ampere-hour | Ah | double | Ah | charge | +| bar | bar | double | bar | pressure | +| becquerel | Bq | double | Bq | radioactivity | +| bel | Bspl | double | bel | intensity, snr, sound | +| bit | bit | double | bit | data, storage | +| bit per second | bit/s | double | bit/s | dataSpeed | +| candela | cd | double | cd | intensity | +| candela per square meter | cd/m2 | double | cd/m² | brightness | +| celsius | Cel | double | °C | temperature | +| centimeter | cm | double | cm | distance, accuracy, range, altitude, height | +| coulomb | C | double | C | electricCharge | +| count per minute | count/min | double | count/min | eventRate, count | +| count per second | count/s | double | count/s | eventRate, count | +| counter | count | int64 | occ. | counter, amount, quantity | +| cubic meter | m3 | double | m³ | volume | +| cubic meter per hour | m3/h | double | m³/h | flowRate | +| cubic meter per second | m3/s | double | m³/s | flowRate | +| day | day | double | day | time, duration, interval, age, period | +| decibel | dB | double | dB | intensity, snr, sound | +| decibel relative to 1 mW | dBm | double | dBm | rssi | +| decibel relative to 1 W | dBW | double | dBW | powerLevel | +| degree | deg | double | ° | angle | +| degrees per second | dps | double | dps | angularVelocity | +| dilution of precision | dop | double | dop | navigation | +| euro | euro | double | € | price | +| euro per watt-hour | euro/Wh | double | €/Wh | energyPrice | +| fahrenheit | Far | double | °F | temperature | +| farad | F | double | F | capacitance | +| gigawatt | GW | double | GW | power, activePower | +| GPS | GPS | object | GPS | location | +| gram | g | double | g | mass, weight | +| gray | Gy | double | Gy | radiation | +| hectopascal | hPa | double | hPa | pressure | +| henry | H | double | H | inductance | +| hertz | hertz | double | Hz | frequency, sound | +| hour | h | double | h | time, duration, interval, age, period | +| index | index | int64 | index | uv | +| joule | J | double | J | energy | +| katal | kat | double | kat | catalyticActivity | +| kelvin | K | double | K | temperature | +| kilogram | kg | double | kg | mass, weight | +| kilometer | km | double | km | distance, accuracy, range, altitude, height | +| kilometer per hour | km/h | double | km/h | velocity, speed | +| kilopascal | kPa | double | kPa | pressure | +| kilowatt | kW | double | kW | power, activePower | +| kilowatt-hour | kWh | double | kWh | energy | +| liter | l | double | l | volume, capacity | +| liter per second | l/s | double | l/s | flowRate | +| lumen | lm | double | lm | flux, light | +| lux | lx | double | lx | flux, light, illuminance | +| mac | IEEE-802 | string | mac | mac | +| megawatt | MW | double | MW | power, activePower | +| megawatt per minute | MW/m | double | MW/m | powerRate | +| megawatt-hour | MWh | double | MWh | energy | +| meter | m | double | m | distance, accuracy, range, altitude, height | +| meter per second | m/s | double | m/s | velocity, speed | +| meter per square second | m/s2 | double | m/s² | acceleration, vibration | +| micro-gravity | ugravity | double | µg | acceleration, vibration | +| microgram | ug | double | µg | mass, weight | +| microgram per cubic meter | ug/m3 | double | µg/m³ | concentration | +| micrometer | um | double | µm | distance, accuracy, range, altitude, height | +| micromole per second and square meter | umol/m2.s | double | µmol/m².s | fluxDensity, intensity | +| microsiemens per centimeter | uS/cm | double | µS/cm | conductivity | +| microvolt | uV | double | µV | batteryVoltage, rmsVoltage, voltage | +| milli-gravity | mgravity | double | mg | acceleration, vibration | +| milliampere | mA | double | mA | current | +| milliampere-hour | mAh | double | mAh | charge | +| millibar | mbar | double | mbar | pressure | +| millileter | ml | double | ml | volume, capacity | +| millimeter | mm | double | mm | distance, accuracy, range, altitude, height | +| millimeter per hour | mm/h | double | mm/h | velocity, speed | +| millimeter per second | mm/s | double | mm/s | velocity, speed | +| millisecond | ms | double | ms | time, duration, interval, age, period | +| millisiemens per centimeter | mS/cm | double | mS/cm | conductivity | +| millivolt | mV | double | mV | batteryVoltage, rmsVoltage, voltage | +| minute | minute | double | min | time, duration, interval, age, period | +| mole | mol | double | mol | amount, quantity | +| month | month | double | month | time, duration, interval, age, period | +| nephelometric turbidity | ntu | double | ntu | nephelometricTurbidity, turbidity | +| newton | N | double | N | force | +| ohm | Ohm | double | Ω | resistance | +| okta | okta | int64 | okta | cloudCover, cover | +| parts per billion | ppb | double | ppb | amount, quantity, concentration, co2Level | +| parts per million | ppm | double | ppm | amount, quantity, concentration, co2Level | +| pascal | Pa | double | Pa | pressure | +| per cubic centimeter | #/cm3 | double | #/cm3 | density | +| percentage | % | double | % | batteryLevel, percentage, per, currentUnbalance, luminosityLevel, occupancyLevel, leakLevel, fillLevel | +| percentage relative humidity | %RH | double | %RH | humidity | +| pH | pH | double | pH | acidity | +| pulse per hour | pulse/h | double | pulse/h | frequency, sound | +| radian | rad | double | rad | angle | +| rate | / | double | rate | rate, powerFactor | +| rotations per minute | rpm | double | rpm | angularVelocity | +| second | s | double | s | time, duration, interval, age, period | +| siemens | S | double | S | conductance | +| siemens per meter | S/m | double | S/m | conductivity | +| sievert | Sv | double | Sv | radiationEffect | +| square meter | m2 | double | m² | area | +| state | state | boolean | bool | leak, presence, status | +| steradian | sr | double | sr | solidAngle | +| tesla | T | double | T | magneticDensity | +| volt | V | double | V | batteryVoltage, rmsVoltage, voltage | +| volt-ampere | VA | double | VA | apparentPower | +| volt-ampere hour | VAh | double | VAh | apparentEnergy | +| volt-ampere reactive | var | double | var | reactivePower | +| volt-ampere reactive hour | varh | double | varh | reactiveEnergy | +| watt | W | double | W | power, activePower | +| watt per hour | W/h | double | W/h | powerRate | +| watt per second | W/s | double | W/s | powerRate | +| watt per square meter | W/m2 | double | W/m² | irradiance, solarRadiation | +| watt-hour | Wh | double | Wh | energy | +| weber | Wb | double | Wb | magneticFlux | +| year | year | double | year | time, duration, interval, age, period | diff --git a/vendors/wavetrend/drivers/README.md b/vendors/wavetrend/drivers/README.md new file mode 100644 index 000000000..62e062d4a --- /dev/null +++ b/vendors/wavetrend/drivers/README.md @@ -0,0 +1,1200 @@ +# JavaScript driver structure + +> If you have a driver already follows the LoRa Alliance standard codec API, then you need just to add `driver.yaml` file as the one [here](sd01-l-v2/driver.yaml). + +This section describes how to build a javascript driver for Actility. + +You can either follow the LoRa Alliance standard codec API described [here](https://resources.lora-alliance.org/document/ts013-1-0-0-payload-codec-api), or follow this documentation. + +- [JavaScript driver structure](#JavaScript-driver-structure) + - [Driver](#driver) + - [API](#API) + - [Driver functions](#driver-functions) + - [Uplink decode](#uplink-decode) + - [Downlink encode](#downlink-encode) + - [Downlink decode](#downlink-decode) + - [Context](#store-and-reload-context) + - [Payload examples](#payload-examples) + - [Json schemas](#json-schemas) + - [Packaging](#packaging) + - [Testing](#testing) + - [Template](sd01-l-v2) +- [Sample driver developer guide](#sample-driver-developer-guide) + + +## Driver + +The `driver` is the piece of code responsible to decode uplinks/downlinks and to encode downlinks for a single device +communication protocol. It is the core part of the LoRaWAN framework to interact with new devices. + +If a device is exposing several incompatible communication protocols, then several drivers needs to be implemented, +one for each. + +The programming language used in this codec is the JavaScript which is a lightweight, interpreted, just-in-time compiled programming language with first class functions. + +More precisely, the JavaScript ES5 is used as it is simple and widely supported in most communities. + +## API + +### Driver functions + +The following sections describe the three javascript functions that a driver can declare to perform encoding and decoding +tasks. + +> A driver must at least declare a `decodeUplink(input)` function to be valid (see next section). + +#### Uplink decode + +This function is mandatory when creating a codec; without it, the codec is considered invalid. + +Uplinks are decoded by calling the following function: + +```javascript +function decodeUplink(input) { + ... + return output; +} +``` + +The `input` is an object provided by the Actility framework that is represented by the following json-schema: + +```json +{ + "bytes": { + "description": "The uplink payload byte array, where each byte is represented by an integer between 0 and 255", + "type": "array", + "items": { + "type": "integer" + }, + "required": true + }, + "fPort": { + "description": "The uplink message LoRaWAN fPort", + "type": "integer", + "required": true + }, + "recvTime": { + "description": "The uplink message datetime recorded by the LoRaWAN network server as a JavaScript Date object", + "type": "string", + "format": "date-time", + "required": true + } +} +``` + +The returned `output` is represented by the following json-schema: + +```json +{ + "data": { + "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", + "type": "Object", + "required": false + }, + "errors": { + "description": "A list of error messages while decoding the provided payload. required if failed.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "warnings": { + "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + } +} +``` +#### Downlink encode + +Contrary to the decodeUplink function, the implementation of this function is only mandatory when a device supports downlinks. + +Downlinks are encoding by calling the following function: + +```javascript +function encodeDownlink(input) { + ... + return output; +} +``` + +The `input` is an object that is represented by the following json-schema: + +```json +{ + "data": { + "description": "The open JavaScript object representing the downlink. It is defined by the codec developer", + "type": "Object" + } +} +``` + +The returned `output` is an object that is represented by the following json-schema: + +```json +{ + "fPort": { + "description": "The downlink LoRaWAN fPort, if no error occurred", + "type": "integer", + "required": true + }, + "bytes": { + "description": "The downlink payload byte array, where each byte is represented by an integer between 0-255, if no error occurred. required if success.", + "type": "array", + "items": { + "type": "integer" + }, + "required": false + }, + "errors": { + "description": "A list of error messages while decoding the provided payload. required if failed.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "warnings": { + "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + } +} +``` + +#### Downlink decode + +The implementation of this function is optional; it may be present when a device supports downlinks, to ease the monitoring and logs of sent downlinks. + +Downlinks are decoded by calling the following function: + +```javascript +function decodeDownlink(input) { + ... + return output; +} +``` + +The `input` is an object provided by the LoRaWAN framework that is represented by the following json-schema: + +```json +{ + "bytes": { + "description": "The downlink payload byte array, where each byte is represented by an integer between 0 and 255", + "type": "array", + "items": { + "type": "integer" + }, + "required": true + }, + "fPort": { + "description": "The downlink message LoRaWAN fPort", + "type": "integer", + "required": true + }, + "recvTime": { + "description": "The downlink message datetime computed by the LoRaWAN platform as a JavaScript Date object", + "type": "string", + "format": "date-time", + "required": true + } +} +``` + +The returned `output` is represented by the following json-schema: + +```json +{ + "data": { + "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", + "type": "Object", + "required": false + }, + "errors": { + "description": "A list of error messages while decoding the provided payload. required if failed.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "warnings": { + "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + } +} +``` + +### Driver Execution Environment and Available Libraries + +Drivers that get __tested locally__ before submission and __deployed__ on our platforms are executed through an isolated virtual machine provided by __isolated-vm__ (a node module that executes the drivers in a __secure environment__). + +This implies that only a __select few libraries__ are made available during the execution of the drivers. + +Currently, only the ``Buffer`` library is available on top of all the standard NodeJS classes, functions and methods (e.g.: ``Array``, ``Object``, ``JSON``, ``Math``, etc.). This list can extend depending on how popular a certain module is becoming in recent drivers. + +### Store and reload context + +On some devices, some information from a previous payload are useful for the current one. Thus, a context array is accessible to the driver's developer where some info can be injected/retrieved while decoding/encoding payloads. + +This context is based on DevEUI, so each device has its own context, even if several devices use the same driver. + +The context in the driver's environment is an array of flexible JSON objects. + +:warning: **WARNING:** If the context remains unchanged, it will not be updated in our database, and persistence is limited to 2 days. To keep your context for longer, add a timestamp or a counter to your context on each uplink. + +#### Enable the context + +To enable the context, you must set useContext to true in the driver's driver.yaml as such: +``` +# When a driver uses a context, this field must be set to true +# https://github.com/actility/device-catalog/blob/main/template/sample-vendor/drivers/README.md#store-and-reload-context +useContext: true +``` + +#### Store a context + +Inside a driver, data can be injected to the context: `context.push()`. + +##### Example: + +```javascript +function decodeUplink(input){ + const raw = Buffer.from(input.bytes); + const temperature = raw.readInt16BE(1)/100; + context.push({ + time: input.recvTime, + currentValue: temperature + }); + ... +} +``` +#### Reload a context + +Inside a driver, data can be retrieved from the context: +- Using `context.shift()` to load the latest context saved. +- Using `context[index]` to load a specific context by using the index. + +##### Example: + +```javascript +function decodeUplink(input){ + const latestContext = context.shift(); + const latestTemperature = latestContext["currentValue"]; + + const raw = Buffer.from(input.bytes); + const temperature = raw.readInt16BE(1)/100; + + const averageTwoMeasures = (temperature + latestTemperature) / 2; + ... +} +``` + +#### Update and Reload a context + +Inside a driver, context can be reloaded and updated for next decode/encode processes. + +##### Example: + +```javascript +function decodeUplink(input){ + const raw = Buffer.from(input.bytes); + const temperature = raw.readInt16BE(1)/100; + + context.push({ + temperature: temperature, + time: input.recvTime + }); + result.temperatureHistory = context; + ... +} +``` + +The result of decoding will be something as below: + +```json +{ + "temperature": 23.3, + "temperatureHistory": [ + { + "temperature": 23.3, + "time": "2024-08-12T15:24:24.249Z" + }, + { + "temperature": 23.2, + "time": "2024-08-12T15:26:24.249Z" + }, + { + "temperature": 22.9, + "time": "2024-08-12T15:28:24.249Z" + }, + { + "temperature": 23.1, + "time": "2024-08-12T15:30:24.249Z" + } + ] +} +``` + +### Payload examples + +:warning: **WARNING:** This section concerns only drivers that follow this guide and respect "lora-alliance" signature and format. For any other format/signature (ttn, chirpstack, actility), the examples should follow the section [Legacy Payload Examples](#legacy-payload-examples-only-signatures-other-than-lora-alliance-are-concerned). + +The following section describes the examples of the payloads of the driver. + +An `examples.json` file of uplink and downlink payloads must be declared directly in the driver package. + +These examples will be used in order to provide for the users of the driver some examples of the payload to be decoded/encoded to test the driver. In addition, it will be used to facilitate the testing of the driver while development. + +**IMPORTANT:** Description should be unique on each driver. +#### Example + +The uplink/downlink decode example used is an object represented by the following json-schema: + +```json +{ + "description": { + "description": "the description of the uplink/downlink example", + "type": "string", + "required": true + }, + "type": { + "description": "the type of the uplink/downlink example", + "type": "string", + "enum": ["uplink", "downlink-decode"], + "required": true + }, + "input": { + "type": "Object", + "items": { + "bytes": { + "description": "the uplink/downlink payload expressed in hexadecimal", + "type": "string", + "required": true + }, + "fPort": { + "description": "the uplink/downlink message LoRaWAN fPort", + "type": "number", + "required": true + }, + "recvTime": { + "description": "the uplink/downlink message time", + "type": "string", + "format": "date-time", + "required": true + } + } + }, + "output": { + "type": "Object", + "items": { + "data": { + "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", + "type": "Object", + "required": false + }, + "errors": { + "description": "A list of error messages while decoding the provided payload. required if failed.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "warnings": { + "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + } + } + } +} +``` + + +The downlink encode example used is an object represented by the following json-schema: + +```json +{ + "description": { + "description": "the description of the downlinn encode example", + "type": "string", + "required": true + }, + "type": { + "description": "the type of the uplink/downlink example", + "type": "string", + "enum": ["downlink-encode"], + "required": true + }, + "input": { + "type": "Object", + "items": { + "data": { + "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", + "type": "Object", + "required": false + } + } + }, + "output": { + "type": "Object", + "items": { + "bytes": { + "description": "the downlink encoded payload expressed in hexadecimal. required if success.", + "type": "string", + "required": false + }, + "fPort": { + "description": "the downlink message LoRaWAN fPort", + "type": "number", + "required": true + }, + "errors": { + "description": "A list of error messages while encoding the provided payload. required if failed.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "warnings": { + "description": "A list of warning messages that do not prevent the codec from encoding the payload. optional.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + } + } + } +} +``` + +### Json Schemas + +The following section describes the Json Schema of the decoded payloads of the driver. + +As the output data from the decoding payload process is not predictable, it is better to declare Json schemas that defines the structure of this output to ease the use of driver after decoding. + +The Json schemas of uplink and downlink payloads must be declared directly in the driver package. +Two Json schemas can be declared following the pattern: `uplink.schema.json` for uplink data, and `downlink.schema.json` for downlink data if supported. + +An `*.schema.json` file contains a generic json schema for all types of payload decoded by this driver of several uplink/downlink examples. + +## Packaging + +To simplify the open distribution and integration with our platform, a packaging leveraging NPMs is defined. + +NPM was chosen because it is the most widely used packaging system for JavaScript code. Also, this approach defines a +clear code layout that can be distributed independently using the developer preferred version control tool. + +You can find a full description of packaging in the guide of a driver [here](#sample-driver-developer-guide). + +## Testing + +Testing your driver is a very important process, thus the user is highly encouraged to test the driver in most possible +use cases as well as error cases. + +**Important:** The test of your driver is needed to prove a minimum test coverage of 85% to be valid on our framework. + +_**PS:** If your driver outputs values as ISO string dates or instances of class Date in the format "xxxx-xx-xxTxx:xx:xx.xxxZ", **declared when compiled**, you can validate the test by replacing the date value by_ "XXXX-XX-XXTXX:XX:XX.XXXZ" _in the JSON examples file._ + +> A pre-implemented [spec file](sd01-l-v2/driver-examples.spec.js) for testing can be copied from the template in order to test the driver with all the provided examples. + +## BACnet Integration + +As you may wish your devices and drivers to include a BACnet integration, our catalogs allow you to do so. +Along with all the driver and device profiles, you can deploy a BACnet mapping inside [this folder](../../../mappings/). +Please refer to [this markdown file for further instructions](../../../mappings/template/how-to.md). + +## +# Sample driver developer guide + +This example describes how you to create a driver for Actility following the LoRa Alliance standard Codec API. + +The concept and API is described [here](#api) + +- [Sample driver developer guide](#sample-driver-developer-guide) + - [Minimal driver](#minimal-driver) + - [Encoding and decoding downlinks](#encoding-and-decoding-downlinks) + - [Returning errors](#returning-errorswarnings) + - [Testing](#testing-the-driver) + +## Minimal driver + +Pre-requirements: you need to have npm installed with version > 5. To test the installed version run: + +```sh +$ npm -v +``` + +We'll start by creating a new npm project that will contain the driver. From an empty directory in a terminal run: + +```sh +$ npm init +``` + +After completing all the information requested by npm you will find a new file `package.json` on the directory you ran +`npm init` similar to the following (ignoring the name, version, author, etc): + +```json +{ + "name": "driver", + "version": "1.0.0", + "description": "My driver", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +``` + +***Important:*** Please make sure to NOT scope your package. + +**PS**: In the driver, the `require()` method is not allowed to import an external module. +If your driver is split into several javascript file (not recommended), you have to use webpack to generate a single Javascript file. +Here is the webpack configuration to be used in that case: +```javascript +module.exports = { + target: "node", + mode: "production", + entry: "./index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "."), + library: "driver", + }, +} +``` + +Now that we have a valid npm project, we will create the driver itself. Open a new file named `index.js` where we will +define only an uplink decode: + +_index.js_: + +```javascript +function decodeUplink(input) { + let result = { + data: {}, + errors: [], + warnings: [] + }; + const raw = Buffer.from(input.bytes); + + if (raw.byteLength > 8) { + result.errors.push("Invalid uplink payload: length exceeds 8 bytes"); + delete result.data; + return result; + } + + for (i = 0; i < raw.byteLength; i++) { + switch (raw[i]) { + // Temperature - 2 bytes + case 0x00: + if (raw.byteLength < i + 3) { + result.errors.push("Invalid uplink payload: index out of bounds when reading temperature"); + delete result.data; + return result; + } + result.data.temperature = raw.readInt16BE(i+1)/100; + if(result.data.temperature > 40){ + result.warnings = ["temperature exceeded the threshold of 40 degrees."]; + } + i += 2; + break; + // Humidity - 2 bytes + case 0x01: + if (raw.byteLength < i + 3) { + result.errors.push("Invalid uplink payload: index out of bounds when reading humidity"); + delete result.data; + return result; + } + result.data.humidity = raw.readInt16BE(i+1)/100; + i += 2; + break; + // Pulse counter - 1 byte + case 0x02: + result.data.pulseCounter = raw.readInt8(i+1); + i += 1; + break; + default: + result.errors.push("Invalid uplink payload: unknown id '" + raw[i] + "'"); + delete result.data; + return result; + } + } + return result; +} +``` + +In this function, we use a utility function called `readShort`, you must add the following code in your `index.js`: + +```javascript +function readShort(bin) { + var result = bin & 0xffff; + if (0x8000 & result) { + result = -(0x010000 - result); + } + return result; +} +``` + +As you can see by inspecting the code, the driver defines a very simple decode function where only two +objects can be retrieved from the payload: temperature, humidity (2 bytes each) and pulse counter (1 byte). + +Now that your driver is finished you can create the npm package. Simply run: + +```shell +npm pack +``` + +This will create a new file with the `.tgz` extension in the current folder containing the complete driver. + +## Encoding and decoding downlinks + +In the previous step we wrote and packaged a driver, which implemented the minimal functionality (i.e.: an uplink decode function). +Now let's extend that driver in order to encode and decode downlinks. + +First, lets add a `encodDownlink(input)` function in `index.js`: + +```javascript +function encodeDownlink(input) { + let result = { + errors: [], + warnings: [] + }; + let raw = new Buffer(4); + let index = 0; + + if (typeof input.data.pulseCounterThreshold !== "undefined") { + if (input.data.pulseCounterThreshold > 255) { + result.errors.push("Invalid downlink: pulseCounterThreshold cannot exceed 255"); + delete result.data; + return result; + } + raw.writeUInt8(0,index); + index+=1; + raw.writeUInt8(input.data.pulseCounterThreshold, index); + index+=1; + } + if (typeof input.data.alarm !== "undefined") { + raw.writeUInt8(1, index); + index+=1; + raw.writeUInt8(input.data.alarm === true? 1 : 0, index); + index+=1; + } + result.bytes = Array.from(raw).slice(0,index); + result.fPort = 16; + return result; +} +``` + +The `encodeDownlink(input)` function takes an object as parameter (see [here](#downlink-encode)) containing the object (called `data`) +that will be encoded as a downlink. Then the function only checks for two objects inside `data` (`pulseCounterThreshold` and `alarm`) +and write their contents as well as their id as byte array. + +We can also add a `decodeDownlink(input)` function. This function will allow us to decode the bytes as they are returned from +`encodeDownlink(input)` and return us the object that represents the downlink. + +Add the following function in `index.js`: + +```javascript +function decodeDownlink(input) { + let result = { + data: {}, + errors: [], + warnings: [] + }; + const raw = Buffer.from(input.bytes); + + if (raw.byteLength > 4) { + result.errors.push("Invalid downlink payload: length exceeds 4 bytes"); + delete result.data; + return result; + } + + for (i = 0; i < raw.byteLength; i += 2) { + switch (raw[i]) { + // Pulse counter threshold - 1 byte + case 0x00: + if (raw.byteLength < i + 2) { + result.errors.push("Invalid downlink payload: index out of bounds when reading pulseCounterThreshold"); + delete result.data; + return result; + } + result.data.pulseCounterThreshold = raw.readUInt8(i+1); + break; + // Alarm - 1 byte + case 0x01: + if (raw.byteLength < i + 2) { + result.errors.push("Invalid downlink payload: index out of bounds when reading alarm"); + delete result.data; + return result; + } + result.data.alarm = raw.readUInt8(i+1) === 1; + break; + default: + result.errors.push("Invalid downlink payload: unknown id '" + raw[i] + "'"); + delete result.data; + return result; + } + } + return result; +} +``` + +The function takes an `input` object (see [here](#downlink-decode)) that will contain `bytes`. This driver will only +decode both objects as returned from `encodeDownlink(input)`: `pulseCounterThreshold` and `alarm`. + +After adding `encodeDownlink(input)` and `decodeDownlink(input)` functions you can re-package your driver. + +## Returning errors/warnings + +As you have noticed, the errors must not be thrown, it can be outputed inside the `errors` array in the output. + +Same for a warning needed to be exposed, a string can be added to the array `warnings` in the output object. + +## Testing the driver + +We use [Jest](https://jestjs.io/) as our testing framweork. + +_Note: when testing, you will need to export the functions that you test (unless of course you copy / paste the functions into the testing file). This is *not* needed in your driver if not tested_. + +To exports functions, you can add the following at the end of the `index.js` file: + +```javascript +exports.decodeUplink = decodeUplink; +exports.decodeDownlink = decodeDownlink; +exports.encodeDownlink = encodeDownlink; +``` + +### Add dependencies + +To add the dependencies, add the following to the `package.json` file: + +```json +"devDependencies": { + "fs-extra": "^11.2.0", + "isolated-vm": "^4.7.2", + "jest": "^29.7.0", + "js-yaml": "^4.1.0", + "path": "^0.12.7" + } +``` + +Then run the following command: + +```shell +npm install +``` + +### Update package.json to add a script + +First, you need to add the `test` script in the `package.json`: + +```json + "scripts": { + "test": "jest --collectCoverage" + } +``` + +**Note:** If your driver does not support a function `encodeDownlink`, all you have to do is to comment/remove the part related to `encodeDownlink` testing inside the pre-implemented test file. + +### Test the different cases of your driver + +In order to facilitate the use cases testing process, we provide the file [driver-examples.spec.js](sd01-l-v2/driver-examples.spec.js). + +This file will automatically get all your examples inside `examples.json` and test them using [Jest](https://jestjs.io/). + +### Execute tests with coverage + +To execute tests, you must use the following command: + +```shell +npm run test +``` + +This command will give a full report about the coverage of your tests. The most important value in this report is the +percentage of the statements' coverage which appears under `stmts`. + +### Add Json Schemas + +To provide json schemas of your driver, create a file named `uplink.schema.json` and add the following json schema that describes the structure of the `decodeUplink` output: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "temperature": { + "type": "number" + }, + "humidity": { + "type": "number" + }, + "pulseCounter": { + "type": "number" + }, + "volumes": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "time": { + "type": "string" + }, + "volume": { + "type": "integer" + } + }, + "required": [ + "time", + "volume" + ] + } + ] + } + }, + "additionalProperties": false +} +``` + +Create a file named `downlink.schema.json` and add the following json schema that describes the structure of the `decodeDownlink` output: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "pulseCounterThreshold": { + "type": "integer" + }, + "alarm": { + "type": "boolean" + } + }, + "additionalProperties": false +} +``` +### Create a tarball from the package + +To create a tarball from the already defined package, you must use the following command: + +```shell +npm pack +``` + +This command must be executed in the root folder of the driver. It will generate a `.tgz` file that contains all the +files and directories of the driver. + +**Important:** You must avoid including the non-necessary files into the `.tgz` file as the `node_modules` +and `coverage` directories for example. (This can be done by adding a `.npmignore` file). + the driver + +#### Points extraction + +Points can be extracted once an uplink has been decoded. In order to extract points, a driver must provide the following function: + +```javascript +function extractPoints(input) {...} +``` + +The `input` is an object provided by the IoT Flow framework that is represented by the following json-schema: + +```json +{ + "message": { + "description": "the object message as returned by the decodeUplink function", + "type": "object", + "required": true + }, + "time": { + "description": "the datetime of the uplink message, it is a real javascript Date object", + "type": "string", + "format": "date-time", + "required": true + } +} +``` + +The returned object must be: +- The wrapped object from the decoded one in case all the event are done at the same time, respecting the ontology. + Here's an example: +```json +{ + "temperature": { + "record": 31.4, + "unitId": "Cel" + }, + "location": { + "unitId": "GPS", + "records": [ + { + "value": [48.875158, 2.333822], + "eventTime": "2019-01-01T10:00:00+01:00" + } + ] + }, + "power:0": { + "record": 0.32, + "unitId": "GW" + }, + "power:1": { + "record": 0.33, + "unitId": "GW" + }, + "power:2": { + "record": 0.4523, + "unitId": "GW" + }, + "power:3": { + "record": 0.4456, + "unitId": "GW" + }, + "power:4": { + "record": 0.4356, + "unitId": "GW" + } +} +``` +- OR, it is defined by the following json-schema in case the point has several values in different timestamp. + +```json +{ + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "eventTime": { + "type": "string", + "format": "date-time", + "required": true + }, + "value": { + "type": [ + "string", + "number", + "boolean" + ], + "required": true + } + } + } + } +} +``` +Here are a few examples: + +Simple : +```json +{ + "temperature": + { + "record": 31.4, + "unitId": "Cel" + } +} +``` + +Multiple measurements with different measurement time : +```json +{ + "temperature": { + "unitId": "Cel", + "records": [ + { + "eventTime": "2019-01-01T10:00:00+01:00", + "value": 31.4 + }, + { + "eventTime": "2019-01-01T11:00:00+01:00", + "value": 31.2 + }, + { + "eventTime": "2019-01-01T12:00:00+01:00", + "value": 32 + } + ] + } +} +``` + +Multiple of the same sensor type : \ +(In case of mutiple sensors of the same type, the ID should start at 0) +```json +{ + "temperature:0": { + "record": 31.4, + "unitId": "Cel" + }, + "temperature:1": { + "record": 31.2, + "unitId": "Cel" + }, + "temperature:2": { + "record": 32, + "unitId": "Cel" + } +} +``` + +---------------------------------------------------------------- + +### Legacy payload examples (only signatures other than lora-alliance are concerned) + +The following section describes the examples of the payloads of the driver. + +Several examples of uplink and downlink payloads must be declared directly in the driver's root directory and especially in a directory `/examples`. The name of each examples file must follow the pattern `*.examples.json`. You can split and organize the examples files according to your own logic. + +These examples will be used in order to provide for the users of the driver some examples of the payload to be decoded/encoded to test the driver. In addition, it will be used to facilitate the testing of the driver while development. + +An `*.examples.json` file contains an array of several uplink/downlink examples. You can find an example of this file in the driver example. + +#### Example + +The uplink/downlink example used is an object represented by the following json-schema: + +```json +{ + "description": { + "description": "the description of the uplink/downlink example", + "type": "string", + "required": true + }, + "type": { + "description": "the type of the uplink/downlink example. type 'downlink' is used for both downlink decoding/encoding in case the function exist.", + "type": "string", + "enum": ["uplink", "downlink"], + "required": true + }, + "bytes": { + "description": "the uplink/downlink payload expressed in hexadecimal", + "type": "string", + "required": true + }, + "fPort": { + "description": "the uplink/downlink message LoRaWAN fPort", + "type": "number", + "required": true + }, + "time": { + "description": "the uplink/downlink message time", + "type": "string", + "format": "date-time", + "required": false + }, + "data": { + "description": "the decoded uplink/downlink view as an output", + "type": "object", + "required": true + } +} +``` + +### Legacy error examples (only signatures other than lora-alliance are concerned) + +These errors examples has a similar concept of the payloads examples. + +To benefit from the automation of the tests, you must create a directory in the driver package named `/errors`. Inside, the name of each error examples file must follow the pattern `*.errors.json`. You can split and organize the errors files according to your own logic. + +**Note:** These errors examples will be only used for unit tests and will not be stored in our framework. + +An `*.errors.json` file contains an array of several uplink/downlink errors examples. + +##### decodeUplink/decodeDownlink error example + +The error example used to test `decodeUplink`/`decodeDownlink` function is an object represented by the following json-schema: + +```json +"description": { + "description": "the description of the error example", + "type": "string", + "required": true + }, + "type": { + "description": "the type of the example", + "type": "string", + "enum": ["uplink", "downlink"], + "required": true + }, + "bytes": { + "description": "the uplink/downlink payload expressed in hexadecimal", + "type": "string", + "required": true + }, + "fPort": { + "description": "the uplink/downlink message LoRaWAN fPort", + "type": "number", + "required": true + }, + "time": { + "description": "the uplink/downlink message time", + "type": "string", + "format": "date-time", + "required": false + }, + "error": { + "description": "the error that should be thrown in case of wrong input", + "type": "string", + "required": true + } +``` + +##### encodeDownlink error example + +The error example used to test `encodeDownlink` function is an object represented by the following json-schema: + +```json +"description": { + "description": "the description of the error example", + "type": "string", + "required": true + }, + "type": { + "description": "the type of the example", + "type": "string", + "enum": ["downlink"], + "required": true + }, + "fPort": { + "description": "the downlink message LoRaWAN fPort", + "type": "number", + "required": true + }, + "time": { + "description": "the downlink message time", + "type": "string", + "format": "date-time", + "required": false + }, + "data": { + "description": "the input to the encodeDownlink function", + "type": "object", + "required": true + }, + "error": { + "description": "the error that should be thrown in case of wrong input", + "type": "string", + "required": true + } +``` \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/.npmignore b/vendors/wavetrend/drivers/sd01-l-v2/.npmignore new file mode 100644 index 000000000..4382cdd52 --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/.npmignore @@ -0,0 +1,12 @@ +/src +/test +/dist +/package +/node_modules +/coverage +/specification +/.settings +gitreadme.md +*.config.js +*.spec.js +*.tgz diff --git a/vendors/wavetrend/drivers/sd01-l-v2/driver.yaml b/vendors/wavetrend/drivers/sd01-l-v2/driver.yaml new file mode 100644 index 000000000..aa13fef2a --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/driver.yaml @@ -0,0 +1,18 @@ +# Formal driver name +name: SD01-L-V2 Payload Codec +# Simple description of the driver functionalities +description: Codec for Wavetrend SD01-L-V2 Water Temperature Monitor +# Mandatory - id of the company that developed the driver +# This id will be used to construct the id of the driver (Should be in lowercase, no special characters, maximum 8 characters) +producerId: wavetrnd +# Email of the developer +developerEmail: support@wavetrend.net +# In case of a driver per model: `::` +# In case of a driver for multiples model: `:generic:` +# Format: `<8 characters max>:<16 characters max>:` +# Needed for linking the model with a specific driver -> must be the same one used in model.yaml in the corresponding model +# You should have only one protocolId per driver +protocolId: wavetrnd:sd01-l:2 +# This is to specify the type of functions signature used in this driver. Possible values: actility, lora-alliance, ttn, chirpstack. +# Keep it empty if you followed the lora-alliance payload codec api +signature: diff --git a/vendors/wavetrend/drivers/sd01-l-v2/examples.json b/vendors/wavetrend/drivers/sd01-l-v2/examples.json new file mode 100644 index 000000000..b543d41be --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/examples.json @@ -0,0 +1,400 @@ +[ + { + "type": "uplink", + "description": "uplink containing configuration response", + "input": { + "bytes": "000000000000000000004A", + "fPort": 4, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "error_code": 0, + "downlink_hours": 0, + "reporting_period": 0, + "message_flags": { + "scald": false, + "freeze": false, + "debug": false, + "history_count": 0, + "simple": false, + "act_poll": false, + "stat_poll": false + }, + "scald_threshold": 0, + "freeze_threshold": 0, + "config_type": [ + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + } + ], + "flow_delta": { + "cold": 4, + "hot": 10 + } + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing install request (device status)", + "input": { + "bytes": "3102010000", + "fPort": 2, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "pvd_level": 6, + "sensor": [ + true, false, false + ], + "firmware_version": { + "major": 2, + "minor": 1 + }, + "reset_reason": 0 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing standard report (full)", + "input": { + "bytes": "5F271B40013150101", + "fPort": 3, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "timestamp": 1596398400, + "sensor_id": 0, + "minC": 19, + "maxC": 21, + "events": 1, + "reports": 1 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing standard report (simple)", + "input": { + "bytes": "5F271B40131513151315", + "fPort": 10, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "timestamp": 1596398400, + "S1minC": 19, + "S1maxC": 21, + "S2minC": 19, + "S2maxC": 21, + "S3minC": 19, + "S4maxC": 21 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing sensor error", + "input": { + "bytes": "00", + "fPort": 5, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "sensor_id": 0 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing general error", + "input": { + "bytes": "000000000000", + "fPort": 6, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "error_code": 0, + "file_hash": 0, + "line": 0 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing freeze alert", + "input": { + "bytes": "0000", + "fPort": 7, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "sensor_id": 0, + "temperature": 0 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing scald alert", + "input": { + "bytes": "0000", + "fPort": 8, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "sensor_id": 0, + "temperature": 0 + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "uplink containing debug report", + "input": { + "bytes": "5F271B400D0000000007FF0000000007FF", + "fPort": 9, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "timestamp": 1596398400, + "pvd_level": 0, + "readings": [ + { + "timestamp": -1, + "sensors": [ + { + "state": 0, + "direction": 0, + "report": false, + "tempC": -27 + }, + { + "state": 0, + "direction": 0, + "report": false, + "tempC": -27 + }, + { + "state": 0, + "direction": 0, + "report": false, + "tempC": null + } + ] + }, + { + "timestamp": 0, + "sensors": [ + { + "state": 0, + "direction": 0, + "report": false, + "tempC": -27 + }, + { + "state": 0, + "direction": 0, + "report": false, + "tempC": -27 + }, + { + "state": 0, + "direction": 0, + "report": false, + "tempC": null + } + ] + } + ] + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "fail decode uplink due to invalid port", + "input": { + "bytes": "", + "fPort": 0, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "errors": [ + "LoRaWAN reserved payload type" + ], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "fail decode uplink due to invalid port", + "input": { + "bytes": "", + "fPort": 1, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "errors": [ + "V1 Deprecated Payload, unsupported" + ], + "warnings": [] + } + }, + { + "type": "uplink", + "description": "fail decode uplink due to invalid port", + "input": { + "bytes": "", + "fPort": 3, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "errors": [ + "Unrecognised type for downlink decoding" + ], + "warnings": [] + } + }, + { + "type": "downlink-decode", + "description": "downlink containing configuration", + "input": { + "bytes": "0000000000000000004A", + "fPort": 2, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "data": { + "type": 2, + "downlink_hours": 0, + "reporting_period": 0, + "message_flags": { + "scald": false, + "freeze": false, + "debug": false, + "history_count": 0, + "simple": false, + "act_poll": false, + "stat_poll": false + }, + "scald_threshold": 0, + "freeze_threshold": 0, + "config_type": [ + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + } + ], + "flow_delta": { + "cold": 4, + "hot": 10 + } + }, + "errors": [], + "warnings": [] + } + }, + { + "type": "downlink-decode", + "description": "fail decode uplink due to invalid port", + "input": { + "bytes": "", + "fPort": 3, + "recvTime": "2020-08-02T20:00:00.000+00:00" + }, + "output": { + "errors": [ + "Unrecognised type for downlink decoding" + ], + "warnings": [] + } + }, + { + "type": "downlink-encode", + "description": "fail decode uplink due to invalid port", + "input": { + "type": 2, + "downlink_hours": 0, + "reporting_period": 0, + "message_flags": { + "scald": false, + "freeze": false, + "debug": false, + "history_count": 0, + "simple": false, + "act_poll": false, + "stat_poll": false + }, + "scald_threshold": 0, + "freeze_threshold": 0, + "config_type": [ + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + }, + { + "flow_settling_count": 0, + "config": 0 + } + ], + "flow_delta": { + "cold": 4, + "hot": 10 + } + }, + "output": { + "bytes": "0000000000000000004A", + "fPort": 2, + "errors": [], + "warnings": [] + } + } +] \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/metadata.json b/vendors/wavetrend/drivers/sd01-l-v2/metadata.json new file mode 100644 index 000000000..e3cd34f34 --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/metadata.json @@ -0,0 +1,16 @@ +{ + "name": "wavetrnd:sd01-l:2", + "version": "2.4.0", + "main": "dist/index.js", + "description": "SD01-L-V2 Payload Codec", + "codecId": "0001", + "sourceUrl": "https://github.com/actility/device-catalog/tree/main/vendors/wavetrend/drivers/sd01-l-v2", + "vendorId": "", + "specVersion": "2.4.0", + "codec": { + "encodeDownlink": true, + "decodeDownlink": true, + "examples": true, + "jsonSchemas": false + } +} diff --git a/vendors/wavetrend/drivers/sd01-l-v2/package-lock.json b/vendors/wavetrend/drivers/sd01-l-v2/package-lock.json new file mode 100644 index 000000000..4286ad7ff --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/package-lock.json @@ -0,0 +1,4695 @@ +{ + "name": "wavetrend-sd01-l-v2", + "version": "2.4.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wavetrend-sd01-l-v2", + "version": "2.4.0", + "devDependencies": { + "cross-env": "^7.0.3", + "jest": "^29.7.0", + "path": "^0.12.7", + "webpack": "^5.90.0", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", + "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.17", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz", + "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001765", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", + "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.277", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz", + "integrity": "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.104.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", + "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.4", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/vendors/wavetrend/drivers/sd01-l-v2/package.json b/vendors/wavetrend/drivers/sd01-l-v2/package.json new file mode 100644 index 000000000..ae7591e1a --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/package.json @@ -0,0 +1,18 @@ +{ + "name": "wavetrend-sd01-l-v2", + "version": "2.4.0", + "description": "LoRa Alliance sample driver npm packaged", + "main": "dist/index.js", + "scripts": { + "test": "node run-driver-test.js", + "build": "webpack --config webpack.config.js" + }, + "metadata": "metadata.json", + "devDependencies": { + "cross-env": "^7.0.3", + "jest": "^29.7.0", + "path": "^0.12.7", + "webpack": "^5.90.0", + "webpack-cli": "^5.1.4" + } +} diff --git a/vendors/wavetrend/drivers/sd01-l-v2/run-driver-test.js b/vendors/wavetrend/drivers/sd01-l-v2/run-driver-test.js new file mode 100644 index 000000000..f47c9b6a2 --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/run-driver-test.js @@ -0,0 +1,20 @@ +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +let testsPath = path.resolve(__dirname, '../../../../tests'); +if(testsPath.includes("device-catalog-private")) { + testsPath = path.resolve(__dirname, "../../../../../device-catalog/tests"); +} + +const driverPath = path.resolve(__dirname); + +if (!fs.existsSync(path.join(testsPath, 'node_modules'))) { + console.log('📦 Installing test dependencies...'); + execSync('npm install', { cwd: testsPath, stdio: 'inherit' }); +} + +execSync(`cross-env DRIVER_PATH="${driverPath}" jest --config=jest.config.js --collectCoverage`, { + cwd: testsPath, + stdio: 'inherit' +}); diff --git a/vendors/wavetrend/drivers/sd01-l-v2/src/downlink.js b/vendors/wavetrend/drivers/sd01-l-v2/src/downlink.js new file mode 100644 index 000000000..93a55a3b7 --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/src/downlink.js @@ -0,0 +1,358 @@ +/** + @file SD01-L Water Temperature Monitor Downlink Payload Formatter for TTN + @module src/downlink.js + @author Dave Meehan + @copyright Wavetrend Europe Ltd + @see {@link https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/} + @see {@link https://www.youtube.com/watch?v=nT2FnwCoP7w} + */ + +/** + * @namespace Wavetrend.SD01L + */ + +/** + * Wavetrend SD01L Payload Type + * @typedef {number} Wavetrend.SD01L.PayloadType + * @readonly + * @memberOf Wavetrend.SD01L + * @enum {Wavetrend.SD01L.PayloadType} + * @property {Wavetrend.SD01L.PayloadType} CONFIGURATION - 1 + */ +const SD01L_DOWNLINK_PAYLOAD_TYPE = { + CONFIGURATION: 2 +}; + +/** + * @typedef {Object} Wavetrend.SD01L.MessageFlags + * @property {boolean} scald - scald reporting enabled (default disabled) + * @property {boolean} freeze - freeze reporting enabled (default disabled) + * @property {boolean} debug - debug reporting enabled (default disabled) + * @property {number} history_count - number of history messages in standard report (default = 0, otherwise 1 or 2) + * @property {boolean} simple - simple report mode (default disabled) + * @property {boolean} act_poll - active polling enabled (default enabled) + * @property {boolean} stat_poll - status polling enabled (default enabled) + */ + +/** + * SD01L Sensor Configuration Type + * @typedef {number} Wavetrend.SD01L.SensorType + * @readonly + * @enum {number} + * @memberOf Wavetrend.SD01L + * @property {Wavetrend.SD01L.SensorType} Disabled - 0 + * @property {Wavetrend.SD01L.SensorType} HotOutletStandard - 1 + * @property {Wavetrend.SD01L.SensorType} HotOutletHealthcare - 2 + * @property {Wavetrend.SD01L.SensorType} ColdOutlet - 3 + * @property {Wavetrend.SD01L.SensorType} ColdUnitRising - 4 + * @property {Wavetrend.SD01L.SensorType} BlendedRisingScaldCheck - 5 + * @property {Wavetrend.SD01L.SensorType} HotUnitOutletFalling - 6 + * @property {Wavetrend.SD01L.SensorType} HotUnitReturnFalling - 7 + * @property {Wavetrend.SD01L.SensorType} HotUnitReturnHealthcareFalling - 8 + */ +const SD01L_SENSOR_TYPE = { + Disabled: 0, + HotOutletStandard: 1, + HotOutletHealthcare: 2, + ColdOutlet: 3, + ColdUnitRising: 4, + BlendedRisingScaldCheck: 5, + HotUnitOutletFalling: 6, + HotUnitReturnFalling: 7, + HotUnitReturnHealthcareFalling: 8, +}; + +/** + * @typedef {Object} Wavetrend.SD01L.SensorConfig + * @property {number} flow_settling_count - number of readings to allow flow to settle (default 0) + * @property {SD01L_SENSOR_TYPE} config - identity of the sensor configuration (default disabled) + */ + +/** + * @typedef {Object} Wavetrend.SD01L.FlowDelta + * @property {number} cold - cold outlet flow delta in range 2-15 + * @property {number} hot - hot outlet flow delta in range 2-15 + */ + +/** + * @typedef Wavetrend.SD01L.Configuration + * @property {number} downlink_hours - number of hours between configuration requests (default 24) + * @property {number} reporting_period - number of minutes between reports (default 60) + * @property {Wavetrend.SD01L.MessageFlags} message_flags - option flags + * @property {number} scald_threshold - temperature above which scald reports will be sent (if enabled, default 60) + * @property {number} freeze_threshold - temperature below which freeze reports will be sent (if enabled, default 4) + * @property {Wavetrend.SD01L.SensorConfig[]} config_type - configuration for each sensor + * @property {Wavetrend.SD01L.FlowDelta} flow_delta - flow delta configuration + */ + +/** + * @typedef {Wavetrend.SD01L.Configuration} Wavetrend.SD01L.DownlinkPayloads + */ + +/** + * Deep merge of config objects to allow defaults to be supplied for anything missing + * @param {*} arg1 + * @param {*} arg2 + * @returns {*} + * @memberOf Wavetrend.SD01L + */ +function mergeConfigs(arg1, arg2) { + + if ((Array.isArray(arg1) && Array.isArray(arg2)) + || (typeof arg1 === 'object' && typeof arg2 === 'object')) { + for (let key in arg2) { + arg1[key] = mergeConfigs(arg1[key], arg2[key]); + } + return arg1; + } + return arg2; +} + +/** + * Encode SD01L specific message payloads + * @param {Wavetrend.SD01L.DownlinkPayloads} object + * @returns { { bytes: number[], fPort: number } } - array of encoded bytes + * @memberOf Wavetrend.SD01L + */ +function Encode_SD01L_Payload(object) { + let bytes = []; + let fPort = 1; + + switch (object.type) { + case SD01L_DOWNLINK_PAYLOAD_TYPE.CONFIGURATION: + fPort = 2; + const defaults = { + downlink_hours: 24, + reporting_period: 60, + message_flags: { + scald: false, + freeze: false, + debug: false, + history_count: 0, + simple: false, + act_poll: true, + stat_poll: true, + }, + scald_threshold: 60, + freeze_threshold: 4, + config_type: [ + {flow_settling_count: 0, config: 0,}, + {flow_settling_count: 0, config: 0,}, + {flow_settling_count: 0, config: 0,}, + ], + flow_delta: { + cold: 4, + hot: 10, + }, + }; + object = mergeConfigs(defaults, object); + + bytes.push(object.downlink_hours & 0xFF); + bytes.push((object.reporting_period & 0xFF00) >>> 8); + bytes.push(object.reporting_period & 0x00FF); + bytes.push( + object.message_flags.scald << 0 >>> 0 + | object.message_flags.freeze << 1 >>> 0 + | object.message_flags.debug << 2 >>> 0 + | (object.message_flags.history_count & 0x03) << 3 >>> 0 + | object.message_flags.simple << 5 >>> 0 + | object.message_flags.act_poll << 6 >>> 0 + | object.message_flags.stat_poll << 7 >>> 0 + ); + bytes.push((object.scald_threshold & 0xFF) >>> 0); + bytes.push((object.freeze_threshold & 0xFF) >>> 0); + for (let sensor = 0; sensor < 3; sensor++) { + bytes.push( + (object.config_type[sensor].flow_settling_count & 0x0F) << 4 >>> 0 + | object.config_type[sensor].config & 0x0F + ); + } + bytes.push( + ((object.flow_delta.cold & 0xF) << 4 >>> 0) + | ((object.flow_delta.hot & 0xF) >>> 0) + ) + break; + + default: + throw "Unrecognised type for downlink decoding"; + } + + return { bytes, fPort }; +} + +/** + * @namespace TTN.Downlink + */ + +/** + * @typedef {Object} TTN.Downlink.EncoderInput + * @property {Wavetrend.SD01L.DownlinkPayloads} data + */ + +/** + * @typedef {Object} TTN.Downlink.EncoderSuccess + * @property {number[]} bytes - byte array of encoded data + * @property {number} fPort - LoRaWAN port number + * @property {string[]} [warnings] - any warnings encountered during encoding + */ + +/** + * @typedef {Object} TTN.Downlink.EncoderError + * @property {string[]} errors - any errors encountered during encoding + */ + +/** + * @typedef {TTN.Downlink.EncoderSuccess|TTN.Downlink.EncoderError} TTN.Downlink.EncoderOutput + */ + +/** + * Entry point for TTN V3 downlink encoder + * @param {TTN.Downlink.EncoderInput} input + * @returns {TTN.Downlink.EncoderOutput} + */ +function encodeDownlink(input) { + let obj = { + warnings: [], + errors: [], + }; + + try { + output = Encode_SD01L_Payload(input.data); + obj.bytes = output.bytes; + obj.fPort = output.fPort; + } catch (error) { + obj.errors.push(error); + } + + return obj; +} + +/** + * Entry point for TTN V2 downlink encoder + * @param {Wavetrend.SD01L.DownlinkPayloads} object + * @returns {number[]} - byte array of encoded payload or empty array + */ +function Encoder(object/*, port */) { + try { + return Encode_SD01L_Payload(object).bytes; + } catch (e) { + return []; + } +} + +/** + * Decode SD01L specific payloads + * @param {number[]} bytes + * @param {number} port + * @return {Wavetrend.SD01L.DownlinkPayloads} + * @memberOf Wavetrend.SD01L + */ +function Decode_SD01L_Payload(bytes, port) { + + let i = 0; + let object = { + type: port, + }; + + switch (object.type) { + case SD01L_DOWNLINK_PAYLOAD_TYPE.CONFIGURATION: + + object.downlink_hours = (bytes[i++] & 0xFF) >>> 0; + object.reporting_period = + ((bytes[i++] & 0xFF) << 8 >>> 0) + + ((bytes[i++] & 0xFF) >>> 0); + + let flags = (bytes[i++] & 0xFF) >>> 0; + object.message_flags = { + scald: !!(flags & 0x01), + freeze: !!(flags & 0x02), + debug: !!(flags & 0x04), + history_count: (flags >>> 3) & 0x03, + simple: !!(flags & 0x20), + act_poll: !!(flags & 0x40), + stat_poll: !!(flags & 0x80), + }; + + object.scald_threshold = (bytes[i++] & 0xFF) << 24 >> 24; + object.freeze_threshold = (bytes[i++] & 0xFF) << 24 >> 24; + + object.config_type = []; + for (let sensor = 0; sensor < 3; sensor++) { + let config = (bytes[i++] & 0xFF) >>> 0; + object.config_type[sensor] = { + flow_settling_count: (config >>> 4) & 0x0F >>> 0, + config: (config & 0x0F) >>> 0, + }; + } + const flow_delta = (bytes[i++] & 0xFF) >>> 0; + object.flow_delta = { + cold: (flow_delta & 0xF0) >>> 4, + hot: (flow_delta & 0x0F) >>> 0, + } + break; + + case 0: + throw "LoRaWAN reserved payload type"; + + case 1: + throw "V1 Deprecated Payload, unsupported"; + + default: + throw "Unrecognised type for downlink decoding"; + } + + return object; +} + +/** + * @typedef {Object} TTN.Downlink.DecoderInput + * @property {number[]} bytes - byte array of encoded data + * @property {number} fPort - LoRaWAN port number + */ + +/** + * @typedef {Object} TTN.Downlink.DecoderSuccess + * @property {Wavetrend.SD01L.DownlinkPayloads} data + * @property {string[]} [warnings] + */ + +/** + * @typedef {Object} TTN.Downlink.DecoderError + * @property {string[]} errors + */ + +/** + * @typedef {TTN.Downlink.DecoderSuccess|TTN.Downlink.DecoderError} TTN.Downlink.DecoderOutput + */ + +/** + * Entry point for TTN V3 downlink decoder (inverse of encodeDownlink) + * @param {TTN.Downlink.DecoderInput} input + * @returns {TTN.Downlink.DecoderOutput} + */ +function decodeDownlink(input) { + let payload = { + warnings: [], + errors: [], + }; + + try { + payload.data = Decode_SD01L_Payload(input.bytes, input.fPort); + } catch (e) { + delete payload.data; + payload.errors.push(e); + } + + return payload; +} + +// NB: Not used for TTN production, required for Unit Testing + +/* istanbul ignore else */ +if (typeof module !== 'undefined') { + module.exports = { + Encoder, + encodeDownlink, + decodeDownlink, + }; +} \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/src/index.js b/vendors/wavetrend/drivers/sd01-l-v2/src/index.js new file mode 100644 index 000000000..e82c7094d --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/src/index.js @@ -0,0 +1,2 @@ +export { decodeUplink } from './uplink'; +export { encodeDownlink, decodeDownlink } from './downlink'; \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/src/uplink.js b/vendors/wavetrend/drivers/sd01-l-v2/src/uplink.js new file mode 100644 index 000000000..03d571cae --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/src/uplink.js @@ -0,0 +1,426 @@ +/** + @file SD01-L Water Temperature Monitor Downlink Payload Formatter for TTN + @module src/uplink.js + @author Dave Meehan + @copyright Wavetrend Europe Ltd + @see {@link https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/} + @see {@link https://www.youtube.com/watch?v=nT2FnwCoP7w} + */ + +/** + * @typedef {Object} Wavetrend.SD01L.Version + * @property {number} major + * @property {number} minor + */ +/** + * Issued by device when installed to acquire operating configuration + * @typedef Wavetrend.SD01L.InstallRequest + * @property {number} pvd_level - current power voltage detector level (0-7) + * @property {boolean[]} sensor - sensor detected + * @property {Wavetrend.SD01L.Version} firmware_version - current firmware version + * @property {number} reset_reason - Reason for last device reset (manufacturer internal) + */ + +/** + * @typedef {number} Wavetrend.SD01L.InstallationErrorCode + * @readonly + * @enum {number} + * @property {Wavetrend.SD01L.InstallationErrorCode} NONE - 0 + * @property {Wavetrend.SD01L.InstallationErrorCode} SENSOR_DISABLED - 1 - Installed sensor cannot be disabled + * @property {Wavetrend.SD01L.InstallationErrorCode} SENSOR_MISSING - 2 - Non-installed sensor cannot be configured + * @property {Wavetrend.SD01L.InstallationErrorCode} DOWNLINK - 3 - Downlink interval out of range + * @property {Wavetrend.SD01L.InstallationErrorCode} MESSAGE_FLAGS - 4 - Illegal message flags specified + * @property {Wavetrend.SD01L.InstallationErrorCode} SCALD_THRESHOLD - 5 - Scald threshold out of range + * @property {Wavetrend.SD01L.InstallationErrorCode} FREEZE_THRESHOLD - 6 - Freeze threshold out of range + * @property {Wavetrend.SD01L.InstallationErrorCode} REPORT_PERIOD - 7 - Report period out of range + * @property {Wavetrend.SD01L.InstallationErrorCode} CONFIG_TYPE - 8 - Sensor configuration type invalid + * @property {Wavetrend.SD01L.InstallationErrorCode} MISC - 9 - Miscellaneous error + * @property {Wavetrend.SD01L.InstallationErrorCode} DOWNLINK_LATE - 10 - Downlink arrived too late + * @property {Wavetrend.SD01L.InstallationErrorCode} DOWNLINK_NONCE - 11 - Downlink nonce mismatch + * @property {Wavetrend.SD01L.InstallationErrorCode} DOWNLINK_DUPLICATE - 12 - Downlink duplicate received + * @property {Wavetrend.SD01L.InstallationErrorCode} HISTORY_COUNT - 13 - History Count out of range + * + */ +const SD01L_INSTALLATION_ERROR_CODE = { + NONE: 0, + SENSOR_DISABLED: 1, + SENSOR_MISSING: 2, + DOWNLINK: 3, + MESSAGE_FLAGS: 4, + SCALD_THRESHOLD: 5, + FREEZE_THRESHOLD: 6, + REPORT_PERIOD: 7, + CONFIG_TYPE: 8, + MISC: 9, + DOWNLINK_LATE: 10, + DOWNLINK_NONCE: 11, + DOWNLINK_DUPLICATE: 12, + HISTORY_COUNT: 13, +}; + +/** + * Issued by device after successfully receiving operating configuration + * @typedef Wavetrend.SD01L.InstallResponse + * @property {Wavetrend.SD01L.InstallationErrorCode} error + */ + +/** + * Issued by the device at the standard report interval + * @typedef Wavetrend.SD01L.StandardReport + * @property {number} timestamp - seconds since Unix epoch + * @property {number} sensor_id - which sensor readings are for (0-2) + * @property {number} minC - degrees C + * @property {number} maxC - degrees C + * @property {number} events - count of total events + * @property {number} reports - count of compliant events * @property {{ sensor: Wavetrend.SD01L.SensorReadings[] }} current + */ + +/** + * Issued by the device if freeze reporting is enabled + * @typedef Wavetrend.SD01L.FreezeReport + * @property {number} sensor_id - sensor number (0-2) + */ + +/** + * Issued by the device if freeze reporting is enabled + * @typedef Wavetrend.SD01L.ScaldReport + * @property {number} sensor_id - sensor number (0-2) + */ + +/** + * Issued by the device if a sensor error is detected + * @typedef Wavetrend.SD01L.SensorErrorReport + * @property {number} sensor_id - sensor number (0-2) + */ + +/** + * Issued by the device if a general device error is detected + * @typedef Wavetrend.SD01L.GeneralErrorReport + * @property {number} error_code - Error code (manufacturer internal) + * @property {number} file_hash - file identity (manufacturer internal) + * @property {number} line - source line (manufacturer internal) + */ + +/** + * Each sensors debug data + * @typedef Wavetrend.SD01L.SensorDebug + * @property {number} direction - N/A + * @property {number} state - detection state + * @property {number} report - report flag + * @property {number} tempC - temperature + */ + +/** + * Each sensors debug data + * @typedef Wavetrend.SD01L.Debug + * @property {number} timestamp - seconds since Unix epoch + * @property {Wavetrend.SD01L.SensorDebug[]} sensors + */ + +/** + * Issued by the device if debug reporting is enabled + * @typedef Wavetrend.SD01L.DebugReport + * @property {number} timestamp - seconds since Unix epoch + * @property {number} pvd_level - PVD level + * @property {Wavetrend.SD01L.Debug[]} readings - Sensor Debug Readings + */ + +/** + * @namespace TTN.Uplink + */ + +/** + * Format of data provided to the V3 decoder by TTN + * @typedef {Object} TTN.Uplink.DecoderInput + * @property {number[]} bytes - array of received bytes + * @property {number} fPort - LoRaWAN port number + */ + +/** + * Composite of all SD01L uplink messages + * @typedef {Wavetrend.SD01L.InstallRequest|Wavetrend.SD01L.InstallResponse|Wavetrend.SD01L.StandardReport|Wavetrend.SD01L.FreezeReport|Wavetrend.SD01L.ScaldReport|Wavetrend.SD01L.SensorErrorReport|Wavetrend.SD01L.GeneralErrorReport|Wavetrend.SD01L.DebugReport} Wavetrend.SD01L.UplinkPayloads + */ + +/** + * Format of the result data expected by the V3 TTN decoder + * @typedef {Object} TTN.Uplink.DecoderSuccess + * @property {Wavetrend.SD01L.UplinkPayloads} data - Decoded payload + * @property {string[]} [warnings] - any warnings generated by the decoding + */ + +/** + * Format of the result data expected by the V3 TTN decoder + * @typedef {Object} TTN.Uplink.DecoderError + * @property {string[]} errors - any errors generated by the decoding + */ + +/** + * Format of the result data expected by the V3 TTN decoder + * @typedef {TTN.Uplink.DecoderSuccess|TTN.Uplink.DecoderError} TTN.Uplink.DecoderOutput + */ + +/** + * Wavetrend SD01L Uplink Payload Type (documented in encoder.js) + * @ignore + */ +const SD01L_UPLINK_PAYLOAD_TYPE = { + INSTALL_REQUEST: 2, + INSTALL_RESPONSE: 4, + STANDARD_REPORT: 3, + FREEZE_REPORT: 7, + SCALD_REPORT: 8, + SENSOR_ERROR_REPORT: 5, + GENERAL_ERROR_REPORT: 6, + SENSOR_DATA_DEBUG: 9, + SIMPLE_REPORT: 10, +}; + +const OFFSET_TYPE = 0; +const OFFSET_VERSION = 1; +const OFFSET_SEQUENCE = 2; +const OFFSET_TIMESTAMP = 3; + +/** + * @typedef Wavetrend.SD01L.PartialPayloadDecode + * @property {number[]} bytes + */ + +/** + * @memberOf Wavetrend.SD01L + * @param {number} input - unsigned value + * @returns {number} - signed representation of LSB of input + */ +function signedByte(input) { + return (input & 0xFF) << 24 >> 24; +} + +/** + * @memberOf Wavetrend.SD01L + * @param {number} input - unsigned value + * @returns {number} - unsigned representation of LSB of input + */ +function unsignedByte(input) { + return (input & 0xFF) >>> 0; +} + +/** + * Decode SD01L specific message payloads + * @param {number[]} bytes + * @param {number} port + * @returns {Wavetrend.SD01L.UplinkPayloads} + * @memberOf Wavetrend.SD01L + */ +function Decode_SD01L_Payload(bytes, port) { + let payload = { }; + let i = 0; + + switch (port) { + case SD01L_UPLINK_PAYLOAD_TYPE.INSTALL_REQUEST: + const flags = unsignedByte(bytes[i++]); + payload.pvd_level = flags >>> 3 & 0x07; + payload.sensor = [ + !!(flags & 0x01), + !!(flags & 0x02), + !!(flags & 0x04), + ]; + payload.firmware_version = { + major: unsignedByte(bytes[i++]), + minor: unsignedByte(bytes[i++]) + }; + payload.reset_reason = (bytes[i++] << 8 >>> 0) + unsignedByte(bytes[i++]); + break; + + case SD01L_UPLINK_PAYLOAD_TYPE.STANDARD_REPORT: + + payload.timestamp = + (unsignedByte(bytes[i++]) << 24 >>> 0) + + (unsignedByte(bytes[i++]) << 16 >>> 0) + + (unsignedByte(bytes[i++]) << 8 >>> 0) + + unsignedByte(bytes[i++]); + + payload.sensor_id = bytes[i++] & 0x03; + payload.minC = signedByte(bytes[i++]); + payload.maxC = signedByte(bytes[i++]); + payload.events = bytes[i++]; + payload.reports = bytes[i++]; + break; + + case SD01L_UPLINK_PAYLOAD_TYPE.INSTALL_RESPONSE: { + + payload.error_code = bytes[i++]; + payload.downlink_hours = bytes[i++]; + payload.reporting_period = + ((bytes[i++] & 0xFF) << 8 >>> 0) + + ((bytes[i++] & 0xFF) >>> 0); + + let flags = (bytes[i++] & 0xFF) >>> 0; + payload.message_flags = { + scald: !!(flags & 0x01), + freeze: !!(flags & 0x02), + debug: !!(flags & 0x04), + history_count: (flags >>> 3) & 0x03, + simple: !!(flags & 0x20), + act_poll: !!(flags & 0x40), + stat_poll: !!(flags & 0x80), + }; + + payload.scald_threshold = (bytes[i++] & 0xFF) << 24 >> 24; + payload.freeze_threshold = (bytes[i++] & 0xFF) << 24 >> 24; + + payload.config_type = []; + for (let sensor = 0; sensor < 3; sensor++) { + let config = (bytes[i++] & 0xFF) >>> 0; + payload.config_type[sensor] = { + flow_settling_count: (config >>> 4) & 0x0F >>> 0, + config: (config & 0x0F) >>> 0, + }; + } + + const flow_delta = (bytes[i++] & 0xFF) >>> 0; + payload.flow_delta = { + cold: (flow_delta & 0xF0) >>> 4, + hot: flow_delta & 0x0F, + } + + break; + } + + case SD01L_UPLINK_PAYLOAD_TYPE.SENSOR_ERROR_REPORT: + + payload.sensor_id = bytes[i++] & 0x03; + break; + + case SD01L_UPLINK_PAYLOAD_TYPE.GENERAL_ERROR_REPORT: + + payload.error_code = (unsignedByte(bytes[i++]) << 8 >>> 0) + unsignedByte(bytes[i++]); + payload.file_hash = (unsignedByte(bytes[i++]) << 8 >>> 0) + unsignedByte(bytes[i++]); + payload.line = (unsignedByte(bytes[i++]) << 8 >>> 0) + unsignedByte(bytes[i++]); + break; + + case SD01L_UPLINK_PAYLOAD_TYPE.FREEZE_REPORT: + case SD01L_UPLINK_PAYLOAD_TYPE.SCALD_REPORT: + + payload.sensor_id = bytes[i++] & 0x03; + payload.temperature = signedByte(bytes[i++]); + break; + + case SD01L_UPLINK_PAYLOAD_TYPE.SENSOR_DATA_DEBUG: { + let readings = []; + + const timestamp = + (unsignedByte(bytes[i++]) << 24 >>> 0) + + (unsignedByte(bytes[i++]) << 16 >>> 0) + + (unsignedByte(bytes[i++]) << 8 >>> 0) + + unsignedByte(bytes[i++]); + + const flags = unsignedByte(bytes[i++]); + const interval_divide = !!(flags & 0b10000000); + let interval = ((flags & 0b01111000) >> 3); + interval = interval_divide ? interval / 10 : interval * 10; + const pvdLevel = (flags & 0b00000111); + + while (i < bytes.length) { + + const reading = { + timestamp, + sensors: [ + { direction: 0, state: 0, report: false, tempC: NaN }, + { direction: 0, state: 0, report: false, tempC: NaN }, + { direction: 0, state: 0, report: false, tempC: NaN }, + ] + } + + for (let sensor = 0 ; sensor < 3 ; sensor++) { + + const data = (unsignedByte(bytes[i++]) << 8 >>> 0) + unsignedByte(bytes[i++]); + + reading.sensors[sensor].direction = (data & 0b1100000000000000) >> 14; + reading.sensors[sensor].state = (data & 0b0011000000000000) >> 12; + reading.sensors[sensor].report = (data & 0b0000100000000000) >> 11 === 1; + const temp_index = (data & 0b0000011111111111); + reading.sensors[sensor].tempC = (temp_index === 2047) ? null : (temp_index - 270) / 10; + } + readings.push(reading); + } + + // Now we know how many readings there are, we can adjust the timestamps + + readings.forEach((reading, index) => { + reading.timestamp -= (readings.length - 1 - index) * interval; + }) + + payload.timestamp = timestamp; + payload.pvd_level = pvdLevel; + payload.readings = readings; + + break; + } + + case SD01L_UPLINK_PAYLOAD_TYPE.SIMPLE_REPORT: + + payload.timestamp = + (unsignedByte(bytes[i++]) << 24 >>> 0) + + (unsignedByte(bytes[i++]) << 16 >>> 0) + + (unsignedByte(bytes[i++]) << 8 >>> 0) + + unsignedByte(bytes[i++]); + + payload.s1MinC = signedByte(bytes[i++]); + payload.s1MaxC = signedByte(bytes[i++]); + + payload.s2MinC = signedByte(bytes[i++]); + payload.s2MaxC = signedByte(bytes[i++]); + + payload.s3MinC = signedByte(bytes[i++]); + payload.s3MaxC = signedByte(bytes[i++]); + break; + + default: + + throw "Unrecognised type for uplink decoding"; + + } + return payload; +} + +/** + * Entry point for TTN V3 uplink decoder + * @param {TTN.Uplink.DecoderInput} input + * @returns {TTN.Uplink.DecoderOutput} - object containing the result of the decode, which might include warnings or errors + */ +function decodeUplink(input) { + let payload = { + warnings: [], + errors: [], + }; + + try { + payload.data = Decode_SD01L_Payload(input.bytes, input.fPort); + } catch (error) { + payload.errors.push(error); + } + + return payload; +} + +/** + * Entry point for TTN V2 uplink decoder + * @param {number[]} bytes - array of received bytes + * @param {number} port - LoRaWAN fPort number + * @returns {Wavetrend.SD01L.UplinkPayloads|null} - object containing decoded payload, or null if an error is encountered + */ +function Decoder(bytes, port) { + try { + return Decode_SD01L_Payload(bytes, port); + } catch (e) { + return null; + } +} + +// NB: Not used for TTN production, required for Unit Testing +/* istanbul ignore else */ +if (typeof module !== 'undefined') { + module.exports = { + Decoder, + decodeUplink, + }; +} \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js b/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js new file mode 100644 index 000000000..ec2c0c47f --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js @@ -0,0 +1,14 @@ +const path = require('path') + +module.exports = { + target: 'node', + mode: 'production', + entry: './src/index.js', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + library: { + type: 'commonjs' + } + } +}; diff --git a/vendors/wavetrend/logo.png b/vendors/wavetrend/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..76da28e4b30a2b6760d797c47e00951cb7fab727 GIT binary patch literal 6821 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 literal 0 HcmV?d00001 diff --git a/vendors/wavetrend/models/sd01-l-v2/logo.png b/vendors/wavetrend/models/sd01-l-v2/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..48d4a19c5b36da1d0e9927c1de7985603445f48e GIT binary patch literal 33265 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 MvZ^vaq|Czp4^Tg+RR910 literal 0 HcmV?d00001 diff --git a/vendors/wavetrend/models/sd01-l-v2/model.yaml b/vendors/wavetrend/models/sd01-l-v2/model.yaml new file mode 100644 index 000000000..d7d797671 --- /dev/null +++ b/vendors/wavetrend/models/sd01-l-v2/model.yaml @@ -0,0 +1,64 @@ +# Commercial name of the model +name: SD01-L-V2 Water Temperature Monitor +# Functional description of the product. Maximum 500 characters. +description: Monitor water temperature for Legionella Compliance +# Logo of the device +logo: logo.png +# ID(s) of the profile that defines the LoRaWAN characteristics of this model. +# id: as defined under /profiles. +# lorawanDeviceProfileID: as defined by LoRa Alliance in https://lora-alliance.org/wp-content/uploads/2020/10/LoRa_Alliance_Vendor_ID_for_QR_Code_02142022.pdf. +# The lorawanDeviceProfileID consists of 8 upper-case hexadecimal characters, 4 characters for VendorID + 4 characters for VendorProfileID. Please consider using single (') or double (") quotation. +deviceProfileIds: + - id: wavetrend_EU868_1.1_classA + lorawanDeviceProfileID: '00010001' + +# You may optionally customize any of the following settings to override the generic value set in LoRaWAN device profiles associated with your model. Leave empty if you want to keep the Device Profile settings. +# Maximum device TX Conducted output power in dBm. +maxTxPower: +# Minimum device TX Conducted output power in dBm. +minTxPower: +# Maximum device TX Radiated output power in dBm. +maxTxEIRP: +# Minimum device TX Radiated output power in dBm. +minTxEIRP: +# Typical mobility profile of the device. Possible values are 'near_static' (also valid for static devices), 'walking_speed', 'vehicular_speed' +# or 'random' (not known, changes over time). +motionIndicator: + +# Is your device certified by the LoRa Alliance? Possible values: true, false. +LoRaWANCertified: +# Always mandatory: `::` (You should have only one per model) +# Format: `<8 characters max>:<16 characters max>:` +# Be careful: Once you chose a model, it cannot be changed later +modelId: wavetrnd:sd01-l:2 +# :: Needed for linking the model with a specific driver -> must be the same one used in driver.yaml in the corresponding model (You might have several ones) +# Format: `<8 characters max>:<16 characters max>:` +# Be careful: Once you chose a protocolId, it cannot be changed later +protocolId: + - wavetrnd:sd01-l:2 +# DataSheet URL (optional) +specificationURL: +# User Guide URL (optional) +userGuideURL: +# : Available sensors following Actility ontology: https://github.com/actility/device-catalog/blob/main/template/sample-vendor/drivers/ONTOLOGY.md +sensors: + - temp1:Cel + - temp2:Cel + - temp3:Cel +# Driver examples +# A list of examples description that are compatible with this model +examples: + wavetrnd:sd01-l:2: + - uplink containing device status + - uplink containing sensor status and history (standard) + - uplink containing sensor status and history (simple) + - uplink containing device configuration result + - uplink containing sensor error + - uplink containing general error + - uplink containing freeze/scald alert + - uplink containing debug data + - downlink containing device configuration + +LoRaWANRelay: + canOperateAsARelay: false + defaultRelayActivation: false \ No newline at end of file diff --git a/vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml b/vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml new file mode 100644 index 000000000..f7ae18410 --- /dev/null +++ b/vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml @@ -0,0 +1,98 @@ +# ID that represents the profile of your device model. +# SHALL Follow this convention: (lowercase) + '_' + + '_' + '_class' + +# Follow the information below to know the profile group to use in the ID +# Profile Group +# RFGroup1: eu863-870, kr920-923, in865-867, ru864-870 +# RFGroup2: us902-928, cn470-510, au915-928 (only for LoRaWAN 1.0.2revB or below) +# RFGroup3: au915-928 (starting from LoRaWAN 1.0.2revC) +# RFGroup4: as923 +# Please do not change the existing IDs (Some may follow the old format) +# The name of the profile .yaml file should be the same as the following ID +id: wavetrnd_EU868_1.1_classA +# LoRaWAN class of the Device: Possible values: [ A, B, C ] (Should not have several values) +# 'A': Class A (Bi-directional end-devices with downlink listening only after uplink transmission) +# 'B': Class B (Bi-directional end-devices with downlink listening on predefined synchronized pingslots) +# 'C': Class C (Bi-directional end-devices with permanent downlink listening) +loRaWANClass: A +# Comma-separated list of regional profiles supported by this device. Possible values are eu868, us915, as923, au915, eu433, in865, kr920, ru864, cn470. +ISMbands: eu868 +# Typical mobility profile of the device. Possible values are 'near_static' (also valid for static devices), 'walking_speed', 'vehicular_speed' +# or 'random' (not known, changes over time). +# The motion indication property will not be taken into consideration here if it is overwritten in the model.yaml +motionIndicator: near_static + +mac: + # Activation modes supported by the device (put true where applicable). + # (ABP) + activationByPersonalization: false + #(OTAA) + overTheAirActivation: true + # Supported version of the LoRaWAN MAC (Layer-2) specification. Possible values are '1.0.0/1.0.1', '1.0.2', '1.0.3', '1.0.4', '1.1' + loRaWANMacVersion: 1.1 + # Supported version of the LoRaWAN regional parameters (PHY) specification. Possible values are '1.0.2revA', '1.0.2revB', '1.0.2revC', + # '1.0.3revA', 'RP2-1.0.0', 'RP2-1.0.1', 'RP2-1.0.2', 'RP2-1.0.3', 'RP2-1.0.4', 'RP2-1.0.5'. + regionalParameterVersion: RP2-1.0.3 + + # The device Tx Power Capabilities here will not be taken into consideration if it is overwritten in the model.yaml + devicesTxPowerCapabilities: + # Minimum device TX Conducted output power in dBm. + minTxPower: 2 # TODO: check if this is correct + # Maximum device TX Conducted output power in dBm. + maxTxPower: 18 # TODO: check if this is correct + # Minimum device TX Radiated output power in dBm. + minTxEIRP: 2 # TODO: check if this is correct + # Maximum device TX Radiated output power in dBm. + maxTxEIRP: 18 # TODO: check if this is correct + + uplinkFrameRepetition: + # Maximum number of transmissions per uplink frame, supported by the device. + maxNbTrans: + # How many uplink transmissions does the device use in Confirmed mode if it doesn't receive any DL ACK? + maxRedundancyForConfirmedUL: + +# The following section defines the default settings used by the device during iniial boot stage. Leave empty if your device respects the +# default values indicated by LoRaWAN Regional Parameters (PHY) specification. Personalize fields only when different from default PHY values. +bootSettings: + # Delay between the end of uplink transmission and the start of downlink RX1 slot, in milliseconds. Refer to 'receiveDelay1' in LoRaWAN + # Specification. + rx1Delay: + # RX1 data rate offset, defining the offset between uplink data rate and the corresponding downlink data rate used for RX1 slot. + rx1DROffset: + # Rx2 DataRate, used to send DL packets over RX2 slot. Note: Data Rate encoding is region-specific, see the applicable LoRaWAN Regional + # Profile. + rx2DataRate: + # Rx2 Frequency expressed in MHz, used to send DL packets over RX2 slot. + rx2Frequency: + # Default data rate used for Class B ping slots. Note: Data Rate encoding is region-specific, see the applicable LoRaWAN Regional Profile. + pingSlotChannelDataRate: + # Default frequency (in MHz) used for Class B ping slots. + pingSlotChannelFrequency: + # beaconFrequency Boot value used by the Device to set the beacon broadcast frequency. This frequency is then aligned by the Network Server to the target value set in RF region. + beaconFrequency: + # Default downlink dwell time (valid only for AS923 and AU915 profiles). Possible values 0 (no limit) or 1 (400ms). + downlinkDwellTime: + # Default uplink dwell time (valid only for AS923 and AU915 profiles). Possible values 0 (no limit) or 1 (400ms). + uplinkDwellTime: + +# Which MAC commands are supported by your device and which are not? Leave it as the template if your device supports all the MAC commands specified for your regional +# profile. Put 'true' only if a command is supported. +supportedMACCommands: + linkADRReqAns: true # TODO: check if this is correct + devStatusReqAns: true # TODO: check if this is correct + joinRequestAccept: true # TODO: check if this is correct + dutyCycleReqAns: true # TODO: check if this is correct + linkCheckReqAns: true # TODO: check if this is correct + rxParamSetupReqAns: true # TODO: check if this is correct + rxTimingSetupReqAns: true # TODO: check if this is correct + newChannelReqAns: true # TODO: check if this is correct + dlChannelReqAns: true # TODO: check if this is correct + txParamSetupReqAns: true # TODO: check if this is correct + pingSlotChannelReqAns: false # TODO: check if this is correct + pingSlotInfoReqAns: true # TODO: check if this is correct + deviceTimeReqAns: true # TODO: check if this is correct + beaconFreqReqAns: false # TODO: check if this is correct + +# Does your device support [Technical Recommendation for LoRaWAN L2 1.0.x Join Security] recommending implemeting the DevNonce as a counter for +# OTAA devices? See https://lora-alliance.org/resource_hub/technical-recommendations-for-preventing-state-synchronization-issues-around-lorawan-1-0-x-join-procedure/ +# Possible values: true, false. This field is automatically forced to true for LoRaWAN MAC versions 1.0.4 and 1.1. +devNonceCounterBased: true \ No newline at end of file diff --git a/vendors/wavetrend/vendor.yaml b/vendors/wavetrend/vendor.yaml new file mode 100644 index 000000000..956b66e20 --- /dev/null +++ b/vendors/wavetrend/vendor.yaml @@ -0,0 +1,19 @@ +# ID of the vendor to be used as an internal reference for Actility vendors. +# Define your own ID following this rule: Maximum of 8 characters in lowercase. +# Be careful: Once you chose a vendor ID, it cannot be changed later +id: wavetrnd +# Official/commercial name of the vendor to be used as a label. +name: Wavetrend Europe Limited +# Simple description of the vendor. Maximum 500 characters. Special characters are not allowed ('\n', '\t', '\r', ect...). +description: Legionella Compliance Monitoring, Pulse Counters and more + +# LoRa-Alliance Vendor ID used for QR code https://lora-alliance.org/wp-content/uploads/2020/10/LoRa_Alliance_Vendor_ID_for_QR_Code_02142022.pdf. It consists of 4 upper-case hexadecimal characters. +loRaAllianceVendorID: +# Logo file name if different from .png (optional). +logo: logo.png +# URL to the company website. +websiteURL: https://wavetrend.net/ +# URL to the company marketplace. +marketplaceURL: https://https://wavetrend.net/project_category/iot-solutions/ +# Priority for an email or a phone number, otherwise an address. +contact: sales@wavetrend.net \ No newline at end of file From 0d57d72aed63a91ee69d28c625e11f6cb37e901b Mon Sep 17 00:00:00 2001 From: Dave Meehan Date: Thu, 22 Jan 2026 15:05:28 +0000 Subject: [PATCH 2/3] Add .gitignore for Wavetrend SD01-L build outputs --- vendors/wavetrend/drivers/sd01-l-v2/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vendors/wavetrend/drivers/sd01-l-v2/.gitignore diff --git a/vendors/wavetrend/drivers/sd01-l-v2/.gitignore b/vendors/wavetrend/drivers/sd01-l-v2/.gitignore new file mode 100644 index 000000000..d77f6bdd8 --- /dev/null +++ b/vendors/wavetrend/drivers/sd01-l-v2/.gitignore @@ -0,0 +1,2 @@ +# Build output +dist/ From 27bf46556bf3cb500f48a4fc57b2cce1835a1eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9na=20MABILLE?= Date: Tue, 3 Feb 2026 11:10:25 +0100 Subject: [PATCH 3/3] Standardize profile and model Add a description in package.json Build driver in current folder instead of dist folder --- vendors/wavetrend/drivers/ONTOLOGY.md | 123 -- vendors/wavetrend/drivers/README.md | 1200 ----------------- .../wavetrend/drivers/sd01-l-v2/package.json | 6 +- .../drivers/sd01-l-v2/webpack.config.js | 2 +- vendors/wavetrend/models/sd01-l-v2/model.yaml | 7 +- ...aml => wavetrend_RFGroup1_1.1_classA.yaml} | 39 +- 6 files changed, 26 insertions(+), 1351 deletions(-) delete mode 100644 vendors/wavetrend/drivers/ONTOLOGY.md delete mode 100644 vendors/wavetrend/drivers/README.md rename vendors/wavetrend/profiles/{wavetrend_EU868_1.1_classA.yaml => wavetrend_RFGroup1_1.1_classA.yaml} (80%) diff --git a/vendors/wavetrend/drivers/ONTOLOGY.md b/vendors/wavetrend/drivers/ONTOLOGY.md deleted file mode 100644 index 1842d35ef..000000000 --- a/vendors/wavetrend/drivers/ONTOLOGY.md +++ /dev/null @@ -1,123 +0,0 @@ -# Ontology - -This is the ontology supported by Actility. You can define a sensor inside your model depending on this table. - -> Our ontology is based on [oBIX protocol](http://docs.oasis-open.org/obix/obix/v1.1/csprd01/obix-v1.1-csprd01.pdf) which provides an extensive database of predefined units that are represented in seven main dimensions. These seven dimensions are represented in SI respectively as kilogram (kg), meter (m), second (sec), Kelvin (K), ampere (A), mole (mol), and candela (cd). - -| Unit | unitId | type | symbol | fields | -|------|--------|------|--------|--------| -| acceleration compared to earth gravity | gravity | double | g | acceleration, vibration | -| ampere | A | double | A | current | -| ampere-hour | Ah | double | Ah | charge | -| bar | bar | double | bar | pressure | -| becquerel | Bq | double | Bq | radioactivity | -| bel | Bspl | double | bel | intensity, snr, sound | -| bit | bit | double | bit | data, storage | -| bit per second | bit/s | double | bit/s | dataSpeed | -| candela | cd | double | cd | intensity | -| candela per square meter | cd/m2 | double | cd/m² | brightness | -| celsius | Cel | double | °C | temperature | -| centimeter | cm | double | cm | distance, accuracy, range, altitude, height | -| coulomb | C | double | C | electricCharge | -| count per minute | count/min | double | count/min | eventRate, count | -| count per second | count/s | double | count/s | eventRate, count | -| counter | count | int64 | occ. | counter, amount, quantity | -| cubic meter | m3 | double | m³ | volume | -| cubic meter per hour | m3/h | double | m³/h | flowRate | -| cubic meter per second | m3/s | double | m³/s | flowRate | -| day | day | double | day | time, duration, interval, age, period | -| decibel | dB | double | dB | intensity, snr, sound | -| decibel relative to 1 mW | dBm | double | dBm | rssi | -| decibel relative to 1 W | dBW | double | dBW | powerLevel | -| degree | deg | double | ° | angle | -| degrees per second | dps | double | dps | angularVelocity | -| dilution of precision | dop | double | dop | navigation | -| euro | euro | double | € | price | -| euro per watt-hour | euro/Wh | double | €/Wh | energyPrice | -| fahrenheit | Far | double | °F | temperature | -| farad | F | double | F | capacitance | -| gigawatt | GW | double | GW | power, activePower | -| GPS | GPS | object | GPS | location | -| gram | g | double | g | mass, weight | -| gray | Gy | double | Gy | radiation | -| hectopascal | hPa | double | hPa | pressure | -| henry | H | double | H | inductance | -| hertz | hertz | double | Hz | frequency, sound | -| hour | h | double | h | time, duration, interval, age, period | -| index | index | int64 | index | uv | -| joule | J | double | J | energy | -| katal | kat | double | kat | catalyticActivity | -| kelvin | K | double | K | temperature | -| kilogram | kg | double | kg | mass, weight | -| kilometer | km | double | km | distance, accuracy, range, altitude, height | -| kilometer per hour | km/h | double | km/h | velocity, speed | -| kilopascal | kPa | double | kPa | pressure | -| kilowatt | kW | double | kW | power, activePower | -| kilowatt-hour | kWh | double | kWh | energy | -| liter | l | double | l | volume, capacity | -| liter per second | l/s | double | l/s | flowRate | -| lumen | lm | double | lm | flux, light | -| lux | lx | double | lx | flux, light, illuminance | -| mac | IEEE-802 | string | mac | mac | -| megawatt | MW | double | MW | power, activePower | -| megawatt per minute | MW/m | double | MW/m | powerRate | -| megawatt-hour | MWh | double | MWh | energy | -| meter | m | double | m | distance, accuracy, range, altitude, height | -| meter per second | m/s | double | m/s | velocity, speed | -| meter per square second | m/s2 | double | m/s² | acceleration, vibration | -| micro-gravity | ugravity | double | µg | acceleration, vibration | -| microgram | ug | double | µg | mass, weight | -| microgram per cubic meter | ug/m3 | double | µg/m³ | concentration | -| micrometer | um | double | µm | distance, accuracy, range, altitude, height | -| micromole per second and square meter | umol/m2.s | double | µmol/m².s | fluxDensity, intensity | -| microsiemens per centimeter | uS/cm | double | µS/cm | conductivity | -| microvolt | uV | double | µV | batteryVoltage, rmsVoltage, voltage | -| milli-gravity | mgravity | double | mg | acceleration, vibration | -| milliampere | mA | double | mA | current | -| milliampere-hour | mAh | double | mAh | charge | -| millibar | mbar | double | mbar | pressure | -| millileter | ml | double | ml | volume, capacity | -| millimeter | mm | double | mm | distance, accuracy, range, altitude, height | -| millimeter per hour | mm/h | double | mm/h | velocity, speed | -| millimeter per second | mm/s | double | mm/s | velocity, speed | -| millisecond | ms | double | ms | time, duration, interval, age, period | -| millisiemens per centimeter | mS/cm | double | mS/cm | conductivity | -| millivolt | mV | double | mV | batteryVoltage, rmsVoltage, voltage | -| minute | minute | double | min | time, duration, interval, age, period | -| mole | mol | double | mol | amount, quantity | -| month | month | double | month | time, duration, interval, age, period | -| nephelometric turbidity | ntu | double | ntu | nephelometricTurbidity, turbidity | -| newton | N | double | N | force | -| ohm | Ohm | double | Ω | resistance | -| okta | okta | int64 | okta | cloudCover, cover | -| parts per billion | ppb | double | ppb | amount, quantity, concentration, co2Level | -| parts per million | ppm | double | ppm | amount, quantity, concentration, co2Level | -| pascal | Pa | double | Pa | pressure | -| per cubic centimeter | #/cm3 | double | #/cm3 | density | -| percentage | % | double | % | batteryLevel, percentage, per, currentUnbalance, luminosityLevel, occupancyLevel, leakLevel, fillLevel | -| percentage relative humidity | %RH | double | %RH | humidity | -| pH | pH | double | pH | acidity | -| pulse per hour | pulse/h | double | pulse/h | frequency, sound | -| radian | rad | double | rad | angle | -| rate | / | double | rate | rate, powerFactor | -| rotations per minute | rpm | double | rpm | angularVelocity | -| second | s | double | s | time, duration, interval, age, period | -| siemens | S | double | S | conductance | -| siemens per meter | S/m | double | S/m | conductivity | -| sievert | Sv | double | Sv | radiationEffect | -| square meter | m2 | double | m² | area | -| state | state | boolean | bool | leak, presence, status | -| steradian | sr | double | sr | solidAngle | -| tesla | T | double | T | magneticDensity | -| volt | V | double | V | batteryVoltage, rmsVoltage, voltage | -| volt-ampere | VA | double | VA | apparentPower | -| volt-ampere hour | VAh | double | VAh | apparentEnergy | -| volt-ampere reactive | var | double | var | reactivePower | -| volt-ampere reactive hour | varh | double | varh | reactiveEnergy | -| watt | W | double | W | power, activePower | -| watt per hour | W/h | double | W/h | powerRate | -| watt per second | W/s | double | W/s | powerRate | -| watt per square meter | W/m2 | double | W/m² | irradiance, solarRadiation | -| watt-hour | Wh | double | Wh | energy | -| weber | Wb | double | Wb | magneticFlux | -| year | year | double | year | time, duration, interval, age, period | diff --git a/vendors/wavetrend/drivers/README.md b/vendors/wavetrend/drivers/README.md deleted file mode 100644 index 62e062d4a..000000000 --- a/vendors/wavetrend/drivers/README.md +++ /dev/null @@ -1,1200 +0,0 @@ -# JavaScript driver structure - -> If you have a driver already follows the LoRa Alliance standard codec API, then you need just to add `driver.yaml` file as the one [here](sd01-l-v2/driver.yaml). - -This section describes how to build a javascript driver for Actility. - -You can either follow the LoRa Alliance standard codec API described [here](https://resources.lora-alliance.org/document/ts013-1-0-0-payload-codec-api), or follow this documentation. - -- [JavaScript driver structure](#JavaScript-driver-structure) - - [Driver](#driver) - - [API](#API) - - [Driver functions](#driver-functions) - - [Uplink decode](#uplink-decode) - - [Downlink encode](#downlink-encode) - - [Downlink decode](#downlink-decode) - - [Context](#store-and-reload-context) - - [Payload examples](#payload-examples) - - [Json schemas](#json-schemas) - - [Packaging](#packaging) - - [Testing](#testing) - - [Template](sd01-l-v2) -- [Sample driver developer guide](#sample-driver-developer-guide) - - -## Driver - -The `driver` is the piece of code responsible to decode uplinks/downlinks and to encode downlinks for a single device -communication protocol. It is the core part of the LoRaWAN framework to interact with new devices. - -If a device is exposing several incompatible communication protocols, then several drivers needs to be implemented, -one for each. - -The programming language used in this codec is the JavaScript which is a lightweight, interpreted, just-in-time compiled programming language with first class functions. - -More precisely, the JavaScript ES5 is used as it is simple and widely supported in most communities. - -## API - -### Driver functions - -The following sections describe the three javascript functions that a driver can declare to perform encoding and decoding -tasks. - -> A driver must at least declare a `decodeUplink(input)` function to be valid (see next section). - -#### Uplink decode - -This function is mandatory when creating a codec; without it, the codec is considered invalid. - -Uplinks are decoded by calling the following function: - -```javascript -function decodeUplink(input) { - ... - return output; -} -``` - -The `input` is an object provided by the Actility framework that is represented by the following json-schema: - -```json -{ - "bytes": { - "description": "The uplink payload byte array, where each byte is represented by an integer between 0 and 255", - "type": "array", - "items": { - "type": "integer" - }, - "required": true - }, - "fPort": { - "description": "The uplink message LoRaWAN fPort", - "type": "integer", - "required": true - }, - "recvTime": { - "description": "The uplink message datetime recorded by the LoRaWAN network server as a JavaScript Date object", - "type": "string", - "format": "date-time", - "required": true - } -} -``` - -The returned `output` is represented by the following json-schema: - -```json -{ - "data": { - "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", - "type": "Object", - "required": false - }, - "errors": { - "description": "A list of error messages while decoding the provided payload. required if failed.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "warnings": { - "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - } -} -``` -#### Downlink encode - -Contrary to the decodeUplink function, the implementation of this function is only mandatory when a device supports downlinks. - -Downlinks are encoding by calling the following function: - -```javascript -function encodeDownlink(input) { - ... - return output; -} -``` - -The `input` is an object that is represented by the following json-schema: - -```json -{ - "data": { - "description": "The open JavaScript object representing the downlink. It is defined by the codec developer", - "type": "Object" - } -} -``` - -The returned `output` is an object that is represented by the following json-schema: - -```json -{ - "fPort": { - "description": "The downlink LoRaWAN fPort, if no error occurred", - "type": "integer", - "required": true - }, - "bytes": { - "description": "The downlink payload byte array, where each byte is represented by an integer between 0-255, if no error occurred. required if success.", - "type": "array", - "items": { - "type": "integer" - }, - "required": false - }, - "errors": { - "description": "A list of error messages while decoding the provided payload. required if failed.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "warnings": { - "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - } -} -``` - -#### Downlink decode - -The implementation of this function is optional; it may be present when a device supports downlinks, to ease the monitoring and logs of sent downlinks. - -Downlinks are decoded by calling the following function: - -```javascript -function decodeDownlink(input) { - ... - return output; -} -``` - -The `input` is an object provided by the LoRaWAN framework that is represented by the following json-schema: - -```json -{ - "bytes": { - "description": "The downlink payload byte array, where each byte is represented by an integer between 0 and 255", - "type": "array", - "items": { - "type": "integer" - }, - "required": true - }, - "fPort": { - "description": "The downlink message LoRaWAN fPort", - "type": "integer", - "required": true - }, - "recvTime": { - "description": "The downlink message datetime computed by the LoRaWAN platform as a JavaScript Date object", - "type": "string", - "format": "date-time", - "required": true - } -} -``` - -The returned `output` is represented by the following json-schema: - -```json -{ - "data": { - "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", - "type": "Object", - "required": false - }, - "errors": { - "description": "A list of error messages while decoding the provided payload. required if failed.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "warnings": { - "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - } -} -``` - -### Driver Execution Environment and Available Libraries - -Drivers that get __tested locally__ before submission and __deployed__ on our platforms are executed through an isolated virtual machine provided by __isolated-vm__ (a node module that executes the drivers in a __secure environment__). - -This implies that only a __select few libraries__ are made available during the execution of the drivers. - -Currently, only the ``Buffer`` library is available on top of all the standard NodeJS classes, functions and methods (e.g.: ``Array``, ``Object``, ``JSON``, ``Math``, etc.). This list can extend depending on how popular a certain module is becoming in recent drivers. - -### Store and reload context - -On some devices, some information from a previous payload are useful for the current one. Thus, a context array is accessible to the driver's developer where some info can be injected/retrieved while decoding/encoding payloads. - -This context is based on DevEUI, so each device has its own context, even if several devices use the same driver. - -The context in the driver's environment is an array of flexible JSON objects. - -:warning: **WARNING:** If the context remains unchanged, it will not be updated in our database, and persistence is limited to 2 days. To keep your context for longer, add a timestamp or a counter to your context on each uplink. - -#### Enable the context - -To enable the context, you must set useContext to true in the driver's driver.yaml as such: -``` -# When a driver uses a context, this field must be set to true -# https://github.com/actility/device-catalog/blob/main/template/sample-vendor/drivers/README.md#store-and-reload-context -useContext: true -``` - -#### Store a context - -Inside a driver, data can be injected to the context: `context.push()`. - -##### Example: - -```javascript -function decodeUplink(input){ - const raw = Buffer.from(input.bytes); - const temperature = raw.readInt16BE(1)/100; - context.push({ - time: input.recvTime, - currentValue: temperature - }); - ... -} -``` -#### Reload a context - -Inside a driver, data can be retrieved from the context: -- Using `context.shift()` to load the latest context saved. -- Using `context[index]` to load a specific context by using the index. - -##### Example: - -```javascript -function decodeUplink(input){ - const latestContext = context.shift(); - const latestTemperature = latestContext["currentValue"]; - - const raw = Buffer.from(input.bytes); - const temperature = raw.readInt16BE(1)/100; - - const averageTwoMeasures = (temperature + latestTemperature) / 2; - ... -} -``` - -#### Update and Reload a context - -Inside a driver, context can be reloaded and updated for next decode/encode processes. - -##### Example: - -```javascript -function decodeUplink(input){ - const raw = Buffer.from(input.bytes); - const temperature = raw.readInt16BE(1)/100; - - context.push({ - temperature: temperature, - time: input.recvTime - }); - result.temperatureHistory = context; - ... -} -``` - -The result of decoding will be something as below: - -```json -{ - "temperature": 23.3, - "temperatureHistory": [ - { - "temperature": 23.3, - "time": "2024-08-12T15:24:24.249Z" - }, - { - "temperature": 23.2, - "time": "2024-08-12T15:26:24.249Z" - }, - { - "temperature": 22.9, - "time": "2024-08-12T15:28:24.249Z" - }, - { - "temperature": 23.1, - "time": "2024-08-12T15:30:24.249Z" - } - ] -} -``` - -### Payload examples - -:warning: **WARNING:** This section concerns only drivers that follow this guide and respect "lora-alliance" signature and format. For any other format/signature (ttn, chirpstack, actility), the examples should follow the section [Legacy Payload Examples](#legacy-payload-examples-only-signatures-other-than-lora-alliance-are-concerned). - -The following section describes the examples of the payloads of the driver. - -An `examples.json` file of uplink and downlink payloads must be declared directly in the driver package. - -These examples will be used in order to provide for the users of the driver some examples of the payload to be decoded/encoded to test the driver. In addition, it will be used to facilitate the testing of the driver while development. - -**IMPORTANT:** Description should be unique on each driver. -#### Example - -The uplink/downlink decode example used is an object represented by the following json-schema: - -```json -{ - "description": { - "description": "the description of the uplink/downlink example", - "type": "string", - "required": true - }, - "type": { - "description": "the type of the uplink/downlink example", - "type": "string", - "enum": ["uplink", "downlink-decode"], - "required": true - }, - "input": { - "type": "Object", - "items": { - "bytes": { - "description": "the uplink/downlink payload expressed in hexadecimal", - "type": "string", - "required": true - }, - "fPort": { - "description": "the uplink/downlink message LoRaWAN fPort", - "type": "number", - "required": true - }, - "recvTime": { - "description": "the uplink/downlink message time", - "type": "string", - "format": "date-time", - "required": true - } - } - }, - "output": { - "type": "Object", - "items": { - "data": { - "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", - "type": "Object", - "required": false - }, - "errors": { - "description": "A list of error messages while decoding the provided payload. required if failed.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "warnings": { - "description": "A list of warning messages that do not prevent the codec from decoding the payload. optional.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - } - } - } -} -``` - - -The downlink encode example used is an object represented by the following json-schema: - -```json -{ - "description": { - "description": "the description of the downlinn encode example", - "type": "string", - "required": true - }, - "type": { - "description": "the type of the uplink/downlink example", - "type": "string", - "enum": ["downlink-encode"], - "required": true - }, - "input": { - "type": "Object", - "items": { - "data": { - "description": "The open JavaScript object representing the decoded payload when no error is encountered while decoding. required if success.", - "type": "Object", - "required": false - } - } - }, - "output": { - "type": "Object", - "items": { - "bytes": { - "description": "the downlink encoded payload expressed in hexadecimal. required if success.", - "type": "string", - "required": false - }, - "fPort": { - "description": "the downlink message LoRaWAN fPort", - "type": "number", - "required": true - }, - "errors": { - "description": "A list of error messages while encoding the provided payload. required if failed.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "warnings": { - "description": "A list of warning messages that do not prevent the codec from encoding the payload. optional.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - } - } - } -} -``` - -### Json Schemas - -The following section describes the Json Schema of the decoded payloads of the driver. - -As the output data from the decoding payload process is not predictable, it is better to declare Json schemas that defines the structure of this output to ease the use of driver after decoding. - -The Json schemas of uplink and downlink payloads must be declared directly in the driver package. -Two Json schemas can be declared following the pattern: `uplink.schema.json` for uplink data, and `downlink.schema.json` for downlink data if supported. - -An `*.schema.json` file contains a generic json schema for all types of payload decoded by this driver of several uplink/downlink examples. - -## Packaging - -To simplify the open distribution and integration with our platform, a packaging leveraging NPMs is defined. - -NPM was chosen because it is the most widely used packaging system for JavaScript code. Also, this approach defines a -clear code layout that can be distributed independently using the developer preferred version control tool. - -You can find a full description of packaging in the guide of a driver [here](#sample-driver-developer-guide). - -## Testing - -Testing your driver is a very important process, thus the user is highly encouraged to test the driver in most possible -use cases as well as error cases. - -**Important:** The test of your driver is needed to prove a minimum test coverage of 85% to be valid on our framework. - -_**PS:** If your driver outputs values as ISO string dates or instances of class Date in the format "xxxx-xx-xxTxx:xx:xx.xxxZ", **declared when compiled**, you can validate the test by replacing the date value by_ "XXXX-XX-XXTXX:XX:XX.XXXZ" _in the JSON examples file._ - -> A pre-implemented [spec file](sd01-l-v2/driver-examples.spec.js) for testing can be copied from the template in order to test the driver with all the provided examples. - -## BACnet Integration - -As you may wish your devices and drivers to include a BACnet integration, our catalogs allow you to do so. -Along with all the driver and device profiles, you can deploy a BACnet mapping inside [this folder](../../../mappings/). -Please refer to [this markdown file for further instructions](../../../mappings/template/how-to.md). - -## -# Sample driver developer guide - -This example describes how you to create a driver for Actility following the LoRa Alliance standard Codec API. - -The concept and API is described [here](#api) - -- [Sample driver developer guide](#sample-driver-developer-guide) - - [Minimal driver](#minimal-driver) - - [Encoding and decoding downlinks](#encoding-and-decoding-downlinks) - - [Returning errors](#returning-errorswarnings) - - [Testing](#testing-the-driver) - -## Minimal driver - -Pre-requirements: you need to have npm installed with version > 5. To test the installed version run: - -```sh -$ npm -v -``` - -We'll start by creating a new npm project that will contain the driver. From an empty directory in a terminal run: - -```sh -$ npm init -``` - -After completing all the information requested by npm you will find a new file `package.json` on the directory you ran -`npm init` similar to the following (ignoring the name, version, author, etc): - -```json -{ - "name": "driver", - "version": "1.0.0", - "description": "My driver", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC" -} -``` - -***Important:*** Please make sure to NOT scope your package. - -**PS**: In the driver, the `require()` method is not allowed to import an external module. -If your driver is split into several javascript file (not recommended), you have to use webpack to generate a single Javascript file. -Here is the webpack configuration to be used in that case: -```javascript -module.exports = { - target: "node", - mode: "production", - entry: "./index.js", - output: { - filename: "main.js", - path: path.resolve(__dirname, "."), - library: "driver", - }, -} -``` - -Now that we have a valid npm project, we will create the driver itself. Open a new file named `index.js` where we will -define only an uplink decode: - -_index.js_: - -```javascript -function decodeUplink(input) { - let result = { - data: {}, - errors: [], - warnings: [] - }; - const raw = Buffer.from(input.bytes); - - if (raw.byteLength > 8) { - result.errors.push("Invalid uplink payload: length exceeds 8 bytes"); - delete result.data; - return result; - } - - for (i = 0; i < raw.byteLength; i++) { - switch (raw[i]) { - // Temperature - 2 bytes - case 0x00: - if (raw.byteLength < i + 3) { - result.errors.push("Invalid uplink payload: index out of bounds when reading temperature"); - delete result.data; - return result; - } - result.data.temperature = raw.readInt16BE(i+1)/100; - if(result.data.temperature > 40){ - result.warnings = ["temperature exceeded the threshold of 40 degrees."]; - } - i += 2; - break; - // Humidity - 2 bytes - case 0x01: - if (raw.byteLength < i + 3) { - result.errors.push("Invalid uplink payload: index out of bounds when reading humidity"); - delete result.data; - return result; - } - result.data.humidity = raw.readInt16BE(i+1)/100; - i += 2; - break; - // Pulse counter - 1 byte - case 0x02: - result.data.pulseCounter = raw.readInt8(i+1); - i += 1; - break; - default: - result.errors.push("Invalid uplink payload: unknown id '" + raw[i] + "'"); - delete result.data; - return result; - } - } - return result; -} -``` - -In this function, we use a utility function called `readShort`, you must add the following code in your `index.js`: - -```javascript -function readShort(bin) { - var result = bin & 0xffff; - if (0x8000 & result) { - result = -(0x010000 - result); - } - return result; -} -``` - -As you can see by inspecting the code, the driver defines a very simple decode function where only two -objects can be retrieved from the payload: temperature, humidity (2 bytes each) and pulse counter (1 byte). - -Now that your driver is finished you can create the npm package. Simply run: - -```shell -npm pack -``` - -This will create a new file with the `.tgz` extension in the current folder containing the complete driver. - -## Encoding and decoding downlinks - -In the previous step we wrote and packaged a driver, which implemented the minimal functionality (i.e.: an uplink decode function). -Now let's extend that driver in order to encode and decode downlinks. - -First, lets add a `encodDownlink(input)` function in `index.js`: - -```javascript -function encodeDownlink(input) { - let result = { - errors: [], - warnings: [] - }; - let raw = new Buffer(4); - let index = 0; - - if (typeof input.data.pulseCounterThreshold !== "undefined") { - if (input.data.pulseCounterThreshold > 255) { - result.errors.push("Invalid downlink: pulseCounterThreshold cannot exceed 255"); - delete result.data; - return result; - } - raw.writeUInt8(0,index); - index+=1; - raw.writeUInt8(input.data.pulseCounterThreshold, index); - index+=1; - } - if (typeof input.data.alarm !== "undefined") { - raw.writeUInt8(1, index); - index+=1; - raw.writeUInt8(input.data.alarm === true? 1 : 0, index); - index+=1; - } - result.bytes = Array.from(raw).slice(0,index); - result.fPort = 16; - return result; -} -``` - -The `encodeDownlink(input)` function takes an object as parameter (see [here](#downlink-encode)) containing the object (called `data`) -that will be encoded as a downlink. Then the function only checks for two objects inside `data` (`pulseCounterThreshold` and `alarm`) -and write their contents as well as their id as byte array. - -We can also add a `decodeDownlink(input)` function. This function will allow us to decode the bytes as they are returned from -`encodeDownlink(input)` and return us the object that represents the downlink. - -Add the following function in `index.js`: - -```javascript -function decodeDownlink(input) { - let result = { - data: {}, - errors: [], - warnings: [] - }; - const raw = Buffer.from(input.bytes); - - if (raw.byteLength > 4) { - result.errors.push("Invalid downlink payload: length exceeds 4 bytes"); - delete result.data; - return result; - } - - for (i = 0; i < raw.byteLength; i += 2) { - switch (raw[i]) { - // Pulse counter threshold - 1 byte - case 0x00: - if (raw.byteLength < i + 2) { - result.errors.push("Invalid downlink payload: index out of bounds when reading pulseCounterThreshold"); - delete result.data; - return result; - } - result.data.pulseCounterThreshold = raw.readUInt8(i+1); - break; - // Alarm - 1 byte - case 0x01: - if (raw.byteLength < i + 2) { - result.errors.push("Invalid downlink payload: index out of bounds when reading alarm"); - delete result.data; - return result; - } - result.data.alarm = raw.readUInt8(i+1) === 1; - break; - default: - result.errors.push("Invalid downlink payload: unknown id '" + raw[i] + "'"); - delete result.data; - return result; - } - } - return result; -} -``` - -The function takes an `input` object (see [here](#downlink-decode)) that will contain `bytes`. This driver will only -decode both objects as returned from `encodeDownlink(input)`: `pulseCounterThreshold` and `alarm`. - -After adding `encodeDownlink(input)` and `decodeDownlink(input)` functions you can re-package your driver. - -## Returning errors/warnings - -As you have noticed, the errors must not be thrown, it can be outputed inside the `errors` array in the output. - -Same for a warning needed to be exposed, a string can be added to the array `warnings` in the output object. - -## Testing the driver - -We use [Jest](https://jestjs.io/) as our testing framweork. - -_Note: when testing, you will need to export the functions that you test (unless of course you copy / paste the functions into the testing file). This is *not* needed in your driver if not tested_. - -To exports functions, you can add the following at the end of the `index.js` file: - -```javascript -exports.decodeUplink = decodeUplink; -exports.decodeDownlink = decodeDownlink; -exports.encodeDownlink = encodeDownlink; -``` - -### Add dependencies - -To add the dependencies, add the following to the `package.json` file: - -```json -"devDependencies": { - "fs-extra": "^11.2.0", - "isolated-vm": "^4.7.2", - "jest": "^29.7.0", - "js-yaml": "^4.1.0", - "path": "^0.12.7" - } -``` - -Then run the following command: - -```shell -npm install -``` - -### Update package.json to add a script - -First, you need to add the `test` script in the `package.json`: - -```json - "scripts": { - "test": "jest --collectCoverage" - } -``` - -**Note:** If your driver does not support a function `encodeDownlink`, all you have to do is to comment/remove the part related to `encodeDownlink` testing inside the pre-implemented test file. - -### Test the different cases of your driver - -In order to facilitate the use cases testing process, we provide the file [driver-examples.spec.js](sd01-l-v2/driver-examples.spec.js). - -This file will automatically get all your examples inside `examples.json` and test them using [Jest](https://jestjs.io/). - -### Execute tests with coverage - -To execute tests, you must use the following command: - -```shell -npm run test -``` - -This command will give a full report about the coverage of your tests. The most important value in this report is the -percentage of the statements' coverage which appears under `stmts`. - -### Add Json Schemas - -To provide json schemas of your driver, create a file named `uplink.schema.json` and add the following json schema that describes the structure of the `decodeUplink` output: - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "temperature": { - "type": "number" - }, - "humidity": { - "type": "number" - }, - "pulseCounter": { - "type": "number" - }, - "volumes": { - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "time": { - "type": "string" - }, - "volume": { - "type": "integer" - } - }, - "required": [ - "time", - "volume" - ] - } - ] - } - }, - "additionalProperties": false -} -``` - -Create a file named `downlink.schema.json` and add the following json schema that describes the structure of the `decodeDownlink` output: - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "pulseCounterThreshold": { - "type": "integer" - }, - "alarm": { - "type": "boolean" - } - }, - "additionalProperties": false -} -``` -### Create a tarball from the package - -To create a tarball from the already defined package, you must use the following command: - -```shell -npm pack -``` - -This command must be executed in the root folder of the driver. It will generate a `.tgz` file that contains all the -files and directories of the driver. - -**Important:** You must avoid including the non-necessary files into the `.tgz` file as the `node_modules` -and `coverage` directories for example. (This can be done by adding a `.npmignore` file). - the driver - -#### Points extraction - -Points can be extracted once an uplink has been decoded. In order to extract points, a driver must provide the following function: - -```javascript -function extractPoints(input) {...} -``` - -The `input` is an object provided by the IoT Flow framework that is represented by the following json-schema: - -```json -{ - "message": { - "description": "the object message as returned by the decodeUplink function", - "type": "object", - "required": true - }, - "time": { - "description": "the datetime of the uplink message, it is a real javascript Date object", - "type": "string", - "format": "date-time", - "required": true - } -} -``` - -The returned object must be: -- The wrapped object from the decoded one in case all the event are done at the same time, respecting the ontology. - Here's an example: -```json -{ - "temperature": { - "record": 31.4, - "unitId": "Cel" - }, - "location": { - "unitId": "GPS", - "records": [ - { - "value": [48.875158, 2.333822], - "eventTime": "2019-01-01T10:00:00+01:00" - } - ] - }, - "power:0": { - "record": 0.32, - "unitId": "GW" - }, - "power:1": { - "record": 0.33, - "unitId": "GW" - }, - "power:2": { - "record": 0.4523, - "unitId": "GW" - }, - "power:3": { - "record": 0.4456, - "unitId": "GW" - }, - "power:4": { - "record": 0.4356, - "unitId": "GW" - } -} -``` -- OR, it is defined by the following json-schema in case the point has several values in different timestamp. - -```json -{ - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "object", - "properties": { - "eventTime": { - "type": "string", - "format": "date-time", - "required": true - }, - "value": { - "type": [ - "string", - "number", - "boolean" - ], - "required": true - } - } - } - } -} -``` -Here are a few examples: - -Simple : -```json -{ - "temperature": - { - "record": 31.4, - "unitId": "Cel" - } -} -``` - -Multiple measurements with different measurement time : -```json -{ - "temperature": { - "unitId": "Cel", - "records": [ - { - "eventTime": "2019-01-01T10:00:00+01:00", - "value": 31.4 - }, - { - "eventTime": "2019-01-01T11:00:00+01:00", - "value": 31.2 - }, - { - "eventTime": "2019-01-01T12:00:00+01:00", - "value": 32 - } - ] - } -} -``` - -Multiple of the same sensor type : \ -(In case of mutiple sensors of the same type, the ID should start at 0) -```json -{ - "temperature:0": { - "record": 31.4, - "unitId": "Cel" - }, - "temperature:1": { - "record": 31.2, - "unitId": "Cel" - }, - "temperature:2": { - "record": 32, - "unitId": "Cel" - } -} -``` - ----------------------------------------------------------------- - -### Legacy payload examples (only signatures other than lora-alliance are concerned) - -The following section describes the examples of the payloads of the driver. - -Several examples of uplink and downlink payloads must be declared directly in the driver's root directory and especially in a directory `/examples`. The name of each examples file must follow the pattern `*.examples.json`. You can split and organize the examples files according to your own logic. - -These examples will be used in order to provide for the users of the driver some examples of the payload to be decoded/encoded to test the driver. In addition, it will be used to facilitate the testing of the driver while development. - -An `*.examples.json` file contains an array of several uplink/downlink examples. You can find an example of this file in the driver example. - -#### Example - -The uplink/downlink example used is an object represented by the following json-schema: - -```json -{ - "description": { - "description": "the description of the uplink/downlink example", - "type": "string", - "required": true - }, - "type": { - "description": "the type of the uplink/downlink example. type 'downlink' is used for both downlink decoding/encoding in case the function exist.", - "type": "string", - "enum": ["uplink", "downlink"], - "required": true - }, - "bytes": { - "description": "the uplink/downlink payload expressed in hexadecimal", - "type": "string", - "required": true - }, - "fPort": { - "description": "the uplink/downlink message LoRaWAN fPort", - "type": "number", - "required": true - }, - "time": { - "description": "the uplink/downlink message time", - "type": "string", - "format": "date-time", - "required": false - }, - "data": { - "description": "the decoded uplink/downlink view as an output", - "type": "object", - "required": true - } -} -``` - -### Legacy error examples (only signatures other than lora-alliance are concerned) - -These errors examples has a similar concept of the payloads examples. - -To benefit from the automation of the tests, you must create a directory in the driver package named `/errors`. Inside, the name of each error examples file must follow the pattern `*.errors.json`. You can split and organize the errors files according to your own logic. - -**Note:** These errors examples will be only used for unit tests and will not be stored in our framework. - -An `*.errors.json` file contains an array of several uplink/downlink errors examples. - -##### decodeUplink/decodeDownlink error example - -The error example used to test `decodeUplink`/`decodeDownlink` function is an object represented by the following json-schema: - -```json -"description": { - "description": "the description of the error example", - "type": "string", - "required": true - }, - "type": { - "description": "the type of the example", - "type": "string", - "enum": ["uplink", "downlink"], - "required": true - }, - "bytes": { - "description": "the uplink/downlink payload expressed in hexadecimal", - "type": "string", - "required": true - }, - "fPort": { - "description": "the uplink/downlink message LoRaWAN fPort", - "type": "number", - "required": true - }, - "time": { - "description": "the uplink/downlink message time", - "type": "string", - "format": "date-time", - "required": false - }, - "error": { - "description": "the error that should be thrown in case of wrong input", - "type": "string", - "required": true - } -``` - -##### encodeDownlink error example - -The error example used to test `encodeDownlink` function is an object represented by the following json-schema: - -```json -"description": { - "description": "the description of the error example", - "type": "string", - "required": true - }, - "type": { - "description": "the type of the example", - "type": "string", - "enum": ["downlink"], - "required": true - }, - "fPort": { - "description": "the downlink message LoRaWAN fPort", - "type": "number", - "required": true - }, - "time": { - "description": "the downlink message time", - "type": "string", - "format": "date-time", - "required": false - }, - "data": { - "description": "the input to the encodeDownlink function", - "type": "object", - "required": true - }, - "error": { - "description": "the error that should be thrown in case of wrong input", - "type": "string", - "required": true - } -``` \ No newline at end of file diff --git a/vendors/wavetrend/drivers/sd01-l-v2/package.json b/vendors/wavetrend/drivers/sd01-l-v2/package.json index ae7591e1a..4ca91d28e 100644 --- a/vendors/wavetrend/drivers/sd01-l-v2/package.json +++ b/vendors/wavetrend/drivers/sd01-l-v2/package.json @@ -1,8 +1,8 @@ { "name": "wavetrend-sd01-l-v2", - "version": "2.4.0", - "description": "LoRa Alliance sample driver npm packaged", - "main": "dist/index.js", + "version": "1.0.0", + "description": "Wavetrend sd01-l-v2 driver", + "main": "index.js", "scripts": { "test": "node run-driver-test.js", "build": "webpack --config webpack.config.js" diff --git a/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js b/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js index ec2c0c47f..e45bf4bea 100644 --- a/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js +++ b/vendors/wavetrend/drivers/sd01-l-v2/webpack.config.js @@ -6,7 +6,7 @@ module.exports = { entry: './src/index.js', output: { filename: 'index.js', - path: path.resolve(__dirname, 'dist'), + path: path.resolve(__dirname, '.'), library: { type: 'commonjs' } diff --git a/vendors/wavetrend/models/sd01-l-v2/model.yaml b/vendors/wavetrend/models/sd01-l-v2/model.yaml index d7d797671..62c7c5d25 100644 --- a/vendors/wavetrend/models/sd01-l-v2/model.yaml +++ b/vendors/wavetrend/models/sd01-l-v2/model.yaml @@ -9,8 +9,7 @@ logo: logo.png # lorawanDeviceProfileID: as defined by LoRa Alliance in https://lora-alliance.org/wp-content/uploads/2020/10/LoRa_Alliance_Vendor_ID_for_QR_Code_02142022.pdf. # The lorawanDeviceProfileID consists of 8 upper-case hexadecimal characters, 4 characters for VendorID + 4 characters for VendorProfileID. Please consider using single (') or double (") quotation. deviceProfileIds: - - id: wavetrend_EU868_1.1_classA - lorawanDeviceProfileID: '00010001' + - id: wavetrnd_RFGroup1_1.1_classA # You may optionally customize any of the following settings to override the generic value set in LoRaWAN device profiles associated with your model. Leave empty if you want to keep the Device Profile settings. # Maximum device TX Conducted output power in dBm. @@ -42,9 +41,7 @@ specificationURL: userGuideURL: # : Available sensors following Actility ontology: https://github.com/actility/device-catalog/blob/main/template/sample-vendor/drivers/ONTOLOGY.md sensors: - - temp1:Cel - - temp2:Cel - - temp3:Cel + - temperature:Cel # Driver examples # A list of examples description that are compatible with this model examples: diff --git a/vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml b/vendors/wavetrend/profiles/wavetrend_RFGroup1_1.1_classA.yaml similarity index 80% rename from vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml rename to vendors/wavetrend/profiles/wavetrend_RFGroup1_1.1_classA.yaml index f7ae18410..4ce458ba9 100644 --- a/vendors/wavetrend/profiles/wavetrend_EU868_1.1_classA.yaml +++ b/vendors/wavetrend/profiles/wavetrend_RFGroup1_1.1_classA.yaml @@ -8,7 +8,7 @@ # RFGroup4: as923 # Please do not change the existing IDs (Some may follow the old format) # The name of the profile .yaml file should be the same as the following ID -id: wavetrnd_EU868_1.1_classA +id: wavetrnd_RFGroup1_1.1_classA # LoRaWAN class of the Device: Possible values: [ A, B, C ] (Should not have several values) # 'A': Class A (Bi-directional end-devices with downlink listening only after uplink transmission) # 'B': Class B (Bi-directional end-devices with downlink listening on predefined synchronized pingslots) @@ -36,13 +36,13 @@ mac: # The device Tx Power Capabilities here will not be taken into consideration if it is overwritten in the model.yaml devicesTxPowerCapabilities: # Minimum device TX Conducted output power in dBm. - minTxPower: 2 # TODO: check if this is correct + minTxPower: 2 # Maximum device TX Conducted output power in dBm. - maxTxPower: 18 # TODO: check if this is correct + maxTxPower: 18 # Minimum device TX Radiated output power in dBm. - minTxEIRP: 2 # TODO: check if this is correct + minTxEIRP: 2 # Maximum device TX Radiated output power in dBm. - maxTxEIRP: 18 # TODO: check if this is correct + maxTxEIRP: 18 uplinkFrameRepetition: # Maximum number of transmissions per uplink frame, supported by the device. @@ -77,20 +77,21 @@ bootSettings: # Which MAC commands are supported by your device and which are not? Leave it as the template if your device supports all the MAC commands specified for your regional # profile. Put 'true' only if a command is supported. supportedMACCommands: - linkADRReqAns: true # TODO: check if this is correct - devStatusReqAns: true # TODO: check if this is correct - joinRequestAccept: true # TODO: check if this is correct - dutyCycleReqAns: true # TODO: check if this is correct - linkCheckReqAns: true # TODO: check if this is correct - rxParamSetupReqAns: true # TODO: check if this is correct - rxTimingSetupReqAns: true # TODO: check if this is correct - newChannelReqAns: true # TODO: check if this is correct - dlChannelReqAns: true # TODO: check if this is correct - txParamSetupReqAns: true # TODO: check if this is correct - pingSlotChannelReqAns: false # TODO: check if this is correct - pingSlotInfoReqAns: true # TODO: check if this is correct - deviceTimeReqAns: true # TODO: check if this is correct - beaconFreqReqAns: false # TODO: check if this is correct + linkADRReqAns: true + devStatusReqAns: true + joinRequestAccept: true + dutyCycleReqAns: true + linkCheckReqAns: true + rxParamSetupReqAns: true + rxTimingSetupReqAns: true + newChannelReqAns: true + dlChannelReqAns: true + txParamSetupReqAns: true + pingSlotChannelReqAns: false + pingSlotInfoReqAns: true + deviceTimeReqAns: true + beaconFreqReqAns: false + extendedNotifyNewEndDeviceReq: false # Does your device support [Technical Recommendation for LoRaWAN L2 1.0.x Join Security] recommending implemeting the DevNonce as a counter for # OTAA devices? See https://lora-alliance.org/resource_hub/technical-recommendations-for-preventing-state-synchronization-issues-around-lorawan-1-0-x-join-procedure/