diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index c255440..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,29 +0,0 @@ -// For format details, see -// https://aka.ms/devcontainer.json. -// For config options, see: -// https://github.com/devcontainers/templates/tree/main/src/typescript-node -{ - "name": "studio-dev", - "image": "mcr.microsoft.com/devcontainers/typescript-node:1-18-bullseye", - "postCreateCommand": "npm install", - "customizations": { - "vscode": { - "extensions": ["ms-vscode-remote.remote-containers", "ms-vscode.vscode-typescript-next", "esbenp.prettier-vscode", "Orta.vscode-jest"] - } - }, - "portsAttributes": { - "80": { - "label": "Application", - "onAutoForward": "openBrowserOnce" - }, - "3000": { - "label": "Application", - "onAutoForward": "openBrowserOnce" - }, - "6006": { - "label": "Storybook", - "onAutoForward": "openBrowserOnce" - } - }, - "forwardPorts": [80, 3000, 6006] -} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..47a96d0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +# https://bun.sh/guides/ecosystem/docker +# docker build -t sqlitcloud-gateway . +# docker run -p 8090:8090 -p 4000:4000 --name sqlitecloud-gateway sqlitecloud-gateway + +# use the official Bun image +# see all versions at https://hub.docker.com/r/oven/bun/tags +FROM oven/bun:1 as base +WORKDIR /usr/src/app + +# install dependencies into temp directory +# this will cache them and speed up future builds +FROM base AS install +RUN mkdir -p /temp/dev +COPY package.json bun.lockb /temp/dev/ +RUN cd /temp/dev && bun install --frozen-lockfile + +# install with --production (exclude devDependencies) +RUN mkdir -p /temp/prod +COPY package.json bun.lockb /temp/prod/ +RUN cd /temp/prod && bun install --frozen-lockfile --production + +# copy node_modules from temp directory +# then copy all (non-ignored) project files into the image +FROM base AS prerelease +COPY --from=install /temp/dev/node_modules node_modules +COPY . . + +# [optional] tests & build +ENV NODE_ENV=production +#RUN bun test +#RUN bun run build +RUN bun build ./src/gateway/gateway.ts --compile --outfile ./sqlitecloud-gateway.out + +# copy production dependencies and source code into final image +FROM base AS release +COPY --from=install /temp/prod/node_modules node_modules +COPY --from=prerelease /usr/src/app/src ./src +COPY --from=prerelease /usr/src/app/public ./public +COPY --from=prerelease /usr/src/app/package.json . +COPY --from=prerelease /usr/src/app/sqlitecloud-gateway.out . + +# run the app +USER bun + +EXPOSE 4000/tcp +EXPOSE 8090/tcp + +#ENTRYPOINT [ "bun", "run", "./src/gateway/gateway.ts" ] +ENTRYPOINT [ "./sqlitecloud-gateway.out" ] diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..6b88db6 Binary files /dev/null and b/bun.lockb differ diff --git a/package-lock.json b/package-lock.json index 187086e..d49938a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,30 @@ { - "name": "sqlitecloud-js", - "version": "0.0.33", + "name": "@sqlitecloud/drivers", + "version": "0.0.50", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "sqlitecloud-js", - "version": "0.0.33", + "name": "@sqlitecloud/drivers", + "version": "0.0.50", "license": "MIT", "dependencies": { "eventemitter3": "^5.0.1", + "express": "^4.18.2", "lz4js": "^0.2.0", + "socket.io": "^4.7.4", "socket.io-client": "^4.7.4" }, "devDependencies": { + "@types/bun": "^1.0.5", + "@types/express": "^4.17.21", "@types/jest": "^29.5.11", "@types/lz4": "^0.6.4", "@types/node": "^12.20.55", "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", "dotenv": "^16.4.1", + "dotenv-cli": "^7.3.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.10.0", "eslint-plugin-node": "^11.1.0", @@ -1553,6 +1558,47 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bun": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.0.5.tgz", + "integrity": "sha512-c14fs5QLLanldcZpX/GjIEKeo++NDzOlixUZ7IUWzN7AoBTisYyWxaxdXNhpAP5I1mPcd92Zagq8sdgTnUXWjg==", + "dev": true, + "dependencies": { + "bun-types": "1.0.26" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.56.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", @@ -1579,6 +1625,30 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -1588,6 +1658,12 @@ "@types/node": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, "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", @@ -1637,18 +1713,65 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, "node_modules/@types/node": { "version": "12.20.55", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", "dev": true }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, "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 }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.31", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", @@ -2029,6 +2152,18 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -2236,6 +2371,11 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2376,6 +2516,61 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2457,6 +2652,33 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bun-types": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.0.26.tgz", + "integrity": "sha512-VcSj+SCaWIcMb0uSGIAtr8P92zq9q+unavcQmx27fk6HulCthXHBVrdGuXxAZbFtv7bHVjizRzR2mk9r/U8Nkg==", + "dev": true, + "dependencies": { + "@types/node": "~20.11.3", + "@types/ws": "~8.5.10" + } + }, + "node_modules/bun-types/node_modules/@types/node": { + "version": "20.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", + "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cacache": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", @@ -2507,6 +2729,24 @@ "dev": true, "optional": true }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2760,12 +3000,56 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, "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 }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -2852,12 +3136,46 @@ "node": ">=0.10.0" } }, + "node_modules/define-data-property": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.3.tgz", + "integrity": "sha512-h3GBouC+RPtNX2N0hHVLo2ZwPYurq8mLmXpOLTsw71gr7lHt5VaI4vVkDUNOfiWmm48JEXe3VM7PmLX45AMmmg==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/detect-libc": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", @@ -2930,6 +3248,35 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, + "node_modules/dotenv-cli": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.3.0.tgz", + "integrity": "sha512-314CA4TyK34YEJ6ntBf80eUY+t1XaFLyem1k9P0sX1gn30qThZ5qZr/ZwE318gEnzyYP9yj9HJk6SqwE0upkfw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, "node_modules/electron-to-chromium": { "version": "1.4.578", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.578.tgz", @@ -2948,6 +3295,14 @@ "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -2958,6 +3313,26 @@ "iconv-lite": "^0.6.2" } }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, "node_modules/engine.io-client": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", @@ -2978,6 +3353,14 @@ "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -3042,6 +3425,25 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", @@ -3057,6 +3459,11 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3424,6 +3831,14 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -3486,6 +3901,60 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3577,6 +4046,36 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -3619,6 +4118,22 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -3655,7 +4170,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3733,6 +4247,24 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -3827,6 +4359,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3863,6 +4406,39 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -3873,7 +4449,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -3894,6 +4469,21 @@ "dev": true, "optional": true }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -4037,8 +4627,7 @@ "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 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/interpret": { "version": "3.1.1", @@ -4056,6 +4645,14 @@ "dev": true, "optional": true }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5141,6 +5738,19 @@ "node": ">= 12" } }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5156,6 +5766,14 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -5169,11 +5787,21 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "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, "engines": { "node": ">= 0.6" } @@ -5182,7 +5810,6 @@ "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, "dependencies": { "mime-db": "1.52.0" }, @@ -5354,8 +5981,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "optional": true, "engines": { "node": ">= 0.6" } @@ -5563,11 +6188,29 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5706,6 +6349,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5739,6 +6390,11 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5892,6 +6548,18 @@ "node": ">= 6" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5917,6 +6585,20 @@ } ] }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5946,6 +6628,39 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -6126,7 +6841,6 @@ "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", @@ -6145,9 +6859,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/schema-utils": { "version": "3.3.0", @@ -6200,6 +6912,47 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/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==" + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -6209,12 +6962,47 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -6260,6 +7048,23 @@ "vscode-textmate": "^8.0.0" } }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -6292,6 +7097,31 @@ "npm": ">= 3.0.0" } }, + "node_modules/socket.io": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, "node_modules/socket.io-client": { "version": "4.7.4", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", @@ -6430,6 +7260,14 @@ "node": ">=8" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6793,6 +7631,14 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6951,6 +7797,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typedoc": { "version": "0.25.3", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.3.tgz", @@ -7034,6 +7892,12 @@ "node": ">=0.8.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -7054,6 +7918,14 @@ "imurmurhash": "^0.1.4" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -7099,6 +7971,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/v8-compile-cache": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", @@ -7125,6 +8005,14 @@ "node": ">=10.12.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vscode-oniguruma": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", diff --git a/package.json b/package.json index 5ca460c..f058267 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sqlitecloud/drivers", - "version": "0.0.41", + "version": "0.0.50", "description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -9,12 +9,16 @@ ], "scripts": { "test": "jest --coverage", - "build": "rm -rf ./lib/ && tsc --project tsconfig.build.json && npx webpack", + "build": "rm -rf ./lib/ && tsc --project tsconfig.build.json && npx webpack && cp ./lib/sqlitecloud.drivers.js ./public/ && cp ./lib/sqlitecloud.drivers.dev.js ./public/", "publish": "npm run build && npm publish --access public", "prettier": "prettier --write 'src/**/*'", "lint": "eslint ./src/ --fix && tsc --noEmit", "typedoc": "rm -rf ./docs/ && typedoc --out docs && typedoc --plugin typedoc-plugin-markdown --out docs/markdown", - "npmgui": "npx npm-gui@latest" + "npmgui": "npx npm-gui@latest", + "gateway-dev": "bun --watch ./src/gateway/gateway.ts", + "gateway-start": "bun --smol run ./src/gateway/gateway.ts", + "gateway-test": "bun test ./src/gateway/connection-bun.test.ts --watch --coverage", + "gateway-build": "./scripts/gateway-build.sh" }, "repository": { "type": "git", @@ -43,16 +47,21 @@ "homepage": "https://github.com/sqlitecloud/sqlitecloud-js#readme", "dependencies": { "eventemitter3": "^5.0.1", + "express": "^4.18.2", "lz4js": "^0.2.0", + "socket.io": "^4.7.4", "socket.io-client": "^4.7.4" }, "devDependencies": { + "@types/bun": "^1.0.5", + "@types/express": "^4.17.21", "@types/jest": "^29.5.11", "@types/lz4": "^0.6.4", "@types/node": "^12.20.55", "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", "dotenv": "^16.4.1", + "dotenv-cli": "^7.3.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.10.0", "eslint-plugin-node": "^11.1.0", diff --git a/public/drivers.html b/public/drivers.html new file mode 100644 index 0000000..11c9cb8 --- /dev/null +++ b/public/drivers.html @@ -0,0 +1,94 @@ + + + + + Driver | SQLite Cloud + + + + + +

SQLite Cloud Driver

+
+ npm sqlitecloud +
+ + +
+
connectionString:
+ +
sql:
+ +
+ + +

Results:

+ + + + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..2e92628 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..db11e72 --- /dev/null +++ b/public/index.html @@ -0,0 +1,109 @@ + + + + + Gateway | SQLite Cloud + + + + +

SQLite Cloud Gateway

+

Disconnected

+ + +
+
connectionString:
+ +
sql:
+ +
+ + +

Messages:

+ + + + + diff --git a/public/sqlitecloud.drivers.dev.js b/public/sqlitecloud.drivers.dev.js new file mode 100644 index 0000000..fde9db9 --- /dev/null +++ b/public/sqlitecloud.drivers.dev.js @@ -0,0 +1,629 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["sqlitecloud"] = factory(); + else + root["sqlitecloud"] = factory(); +})(this, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ "./lib/drivers/connection-tls.js": +/*!***************************************!*\ + !*** ./lib/drivers/connection-tls.js ***! + \***************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\n/**\n * connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol\n */\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.SQLiteCloudTlsConnection = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\nconst connection_1 = __webpack_require__(/*! ./connection */ \"./lib/drivers/connection.js\");\nconst protocol_1 = __webpack_require__(/*! ./protocol */ \"./lib/drivers/protocol.js\");\nconst utilities_1 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\nconst protocol_2 = __webpack_require__(/*! ./protocol */ \"./lib/drivers/protocol.js\");\nconst net_1 = __importDefault(__webpack_require__(/*! net */ \"?83b6\"));\nconst tls_1 = __importDefault(__webpack_require__(/*! tls */ \"?4235\"));\n/**\n * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.\n * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.\n * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.\n * A connection socket is established when the connection is created and closed when the connection is closed.\n * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,\n * it cannot be reopened and you must create a new connection.\n */\nclass SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {\n /** True if connection is open */\n get connected() {\n return !!this.socket;\n }\n /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */\n connectTransport(config, callback) {\n // connection established while we were waiting in line?\n console.assert(!this.connected, 'Connection already established');\n // clear all listeners and call done in the operations queue\n const finish = error => {\n if (this.socket) {\n this.socket.removeAllListeners('data');\n this.socket.removeAllListeners('error');\n this.socket.removeAllListeners('close');\n if (error) {\n this.close();\n }\n }\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n };\n this.config = config;\n const initializationCommands = (0, utilities_1.getInitializationCommands)(config);\n if (config.insecure) {\n // connect to plain socket, without encryption, only if insecure parameter specified\n // this option is mainly for testing purposes and is not available on production nodes\n // which would need to connect using tls and proper certificates as per code below\n const connectionOptions = {\n host: config.host,\n port: config.port\n };\n this.socket = net_1.default.connect(connectionOptions, () => {\n console.warn(`TlsConnection.connectTransport - connected to ${config.host}:${config.port} using insecure protocol`);\n // send initialization commands\n console.assert(this.socket, 'Connection already closed');\n this.transportCommands(initializationCommands, error => {\n if (error && this.socket) {\n this.close();\n }\n if (callback) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n callback = undefined;\n }\n finish(error);\n });\n });\n }\n else {\n // connect to tls socket, initialize connection, setup event handlers\n this.socket = tls_1.default.connect(this.config.port, this.config.host, this.config.tlsOptions, () => {\n const tlsSocket = this.socket;\n if (!(tlsSocket === null || tlsSocket === void 0 ? void 0 : tlsSocket.authorized)) {\n const anonimizedError = (0, utilities_1.anonimizeError)(tlsSocket.authorizationError);\n console.error('Connection was not authorized', anonimizedError);\n this.close();\n finish(new types_1.SQLiteCloudError('Connection was not authorized', { cause: anonimizedError }));\n }\n else {\n // the connection was closed before it was even opened,\n // eg. client closed the connection before the server accepted it\n if (this.socket === null) {\n finish(new types_1.SQLiteCloudError('Connection was closed before it was done opening'));\n return;\n }\n // send initialization commands\n console.assert(this.socket, 'Connection already closed');\n this.transportCommands(initializationCommands, error => {\n if (error && this.socket) {\n this.close();\n }\n if (callback) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n callback = undefined;\n }\n finish(error);\n });\n }\n });\n }\n this.socket.on('close', () => {\n this.socket = null;\n finish(new types_1.SQLiteCloudError('Connection was closed'));\n });\n this.socket.once('error', (error) => {\n console.error('Connection error', error);\n finish(new types_1.SQLiteCloudError('Connection error', { cause: error }));\n });\n return this;\n }\n /** Will send a command immediately (no queueing), return the rowset/result or throw an error */\n transportCommands(commands, callback) {\n var _a, _b, _c;\n // connection needs to be established?\n if (!this.socket) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));\n return this;\n }\n // compose commands following SCPC protocol\n commands = (0, protocol_1.formatCommand)(commands);\n let buffer = Buffer.alloc(0);\n const rowsetChunks = [];\n // const startedOn = new Date()\n // define what to do if an answer does not arrive within the set timeout\n let socketTimeout;\n // clear all listeners and call done in the operations queue\n const finish = (error, result) => {\n clearTimeout(socketTimeout);\n if (this.socket) {\n this.socket.removeAllListeners('data');\n this.socket.removeAllListeners('error');\n this.socket.removeAllListeners('close');\n }\n if (callback) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);\n callback = undefined;\n }\n };\n // define the Promise that waits for the server response\n const readData = (data) => {\n var _a, _b;\n try {\n // on first ondata event, dataType is read from data, on subsequent ondata event, is read from buffer that is the concatanations of data received on each ondata event\n let dataType = buffer.length === 0 ? data.subarray(0, 1).toString() : buffer.subarray(0, 1).toString('utf8');\n buffer = Buffer.concat([buffer, data]);\n const commandLength = (0, protocol_1.hasCommandLength)(dataType);\n if (commandLength) {\n const commandLength = (0, protocol_1.parseCommandLength)(buffer);\n const hasReceivedEntireCommand = buffer.length - buffer.indexOf(' ') - 1 >= commandLength ? true : false;\n if (hasReceivedEntireCommand) {\n if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.verbose) {\n let bufferString = buffer.toString('utf8');\n if (bufferString.length > 1000) {\n bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);\n }\n // const elapsedMs = new Date().getTime() - startedOn.getTime()\n // console.debug(`Receive: ${bufferString} - ${elapsedMs}ms`)\n }\n // need to decompress this buffer before decoding?\n if (dataType === protocol_1.CMD_COMPRESSED) {\n ;\n ({ buffer, dataType } = (0, protocol_1.decompressBuffer)(buffer));\n }\n if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {\n (_b = this.socket) === null || _b === void 0 ? void 0 : _b.off('data', readData);\n const { data } = (0, protocol_1.popData)(buffer);\n finish(null, data);\n }\n else {\n // check if rowset received the ending chunk\n if ((0, protocol_1.bufferEndsWith)(buffer, protocol_1.ROWSET_CHUNKS_END)) {\n rowsetChunks.push(buffer);\n const parsedData = (0, protocol_2.parseRowsetChunks)(rowsetChunks);\n finish === null || finish === void 0 ? void 0 : finish.call(this, null, parsedData);\n }\n else {\n // no ending string? ask server for another chunk\n rowsetChunks.push(buffer);\n buffer = Buffer.alloc(0);\n }\n }\n }\n }\n else {\n // command with no explicit len so make sure that the final character is a space\n const lastChar = buffer.subarray(buffer.length - 1, buffer.length).toString('utf8');\n if (lastChar == ' ') {\n const { data } = (0, protocol_1.popData)(buffer);\n finish(null, data);\n }\n }\n }\n catch (error) {\n console.assert(error instanceof Error);\n if (error instanceof Error) {\n finish(error);\n }\n }\n };\n (_a = this.socket) === null || _a === void 0 ? void 0 : _a.once('close', () => {\n finish(new types_1.SQLiteCloudError('Connection was closed', { cause: (0, utilities_1.anonimizeCommand)(commands) }));\n });\n (_b = this.socket) === null || _b === void 0 ? void 0 : _b.write(commands, 'utf8', () => {\n var _a, _b;\n // @ts-ignore\n socketTimeout = setTimeout(() => {\n const timeoutError = new types_1.SQLiteCloudError('Request timed out', { cause: (0, utilities_1.anonimizeCommand)(commands) });\n // console.debug(`Request timed out, config.timeout is ${this.config?.timeout as number}ms`, timeoutError)\n finish(timeoutError);\n }, (_a = this.config) === null || _a === void 0 ? void 0 : _a.timeout);\n (_b = this.socket) === null || _b === void 0 ? void 0 : _b.on('data', readData);\n });\n (_c = this.socket) === null || _c === void 0 ? void 0 : _c.once('error', (error) => {\n console.error('Socket error', error);\n this.close();\n finish(new types_1.SQLiteCloudError('Socket error', { cause: (0, utilities_1.anonimizeError)(error) }));\n });\n return this;\n }\n /** Disconnect from server, release connection. */\n close() {\n console.assert(this.socket !== null, 'TlsConnection.close - connection already closed');\n this.operations.clear();\n if (this.socket) {\n this.socket.destroy();\n this.socket = null;\n }\n this.socket = undefined;\n return this;\n }\n}\nexports.SQLiteCloudTlsConnection = SQLiteCloudTlsConnection;\nexports[\"default\"] = SQLiteCloudTlsConnection;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/connection-tls.js?"); + +/***/ }), + +/***/ "./lib/drivers/connection-ws.js": +/*!**************************************!*\ + !*** ./lib/drivers/connection-ws.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n/**\n * transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.SQLiteCloudWebsocketConnection = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\nconst rowset_1 = __webpack_require__(/*! ./rowset */ \"./lib/drivers/rowset.js\");\nconst connection_1 = __webpack_require__(/*! ./connection */ \"./lib/drivers/connection.js\");\nconst socket_io_client_1 = __webpack_require__(/*! socket.io-client */ \"./node_modules/socket.io-client/build/cjs/index.js\");\n/**\n * Implementation of TransportConnection that connects to the database indirectly\n * via SQLite Cloud Gateway, a socket.io based deamon that responds to sql query\n * requests by returning results and rowsets in json format. The gateway handles\n * connect, disconnect, retries, order of operations, timeouts, etc.\n */\nclass SQLiteCloudWebsocketConnection extends connection_1.SQLiteCloudConnection {\n /** True if connection is open */\n get connected() {\n return !!this.socket;\n }\n /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */\n connectTransport(config, callback) {\n var _a;\n try {\n // connection established while we were waiting in line?\n console.assert(!this.connected, 'Connection already established');\n if (!this.socket) {\n this.config = config;\n const connectionString = this.config.connectionString;\n const gatewayUrl = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.gatewayUrl) || `ws://${this.config.host}:4000`;\n this.socket = (0, socket_io_client_1.io)(gatewayUrl, { auth: { token: connectionString } });\n }\n callback === null || callback === void 0 ? void 0 : callback.call(this, null);\n }\n catch (error) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n return this;\n }\n /** Will send a command immediately (no queueing), return the rowset/result or throw an error */\n transportCommands(commands, callback) {\n // connection needs to be established?\n if (!this.socket) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));\n return this;\n }\n this.socket.emit('v1/sql', { sql: commands, row: 'array' }, (response) => {\n if (response === null || response === void 0 ? void 0 : response.error) {\n const error = new types_1.SQLiteCloudError(response.error.detail, Object.assign({}, response.error));\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n else {\n const { data, metadata } = response;\n if (data && metadata) {\n if (metadata.numberOfRows !== undefined && metadata.numberOfColumns !== undefined && metadata.columns !== undefined) {\n console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.transportCommands - data is not an array');\n // we can recreate a SQLiteCloudRowset from the response which we know to be an array of arrays\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n const rowset = new rowset_1.SQLiteCloudRowset(metadata, data.flat());\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, rowset);\n return;\n }\n }\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, response === null || response === void 0 ? void 0 : response.data);\n }\n });\n return this;\n }\n /** Disconnect socket.io from server */\n close() {\n var _a;\n console.assert(this.socket !== null, 'SQLiteCloudWebsocketConnection.close - connection already closed');\n if (this.socket) {\n (_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();\n this.socket = undefined;\n }\n this.operations.clear();\n this.socket = undefined;\n return this;\n }\n}\nexports.SQLiteCloudWebsocketConnection = SQLiteCloudWebsocketConnection;\nexports[\"default\"] = SQLiteCloudWebsocketConnection;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/connection-ws.js?"); + +/***/ }), + +/***/ "./lib/drivers/connection.js": +/*!***********************************!*\ + !*** ./lib/drivers/connection.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n/**\n * connection.ts - base abstract class for sqlitecloud server connections\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.SQLiteCloudConnection = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\nconst utilities_1 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\nconst queue_1 = __webpack_require__(/*! ./queue */ \"./lib/drivers/queue.js\");\nconst utilities_2 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\n/**\n * Base class for SQLiteCloudConnection handles basics and defines methods.\n * Actual connection management and communication with the server in concrete classes.\n */\nclass SQLiteCloudConnection {\n /** Parse and validate provided connectionString or configuration */\n constructor(config, callback) {\n /** Operations are serialized by waiting an any pending promises */\n this.operations = new queue_1.OperationsQueue();\n if (typeof config === 'string') {\n this.config = (0, utilities_1.validateConfiguration)({ connectionString: config });\n }\n else {\n this.config = (0, utilities_1.validateConfiguration)(config);\n }\n // connect transport layer to server\n this.connect(callback);\n }\n //\n // internal methods (some are implemented in concrete classes using different transport layers)\n //\n /** Connect will establish a tls or websocket transport to the server based on configuration and environment */\n connect(callback) {\n this.operations.enqueue(done => {\n this.connectTransport(this.config, error => {\n if (error) {\n console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${error.toString()}`, error);\n this.close();\n }\n callback === null || callback === void 0 ? void 0 : callback.call(this, error || null);\n done(error);\n });\n });\n return this;\n }\n /** Will log to console if verbose mode is enabled */\n log(message, ...optionalParams) {\n if (this.config.verbose) {\n message = (0, utilities_2.anonimizeCommand)(message);\n console.log(`${new Date().toISOString()} ${this.config.clientId}: ${message}`, ...optionalParams);\n }\n }\n /** Enable verbose logging for debug purposes */\n verbose() {\n this.config.verbose = true;\n }\n /** Will enquee a command to be executed and callback with the resulting rowset/result/error */\n sendCommands(commands, callback) {\n this.operations.enqueue(done => {\n if (!this.connected) {\n const error = new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' });\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n done(error);\n }\n this.transportCommands(commands, (error, result) => {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);\n done(error);\n });\n });\n return this;\n }\n}\nexports.SQLiteCloudConnection = SQLiteCloudConnection;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/connection.js?"); + +/***/ }), + +/***/ "./lib/drivers/database.js": +/*!*********************************!*\ + !*** ./lib/drivers/database.js ***! + \*********************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\n//\n// database.ts - database driver api, implements and extends sqlite3\n//\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Database = void 0;\nconst rowset_1 = __webpack_require__(/*! ./rowset */ \"./lib/drivers/rowset.js\");\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\nconst utilities_1 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\nconst statement_1 = __webpack_require__(/*! ./statement */ \"./lib/drivers/statement.js\");\nconst eventemitter3_1 = __importDefault(__webpack_require__(/*! eventemitter3 */ \"./node_modules/eventemitter3/index.js\"));\nconst utilities_2 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\n// Uses eventemitter3 instead of node events for browser compatibility\n// https://github.com/primus/eventemitter3\n/**\n * Creating a Database object automatically opens a connection to the SQLite database.\n * When the connection is established the Database object emits an open event and calls\n * the optional provided callback. If the connection cannot be established an error event\n * will be emitted and the optional callback is called with the error information.\n */\nclass Database extends eventemitter3_1.default {\n constructor(config, mode, callback) {\n super();\n /** Database connections */\n this.connections = [];\n this.config = typeof config === 'string' ? { connectionString: config } : config;\n // mode is optional and so is callback\n // https://github.com/TryGhost/node-sqlite3/wiki/API#new-sqlite3databasefilename--mode--callback\n if (typeof mode === 'function') {\n callback = mode;\n mode = undefined;\n }\n // mode is ignored for now\n // opens first connection to the database automatically\n this.getConnection((error, _connection) => {\n if (callback) {\n callback.call(this, error);\n }\n });\n }\n //\n // private methods\n //\n /** Returns first available connection from connection pool */\n getConnection(callback) {\n var _a, _b, _c;\n // TODO sqlitecloud-js / implement database connection pool #10\n if (((_a = this.connections) === null || _a === void 0 ? void 0 : _a.length) > 0) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);\n }\n else {\n // connect using websocket if tls is not supported or if explicitly requested\n const useWebsocket = utilities_2.isBrowser || ((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket) || ((_c = this.config) === null || _c === void 0 ? void 0 : _c.gatewayUrl);\n if (useWebsocket) {\n // socket.io transport works in both node.js and browser environments and connects via SQLite Cloud Gateway\n Promise.resolve().then(() => __importStar(__webpack_require__(/*! ./connection-ws */ \"./lib/drivers/connection-ws.js\"))).then(module => {\n this.connections.push(new module.default(this.config, error => {\n if (error) {\n this.handleError(this.connections[0], error, callback);\n }\n else {\n console.assert;\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);\n this.emitEvent('open');\n }\n }));\n })\n .catch(error => {\n this.handleError(null, error, callback);\n });\n }\n else {\n // tls sockets work only in node.js environments\n Promise.resolve().then(() => __importStar(__webpack_require__(/*! ./connection-tls */ \"./lib/drivers/connection-tls.js\"))).then(module => {\n this.connections.push(new module.default(this.config, error => {\n if (error) {\n this.handleError(this.connections[0], error, callback);\n }\n else {\n console.assert;\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);\n this.emitEvent('open');\n }\n }));\n })\n .catch(error => {\n this.handleError(null, error, callback);\n });\n }\n }\n }\n /** Handles an error by closing the connection, calling the callback and/or emitting an error event */\n handleError(connection, error, callback) {\n // an errored connection is thrown out\n if (connection) {\n this.connections = this.connections.filter(c => c !== connection);\n connection.close();\n }\n if (callback) {\n callback.call(this, error);\n }\n else {\n this.emitEvent('error', error);\n }\n }\n /**\n * Some queries like inserts or updates processed via run or exec may generate\n * an empty result (eg. no data was selected), but still have some metadata.\n * For example the server may pass the id of the last row that was modified.\n * In this case the callback results should be empty but the context may contain\n * additional information like lastID, etc.\n * @see https://github.com/TryGhost/node-sqlite3/wiki/API#runsql--param---callback\n * @param results Results received from the server\n * @returns A context object if one makes sense, otherwise undefined\n */\n processContext(results) {\n if (results) {\n if (Array.isArray(results) && results.length > 0) {\n switch (results[0]) {\n case types_1.SQLiteCloudArrayType.ARRAY_TYPE_SQLITE_EXEC:\n return {\n lastID: results[2],\n changes: results[3],\n totalChanges: results[4],\n finalized: results[5] // FINALIZED\n };\n }\n }\n }\n return undefined;\n }\n /** Emits given event with optional arguments on the next tick so callbacks can complete first */\n emitEvent(event, ...args) {\n setTimeout(() => {\n this.emit(event, ...args);\n }, 0);\n }\n //\n // public methods\n //\n /**\n * Returns the configuration with which this database was opened.\n * The configuration is readonly and cannot be changed as there may\n * be multiple connections using the same configuration.\n * @returns {SQLiteCloudConfig} A configuration object\n */\n getConfiguration() {\n return JSON.parse(JSON.stringify(this.config));\n }\n /** Enable verbose mode */\n verbose() {\n this.config.verbose = true;\n for (const connection of this.connections) {\n connection.verbose();\n }\n return this;\n }\n /** Set a configuration option for the database */\n configure(_option, _value) {\n // https://github.com/TryGhost/node-sqlite3/wiki/API#configureoption-value\n return this;\n }\n run(sql, ...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n const preparedSql = (args === null || args === void 0 ? void 0 : args.length) > 0 ? (0, utilities_1.prepareSql)(sql, ...args) : sql;\n this.getConnection((error, connection) => {\n if (error || !connection) {\n this.handleError(null, error, callback);\n }\n else {\n connection.sendCommands(preparedSql, (error, results) => {\n if (error) {\n this.handleError(connection, error, callback);\n }\n else {\n // context may include id of last row inserted, total changes, etc...\n const context = this.processContext(results);\n callback === null || callback === void 0 ? void 0 : callback.call(context || this, null, context ? undefined : results);\n }\n });\n }\n });\n return this;\n }\n get(sql, ...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n const preparedSql = (args === null || args === void 0 ? void 0 : args.length) > 0 ? (0, utilities_1.prepareSql)(sql, ...args) : sql;\n this.getConnection((error, connection) => {\n if (error || !connection) {\n this.handleError(null, error, callback);\n }\n else {\n connection.sendCommands(preparedSql, (error, results) => {\n if (error) {\n this.handleError(connection, error, callback);\n }\n else {\n if (results && results instanceof rowset_1.SQLiteCloudRowset && results.length > 0) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, results[0]);\n }\n else {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null);\n }\n }\n });\n }\n });\n return this;\n }\n all(sql, ...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n const preparedSql = (args === null || args === void 0 ? void 0 : args.length) > 0 ? (0, utilities_1.prepareSql)(sql, ...args) : sql;\n this.getConnection((error, connection) => {\n if (error || !connection) {\n this.handleError(null, error, callback);\n }\n else {\n connection.sendCommands(preparedSql, (error, results) => {\n if (error) {\n this.handleError(connection, error, callback);\n }\n else {\n if (results && results instanceof rowset_1.SQLiteCloudRowset) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null, results);\n }\n else {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null);\n }\n }\n });\n }\n });\n return this;\n }\n each(sql, ...params) {\n // extract optional parameters and one or two callbacks\n const { args, callback, complete } = (0, utilities_1.popCallback)(params);\n const preparedSql = (args === null || args === void 0 ? void 0 : args.length) > 0 ? (0, utilities_1.prepareSql)(sql, ...args) : sql;\n this.getConnection((error, connection) => {\n if (error || !connection) {\n this.handleError(null, error, callback);\n }\n else {\n connection.sendCommands(preparedSql, (error, rowset) => {\n if (error) {\n this.handleError(connection, error, callback);\n }\n else {\n if (rowset && rowset instanceof rowset_1.SQLiteCloudRowset) {\n if (callback) {\n for (const row of rowset) {\n callback.call(this, null, row);\n }\n }\n if (complete) {\n ;\n complete.call(this, null, rowset.numberOfRows);\n }\n }\n else {\n callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Invalid rowset'));\n }\n }\n });\n }\n });\n return this;\n }\n /**\n * Prepares the SQL statement and optionally binds the specified parameters and\n * calls the callback when done. The function returns a Statement object.\n * When preparing was successful, the first and only argument to the callback\n * is null, otherwise it is the error object. When bind parameters are supplied,\n * they are bound to the prepared statement before calling the callback.\n */\n prepare(sql, ...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n return new statement_1.Statement(this, sql, ...args, callback);\n }\n /**\n * Runs all SQL queries in the supplied string. No result rows are retrieved.\n * The function returns the Database object to allow for function chaining.\n * If a query fails, no subsequent statements will be executed (wrap it in a\n * transaction if you want all or none to be executed). When all statements\n * have been executed successfully, or when an error occurs, the callback\n * function is called, with the first parameter being either null or an error\n * object. When no callback is provided and an error occurs, an error event\n * will be emitted on the database object.\n */\n exec(sql, callback) {\n this.getConnection((error, connection) => {\n if (error || !connection) {\n this.handleError(null, error, callback);\n }\n else {\n connection.sendCommands(sql, (error, results) => {\n if (error) {\n this.handleError(connection, error, callback);\n }\n else {\n const context = this.processContext(results);\n callback === null || callback === void 0 ? void 0 : callback.call(context ? context : this, null);\n }\n });\n }\n });\n return this;\n }\n /**\n * If the optional callback is provided, this function will be called when the\n * database was closed successfully or when an error occurred. The first argument\n * is an error object. When it is null, closing succeeded. If no callback is provided\n * and an error occurred, an error event with the error object as the only parameter\n * will be emitted on the database object. If closing succeeded, a close event with no\n * parameters is emitted, regardless of whether a callback was provided or not.\n */\n close(callback) {\n var _a;\n if (((_a = this.connections) === null || _a === void 0 ? void 0 : _a.length) > 0) {\n for (const connection of this.connections) {\n connection.close();\n }\n }\n callback === null || callback === void 0 ? void 0 : callback.call(this, null);\n this.emitEvent('close');\n }\n /**\n * Loads a compiled SQLite extension into the database connection object.\n * @param path Filename of the extension to load.\n * @param callback If provided, this function will be called when the extension\n * was loaded successfully or when an error occurred. The first argument is an\n * error object. When it is null, loading succeeded. If no callback is provided\n * and an error occurred, an error event with the error object as the only parameter\n * will be emitted on the database object.\n */\n loadExtension(_path, callback) {\n // TODO sqlitecloud-js / implement database loadExtension #17\n if (callback) {\n callback.call(this, new Error('Database.loadExtension - Not implemented'));\n }\n else {\n this.emitEvent('error', new Error('Database.loadExtension - Not implemented'));\n }\n return this;\n }\n /**\n * Allows the user to interrupt long-running queries. Wrapper around\n * sqlite3_interrupt and causes other data-fetching functions to be\n * passed an err with code = sqlite3.INTERRUPT. The database must be\n * open to use this function.\n */\n interrupt() {\n // TODO sqlitecloud-js / implement database interrupt #13\n }\n //\n // extended APIs\n //\n /**\n * Sql is a promise based API for executing SQL statements. You can\n * pass a simple string with a SQL statement or a template string\n * using backticks and parameters in ${parameter} format. These parameters\n * will be properly escaped and quoted like when using a prepared statement.\n * @param sql A sql string or a template string in `backticks` format\n * @returns An array of rows in case of selections or an object with\n * metadata in case of insert, update, delete.\n */\n sql(sql, ...values) {\n return __awaiter(this, void 0, void 0, function* () {\n let preparedSql = '';\n // sql is a TemplateStringsArray, the 'raw' property is specific to TemplateStringsArray\n if (Array.isArray(sql) && 'raw' in sql) {\n sql.forEach((string, i) => {\n preparedSql += string + (i < values.length ? '?' : '');\n });\n preparedSql = (0, utilities_1.prepareSql)(preparedSql, ...values);\n }\n else {\n if (typeof sql === 'string') {\n if ((values === null || values === void 0 ? void 0 : values.length) > 0) {\n preparedSql = (0, utilities_1.prepareSql)(sql, ...values);\n }\n else {\n preparedSql = sql;\n }\n }\n else {\n throw new Error('Invalid sql');\n }\n }\n return new Promise((resolve, reject) => {\n this.getConnection((error, connection) => {\n if (error || !connection) {\n reject(error);\n }\n else {\n connection.sendCommands(preparedSql, (error, results) => {\n if (error) {\n reject(error);\n }\n else {\n // metadata for operations like insert, update, delete?\n const context = this.processContext(results);\n resolve(context ? context : results);\n }\n });\n }\n });\n });\n });\n }\n}\nexports.Database = Database;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/database.js?"); + +/***/ }), + +/***/ "./lib/drivers/protocol.js": +/*!*********************************!*\ + !*** ./lib/drivers/protocol.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n//\n// protocol.ts - low level protocol handling for SQLiteCloud transport\n//\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.formatCommand = exports.popData = exports.parseRowsetChunks = exports.bufferEndsWith = exports.bufferStartsWith = exports.parseRowsetHeader = exports.parseArray = exports.parseError = exports.decompressBuffer = exports.parseCommandLength = exports.hasCommandLength = exports.ROWSET_CHUNKS_END = exports.CMD_ARRAY = exports.CMD_COMMAND = exports.CMD_COMPRESSED = exports.CMD_BLOB = exports.CMD_NULL = exports.CMD_JSON = exports.CMD_ROWSET_CHUNK = exports.CMD_ROWSET = exports.CMD_FLOAT = exports.CMD_INT = exports.CMD_ERROR = exports.CMD_ZEROSTRING = exports.CMD_STRING = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\nconst rowset_1 = __webpack_require__(/*! ./rowset */ \"./lib/drivers/rowset.js\");\nconst lz4 = __webpack_require__(/*! lz4js */ \"./node_modules/lz4js/lz4.js\");\n// The server communicates with clients via commands defined in\n// SQLiteCloud Server Protocol (SCSP), see more at:\n// https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md\nexports.CMD_STRING = '+';\nexports.CMD_ZEROSTRING = '!';\nexports.CMD_ERROR = '-';\nexports.CMD_INT = ':';\nexports.CMD_FLOAT = ',';\nexports.CMD_ROWSET = '*';\nexports.CMD_ROWSET_CHUNK = '/';\nexports.CMD_JSON = '#';\nexports.CMD_NULL = '_';\nexports.CMD_BLOB = '$';\nexports.CMD_COMPRESSED = '%';\nexports.CMD_COMMAND = '^';\nexports.CMD_ARRAY = '=';\n// const CMD_RAWJSON = '{'\n// const CMD_PUBSUB = '|'\n// const CMD_RECONNECT = '@'\n// To mark the end of the Rowset, the special string /LEN 0 0 0 is sent (LEN is always 6 in this case)\n// https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk\nexports.ROWSET_CHUNKS_END = '/6 0 0 0 ';\n//\n// utility functions\n//\n/** Analyze first character to check if corresponding data type has LEN */\nfunction hasCommandLength(firstCharacter) {\n return firstCharacter == exports.CMD_INT || firstCharacter == exports.CMD_FLOAT || firstCharacter == exports.CMD_NULL ? false : true;\n}\nexports.hasCommandLength = hasCommandLength;\n/** Analyze a command with explict LEN and extract it */\nfunction parseCommandLength(data) {\n return parseInt(data.subarray(1, data.indexOf(' ')).toString('utf8'));\n}\nexports.parseCommandLength = parseCommandLength;\n/** Receive a compressed buffer, decompress with lz4, return buffer and datatype */\nfunction decompressBuffer(buffer) {\n const spaceIndex = buffer.indexOf(' ');\n buffer = buffer.subarray(spaceIndex + 1);\n // extract compressed size\n const compressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8'));\n buffer = buffer.subarray(buffer.indexOf(' ') + 1);\n // extract decompressed size\n const decompressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8'));\n buffer = buffer.subarray(buffer.indexOf(' ') + 1);\n // extract compressed dataType\n const dataType = buffer.subarray(0, 1).toString('utf8');\n const decompressedBuffer = Buffer.alloc(decompressedSize);\n const compressedBuffer = buffer.subarray(buffer.length - compressedSize);\n // lz4js library is javascript and doesn't have types so we silence the type check\n // eslint-disable-next-line\n const decompressionResult = lz4.decompressBlock(compressedBuffer, decompressedBuffer, 0, compressedSize, 0);\n buffer = Buffer.concat([buffer.subarray(0, buffer.length - compressedSize), decompressedBuffer]);\n if (decompressionResult <= 0 || decompressionResult !== decompressedSize) {\n throw new Error(`lz4 decompression error at offset ${decompressionResult}`);\n }\n return { buffer, dataType };\n}\nexports.decompressBuffer = decompressBuffer;\n/** Parse error message or extended error message */\nfunction parseError(buffer, spaceIndex) {\n const errorBuffer = buffer.subarray(spaceIndex + 1);\n const errorString = errorBuffer.toString('utf8');\n const parts = errorString.split(' ');\n let errorCodeStr = parts.shift() || '0'; // Default errorCode is '0' if not present\n let extErrCodeStr = '0'; // Default extended error code\n let offsetCodeStr = '-1'; // Default offset code\n // Split the errorCode by ':' to check for extended error codes\n const errorCodeParts = errorCodeStr.split(':');\n errorCodeStr = errorCodeParts[0];\n if (errorCodeParts.length > 1) {\n extErrCodeStr = errorCodeParts[1];\n if (errorCodeParts.length > 2) {\n offsetCodeStr = errorCodeParts[2];\n }\n }\n // Rest of the error string is the error message\n const errorMessage = parts.join(' ');\n // Parse error codes to integers safely, defaulting to 0 if NaN\n const errorCode = parseInt(errorCodeStr);\n const extErrCode = parseInt(extErrCodeStr);\n const offsetCode = parseInt(offsetCodeStr);\n // create an Error object and add the custom properties\n throw new types_1.SQLiteCloudError(errorMessage, {\n errorCode: errorCode.toString(),\n externalErrorCode: extErrCode.toString(),\n offsetCode\n });\n}\nexports.parseError = parseError;\n/** Parse an array of items (each of which will be parsed by type separately) */\nfunction parseArray(buffer, spaceIndex) {\n const parsedData = [];\n const array = buffer.subarray(spaceIndex + 1, buffer.length);\n const numberOfItems = parseInt(array.subarray(0, spaceIndex - 2).toString('utf8'));\n let arrayItems = array.subarray(array.indexOf(' ') + 1, array.length);\n for (let i = 0; i < numberOfItems; i++) {\n const { data, fwdBuffer: buffer } = popData(arrayItems);\n parsedData.push(data);\n arrayItems = buffer;\n }\n return parsedData;\n}\nexports.parseArray = parseArray;\n/** Parse header in a rowset or chunk of a chunked rowset */\nfunction parseRowsetHeader(buffer) {\n const index = parseInt(buffer.subarray(0, buffer.indexOf(':') + 1).toString());\n buffer = buffer.subarray(buffer.indexOf(':') + 1);\n // extract rowset header\n const { data, fwdBuffer } = popIntegers(buffer, 3);\n return {\n index,\n metadata: {\n version: data[0],\n numberOfRows: data[1],\n numberOfColumns: data[2],\n columns: []\n },\n fwdBuffer\n };\n}\nexports.parseRowsetHeader = parseRowsetHeader;\n/** Extract column names and, optionally, more metadata out of a rowset's header */\nfunction parseRowsetColumnsMetadata(buffer, metadata) {\n function popForward() {\n const { data, fwdBuffer: fwdBuffer } = popData(buffer); // buffer in parent scope\n buffer = fwdBuffer;\n return data;\n }\n for (let i = 0; i < metadata.numberOfColumns; i++) {\n metadata.columns.push({ name: popForward() });\n }\n // extract additional metadata if rowset has version 2\n if (metadata.version == 2) {\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].type = popForward();\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].database = popForward();\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].table = popForward();\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].column = popForward(); // original column name\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].notNull = popForward();\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].primaryKey = popForward();\n for (let i = 0; i < metadata.numberOfColumns; i++)\n metadata.columns[i].autoIncrement = popForward();\n }\n return buffer;\n}\n/** Parse a regular rowset (no chunks) */\nfunction parseRowset(buffer, spaceIndex) {\n buffer = buffer.subarray(spaceIndex + 1, buffer.length);\n const { metadata, fwdBuffer } = parseRowsetHeader(buffer);\n buffer = parseRowsetColumnsMetadata(fwdBuffer, metadata);\n // decode each rowset item\n const data = [];\n for (let j = 0; j < metadata.numberOfRows * metadata.numberOfColumns; j++) {\n const { data: rowData, fwdBuffer } = popData(buffer);\n data.push(rowData);\n buffer = fwdBuffer;\n }\n console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'SQLiteCloudConnection.parseRowset - invalid rowset data');\n return new rowset_1.SQLiteCloudRowset(metadata, data);\n}\nfunction bufferStartsWith(buffer, prefix) {\n return buffer.length >= prefix.length && buffer.subarray(0, prefix.length).toString('utf8') === prefix;\n}\nexports.bufferStartsWith = bufferStartsWith;\nfunction bufferEndsWith(buffer, suffix) {\n return buffer.length >= suffix.length && buffer.subarray(buffer.length - suffix.length, buffer.length).toString('utf8') === suffix;\n}\nexports.bufferEndsWith = bufferEndsWith;\n/**\n * Parse a chunk of a chunked rowset command, eg:\n * *LEN 0:VERS NROWS NCOLS DATA\n * @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk\n */\nfunction parseRowsetChunks(buffers) {\n let buffer = Buffer.concat(buffers);\n if (!bufferStartsWith(buffer, exports.CMD_ROWSET_CHUNK) || !bufferEndsWith(buffer, exports.ROWSET_CHUNKS_END)) {\n throw new Error('SQLiteCloudConnection.parseRowsetChunks - invalid chunks buffer');\n }\n let metadata = { version: 1, numberOfColumns: 0, numberOfRows: 0, columns: [] };\n const data = [];\n // validate and skip data type\n const dataType = buffer.subarray(0, 1).toString();\n console.assert(dataType === exports.CMD_ROWSET_CHUNK);\n buffer = buffer.subarray(buffer.indexOf(' ') + 1);\n while (buffer.length > 0 && !bufferStartsWith(buffer, exports.ROWSET_CHUNKS_END)) {\n // chunk header, eg: 0:VERS NROWS NCOLS\n const { index: chunkIndex, metadata: chunkMetadata, fwdBuffer } = parseRowsetHeader(buffer);\n buffer = fwdBuffer;\n // first chunk? extract columns metadata\n if (chunkIndex === 1) {\n metadata = chunkMetadata;\n buffer = parseRowsetColumnsMetadata(buffer, metadata);\n }\n else {\n metadata.numberOfRows += chunkMetadata.numberOfRows;\n }\n // extract single rowset row\n for (let k = 0; k < chunkMetadata.numberOfRows * metadata.numberOfColumns; k++) {\n const { data: itemData, fwdBuffer } = popData(buffer);\n data.push(itemData);\n buffer = fwdBuffer;\n }\n }\n console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'parseRowsetChunks - invalid rowset data');\n const rowset = new rowset_1.SQLiteCloudRowset(metadata, data);\n // console.debug(`parseRowsetChunks - ${rowset.numberOfRows} rows, ${rowset.numberOfColumns} columns`)\n return rowset;\n}\nexports.parseRowsetChunks = parseRowsetChunks;\n/** Pop one or more space separated integers from beginning of buffer, move buffer forward */\nfunction popIntegers(buffer, numberOfIntegers = 1) {\n const data = [];\n for (let i = 0; i < numberOfIntegers; i++) {\n const spaceIndex = buffer.indexOf(' ');\n data[i] = parseInt(buffer.subarray(0, spaceIndex).toString());\n buffer = buffer.subarray(spaceIndex + 1);\n }\n return { data, fwdBuffer: buffer };\n}\n/** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */\nfunction popData(buffer) {\n function popResults(data) {\n const fwdBuffer = buffer.subarray(commandEnd);\n return { data, fwdBuffer };\n }\n // first character is the data type\n console.assert(buffer && buffer instanceof Buffer);\n const dataType = buffer.subarray(0, 1).toString('utf8');\n console.assert(dataType !== exports.CMD_COMPRESSED, \"Compressed data shouldn't be decompressed before parsing\");\n console.assert(dataType !== exports.CMD_ROWSET_CHUNK, 'Chunked data should be parsed by parseRowsetChunks');\n let spaceIndex = buffer.indexOf(' ');\n if (spaceIndex === -1) {\n spaceIndex = buffer.length - 1;\n }\n let commandEnd = -1;\n if (dataType === exports.CMD_INT || dataType === exports.CMD_FLOAT || dataType === exports.CMD_NULL) {\n commandEnd = spaceIndex + 1;\n }\n else {\n const commandLength = parseInt(buffer.subarray(1, spaceIndex).toString());\n commandEnd = spaceIndex + 1 + commandLength;\n }\n switch (dataType) {\n case exports.CMD_INT:\n return popResults(parseInt(buffer.subarray(1, spaceIndex).toString()));\n case exports.CMD_FLOAT:\n return popResults(parseFloat(buffer.subarray(1, spaceIndex).toString()));\n case exports.CMD_NULL:\n return popResults(null);\n case exports.CMD_STRING:\n return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8'));\n case exports.CMD_ZEROSTRING:\n return popResults(buffer.subarray(spaceIndex + 1, commandEnd - 1).toString('utf8'));\n case exports.CMD_COMMAND:\n return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8'));\n case exports.CMD_JSON:\n return popResults(JSON.parse(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8')));\n case exports.CMD_BLOB:\n return popResults(buffer.subarray(spaceIndex + 1, commandEnd));\n case exports.CMD_ARRAY:\n return popResults(parseArray(buffer, spaceIndex));\n case exports.CMD_ROWSET:\n return popResults(parseRowset(buffer, spaceIndex));\n case exports.CMD_ERROR:\n parseError(buffer, spaceIndex); // throws custom error\n break;\n }\n throw new TypeError(`Data type: ${dataType} is not defined in SCSP`);\n}\nexports.popData = popData;\n/** Format a command to be sent via SCSP protocol */\nfunction formatCommand(command) {\n const commandLength = Buffer.byteLength(command, 'utf-8');\n return `+${commandLength} ${command}`;\n}\nexports.formatCommand = formatCommand;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/protocol.js?"); + +/***/ }), + +/***/ "./lib/drivers/queue.js": +/*!******************************!*\ + !*** ./lib/drivers/queue.js ***! + \******************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\n//\n// queue.ts - simple task queue used to linearize async operations\n//\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.OperationsQueue = void 0;\nclass OperationsQueue {\n constructor() {\n this.queue = [];\n this.isProcessing = false;\n }\n /** Add operations to the queue, process immediately if possible, else wait for previous operations to complete */\n enqueue(operation) {\n this.queue.push(operation);\n if (!this.isProcessing) {\n this.processNext();\n }\n }\n /** Clear the queue */\n clear() {\n this.queue = [];\n this.isProcessing = false;\n }\n /** Process the next operation in the queue */\n processNext() {\n if (this.queue.length === 0) {\n this.isProcessing = false;\n return;\n }\n this.isProcessing = true;\n const operation = this.queue.shift();\n operation === null || operation === void 0 ? void 0 : operation(() => {\n // could receive (error) => { ...\n // if (error) {\n // console.warn('OperationQueue.processNext - error in operation', error)\n // }\n // process the next operation in the queue\n this.processNext();\n });\n }\n}\nexports.OperationsQueue = OperationsQueue;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/queue.js?"); + +/***/ }), + +/***/ "./lib/drivers/rowset.js": +/*!*******************************!*\ + !*** ./lib/drivers/rowset.js ***! + \*******************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\n//\n// rowset.ts\n//\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _SQLiteCloudRow_rowset, _SQLiteCloudRow_data, _SQLiteCloudRowset_metadata, _SQLiteCloudRowset_data;\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.SQLiteCloudRowset = exports.SQLiteCloudRow = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\n/** A single row in a dataset with values accessible by column name */\nclass SQLiteCloudRow {\n constructor(rowset, columnsNames, data) {\n // rowset is private\n _SQLiteCloudRow_rowset.set(this, void 0);\n // data is private\n _SQLiteCloudRow_data.set(this, void 0);\n __classPrivateFieldSet(this, _SQLiteCloudRow_rowset, rowset, \"f\");\n __classPrivateFieldSet(this, _SQLiteCloudRow_data, data, \"f\");\n for (let i = 0; i < columnsNames.length; i++) {\n this[columnsNames[i]] = data[i];\n }\n }\n /** Returns the rowset that this row belongs to */\n // @ts-expect-error\n getRowset() {\n return __classPrivateFieldGet(this, _SQLiteCloudRow_rowset, \"f\");\n }\n /** Returns rowset data as a plain array of values */\n // @ts-expect-error\n getData() {\n return __classPrivateFieldGet(this, _SQLiteCloudRow_data, \"f\");\n }\n}\nexports.SQLiteCloudRow = SQLiteCloudRow;\n_SQLiteCloudRow_rowset = new WeakMap(), _SQLiteCloudRow_data = new WeakMap();\n/* A set of rows returned by a query */\nclass SQLiteCloudRowset extends Array {\n constructor(metadata, data) {\n super(metadata.numberOfRows);\n /** Metadata contains number of rows and columns, column names, types, etc. */\n _SQLiteCloudRowset_metadata.set(this, void 0);\n /** Actual data organized in rows */\n _SQLiteCloudRowset_data.set(this, void 0);\n // console.assert(data !== undefined && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'Invalid rowset data')\n // console.assert(metadata !== undefined && metadata.columns.length === metadata.numberOfColumns, 'Invalid columns metadata')\n __classPrivateFieldSet(this, _SQLiteCloudRowset_metadata, metadata, \"f\");\n __classPrivateFieldSet(this, _SQLiteCloudRowset_data, data, \"f\");\n // adjust missing column names, duplicate column names, etc.\n const columnNames = this.columnsNames;\n for (let i = 0; i < metadata.numberOfColumns; i++) {\n if (!columnNames[i]) {\n columnNames[i] = `column_${i}`;\n }\n let j = 0;\n while (columnNames.findIndex((name, index) => index !== i && name === columnNames[i]) >= 0) {\n columnNames[i] = `${columnNames[i]}_${j}`;\n j++;\n }\n }\n for (let i = 0, start = 0; i < metadata.numberOfRows; i++, start += metadata.numberOfColumns) {\n this[i] = new SQLiteCloudRow(this, columnNames, data.slice(start, start + metadata.numberOfColumns));\n }\n }\n /**\n * Rowset version is 1 for a rowset with simple column names, 2 for extended metadata\n * @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md\n */\n get version() {\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\").version;\n }\n /** Number of rows in row set */\n get numberOfRows() {\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\").numberOfRows;\n }\n /** Number of columns in row set */\n get numberOfColumns() {\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\").numberOfColumns;\n }\n /** Array of columns names */\n get columnsNames() {\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\").columns.map(column => column.name);\n }\n /** Get rowset metadata */\n get metadata() {\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\");\n }\n /** Return value of item at given row and column */\n getItem(row, column) {\n if (row < 0 || row >= this.numberOfRows || column < 0 || column >= this.numberOfColumns) {\n throw new types_1.SQLiteCloudError(`This rowset has ${this.numberOfColumns} columns by ${this.numberOfRows} rows, requested column ${column} and row ${row} is invalid.`);\n }\n return __classPrivateFieldGet(this, _SQLiteCloudRowset_data, \"f\")[row * this.numberOfColumns + column];\n }\n /** Returns a subset of rows from this rowset */\n slice(start, end) {\n // validate and apply boundaries\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice\n start = start === undefined ? 0 : start < 0 ? this.numberOfRows + start : start;\n start = Math.min(Math.max(start, 0), this.numberOfRows);\n end = end === undefined ? this.numberOfRows : end < 0 ? this.numberOfRows + end : end;\n end = Math.min(Math.max(start, end), this.numberOfRows);\n const slicedMetadata = Object.assign(Object.assign({}, __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\")), { numberOfRows: end - start });\n const slicedData = __classPrivateFieldGet(this, _SQLiteCloudRowset_data, \"f\").slice(start * this.numberOfColumns, end * this.numberOfColumns);\n console.assert(slicedData && slicedData.length === slicedMetadata.numberOfRows * slicedMetadata.numberOfColumns, 'SQLiteCloudRowset.slice - invalid rowset data');\n return new SQLiteCloudRowset(slicedMetadata, slicedData);\n }\n map(fn) {\n const results = [];\n for (let i = 0; i < this.numberOfRows; i++) {\n const row = this[i];\n results.push(fn(row, i, this));\n }\n return results;\n }\n /** Returns an instance of SQLiteCloudRowset where rows have been filtered via given callback */\n filter(fn) {\n const filteredData = [];\n for (let i = 0; i < this.numberOfRows; i++) {\n const row = this[i];\n if (fn(row, i, this)) {\n filteredData.push(...__classPrivateFieldGet(this, _SQLiteCloudRowset_data, \"f\").slice(i * this.numberOfColumns, (i + 1) * this.numberOfColumns));\n }\n }\n return new SQLiteCloudRowset(Object.assign(Object.assign({}, __classPrivateFieldGet(this, _SQLiteCloudRowset_metadata, \"f\")), { numberOfRows: filteredData.length / this.numberOfColumns }), filteredData);\n }\n}\nexports.SQLiteCloudRowset = SQLiteCloudRowset;\n_SQLiteCloudRowset_metadata = new WeakMap(), _SQLiteCloudRowset_data = new WeakMap();\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/rowset.js?"); + +/***/ }), + +/***/ "./lib/drivers/statement.js": +/*!**********************************!*\ + !*** ./lib/drivers/statement.js ***! + \**********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n/**\n * statement.ts\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Statement = void 0;\nconst utilities_1 = __webpack_require__(/*! ./utilities */ \"./lib/drivers/utilities.js\");\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n/** A statement generated by Database.prepare used to prepare SQL with ? bindings */\nclass Statement {\n constructor(database, sql, ...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n this._database = database;\n this._sql = sql;\n if ((args === null || args === void 0 ? void 0 : args.length) > 0) {\n this.bind(...args, callback);\n }\n else {\n callback === null || callback === void 0 ? void 0 : callback.call(this, null);\n }\n }\n /**\n * Binds parameters to the prepared statement and calls the callback when done\n * or when an error occurs. The function returns the Statement object to allow\n * for function chaining. The first and only argument to the callback is null\n * when binding was successful, otherwise it is the error object. Binding parameters\n * with this function completely resets the statement object and row cursor and\n * removes all previously bound parameters, if any. Currently bound parameters\n * are escaped client side and turned into literals before being executed on the server.\n */\n bind(...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params);\n try {\n this._preparedSql = (0, utilities_1.prepareSql)(this._sql, ...args);\n if (callback) {\n callback.call(this, null);\n }\n }\n catch (error) {\n this._preparedSql = undefined;\n if (callback) {\n callback.call(this, error);\n }\n }\n return this;\n }\n run(...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params || []);\n if ((args === null || args === void 0 ? void 0 : args.length) > 0) {\n // apply new bindings then execute\n this.bind(...args, (error) => {\n if (error) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n else {\n this._database.run(this._preparedSql || '', callback);\n }\n });\n }\n else {\n // execute prepared sql with same bindings\n this._database.run(this._preparedSql || '', callback);\n }\n return this;\n }\n get(...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params || []);\n if ((args === null || args === void 0 ? void 0 : args.length) > 0) {\n // apply new bindings then execute\n this.bind(...args, (error) => {\n if (error) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n else {\n this._database.get(this._preparedSql || '', callback);\n }\n });\n }\n else {\n // execute prepared sql with same bindings\n this._database.get(this._preparedSql || '', callback);\n }\n return this;\n }\n all(...params) {\n const { args, callback } = (0, utilities_1.popCallback)(params || []);\n if ((args === null || args === void 0 ? void 0 : args.length) > 0) {\n // apply new bindings then execute\n this.bind(...args, (error) => {\n if (error) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n else {\n this._database.all(this._preparedSql || '', callback);\n }\n });\n }\n else {\n // execute prepared sql with same bindings\n this._database.all(this._preparedSql || '', callback);\n }\n return this;\n }\n each(...params) {\n const { args, callback, complete } = (0, utilities_1.popCallback)(params);\n if ((args === null || args === void 0 ? void 0 : args.length) > 0) {\n // apply new bindings then execute\n this.bind(...args, (error) => {\n if (error) {\n callback === null || callback === void 0 ? void 0 : callback.call(this, error);\n }\n else {\n this._database.each(this._preparedSql || '', callback, complete);\n }\n });\n }\n else {\n // execute prepared sql with same bindings\n this._database.each(this._preparedSql || '', callback, complete);\n }\n return this;\n }\n}\nexports.Statement = Statement;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/statement.js?"); + +/***/ }), + +/***/ "./lib/drivers/types.js": +/*!******************************!*\ + !*** ./lib/drivers/types.js ***! + \******************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\n/**\n * types.ts - shared types and interfaces\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.SQLiteCloudArrayType = exports.SQLiteCloudError = exports.DEFAULT_PORT = exports.DEFAULT_TIMEOUT = void 0;\n/** Default timeout value for queries */\nexports.DEFAULT_TIMEOUT = 300 * 1000;\n/** Default tls connection port */\nexports.DEFAULT_PORT = 9960;\n/** Custom error reported by SQLiteCloud drivers */\nclass SQLiteCloudError extends Error {\n constructor(message, args) {\n super(message);\n this.name = 'SQLiteCloudError';\n if (args) {\n Object.assign(this, args);\n }\n }\n}\nexports.SQLiteCloudError = SQLiteCloudError;\n/**\n * Certain responses include arrays with various types of metadata.\n * The first entry is always an array type from this list. This enum\n * is called SQCLOUD_ARRAY_TYPE in the C API.\n */\nvar SQLiteCloudArrayType;\n(function (SQLiteCloudArrayType) {\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_SQLITE_EXEC\"] = 10] = \"ARRAY_TYPE_SQLITE_EXEC\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_DB_STATUS\"] = 11] = \"ARRAY_TYPE_DB_STATUS\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_METADATA\"] = 12] = \"ARRAY_TYPE_METADATA\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_STEP\"] = 20] = \"ARRAY_TYPE_VM_STEP\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_COMPILE\"] = 21] = \"ARRAY_TYPE_VM_COMPILE\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_STEP_ONE\"] = 22] = \"ARRAY_TYPE_VM_STEP_ONE\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_SQL\"] = 23] = \"ARRAY_TYPE_VM_SQL\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_STATUS\"] = 24] = \"ARRAY_TYPE_VM_STATUS\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_VM_LIST\"] = 25] = \"ARRAY_TYPE_VM_LIST\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_BACKUP_INIT\"] = 40] = \"ARRAY_TYPE_BACKUP_INIT\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_BACKUP_STEP\"] = 41] = \"ARRAY_TYPE_BACKUP_STEP\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_BACKUP_END\"] = 42] = \"ARRAY_TYPE_BACKUP_END\";\n SQLiteCloudArrayType[SQLiteCloudArrayType[\"ARRAY_TYPE_SQLITE_STATUS\"] = 50] = \"ARRAY_TYPE_SQLITE_STATUS\"; // used in sqlite_status\n})(SQLiteCloudArrayType = exports.SQLiteCloudArrayType || (exports.SQLiteCloudArrayType = {}));\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/types.js?"); + +/***/ }), + +/***/ "./lib/drivers/utilities.js": +/*!**********************************!*\ + !*** ./lib/drivers/utilities.js ***! + \**********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n//\n// utilities.ts - utility methods to manipulate SQL statements\n//\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.parseBoolean = exports.parseConnectionString = exports.validateConfiguration = exports.popCallback = exports.prepareSql = exports.escapeSqlParameter = exports.getInitializationCommands = exports.anonimizeError = exports.anonimizeCommand = exports.isNode = exports.isBrowser = void 0;\nconst types_1 = __webpack_require__(/*! ./types */ \"./lib/drivers/types.js\");\n//\n// determining running environment, thanks to browser-or-node\n// https://www.npmjs.com/package/browser-or-node\n//\nexports.isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';\nexports.isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;\n//\n// utility methods\n//\n/** Messages going to the server are sometimes logged when error conditions occour and need to be stripped of user credentials */\nfunction anonimizeCommand(message) {\n // hide password in AUTH command if needed\n message = message.replace(/USER \\S+/, 'USER ******');\n message = message.replace(/PASSWORD \\S+?(?=;)/, 'PASSWORD ******');\n message = message.replace(/HASH \\S+?(?=;)/, 'HASH ******');\n return message;\n}\nexports.anonimizeCommand = anonimizeCommand;\n/** Strip message code in error of user credentials */\nfunction anonimizeError(error) {\n if (error === null || error === void 0 ? void 0 : error.message) {\n error.message = anonimizeCommand(error.message);\n }\n return error;\n}\nexports.anonimizeError = anonimizeError;\n/** Initialization commands sent to database when connection is established */\nfunction getInitializationCommands(config) {\n // first user authentication, then all other commands\n let commands = `AUTH USER ${config.username || ''} ${config.passwordHashed ? 'HASH' : 'PASSWORD'} ${config.password || ''}; `;\n if (config.database) {\n if (config.createDatabase && !config.dbMemory) {\n commands += `CREATE DATABASE ${config.database} IF NOT EXISTS; `;\n }\n commands += `USE DATABASE ${config.database}; `;\n }\n if (config.compression) {\n commands += 'SET CLIENT KEY COMPRESSION TO 1; ';\n }\n if (config.nonlinearizable) {\n commands += 'SET CLIENT KEY NONLINEARIZABLE TO 1; ';\n }\n if (config.noBlob) {\n commands += 'SET CLIENT KEY NOBLOB TO 1; ';\n }\n if (config.maxData) {\n commands += `SET CLIENT KEY MAXDATA TO ${config.maxData}; `;\n }\n if (config.maxRows) {\n commands += `SET CLIENT KEY MAXROWS TO ${config.maxRows}; `;\n }\n if (config.maxRowset) {\n commands += `SET CLIENT KEY MAXROWSET TO ${config.maxRowset}; `;\n }\n return commands;\n}\nexports.getInitializationCommands = getInitializationCommands;\n/** Takes a generic value and escapes it so it can replace ? as a binding in a prepared SQL statement */\nfunction escapeSqlParameter(param) {\n if (param === null || param === undefined) {\n return 'NULL';\n }\n if (typeof param === 'string') {\n // replace single quote with two single quotes\n param = param.replace(/'/g, \"''\");\n return `'${param}'`;\n }\n if (typeof param === 'number') {\n return param.toString();\n }\n if (typeof param === 'boolean') {\n return param ? '1' : '0';\n }\n // serialize buffer as X'...' hex encoded string\n if (Buffer.isBuffer(param)) {\n return `X'${param.toString('hex')}'`;\n }\n if (typeof param === 'object') {\n // serialize json then escape single quotes\n let json = JSON.stringify(param);\n json = json.replace(/'/g, \"''\");\n return `'${json}'`;\n }\n throw new types_1.SQLiteCloudError(`Unsupported parameter type: ${typeof param}`);\n}\nexports.escapeSqlParameter = escapeSqlParameter;\n/** Take a sql statement and replaces ? or $named parameters that are properly serialized and escaped. */\nfunction prepareSql(sql, ...params) {\n // parameters where passed as an array of parameters?\n if ((params === null || params === void 0 ? void 0 : params.length) === 1 && Array.isArray(params[0])) {\n params = params[0];\n }\n // replace ? or ?idx parameters passed as args or as an array\n let parameterIndex = 1;\n let preparedSql = sql.replace(/\\?(\\d+)?/g, (match, matchIndex) => {\n const index = matchIndex ? parseInt(matchIndex) : parameterIndex;\n parameterIndex++;\n let sqlParameter;\n if (params[0] && typeof params[0] === 'object' && !(params[0] instanceof Buffer)) {\n sqlParameter = params[0][index];\n }\n if (!sqlParameter) {\n if (index > params.length) {\n throw new types_1.SQLiteCloudError('Not enough parameters');\n }\n sqlParameter = params[index - 1];\n }\n return sqlParameter !== null && sqlParameter !== undefined ? escapeSqlParameter(sqlParameter) : 'NULL';\n });\n // replace $named or :named parameters passed as an object\n if ((params === null || params === void 0 ? void 0 : params.length) === 1 && params[0] && typeof params[0] === 'object') {\n const namedParams = params[0];\n for (const [paramKey, param] of Object.entries(namedParams)) {\n const firstChar = paramKey.charAt(0);\n if (firstChar == '$' || firstChar == ':' || firstChar == '@') {\n const escapedParam = escapeSqlParameter(param);\n preparedSql = preparedSql.replace(new RegExp(`\\\\${paramKey}`, 'g'), escapedParam);\n }\n }\n }\n return preparedSql;\n}\nexports.prepareSql = prepareSql;\n/**\n * Many of the methods in our API may contain a callback as their last argument.\n * This method will take the arguments array passed to the method and return an object\n * containing the arguments array with the callbacks removed (if any), and the callback itself.\n * If there are multiple callbacks, the first one is returned as 'callback' and the last one\n * as 'completeCallback'.\n */\nfunction popCallback(args) {\n const remaining = args;\n // at least 1 callback?\n if (args && args.length > 0 && typeof args[args.length - 1] === 'function') {\n // at least 2 callbacks?\n if (args.length > 1 && typeof args[args.length - 2] === 'function') {\n return { args: remaining.slice(0, -2), callback: args[args.length - 2], complete: args[args.length - 1] };\n }\n return { args: remaining.slice(0, -1), callback: args[args.length - 1] };\n }\n return { args: remaining };\n}\nexports.popCallback = popCallback;\n//\n// configuration validation\n//\n/** Validate configuration, apply defaults, throw if something is missing or misconfigured */\nfunction validateConfiguration(config) {\n console.assert(config, 'SQLiteCloudConnection.validateConfiguration - missing config');\n if (config.connectionString) {\n config = Object.assign(Object.assign(Object.assign({}, config), parseConnectionString(config.connectionString)), { connectionString: config.connectionString // keep original connection string\n });\n }\n // apply defaults where needed\n config.port || (config.port = types_1.DEFAULT_PORT);\n config.timeout = config.timeout && config.timeout > 0 ? config.timeout : types_1.DEFAULT_TIMEOUT;\n config.clientId || (config.clientId = 'SQLiteCloud');\n config.verbose = parseBoolean(config.verbose);\n config.noBlob = parseBoolean(config.noBlob);\n config.compression = parseBoolean(config.compression);\n config.createDatabase = parseBoolean(config.createDatabase);\n config.nonlinearizable = parseBoolean(config.nonlinearizable);\n config.insecure = parseBoolean(config.insecure);\n if (!config.username || !config.password || !config.host) {\n console.error('SQLiteCloudConnection.validateConfiguration - missing arguments', config);\n throw new types_1.SQLiteCloudError('The user, password and host arguments must be specified.', { errorCode: 'ERR_MISSING_ARGS' });\n }\n if (!config.connectionString) {\n // build connection string from configuration, values are already validated\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n config.connectionString = `sqlitecloud://${config.username}:${config.password}@${config.host}:${config.port}/${config.database}`;\n }\n return config;\n}\nexports.validateConfiguration = validateConfiguration;\n/** Parse connectionString like sqlitecloud://username:password@host:port/database?option1=xxx&option2=xxx into its components */\nfunction parseConnectionString(connectionString) {\n try {\n // The URL constructor throws a TypeError if the URL is not valid.\n // in spite of having the same structure as a regular url\n // protocol://username:password@host:port/database?option1=xxx&option2=xxx)\n // the sqlitecloud: protocol is not recognized by the URL constructor in browsers\n // so we need to replace it with https: to make it work\n const knownProtocolUrl = connectionString.replace('sqlitecloud:', 'https:');\n const url = new URL(knownProtocolUrl);\n const options = {};\n url.searchParams.forEach((value, key) => {\n options[key] = value;\n });\n const config = Object.assign({ username: url.username, password: url.password, host: url.hostname, port: url.port ? parseInt(url.port) : undefined }, options);\n const database = url.pathname.replace('/', ''); // pathname is database name, remove the leading slash\n if (database) {\n config.database = database;\n }\n return config;\n }\n catch (error) {\n throw new types_1.SQLiteCloudError(`Invalid connection string: ${connectionString}`);\n }\n}\nexports.parseConnectionString = parseConnectionString;\n/** Returns true if value is 1 or true */\nfunction parseBoolean(value) {\n if (typeof value === 'string') {\n return value.toLowerCase() === 'true' || value === '1';\n }\n return value ? true : false;\n}\nexports.parseBoolean = parseBoolean;\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/drivers/utilities.js?"); + +/***/ }), + +/***/ "./lib/index.js": +/*!**********************!*\ + !*** ./lib/index.js ***! + \**********************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n//\n// index.ts - export drivers classes, utilities, types\n//\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.validateConfiguration = exports.parseConnectionString = exports.prepareSql = exports.escapeSqlParameter = exports.SQLiteCloudRow = exports.SQLiteCloudRowset = exports.SQLiteCloudError = exports.SQLiteCloudConnection = exports.Statement = exports.Database = void 0;\n// include ONLY packages used by drivers\n// do NOT include anything related to gateway or bun or express\n// connection-tls does not want/need to load on browser and is loaded dynamically by Database\n// connection-ws does not want/need to load on node and is loaded dynamically by Database\nvar database_1 = __webpack_require__(/*! ./drivers/database */ \"./lib/drivers/database.js\");\nObject.defineProperty(exports, \"Database\", ({ enumerable: true, get: function () { return database_1.Database; } }));\nvar statement_1 = __webpack_require__(/*! ./drivers/statement */ \"./lib/drivers/statement.js\");\nObject.defineProperty(exports, \"Statement\", ({ enumerable: true, get: function () { return statement_1.Statement; } }));\nvar connection_1 = __webpack_require__(/*! ./drivers/connection */ \"./lib/drivers/connection.js\");\nObject.defineProperty(exports, \"SQLiteCloudConnection\", ({ enumerable: true, get: function () { return connection_1.SQLiteCloudConnection; } }));\nvar types_1 = __webpack_require__(/*! ./drivers/types */ \"./lib/drivers/types.js\");\nObject.defineProperty(exports, \"SQLiteCloudError\", ({ enumerable: true, get: function () { return types_1.SQLiteCloudError; } }));\nvar rowset_1 = __webpack_require__(/*! ./drivers/rowset */ \"./lib/drivers/rowset.js\");\nObject.defineProperty(exports, \"SQLiteCloudRowset\", ({ enumerable: true, get: function () { return rowset_1.SQLiteCloudRowset; } }));\nObject.defineProperty(exports, \"SQLiteCloudRow\", ({ enumerable: true, get: function () { return rowset_1.SQLiteCloudRow; } }));\nvar utilities_1 = __webpack_require__(/*! ./drivers/utilities */ \"./lib/drivers/utilities.js\");\nObject.defineProperty(exports, \"escapeSqlParameter\", ({ enumerable: true, get: function () { return utilities_1.escapeSqlParameter; } }));\nObject.defineProperty(exports, \"prepareSql\", ({ enumerable: true, get: function () { return utilities_1.prepareSql; } }));\nObject.defineProperty(exports, \"parseConnectionString\", ({ enumerable: true, get: function () { return utilities_1.parseConnectionString; } }));\nObject.defineProperty(exports, \"validateConfiguration\", ({ enumerable: true, get: function () { return utilities_1.validateConfiguration; } }));\n\n\n//# sourceURL=webpack://sqlitecloud/./lib/index.js?"); + +/***/ }), + +/***/ "./node_modules/debug/src/browser.js": +/*!*******************************************!*\ + !*** ./node_modules/debug/src/browser.js ***! + \*******************************************/ +/***/ ((module, exports, __webpack_require__) => { + +eval("/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug');\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = process.env.DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = __webpack_require__(/*! ./common */ \"./node_modules/debug/src/common.js\")(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/debug/src/browser.js?"); + +/***/ }), + +/***/ "./node_modules/debug/src/common.js": +/*!******************************************!*\ + !*** ./node_modules/debug/src/common.js ***! + \******************************************/ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +eval("\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = __webpack_require__(/*! ms */ \"./node_modules/ms/index.js\");\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tlet i;\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n\t\tconst len = split.length;\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tif (!split[i]) {\n\t\t\t\t// ignore empty strings\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnamespaces = split[i].replace(/\\*/g, '.*?');\n\n\t\t\tif (namespaces[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(new RegExp('^' + namespaces + '$'));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names.map(toNamespace),\n\t\t\t...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tif (name[name.length - 1] === '*') {\n\t\t\treturn true;\n\t\t}\n\n\t\tlet i;\n\t\tlet len;\n\n\t\tfor (i = 0, len = createDebug.skips.length; i < len; i++) {\n\t\t\tif (createDebug.skips[i].test(name)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (i = 0, len = createDebug.names.length; i < len; i++) {\n\t\t\tif (createDebug.names[i].test(name)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Convert regexp to namespace\n\t*\n\t* @param {RegExp} regxep\n\t* @return {String} namespace\n\t* @api private\n\t*/\n\tfunction toNamespace(regexp) {\n\t\treturn regexp.toString()\n\t\t\t.substring(2, regexp.toString().length - 2)\n\t\t\t.replace(/\\.\\*\\?$/, '*');\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/debug/src/common.js?"); + +/***/ }), + +/***/ "./node_modules/eventemitter3/index.js": +/*!*********************************************!*\ + !*** ./node_modules/eventemitter3/index.js ***! + \*********************************************/ +/***/ ((module) => { + +"use strict"; +eval("\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif (true) {\n module.exports = EventEmitter;\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/eventemitter3/index.js?"); + +/***/ }), + +/***/ "./node_modules/lz4js/lz4.js": +/*!***********************************!*\ + !*** ./node_modules/lz4js/lz4.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("// lz4.js - An implementation of Lz4 in plain JavaScript.\n//\n// TODO:\n// - Unify header parsing/writing.\n// - Support options (block size, checksums)\n// - Support streams\n// - Better error handling (handle bad offset, etc.)\n// - HC support (better search algorithm)\n// - Tests/benchmarking\n\nvar xxhash = __webpack_require__(/*! ./xxh32.js */ \"./node_modules/lz4js/xxh32.js\");\nvar util = __webpack_require__(/*! ./util.js */ \"./node_modules/lz4js/util.js\");\n\n// Constants\n// --\n\n// Compression format parameters/constants.\nvar minMatch = 4;\nvar minLength = 13;\nvar searchLimit = 5;\nvar skipTrigger = 6;\nvar hashSize = 1 << 16;\n\n// Token constants.\nvar mlBits = 4;\nvar mlMask = (1 << mlBits) - 1;\nvar runBits = 4;\nvar runMask = (1 << runBits) - 1;\n\n// Shared buffers\nvar blockBuf = makeBuffer(5 << 20);\nvar hashTable = makeHashTable();\n\n// Frame constants.\nvar magicNum = 0x184D2204;\n\n// Frame descriptor flags.\nvar fdContentChksum = 0x4;\nvar fdContentSize = 0x8;\nvar fdBlockChksum = 0x10;\n// var fdBlockIndep = 0x20;\nvar fdVersion = 0x40;\nvar fdVersionMask = 0xC0;\n\n// Block sizes.\nvar bsUncompressed = 0x80000000;\nvar bsDefault = 7;\nvar bsShift = 4;\nvar bsMask = 7;\nvar bsMap = {\n 4: 0x10000,\n 5: 0x40000,\n 6: 0x100000,\n 7: 0x400000\n};\n\n// Utility functions/primitives\n// --\n\n// Makes our hashtable. On older browsers, may return a plain array.\nfunction makeHashTable () {\n try {\n return new Uint32Array(hashSize);\n } catch (error) {\n var hashTable = new Array(hashSize);\n\n for (var i = 0; i < hashSize; i++) {\n hashTable[i] = 0;\n }\n\n return hashTable;\n }\n}\n\n// Clear hashtable.\nfunction clearHashTable (table) {\n for (var i = 0; i < hashSize; i++) {\n hashTable[i] = 0;\n }\n}\n\n// Makes a byte buffer. On older browsers, may return a plain array.\nfunction makeBuffer (size) {\n try {\n return new Uint8Array(size);\n } catch (error) {\n var buf = new Array(size);\n\n for (var i = 0; i < size; i++) {\n buf[i] = 0;\n }\n\n return buf;\n }\n}\n\nfunction sliceArray (array, start, end) {\n if (typeof array.buffer !== undefined) {\n if (Uint8Array.prototype.slice) {\n return array.slice(start, end);\n } else {\n // Uint8Array#slice polyfill.\n var len = array.length;\n\n // Calculate start.\n start = start | 0;\n start = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);\n\n // Calculate end.\n end = (end === undefined) ? len : end | 0;\n end = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);\n\n // Copy into new array.\n var arraySlice = new Uint8Array(end - start);\n for (var i = start, n = 0; i < end;) {\n arraySlice[n++] = array[i++];\n }\n\n return arraySlice;\n }\n } else {\n // Assume normal array.\n return array.slice(start, end);\n }\n}\n\n// Implementation\n// --\n\n// Calculates an upper bound for lz4 compression.\nexports.compressBound = function compressBound (n) {\n return (n + (n / 255) + 16) | 0;\n};\n\n// Calculates an upper bound for lz4 decompression, by reading the data.\nexports.decompressBound = function decompressBound (src) {\n var sIndex = 0;\n\n // Read magic number\n if (util.readU32(src, sIndex) !== magicNum) {\n throw new Error('invalid magic number');\n }\n\n sIndex += 4;\n\n // Read descriptor\n var descriptor = src[sIndex++];\n\n // Check version\n if ((descriptor & fdVersionMask) !== fdVersion) {\n throw new Error('incompatible descriptor version ' + (descriptor & fdVersionMask));\n }\n\n // Read flags\n var useBlockSum = (descriptor & fdBlockChksum) !== 0;\n var useContentSize = (descriptor & fdContentSize) !== 0;\n\n // Read block size\n var bsIdx = (src[sIndex++] >> bsShift) & bsMask;\n\n if (bsMap[bsIdx] === undefined) {\n throw new Error('invalid block size ' + bsIdx);\n }\n\n var maxBlockSize = bsMap[bsIdx];\n\n // Get content size\n if (useContentSize) {\n return util.readU64(src, sIndex);\n }\n\n // Checksum\n sIndex++;\n\n // Read blocks.\n var maxSize = 0;\n while (true) {\n var blockSize = util.readU32(src, sIndex);\n sIndex += 4;\n\n if (blockSize & bsUncompressed) {\n blockSize &= ~bsUncompressed;\n maxSize += blockSize;\n } else {\n maxSize += maxBlockSize;\n }\n\n if (blockSize === 0) {\n return maxSize;\n }\n\n if (useBlockSum) {\n sIndex += 4;\n }\n\n sIndex += blockSize;\n }\n};\n\n// Creates a buffer of a given byte-size, falling back to plain arrays.\nexports.makeBuffer = makeBuffer;\n\n// Decompresses a block of Lz4.\nexports.decompressBlock = function decompressBlock (src, dst, sIndex, sLength, dIndex) {\n var mLength, mOffset, sEnd, n, i;\n\n // Setup initial state.\n sEnd = sIndex + sLength;\n\n // Consume entire input block.\n while (sIndex < sEnd) {\n var token = src[sIndex++];\n\n // Copy literals.\n var literalCount = (token >> 4);\n if (literalCount > 0) {\n // Parse length.\n if (literalCount === 0xf) {\n while (true) {\n literalCount += src[sIndex];\n if (src[sIndex++] !== 0xff) {\n break;\n }\n }\n }\n\n // Copy literals\n for (n = sIndex + literalCount; sIndex < n;) {\n dst[dIndex++] = src[sIndex++];\n }\n }\n\n if (sIndex >= sEnd) {\n break;\n }\n\n // Copy match.\n mLength = (token & 0xf);\n\n // Parse offset.\n mOffset = src[sIndex++] | (src[sIndex++] << 8);\n\n // Parse length.\n if (mLength === 0xf) {\n while (true) {\n mLength += src[sIndex];\n if (src[sIndex++] !== 0xff) {\n break;\n }\n }\n }\n\n mLength += minMatch;\n\n // Copy match.\n for (i = dIndex - mOffset, n = i + mLength; i < n;) {\n dst[dIndex++] = dst[i++] | 0;\n }\n }\n\n return dIndex;\n};\n\n// Compresses a block with Lz4.\nexports.compressBlock = function compressBlock (src, dst, sIndex, sLength, hashTable) {\n var mIndex, mAnchor, mLength, mOffset, mStep;\n var literalCount, dIndex, sEnd, n;\n\n // Setup initial state.\n dIndex = 0;\n sEnd = sLength + sIndex;\n mAnchor = sIndex;\n\n // Process only if block is large enough.\n if (sLength >= minLength) {\n var searchMatchCount = (1 << skipTrigger) + 3;\n\n // Consume until last n literals (Lz4 spec limitation.)\n while (sIndex + minMatch < sEnd - searchLimit) {\n var seq = util.readU32(src, sIndex);\n var hash = util.hashU32(seq) >>> 0;\n\n // Crush hash to 16 bits.\n hash = ((hash >> 16) ^ hash) >>> 0 & 0xffff;\n\n // Look for a match in the hashtable. NOTE: remove one; see below.\n mIndex = hashTable[hash] - 1;\n\n // Put pos in hash table. NOTE: add one so that zero = invalid.\n hashTable[hash] = sIndex + 1;\n\n // Determine if there is a match (within range.)\n if (mIndex < 0 || ((sIndex - mIndex) >>> 16) > 0 || util.readU32(src, mIndex) !== seq) {\n mStep = searchMatchCount++ >> skipTrigger;\n sIndex += mStep;\n continue;\n }\n\n searchMatchCount = (1 << skipTrigger) + 3;\n\n // Calculate literal count and offset.\n literalCount = sIndex - mAnchor;\n mOffset = sIndex - mIndex;\n\n // We've already matched one word, so get that out of the way.\n sIndex += minMatch;\n mIndex += minMatch;\n\n // Determine match length.\n // N.B.: mLength does not include minMatch, Lz4 adds it back\n // in decoding.\n mLength = sIndex;\n while (sIndex < sEnd - searchLimit && src[sIndex] === src[mIndex]) {\n sIndex++;\n mIndex++;\n }\n mLength = sIndex - mLength;\n\n // Write token + literal count.\n var token = mLength < mlMask ? mLength : mlMask;\n if (literalCount >= runMask) {\n dst[dIndex++] = (runMask << mlBits) + token;\n for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {\n dst[dIndex++] = 0xff;\n }\n dst[dIndex++] = n;\n } else {\n dst[dIndex++] = (literalCount << mlBits) + token;\n }\n\n // Write literals.\n for (var i = 0; i < literalCount; i++) {\n dst[dIndex++] = src[mAnchor + i];\n }\n\n // Write offset.\n dst[dIndex++] = mOffset;\n dst[dIndex++] = (mOffset >> 8);\n\n // Write match length.\n if (mLength >= mlMask) {\n for (n = mLength - mlMask; n >= 0xff; n -= 0xff) {\n dst[dIndex++] = 0xff;\n }\n dst[dIndex++] = n;\n }\n\n // Move the anchor.\n mAnchor = sIndex;\n }\n }\n\n // Nothing was encoded.\n if (mAnchor === 0) {\n return 0;\n }\n\n // Write remaining literals.\n // Write literal token+count.\n literalCount = sEnd - mAnchor;\n if (literalCount >= runMask) {\n dst[dIndex++] = (runMask << mlBits);\n for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {\n dst[dIndex++] = 0xff;\n }\n dst[dIndex++] = n;\n } else {\n dst[dIndex++] = (literalCount << mlBits);\n }\n\n // Write literals.\n sIndex = mAnchor;\n while (sIndex < sEnd) {\n dst[dIndex++] = src[sIndex++];\n }\n\n return dIndex;\n};\n\n// Decompresses a frame of Lz4 data.\nexports.decompressFrame = function decompressFrame (src, dst) {\n var useBlockSum, useContentSum, useContentSize, descriptor;\n var sIndex = 0;\n var dIndex = 0;\n\n // Read magic number\n if (util.readU32(src, sIndex) !== magicNum) {\n throw new Error('invalid magic number');\n }\n\n sIndex += 4;\n\n // Read descriptor\n descriptor = src[sIndex++];\n\n // Check version\n if ((descriptor & fdVersionMask) !== fdVersion) {\n throw new Error('incompatible descriptor version');\n }\n\n // Read flags\n useBlockSum = (descriptor & fdBlockChksum) !== 0;\n useContentSum = (descriptor & fdContentChksum) !== 0;\n useContentSize = (descriptor & fdContentSize) !== 0;\n\n // Read block size\n var bsIdx = (src[sIndex++] >> bsShift) & bsMask;\n\n if (bsMap[bsIdx] === undefined) {\n throw new Error('invalid block size');\n }\n\n if (useContentSize) {\n // TODO: read content size\n sIndex += 8;\n }\n\n sIndex++;\n\n // Read blocks.\n while (true) {\n var compSize;\n\n compSize = util.readU32(src, sIndex);\n sIndex += 4;\n\n if (compSize === 0) {\n break;\n }\n\n if (useBlockSum) {\n // TODO: read block checksum\n sIndex += 4;\n }\n\n // Check if block is compressed\n if ((compSize & bsUncompressed) !== 0) {\n // Mask off the 'uncompressed' bit\n compSize &= ~bsUncompressed;\n\n // Copy uncompressed data into destination buffer.\n for (var j = 0; j < compSize; j++) {\n dst[dIndex++] = src[sIndex++];\n }\n } else {\n // Decompress into blockBuf\n dIndex = exports.decompressBlock(src, dst, sIndex, compSize, dIndex);\n sIndex += compSize;\n }\n }\n\n if (useContentSum) {\n // TODO: read content checksum\n sIndex += 4;\n }\n\n return dIndex;\n};\n\n// Compresses data to an Lz4 frame.\nexports.compressFrame = function compressFrame (src, dst) {\n var dIndex = 0;\n\n // Write magic number.\n util.writeU32(dst, dIndex, magicNum);\n dIndex += 4;\n\n // Descriptor flags.\n dst[dIndex++] = fdVersion;\n dst[dIndex++] = bsDefault << bsShift;\n\n // Descriptor checksum.\n dst[dIndex] = xxhash.hash(0, dst, 4, dIndex - 4) >> 8;\n dIndex++;\n\n // Write blocks.\n var maxBlockSize = bsMap[bsDefault];\n var remaining = src.length;\n var sIndex = 0;\n\n // Clear the hashtable.\n clearHashTable(hashTable);\n\n // Split input into blocks and write.\n while (remaining > 0) {\n var compSize = 0;\n var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining;\n\n compSize = exports.compressBlock(src, blockBuf, sIndex, blockSize, hashTable);\n\n if (compSize > blockSize || compSize === 0) {\n // Output uncompressed.\n util.writeU32(dst, dIndex, 0x80000000 | blockSize);\n dIndex += 4;\n\n for (var z = sIndex + blockSize; sIndex < z;) {\n dst[dIndex++] = src[sIndex++];\n }\n\n remaining -= blockSize;\n } else {\n // Output compressed.\n util.writeU32(dst, dIndex, compSize);\n dIndex += 4;\n\n for (var j = 0; j < compSize;) {\n dst[dIndex++] = blockBuf[j++];\n }\n\n sIndex += blockSize;\n remaining -= blockSize;\n }\n }\n\n // Write blank end block.\n util.writeU32(dst, dIndex, 0);\n dIndex += 4;\n\n return dIndex;\n};\n\n// Decompresses a buffer containing an Lz4 frame. maxSize is optional; if not\n// provided, a maximum size will be determined by examining the data. The\n// buffer returned will always be perfectly-sized.\nexports.decompress = function decompress (src, maxSize) {\n var dst, size;\n\n if (maxSize === undefined) {\n maxSize = exports.decompressBound(src);\n }\n\n dst = exports.makeBuffer(maxSize);\n size = exports.decompressFrame(src, dst);\n\n if (size !== maxSize) {\n dst = sliceArray(dst, 0, size);\n }\n\n return dst;\n};\n\n// Compresses a buffer to an Lz4 frame. maxSize is optional; if not provided,\n// a buffer will be created based on the theoretical worst output size for a\n// given input size. The buffer returned will always be perfectly-sized.\nexports.compress = function compress (src, maxSize) {\n var dst, size;\n\n if (maxSize === undefined) {\n maxSize = exports.compressBound(src.length);\n }\n\n dst = exports.makeBuffer(maxSize);\n size = exports.compressFrame(src, dst);\n\n if (size !== maxSize) {\n dst = sliceArray(dst, 0, size);\n }\n\n return dst;\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/lz4js/lz4.js?"); + +/***/ }), + +/***/ "./node_modules/lz4js/util.js": +/*!************************************!*\ + !*** ./node_modules/lz4js/util.js ***! + \************************************/ +/***/ ((__unused_webpack_module, exports) => { + +eval("// Simple hash function, from: http://burtleburtle.net/bob/hash/integer.html.\n// Chosen because it doesn't use multiply and achieves full avalanche.\nexports.hashU32 = function hashU32 (a) {\n a = a | 0;\n a = a + 2127912214 + (a << 12) | 0;\n a = a ^ -949894596 ^ a >>> 19;\n a = a + 374761393 + (a << 5) | 0;\n a = a + -744332180 ^ a << 9;\n a = a + -42973499 + (a << 3) | 0;\n return a ^ -1252372727 ^ a >>> 16 | 0;\n};\n\n// Reads a 64-bit little-endian integer from an array.\nexports.readU64 = function readU64 (b, n) {\n var x = 0;\n x |= b[n++] << 0;\n x |= b[n++] << 8;\n x |= b[n++] << 16;\n x |= b[n++] << 24;\n x |= b[n++] << 32;\n x |= b[n++] << 40;\n x |= b[n++] << 48;\n x |= b[n++] << 56;\n return x;\n};\n\n// Reads a 32-bit little-endian integer from an array.\nexports.readU32 = function readU32 (b, n) {\n var x = 0;\n x |= b[n++] << 0;\n x |= b[n++] << 8;\n x |= b[n++] << 16;\n x |= b[n++] << 24;\n return x;\n};\n\n// Writes a 32-bit little-endian integer from an array.\nexports.writeU32 = function writeU32 (b, n, x) {\n b[n++] = (x >> 0) & 0xff;\n b[n++] = (x >> 8) & 0xff;\n b[n++] = (x >> 16) & 0xff;\n b[n++] = (x >> 24) & 0xff;\n};\n\n// Multiplies two numbers using 32-bit integer multiplication.\n// Algorithm from Emscripten.\nexports.imul = function imul (a, b) {\n var ah = a >>> 16;\n var al = a & 65535;\n var bh = b >>> 16;\n var bl = b & 65535;\n\n return al * bl + (ah * bl + al * bh << 16) | 0;\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/lz4js/util.js?"); + +/***/ }), + +/***/ "./node_modules/lz4js/xxh32.js": +/*!*************************************!*\ + !*** ./node_modules/lz4js/xxh32.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("// xxh32.js - implementation of xxhash32 in plain JavaScript\nvar util = __webpack_require__(/*! ./util.js */ \"./node_modules/lz4js/util.js\");\n\n// xxhash32 primes\nvar prime1 = 0x9e3779b1;\nvar prime2 = 0x85ebca77;\nvar prime3 = 0xc2b2ae3d;\nvar prime4 = 0x27d4eb2f;\nvar prime5 = 0x165667b1;\n\n// Utility functions/primitives\n// --\n\nfunction rotl32 (x, r) {\n x = x | 0;\n r = r | 0;\n\n return x >>> (32 - r | 0) | x << r | 0;\n}\n\nfunction rotmul32 (h, r, m) {\n h = h | 0;\n r = r | 0;\n m = m | 0;\n\n return util.imul(h >>> (32 - r | 0) | h << r, m) | 0;\n}\n\nfunction shiftxor32 (h, s) {\n h = h | 0;\n s = s | 0;\n\n return h >>> s ^ h | 0;\n}\n\n// Implementation\n// --\n\nfunction xxhapply (h, src, m0, s, m1) {\n return rotmul32(util.imul(src, m0) + h, s, m1);\n}\n\nfunction xxh1 (h, src, index) {\n return rotmul32((h + util.imul(src[index], prime5)), 11, prime1);\n}\n\nfunction xxh4 (h, src, index) {\n return xxhapply(h, util.readU32(src, index), prime3, 17, prime4);\n}\n\nfunction xxh16 (h, src, index) {\n return [\n xxhapply(h[0], util.readU32(src, index + 0), prime2, 13, prime1),\n xxhapply(h[1], util.readU32(src, index + 4), prime2, 13, prime1),\n xxhapply(h[2], util.readU32(src, index + 8), prime2, 13, prime1),\n xxhapply(h[3], util.readU32(src, index + 12), prime2, 13, prime1)\n ];\n}\n\nfunction xxh32 (seed, src, index, len) {\n var h, l;\n l = len;\n if (len >= 16) {\n h = [\n seed + prime1 + prime2,\n seed + prime2,\n seed,\n seed - prime1\n ];\n\n while (len >= 16) {\n h = xxh16(h, src, index);\n\n index += 16;\n len -= 16;\n }\n\n h = rotl32(h[0], 1) + rotl32(h[1], 7) + rotl32(h[2], 12) + rotl32(h[3], 18) + l;\n } else {\n h = (seed + prime5 + len) >>> 0;\n }\n\n while (len >= 4) {\n h = xxh4(h, src, index);\n\n index += 4;\n len -= 4;\n }\n\n while (len > 0) {\n h = xxh1(h, src, index);\n\n index++;\n len--;\n }\n\n h = shiftxor32(util.imul(shiftxor32(util.imul(shiftxor32(h, 15), prime2), 13), prime3), 16);\n\n return h >>> 0;\n}\n\nexports.hash = xxh32;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/lz4js/xxh32.js?"); + +/***/ }), + +/***/ "./node_modules/ms/index.js": +/*!**********************************!*\ + !*** ./node_modules/ms/index.js ***! + \**********************************/ +/***/ ((module) => { + +eval("/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/ms/index.js?"); + +/***/ }), + +/***/ "?83b6": +/*!*********************!*\ + !*** net (ignored) ***! + \*********************/ +/***/ (() => { + +eval("/* (ignored) */\n\n//# sourceURL=webpack://sqlitecloud/net_(ignored)?"); + +/***/ }), + +/***/ "?4235": +/*!*********************!*\ + !*** tls (ignored) ***! + \*********************/ +/***/ (() => { + +eval("/* (ignored) */\n\n//# sourceURL=webpack://sqlitecloud/tls_(ignored)?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/contrib/has-cors.js": +/*!*********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/contrib/has-cors.js ***! + \*********************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.hasCORS = void 0;\n// imported from https://github.com/component/has-cors\nlet value = false;\ntry {\n value = typeof XMLHttpRequest !== 'undefined' &&\n 'withCredentials' in new XMLHttpRequest();\n}\ncatch (err) {\n // if XMLHttp support is disabled in IE then it will throw\n // when trying to create\n}\nexports.hasCORS = value;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/contrib/has-cors.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/contrib/parseqs.js": +/*!********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/contrib/parseqs.js ***! + \********************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\n// imported from https://github.com/galkn/querystring\n/**\n * Compiles a querystring\n * Returns string representation of the object\n *\n * @param {Object}\n * @api private\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.decode = exports.encode = void 0;\nfunction encode(obj) {\n let str = '';\n for (let i in obj) {\n if (obj.hasOwnProperty(i)) {\n if (str.length)\n str += '&';\n str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);\n }\n }\n return str;\n}\nexports.encode = encode;\n/**\n * Parses a simple querystring into an object\n *\n * @param {String} qs\n * @api private\n */\nfunction decode(qs) {\n let qry = {};\n let pairs = qs.split('&');\n for (let i = 0, l = pairs.length; i < l; i++) {\n let pair = pairs[i].split('=');\n qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n }\n return qry;\n}\nexports.decode = decode;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/contrib/parseqs.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/contrib/parseuri.js": +/*!*********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/contrib/parseuri.js ***! + \*********************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.parse = void 0;\n// imported from https://github.com/galkn/parseuri\n/**\n * Parses a URI\n *\n * Note: we could also have used the built-in URL object, but it isn't supported on all platforms.\n *\n * See:\n * - https://developer.mozilla.org/en-US/docs/Web/API/URL\n * - https://caniuse.com/url\n * - https://www.rfc-editor.org/rfc/rfc3986#appendix-B\n *\n * History of the parse() method:\n * - first commit: https://github.com/socketio/socket.io-client/commit/4ee1d5d94b3906a9c052b459f1a818b15f38f91c\n * - export into its own module: https://github.com/socketio/engine.io-client/commit/de2c561e4564efeb78f1bdb1ba39ef81b2822cb3\n * - reimport: https://github.com/socketio/engine.io-client/commit/df32277c3f6d622eec5ed09f493cae3f3391d242\n *\n * @author Steven Levithan (MIT license)\n * @api private\n */\nconst re = /^(?:(?![^:@\\/?#]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@\\/?#]*)(?::([^:@\\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;\nconst parts = [\n 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'\n];\nfunction parse(str) {\n if (str.length > 2000) {\n throw \"URI too long\";\n }\n const src = str, b = str.indexOf('['), e = str.indexOf(']');\n if (b != -1 && e != -1) {\n str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);\n }\n let m = re.exec(str || ''), uri = {}, i = 14;\n while (i--) {\n uri[parts[i]] = m[i] || '';\n }\n if (b != -1 && e != -1) {\n uri.source = src;\n uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');\n uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');\n uri.ipv6uri = true;\n }\n uri.pathNames = pathNames(uri, uri['path']);\n uri.queryKey = queryKey(uri, uri['query']);\n return uri;\n}\nexports.parse = parse;\nfunction pathNames(obj, path) {\n const regx = /\\/{2,9}/g, names = path.replace(regx, \"/\").split(\"/\");\n if (path.slice(0, 1) == '/' || path.length === 0) {\n names.splice(0, 1);\n }\n if (path.slice(-1) == '/') {\n names.splice(names.length - 1, 1);\n }\n return names;\n}\nfunction queryKey(uri, query) {\n const data = {};\n query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) {\n if ($1) {\n data[$1] = $2;\n }\n });\n return data;\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/contrib/parseuri.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/contrib/yeast.js": +/*!******************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/contrib/yeast.js ***! + \******************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("// imported from https://github.com/unshiftio/yeast\n\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.yeast = exports.decode = exports.encode = void 0;\nconst alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''), length = 64, map = {};\nlet seed = 0, i = 0, prev;\n/**\n * Return a string representing the specified number.\n *\n * @param {Number} num The number to convert.\n * @returns {String} The string representation of the number.\n * @api public\n */\nfunction encode(num) {\n let encoded = '';\n do {\n encoded = alphabet[num % length] + encoded;\n num = Math.floor(num / length);\n } while (num > 0);\n return encoded;\n}\nexports.encode = encode;\n/**\n * Return the integer value specified by the given string.\n *\n * @param {String} str The string to convert.\n * @returns {Number} The integer value represented by the string.\n * @api public\n */\nfunction decode(str) {\n let decoded = 0;\n for (i = 0; i < str.length; i++) {\n decoded = decoded * length + map[str.charAt(i)];\n }\n return decoded;\n}\nexports.decode = decode;\n/**\n * Yeast: A tiny growing id generator.\n *\n * @returns {String} A unique id.\n * @api public\n */\nfunction yeast() {\n const now = encode(+new Date());\n if (now !== prev)\n return seed = 0, prev = now;\n return now + '.' + encode(seed++);\n}\nexports.yeast = yeast;\n//\n// Map each character to its index.\n//\nfor (; i < length; i++)\n map[alphabet[i]] = i;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/contrib/yeast.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/globalThis.browser.js": +/*!***********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/globalThis.browser.js ***! + \***********************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.globalThisShim = void 0;\nexports.globalThisShim = (() => {\n if (typeof self !== \"undefined\") {\n return self;\n }\n else if (typeof window !== \"undefined\") {\n return window;\n }\n else {\n return Function(\"return this\")();\n }\n})();\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/globalThis.browser.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/index.js": +/*!**********************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/index.js ***! + \**********************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.nextTick = exports.parse = exports.installTimerFunctions = exports.transports = exports.TransportError = exports.Transport = exports.protocol = exports.Socket = void 0;\nconst socket_js_1 = __webpack_require__(/*! ./socket.js */ \"./node_modules/engine.io-client/build/cjs/socket.js\");\nObject.defineProperty(exports, \"Socket\", ({ enumerable: true, get: function () { return socket_js_1.Socket; } }));\nexports.protocol = socket_js_1.Socket.protocol;\nvar transport_js_1 = __webpack_require__(/*! ./transport.js */ \"./node_modules/engine.io-client/build/cjs/transport.js\");\nObject.defineProperty(exports, \"Transport\", ({ enumerable: true, get: function () { return transport_js_1.Transport; } }));\nObject.defineProperty(exports, \"TransportError\", ({ enumerable: true, get: function () { return transport_js_1.TransportError; } }));\nvar index_js_1 = __webpack_require__(/*! ./transports/index.js */ \"./node_modules/engine.io-client/build/cjs/transports/index.js\");\nObject.defineProperty(exports, \"transports\", ({ enumerable: true, get: function () { return index_js_1.transports; } }));\nvar util_js_1 = __webpack_require__(/*! ./util.js */ \"./node_modules/engine.io-client/build/cjs/util.js\");\nObject.defineProperty(exports, \"installTimerFunctions\", ({ enumerable: true, get: function () { return util_js_1.installTimerFunctions; } }));\nvar parseuri_js_1 = __webpack_require__(/*! ./contrib/parseuri.js */ \"./node_modules/engine.io-client/build/cjs/contrib/parseuri.js\");\nObject.defineProperty(exports, \"parse\", ({ enumerable: true, get: function () { return parseuri_js_1.parse; } }));\nvar websocket_constructor_js_1 = __webpack_require__(/*! ./transports/websocket-constructor.js */ \"./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js\");\nObject.defineProperty(exports, \"nextTick\", ({ enumerable: true, get: function () { return websocket_constructor_js_1.nextTick; } }));\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/index.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/socket.js": +/*!***********************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/socket.js ***! + \***********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Socket = void 0;\nconst index_js_1 = __webpack_require__(/*! ./transports/index.js */ \"./node_modules/engine.io-client/build/cjs/transports/index.js\");\nconst util_js_1 = __webpack_require__(/*! ./util.js */ \"./node_modules/engine.io-client/build/cjs/util.js\");\nconst parseqs_js_1 = __webpack_require__(/*! ./contrib/parseqs.js */ \"./node_modules/engine.io-client/build/cjs/contrib/parseqs.js\");\nconst parseuri_js_1 = __webpack_require__(/*! ./contrib/parseuri.js */ \"./node_modules/engine.io-client/build/cjs/contrib/parseuri.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst engine_io_parser_1 = __webpack_require__(/*! engine.io-parser */ \"./node_modules/engine.io-parser/build/cjs/index.js\");\nconst websocket_constructor_js_1 = __webpack_require__(/*! ./transports/websocket-constructor.js */ \"./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js\");\nconst debug = (0, debug_1.default)(\"engine.io-client:socket\"); // debug()\nclass Socket extends component_emitter_1.Emitter {\n /**\n * Socket constructor.\n *\n * @param {String|Object} uri - uri or options\n * @param {Object} opts - options\n */\n constructor(uri, opts = {}) {\n super();\n this.binaryType = websocket_constructor_js_1.defaultBinaryType;\n this.writeBuffer = [];\n if (uri && \"object\" === typeof uri) {\n opts = uri;\n uri = null;\n }\n if (uri) {\n uri = (0, parseuri_js_1.parse)(uri);\n opts.hostname = uri.host;\n opts.secure = uri.protocol === \"https\" || uri.protocol === \"wss\";\n opts.port = uri.port;\n if (uri.query)\n opts.query = uri.query;\n }\n else if (opts.host) {\n opts.hostname = (0, parseuri_js_1.parse)(opts.host).host;\n }\n (0, util_js_1.installTimerFunctions)(this, opts);\n this.secure =\n null != opts.secure\n ? opts.secure\n : typeof location !== \"undefined\" && \"https:\" === location.protocol;\n if (opts.hostname && !opts.port) {\n // if no port is specified manually, use the protocol default\n opts.port = this.secure ? \"443\" : \"80\";\n }\n this.hostname =\n opts.hostname ||\n (typeof location !== \"undefined\" ? location.hostname : \"localhost\");\n this.port =\n opts.port ||\n (typeof location !== \"undefined\" && location.port\n ? location.port\n : this.secure\n ? \"443\"\n : \"80\");\n this.transports = opts.transports || [\n \"polling\",\n \"websocket\",\n \"webtransport\",\n ];\n this.writeBuffer = [];\n this.prevBufferLen = 0;\n this.opts = Object.assign({\n path: \"/engine.io\",\n agent: false,\n withCredentials: false,\n upgrade: true,\n timestampParam: \"t\",\n rememberUpgrade: false,\n addTrailingSlash: true,\n rejectUnauthorized: true,\n perMessageDeflate: {\n threshold: 1024,\n },\n transportOptions: {},\n closeOnBeforeunload: false,\n }, opts);\n this.opts.path =\n this.opts.path.replace(/\\/$/, \"\") +\n (this.opts.addTrailingSlash ? \"/\" : \"\");\n if (typeof this.opts.query === \"string\") {\n this.opts.query = (0, parseqs_js_1.decode)(this.opts.query);\n }\n // set on handshake\n this.id = null;\n this.upgrades = null;\n this.pingInterval = null;\n this.pingTimeout = null;\n // set on heartbeat\n this.pingTimeoutTimer = null;\n if (typeof addEventListener === \"function\") {\n if (this.opts.closeOnBeforeunload) {\n // Firefox closes the connection when the \"beforeunload\" event is emitted but not Chrome. This event listener\n // ensures every browser behaves the same (no \"disconnect\" event at the Socket.IO level when the page is\n // closed/reloaded)\n this.beforeunloadEventListener = () => {\n if (this.transport) {\n // silently close the transport\n this.transport.removeAllListeners();\n this.transport.close();\n }\n };\n addEventListener(\"beforeunload\", this.beforeunloadEventListener, false);\n }\n if (this.hostname !== \"localhost\") {\n this.offlineEventListener = () => {\n this.onClose(\"transport close\", {\n description: \"network connection lost\",\n });\n };\n addEventListener(\"offline\", this.offlineEventListener, false);\n }\n }\n this.open();\n }\n /**\n * Creates transport of the given type.\n *\n * @param {String} name - transport name\n * @return {Transport}\n * @private\n */\n createTransport(name) {\n debug('creating transport \"%s\"', name);\n const query = Object.assign({}, this.opts.query);\n // append engine.io protocol identifier\n query.EIO = engine_io_parser_1.protocol;\n // transport name\n query.transport = name;\n // session id if we already have one\n if (this.id)\n query.sid = this.id;\n const opts = Object.assign({}, this.opts, {\n query,\n socket: this,\n hostname: this.hostname,\n secure: this.secure,\n port: this.port,\n }, this.opts.transportOptions[name]);\n debug(\"options: %j\", opts);\n return new index_js_1.transports[name](opts);\n }\n /**\n * Initializes transport to use and starts probe.\n *\n * @private\n */\n open() {\n let transport;\n if (this.opts.rememberUpgrade &&\n Socket.priorWebsocketSuccess &&\n this.transports.indexOf(\"websocket\") !== -1) {\n transport = \"websocket\";\n }\n else if (0 === this.transports.length) {\n // Emit error on next tick so it can be listened to\n this.setTimeoutFn(() => {\n this.emitReserved(\"error\", \"No transports available\");\n }, 0);\n return;\n }\n else {\n transport = this.transports[0];\n }\n this.readyState = \"opening\";\n // Retry with the next transport if the transport is disabled (jsonp: false)\n try {\n transport = this.createTransport(transport);\n }\n catch (e) {\n debug(\"error while creating transport: %s\", e);\n this.transports.shift();\n this.open();\n return;\n }\n transport.open();\n this.setTransport(transport);\n }\n /**\n * Sets the current transport. Disables the existing one (if any).\n *\n * @private\n */\n setTransport(transport) {\n debug(\"setting transport %s\", transport.name);\n if (this.transport) {\n debug(\"clearing existing transport %s\", this.transport.name);\n this.transport.removeAllListeners();\n }\n // set up transport\n this.transport = transport;\n // set up transport listeners\n transport\n .on(\"drain\", this.onDrain.bind(this))\n .on(\"packet\", this.onPacket.bind(this))\n .on(\"error\", this.onError.bind(this))\n .on(\"close\", (reason) => this.onClose(\"transport close\", reason));\n }\n /**\n * Probes a transport.\n *\n * @param {String} name - transport name\n * @private\n */\n probe(name) {\n debug('probing transport \"%s\"', name);\n let transport = this.createTransport(name);\n let failed = false;\n Socket.priorWebsocketSuccess = false;\n const onTransportOpen = () => {\n if (failed)\n return;\n debug('probe transport \"%s\" opened', name);\n transport.send([{ type: \"ping\", data: \"probe\" }]);\n transport.once(\"packet\", (msg) => {\n if (failed)\n return;\n if (\"pong\" === msg.type && \"probe\" === msg.data) {\n debug('probe transport \"%s\" pong', name);\n this.upgrading = true;\n this.emitReserved(\"upgrading\", transport);\n if (!transport)\n return;\n Socket.priorWebsocketSuccess = \"websocket\" === transport.name;\n debug('pausing current transport \"%s\"', this.transport.name);\n this.transport.pause(() => {\n if (failed)\n return;\n if (\"closed\" === this.readyState)\n return;\n debug(\"changing transport and sending upgrade packet\");\n cleanup();\n this.setTransport(transport);\n transport.send([{ type: \"upgrade\" }]);\n this.emitReserved(\"upgrade\", transport);\n transport = null;\n this.upgrading = false;\n this.flush();\n });\n }\n else {\n debug('probe transport \"%s\" failed', name);\n const err = new Error(\"probe error\");\n // @ts-ignore\n err.transport = transport.name;\n this.emitReserved(\"upgradeError\", err);\n }\n });\n };\n function freezeTransport() {\n if (failed)\n return;\n // Any callback called by transport should be ignored since now\n failed = true;\n cleanup();\n transport.close();\n transport = null;\n }\n // Handle any error that happens while probing\n const onerror = (err) => {\n const error = new Error(\"probe error: \" + err);\n // @ts-ignore\n error.transport = transport.name;\n freezeTransport();\n debug('probe transport \"%s\" failed because of error: %s', name, err);\n this.emitReserved(\"upgradeError\", error);\n };\n function onTransportClose() {\n onerror(\"transport closed\");\n }\n // When the socket is closed while we're probing\n function onclose() {\n onerror(\"socket closed\");\n }\n // When the socket is upgraded while we're probing\n function onupgrade(to) {\n if (transport && to.name !== transport.name) {\n debug('\"%s\" works - aborting \"%s\"', to.name, transport.name);\n freezeTransport();\n }\n }\n // Remove all listeners on the transport and on self\n const cleanup = () => {\n transport.removeListener(\"open\", onTransportOpen);\n transport.removeListener(\"error\", onerror);\n transport.removeListener(\"close\", onTransportClose);\n this.off(\"close\", onclose);\n this.off(\"upgrading\", onupgrade);\n };\n transport.once(\"open\", onTransportOpen);\n transport.once(\"error\", onerror);\n transport.once(\"close\", onTransportClose);\n this.once(\"close\", onclose);\n this.once(\"upgrading\", onupgrade);\n if (this.upgrades.indexOf(\"webtransport\") !== -1 &&\n name !== \"webtransport\") {\n // favor WebTransport\n this.setTimeoutFn(() => {\n if (!failed) {\n transport.open();\n }\n }, 200);\n }\n else {\n transport.open();\n }\n }\n /**\n * Called when connection is deemed open.\n *\n * @private\n */\n onOpen() {\n debug(\"socket open\");\n this.readyState = \"open\";\n Socket.priorWebsocketSuccess = \"websocket\" === this.transport.name;\n this.emitReserved(\"open\");\n this.flush();\n // we check for `readyState` in case an `open`\n // listener already closed the socket\n if (\"open\" === this.readyState && this.opts.upgrade) {\n debug(\"starting upgrade probes\");\n let i = 0;\n const l = this.upgrades.length;\n for (; i < l; i++) {\n this.probe(this.upgrades[i]);\n }\n }\n }\n /**\n * Handles a packet.\n *\n * @private\n */\n onPacket(packet) {\n if (\"opening\" === this.readyState ||\n \"open\" === this.readyState ||\n \"closing\" === this.readyState) {\n debug('socket receive: type \"%s\", data \"%s\"', packet.type, packet.data);\n this.emitReserved(\"packet\", packet);\n // Socket is live - any packet counts\n this.emitReserved(\"heartbeat\");\n this.resetPingTimeout();\n switch (packet.type) {\n case \"open\":\n this.onHandshake(JSON.parse(packet.data));\n break;\n case \"ping\":\n this.sendPacket(\"pong\");\n this.emitReserved(\"ping\");\n this.emitReserved(\"pong\");\n break;\n case \"error\":\n const err = new Error(\"server error\");\n // @ts-ignore\n err.code = packet.data;\n this.onError(err);\n break;\n case \"message\":\n this.emitReserved(\"data\", packet.data);\n this.emitReserved(\"message\", packet.data);\n break;\n }\n }\n else {\n debug('packet received with socket readyState \"%s\"', this.readyState);\n }\n }\n /**\n * Called upon handshake completion.\n *\n * @param {Object} data - handshake obj\n * @private\n */\n onHandshake(data) {\n this.emitReserved(\"handshake\", data);\n this.id = data.sid;\n this.transport.query.sid = data.sid;\n this.upgrades = this.filterUpgrades(data.upgrades);\n this.pingInterval = data.pingInterval;\n this.pingTimeout = data.pingTimeout;\n this.maxPayload = data.maxPayload;\n this.onOpen();\n // In case open handler closes socket\n if (\"closed\" === this.readyState)\n return;\n this.resetPingTimeout();\n }\n /**\n * Sets and resets ping timeout timer based on server pings.\n *\n * @private\n */\n resetPingTimeout() {\n this.clearTimeoutFn(this.pingTimeoutTimer);\n this.pingTimeoutTimer = this.setTimeoutFn(() => {\n this.onClose(\"ping timeout\");\n }, this.pingInterval + this.pingTimeout);\n if (this.opts.autoUnref) {\n this.pingTimeoutTimer.unref();\n }\n }\n /**\n * Called on `drain` event\n *\n * @private\n */\n onDrain() {\n this.writeBuffer.splice(0, this.prevBufferLen);\n // setting prevBufferLen = 0 is very important\n // for example, when upgrading, upgrade packet is sent over,\n // and a nonzero prevBufferLen could cause problems on `drain`\n this.prevBufferLen = 0;\n if (0 === this.writeBuffer.length) {\n this.emitReserved(\"drain\");\n }\n else {\n this.flush();\n }\n }\n /**\n * Flush write buffers.\n *\n * @private\n */\n flush() {\n if (\"closed\" !== this.readyState &&\n this.transport.writable &&\n !this.upgrading &&\n this.writeBuffer.length) {\n const packets = this.getWritablePackets();\n debug(\"flushing %d packets in socket\", packets.length);\n this.transport.send(packets);\n // keep track of current length of writeBuffer\n // splice writeBuffer and callbackBuffer on `drain`\n this.prevBufferLen = packets.length;\n this.emitReserved(\"flush\");\n }\n }\n /**\n * Ensure the encoded size of the writeBuffer is below the maxPayload value sent by the server (only for HTTP\n * long-polling)\n *\n * @private\n */\n getWritablePackets() {\n const shouldCheckPayloadSize = this.maxPayload &&\n this.transport.name === \"polling\" &&\n this.writeBuffer.length > 1;\n if (!shouldCheckPayloadSize) {\n return this.writeBuffer;\n }\n let payloadSize = 1; // first packet type\n for (let i = 0; i < this.writeBuffer.length; i++) {\n const data = this.writeBuffer[i].data;\n if (data) {\n payloadSize += (0, util_js_1.byteLength)(data);\n }\n if (i > 0 && payloadSize > this.maxPayload) {\n debug(\"only send %d out of %d packets\", i, this.writeBuffer.length);\n return this.writeBuffer.slice(0, i);\n }\n payloadSize += 2; // separator + packet type\n }\n debug(\"payload size is %d (max: %d)\", payloadSize, this.maxPayload);\n return this.writeBuffer;\n }\n /**\n * Sends a message.\n *\n * @param {String} msg - message.\n * @param {Object} options.\n * @param {Function} callback function.\n * @return {Socket} for chaining.\n */\n write(msg, options, fn) {\n this.sendPacket(\"message\", msg, options, fn);\n return this;\n }\n send(msg, options, fn) {\n this.sendPacket(\"message\", msg, options, fn);\n return this;\n }\n /**\n * Sends a packet.\n *\n * @param {String} type: packet type.\n * @param {String} data.\n * @param {Object} options.\n * @param {Function} fn - callback function.\n * @private\n */\n sendPacket(type, data, options, fn) {\n if (\"function\" === typeof data) {\n fn = data;\n data = undefined;\n }\n if (\"function\" === typeof options) {\n fn = options;\n options = null;\n }\n if (\"closing\" === this.readyState || \"closed\" === this.readyState) {\n return;\n }\n options = options || {};\n options.compress = false !== options.compress;\n const packet = {\n type: type,\n data: data,\n options: options,\n };\n this.emitReserved(\"packetCreate\", packet);\n this.writeBuffer.push(packet);\n if (fn)\n this.once(\"flush\", fn);\n this.flush();\n }\n /**\n * Closes the connection.\n */\n close() {\n const close = () => {\n this.onClose(\"forced close\");\n debug(\"socket closing - telling transport to close\");\n this.transport.close();\n };\n const cleanupAndClose = () => {\n this.off(\"upgrade\", cleanupAndClose);\n this.off(\"upgradeError\", cleanupAndClose);\n close();\n };\n const waitForUpgrade = () => {\n // wait for upgrade to finish since we can't send packets while pausing a transport\n this.once(\"upgrade\", cleanupAndClose);\n this.once(\"upgradeError\", cleanupAndClose);\n };\n if (\"opening\" === this.readyState || \"open\" === this.readyState) {\n this.readyState = \"closing\";\n if (this.writeBuffer.length) {\n this.once(\"drain\", () => {\n if (this.upgrading) {\n waitForUpgrade();\n }\n else {\n close();\n }\n });\n }\n else if (this.upgrading) {\n waitForUpgrade();\n }\n else {\n close();\n }\n }\n return this;\n }\n /**\n * Called upon transport error\n *\n * @private\n */\n onError(err) {\n debug(\"socket error %j\", err);\n Socket.priorWebsocketSuccess = false;\n this.emitReserved(\"error\", err);\n this.onClose(\"transport error\", err);\n }\n /**\n * Called upon transport close.\n *\n * @private\n */\n onClose(reason, description) {\n if (\"opening\" === this.readyState ||\n \"open\" === this.readyState ||\n \"closing\" === this.readyState) {\n debug('socket close with reason: \"%s\"', reason);\n // clear timers\n this.clearTimeoutFn(this.pingTimeoutTimer);\n // stop event from firing again for transport\n this.transport.removeAllListeners(\"close\");\n // ensure transport won't stay open\n this.transport.close();\n // ignore further transport communication\n this.transport.removeAllListeners();\n if (typeof removeEventListener === \"function\") {\n removeEventListener(\"beforeunload\", this.beforeunloadEventListener, false);\n removeEventListener(\"offline\", this.offlineEventListener, false);\n }\n // set ready state\n this.readyState = \"closed\";\n // clear session id\n this.id = null;\n // emit close event\n this.emitReserved(\"close\", reason, description);\n // clean buffers after, so users can still\n // grab the buffers on `close` event\n this.writeBuffer = [];\n this.prevBufferLen = 0;\n }\n }\n /**\n * Filters upgrades, returning only those matching client transports.\n *\n * @param {Array} upgrades - server upgrades\n * @private\n */\n filterUpgrades(upgrades) {\n const filteredUpgrades = [];\n let i = 0;\n const j = upgrades.length;\n for (; i < j; i++) {\n if (~this.transports.indexOf(upgrades[i]))\n filteredUpgrades.push(upgrades[i]);\n }\n return filteredUpgrades;\n }\n}\nexports.Socket = Socket;\nSocket.protocol = engine_io_parser_1.protocol;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/socket.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transport.js": +/*!**************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transport.js ***! + \**************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Transport = exports.TransportError = void 0;\nconst engine_io_parser_1 = __webpack_require__(/*! engine.io-parser */ \"./node_modules/engine.io-parser/build/cjs/index.js\");\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst util_js_1 = __webpack_require__(/*! ./util.js */ \"./node_modules/engine.io-client/build/cjs/util.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst parseqs_js_1 = __webpack_require__(/*! ./contrib/parseqs.js */ \"./node_modules/engine.io-client/build/cjs/contrib/parseqs.js\");\nconst debug = (0, debug_1.default)(\"engine.io-client:transport\"); // debug()\nclass TransportError extends Error {\n constructor(reason, description, context) {\n super(reason);\n this.description = description;\n this.context = context;\n this.type = \"TransportError\";\n }\n}\nexports.TransportError = TransportError;\nclass Transport extends component_emitter_1.Emitter {\n /**\n * Transport abstract constructor.\n *\n * @param {Object} opts - options\n * @protected\n */\n constructor(opts) {\n super();\n this.writable = false;\n (0, util_js_1.installTimerFunctions)(this, opts);\n this.opts = opts;\n this.query = opts.query;\n this.socket = opts.socket;\n }\n /**\n * Emits an error.\n *\n * @param {String} reason\n * @param description\n * @param context - the error context\n * @return {Transport} for chaining\n * @protected\n */\n onError(reason, description, context) {\n super.emitReserved(\"error\", new TransportError(reason, description, context));\n return this;\n }\n /**\n * Opens the transport.\n */\n open() {\n this.readyState = \"opening\";\n this.doOpen();\n return this;\n }\n /**\n * Closes the transport.\n */\n close() {\n if (this.readyState === \"opening\" || this.readyState === \"open\") {\n this.doClose();\n this.onClose();\n }\n return this;\n }\n /**\n * Sends multiple packets.\n *\n * @param {Array} packets\n */\n send(packets) {\n if (this.readyState === \"open\") {\n this.write(packets);\n }\n else {\n // this might happen if the transport was silently closed in the beforeunload event handler\n debug(\"transport is not open, discarding packets\");\n }\n }\n /**\n * Called upon open\n *\n * @protected\n */\n onOpen() {\n this.readyState = \"open\";\n this.writable = true;\n super.emitReserved(\"open\");\n }\n /**\n * Called with data.\n *\n * @param {String} data\n * @protected\n */\n onData(data) {\n const packet = (0, engine_io_parser_1.decodePacket)(data, this.socket.binaryType);\n this.onPacket(packet);\n }\n /**\n * Called with a decoded packet.\n *\n * @protected\n */\n onPacket(packet) {\n super.emitReserved(\"packet\", packet);\n }\n /**\n * Called upon close.\n *\n * @protected\n */\n onClose(details) {\n this.readyState = \"closed\";\n super.emitReserved(\"close\", details);\n }\n /**\n * Pauses the transport, in order not to lose packets during an upgrade.\n *\n * @param onPause\n */\n pause(onPause) { }\n createUri(schema, query = {}) {\n return (schema +\n \"://\" +\n this._hostname() +\n this._port() +\n this.opts.path +\n this._query(query));\n }\n _hostname() {\n const hostname = this.opts.hostname;\n return hostname.indexOf(\":\") === -1 ? hostname : \"[\" + hostname + \"]\";\n }\n _port() {\n if (this.opts.port &&\n ((this.opts.secure && Number(this.opts.port !== 443)) ||\n (!this.opts.secure && Number(this.opts.port) !== 80))) {\n return \":\" + this.opts.port;\n }\n else {\n return \"\";\n }\n }\n _query(query) {\n const encodedQuery = (0, parseqs_js_1.encode)(query);\n return encodedQuery.length ? \"?\" + encodedQuery : \"\";\n }\n}\nexports.Transport = Transport;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transport.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/index.js": +/*!*********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/index.js ***! + \*********************************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.transports = void 0;\nconst polling_js_1 = __webpack_require__(/*! ./polling.js */ \"./node_modules/engine.io-client/build/cjs/transports/polling.js\");\nconst websocket_js_1 = __webpack_require__(/*! ./websocket.js */ \"./node_modules/engine.io-client/build/cjs/transports/websocket.js\");\nconst webtransport_js_1 = __webpack_require__(/*! ./webtransport.js */ \"./node_modules/engine.io-client/build/cjs/transports/webtransport.js\");\nexports.transports = {\n websocket: websocket_js_1.WS,\n webtransport: webtransport_js_1.WT,\n polling: polling_js_1.Polling,\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/index.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/polling.js": +/*!***********************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/polling.js ***! + \***********************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Request = exports.Polling = void 0;\nconst transport_js_1 = __webpack_require__(/*! ../transport.js */ \"./node_modules/engine.io-client/build/cjs/transport.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst yeast_js_1 = __webpack_require__(/*! ../contrib/yeast.js */ \"./node_modules/engine.io-client/build/cjs/contrib/yeast.js\");\nconst engine_io_parser_1 = __webpack_require__(/*! engine.io-parser */ \"./node_modules/engine.io-parser/build/cjs/index.js\");\nconst xmlhttprequest_js_1 = __webpack_require__(/*! ./xmlhttprequest.js */ \"./node_modules/engine.io-client/build/cjs/transports/xmlhttprequest.browser.js\");\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst util_js_1 = __webpack_require__(/*! ../util.js */ \"./node_modules/engine.io-client/build/cjs/util.js\");\nconst globalThis_js_1 = __webpack_require__(/*! ../globalThis.js */ \"./node_modules/engine.io-client/build/cjs/globalThis.browser.js\");\nconst debug = (0, debug_1.default)(\"engine.io-client:polling\"); // debug()\nfunction empty() { }\nconst hasXHR2 = (function () {\n const xhr = new xmlhttprequest_js_1.XHR({\n xdomain: false,\n });\n return null != xhr.responseType;\n})();\nclass Polling extends transport_js_1.Transport {\n /**\n * XHR Polling constructor.\n *\n * @param {Object} opts\n * @package\n */\n constructor(opts) {\n super(opts);\n this.polling = false;\n if (typeof location !== \"undefined\") {\n const isSSL = \"https:\" === location.protocol;\n let port = location.port;\n // some user agents have empty `location.port`\n if (!port) {\n port = isSSL ? \"443\" : \"80\";\n }\n this.xd =\n (typeof location !== \"undefined\" &&\n opts.hostname !== location.hostname) ||\n port !== opts.port;\n }\n /**\n * XHR supports binary\n */\n const forceBase64 = opts && opts.forceBase64;\n this.supportsBinary = hasXHR2 && !forceBase64;\n if (this.opts.withCredentials) {\n this.cookieJar = (0, xmlhttprequest_js_1.createCookieJar)();\n }\n }\n get name() {\n return \"polling\";\n }\n /**\n * Opens the socket (triggers polling). We write a PING message to determine\n * when the transport is open.\n *\n * @protected\n */\n doOpen() {\n this.poll();\n }\n /**\n * Pauses polling.\n *\n * @param {Function} onPause - callback upon buffers are flushed and transport is paused\n * @package\n */\n pause(onPause) {\n this.readyState = \"pausing\";\n const pause = () => {\n debug(\"paused\");\n this.readyState = \"paused\";\n onPause();\n };\n if (this.polling || !this.writable) {\n let total = 0;\n if (this.polling) {\n debug(\"we are currently polling - waiting to pause\");\n total++;\n this.once(\"pollComplete\", function () {\n debug(\"pre-pause polling complete\");\n --total || pause();\n });\n }\n if (!this.writable) {\n debug(\"we are currently writing - waiting to pause\");\n total++;\n this.once(\"drain\", function () {\n debug(\"pre-pause writing complete\");\n --total || pause();\n });\n }\n }\n else {\n pause();\n }\n }\n /**\n * Starts polling cycle.\n *\n * @private\n */\n poll() {\n debug(\"polling\");\n this.polling = true;\n this.doPoll();\n this.emitReserved(\"poll\");\n }\n /**\n * Overloads onData to detect payloads.\n *\n * @protected\n */\n onData(data) {\n debug(\"polling got data %s\", data);\n const callback = (packet) => {\n // if its the first message we consider the transport open\n if (\"opening\" === this.readyState && packet.type === \"open\") {\n this.onOpen();\n }\n // if its a close packet, we close the ongoing requests\n if (\"close\" === packet.type) {\n this.onClose({ description: \"transport closed by the server\" });\n return false;\n }\n // otherwise bypass onData and handle the message\n this.onPacket(packet);\n };\n // decode payload\n (0, engine_io_parser_1.decodePayload)(data, this.socket.binaryType).forEach(callback);\n // if an event did not trigger closing\n if (\"closed\" !== this.readyState) {\n // if we got data we're not polling\n this.polling = false;\n this.emitReserved(\"pollComplete\");\n if (\"open\" === this.readyState) {\n this.poll();\n }\n else {\n debug('ignoring poll - transport state \"%s\"', this.readyState);\n }\n }\n }\n /**\n * For polling, send a close packet.\n *\n * @protected\n */\n doClose() {\n const close = () => {\n debug(\"writing close packet\");\n this.write([{ type: \"close\" }]);\n };\n if (\"open\" === this.readyState) {\n debug(\"transport open - closing\");\n close();\n }\n else {\n // in case we're trying to close while\n // handshaking is in progress (GH-164)\n debug(\"transport not open - deferring close\");\n this.once(\"open\", close);\n }\n }\n /**\n * Writes a packets payload.\n *\n * @param {Array} packets - data packets\n * @protected\n */\n write(packets) {\n this.writable = false;\n (0, engine_io_parser_1.encodePayload)(packets, (data) => {\n this.doWrite(data, () => {\n this.writable = true;\n this.emitReserved(\"drain\");\n });\n });\n }\n /**\n * Generates uri for connection.\n *\n * @private\n */\n uri() {\n const schema = this.opts.secure ? \"https\" : \"http\";\n const query = this.query || {};\n // cache busting is forced\n if (false !== this.opts.timestampRequests) {\n query[this.opts.timestampParam] = (0, yeast_js_1.yeast)();\n }\n if (!this.supportsBinary && !query.sid) {\n query.b64 = 1;\n }\n return this.createUri(schema, query);\n }\n /**\n * Creates a request.\n *\n * @param {String} method\n * @private\n */\n request(opts = {}) {\n Object.assign(opts, { xd: this.xd, cookieJar: this.cookieJar }, this.opts);\n return new Request(this.uri(), opts);\n }\n /**\n * Sends data.\n *\n * @param {String} data to send.\n * @param {Function} called upon flush.\n * @private\n */\n doWrite(data, fn) {\n const req = this.request({\n method: \"POST\",\n data: data,\n });\n req.on(\"success\", fn);\n req.on(\"error\", (xhrStatus, context) => {\n this.onError(\"xhr post error\", xhrStatus, context);\n });\n }\n /**\n * Starts a poll cycle.\n *\n * @private\n */\n doPoll() {\n debug(\"xhr poll\");\n const req = this.request();\n req.on(\"data\", this.onData.bind(this));\n req.on(\"error\", (xhrStatus, context) => {\n this.onError(\"xhr poll error\", xhrStatus, context);\n });\n this.pollXhr = req;\n }\n}\nexports.Polling = Polling;\nclass Request extends component_emitter_1.Emitter {\n /**\n * Request constructor\n *\n * @param {Object} options\n * @package\n */\n constructor(uri, opts) {\n super();\n (0, util_js_1.installTimerFunctions)(this, opts);\n this.opts = opts;\n this.method = opts.method || \"GET\";\n this.uri = uri;\n this.data = undefined !== opts.data ? opts.data : null;\n this.create();\n }\n /**\n * Creates the XHR object and sends the request.\n *\n * @private\n */\n create() {\n var _a;\n const opts = (0, util_js_1.pick)(this.opts, \"agent\", \"pfx\", \"key\", \"passphrase\", \"cert\", \"ca\", \"ciphers\", \"rejectUnauthorized\", \"autoUnref\");\n opts.xdomain = !!this.opts.xd;\n const xhr = (this.xhr = new xmlhttprequest_js_1.XHR(opts));\n try {\n debug(\"xhr open %s: %s\", this.method, this.uri);\n xhr.open(this.method, this.uri, true);\n try {\n if (this.opts.extraHeaders) {\n xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);\n for (let i in this.opts.extraHeaders) {\n if (this.opts.extraHeaders.hasOwnProperty(i)) {\n xhr.setRequestHeader(i, this.opts.extraHeaders[i]);\n }\n }\n }\n }\n catch (e) { }\n if (\"POST\" === this.method) {\n try {\n xhr.setRequestHeader(\"Content-type\", \"text/plain;charset=UTF-8\");\n }\n catch (e) { }\n }\n try {\n xhr.setRequestHeader(\"Accept\", \"*/*\");\n }\n catch (e) { }\n (_a = this.opts.cookieJar) === null || _a === void 0 ? void 0 : _a.addCookies(xhr);\n // ie6 check\n if (\"withCredentials\" in xhr) {\n xhr.withCredentials = this.opts.withCredentials;\n }\n if (this.opts.requestTimeout) {\n xhr.timeout = this.opts.requestTimeout;\n }\n xhr.onreadystatechange = () => {\n var _a;\n if (xhr.readyState === 3) {\n (_a = this.opts.cookieJar) === null || _a === void 0 ? void 0 : _a.parseCookies(xhr);\n }\n if (4 !== xhr.readyState)\n return;\n if (200 === xhr.status || 1223 === xhr.status) {\n this.onLoad();\n }\n else {\n // make sure the `error` event handler that's user-set\n // does not throw in the same tick and gets caught here\n this.setTimeoutFn(() => {\n this.onError(typeof xhr.status === \"number\" ? xhr.status : 0);\n }, 0);\n }\n };\n debug(\"xhr data %s\", this.data);\n xhr.send(this.data);\n }\n catch (e) {\n // Need to defer since .create() is called directly from the constructor\n // and thus the 'error' event can only be only bound *after* this exception\n // occurs. Therefore, also, we cannot throw here at all.\n this.setTimeoutFn(() => {\n this.onError(e);\n }, 0);\n return;\n }\n if (typeof document !== \"undefined\") {\n this.index = Request.requestsCount++;\n Request.requests[this.index] = this;\n }\n }\n /**\n * Called upon error.\n *\n * @private\n */\n onError(err) {\n this.emitReserved(\"error\", err, this.xhr);\n this.cleanup(true);\n }\n /**\n * Cleans up house.\n *\n * @private\n */\n cleanup(fromError) {\n if (\"undefined\" === typeof this.xhr || null === this.xhr) {\n return;\n }\n this.xhr.onreadystatechange = empty;\n if (fromError) {\n try {\n this.xhr.abort();\n }\n catch (e) { }\n }\n if (typeof document !== \"undefined\") {\n delete Request.requests[this.index];\n }\n this.xhr = null;\n }\n /**\n * Called upon load.\n *\n * @private\n */\n onLoad() {\n const data = this.xhr.responseText;\n if (data !== null) {\n this.emitReserved(\"data\", data);\n this.emitReserved(\"success\");\n this.cleanup();\n }\n }\n /**\n * Aborts the request.\n *\n * @package\n */\n abort() {\n this.cleanup();\n }\n}\nexports.Request = Request;\nRequest.requestsCount = 0;\nRequest.requests = {};\n/**\n * Aborts pending requests when unloading the window. This is needed to prevent\n * memory leaks (e.g. when using IE) and to ensure that no spurious error is\n * emitted.\n */\nif (typeof document !== \"undefined\") {\n // @ts-ignore\n if (typeof attachEvent === \"function\") {\n // @ts-ignore\n attachEvent(\"onunload\", unloadHandler);\n }\n else if (typeof addEventListener === \"function\") {\n const terminationEvent = \"onpagehide\" in globalThis_js_1.globalThisShim ? \"pagehide\" : \"unload\";\n addEventListener(terminationEvent, unloadHandler, false);\n }\n}\nfunction unloadHandler() {\n for (let i in Request.requests) {\n if (Request.requests.hasOwnProperty(i)) {\n Request.requests[i].abort();\n }\n }\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/polling.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js": +/*!*********************************************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js ***! + \*********************************************************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.defaultBinaryType = exports.usingBrowserWebSocket = exports.WebSocket = exports.nextTick = void 0;\nconst globalThis_js_1 = __webpack_require__(/*! ../globalThis.js */ \"./node_modules/engine.io-client/build/cjs/globalThis.browser.js\");\nexports.nextTick = (() => {\n const isPromiseAvailable = typeof Promise === \"function\" && typeof Promise.resolve === \"function\";\n if (isPromiseAvailable) {\n return (cb) => Promise.resolve().then(cb);\n }\n else {\n return (cb, setTimeoutFn) => setTimeoutFn(cb, 0);\n }\n})();\nexports.WebSocket = globalThis_js_1.globalThisShim.WebSocket || globalThis_js_1.globalThisShim.MozWebSocket;\nexports.usingBrowserWebSocket = true;\nexports.defaultBinaryType = \"arraybuffer\";\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/websocket.js": +/*!*************************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/websocket.js ***! + \*************************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.WS = void 0;\nconst transport_js_1 = __webpack_require__(/*! ../transport.js */ \"./node_modules/engine.io-client/build/cjs/transport.js\");\nconst yeast_js_1 = __webpack_require__(/*! ../contrib/yeast.js */ \"./node_modules/engine.io-client/build/cjs/contrib/yeast.js\");\nconst util_js_1 = __webpack_require__(/*! ../util.js */ \"./node_modules/engine.io-client/build/cjs/util.js\");\nconst websocket_constructor_js_1 = __webpack_require__(/*! ./websocket-constructor.js */ \"./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst engine_io_parser_1 = __webpack_require__(/*! engine.io-parser */ \"./node_modules/engine.io-parser/build/cjs/index.js\");\nconst debug = (0, debug_1.default)(\"engine.io-client:websocket\"); // debug()\n// detect ReactNative environment\nconst isReactNative = typeof navigator !== \"undefined\" &&\n typeof navigator.product === \"string\" &&\n navigator.product.toLowerCase() === \"reactnative\";\nclass WS extends transport_js_1.Transport {\n /**\n * WebSocket transport constructor.\n *\n * @param {Object} opts - connection options\n * @protected\n */\n constructor(opts) {\n super(opts);\n this.supportsBinary = !opts.forceBase64;\n }\n get name() {\n return \"websocket\";\n }\n doOpen() {\n if (!this.check()) {\n // let probe timeout\n return;\n }\n const uri = this.uri();\n const protocols = this.opts.protocols;\n // React Native only supports the 'headers' option, and will print a warning if anything else is passed\n const opts = isReactNative\n ? {}\n : (0, util_js_1.pick)(this.opts, \"agent\", \"perMessageDeflate\", \"pfx\", \"key\", \"passphrase\", \"cert\", \"ca\", \"ciphers\", \"rejectUnauthorized\", \"localAddress\", \"protocolVersion\", \"origin\", \"maxPayload\", \"family\", \"checkServerIdentity\");\n if (this.opts.extraHeaders) {\n opts.headers = this.opts.extraHeaders;\n }\n try {\n this.ws =\n websocket_constructor_js_1.usingBrowserWebSocket && !isReactNative\n ? protocols\n ? new websocket_constructor_js_1.WebSocket(uri, protocols)\n : new websocket_constructor_js_1.WebSocket(uri)\n : new websocket_constructor_js_1.WebSocket(uri, protocols, opts);\n }\n catch (err) {\n return this.emitReserved(\"error\", err);\n }\n this.ws.binaryType = this.socket.binaryType;\n this.addEventListeners();\n }\n /**\n * Adds event listeners to the socket\n *\n * @private\n */\n addEventListeners() {\n this.ws.onopen = () => {\n if (this.opts.autoUnref) {\n this.ws._socket.unref();\n }\n this.onOpen();\n };\n this.ws.onclose = (closeEvent) => this.onClose({\n description: \"websocket connection closed\",\n context: closeEvent,\n });\n this.ws.onmessage = (ev) => this.onData(ev.data);\n this.ws.onerror = (e) => this.onError(\"websocket error\", e);\n }\n write(packets) {\n this.writable = false;\n // encodePacket efficient as it uses WS framing\n // no need for encodePayload\n for (let i = 0; i < packets.length; i++) {\n const packet = packets[i];\n const lastPacket = i === packets.length - 1;\n (0, engine_io_parser_1.encodePacket)(packet, this.supportsBinary, (data) => {\n // always create a new object (GH-437)\n const opts = {};\n if (!websocket_constructor_js_1.usingBrowserWebSocket) {\n if (packet.options) {\n opts.compress = packet.options.compress;\n }\n if (this.opts.perMessageDeflate) {\n const len = \n // @ts-ignore\n \"string\" === typeof data ? Buffer.byteLength(data) : data.length;\n if (len < this.opts.perMessageDeflate.threshold) {\n opts.compress = false;\n }\n }\n }\n // Sometimes the websocket has already been closed but the browser didn't\n // have a chance of informing us about it yet, in that case send will\n // throw an error\n try {\n if (websocket_constructor_js_1.usingBrowserWebSocket) {\n // TypeError is thrown when passing the second argument on Safari\n this.ws.send(data);\n }\n else {\n this.ws.send(data, opts);\n }\n }\n catch (e) {\n debug(\"websocket closed before onclose event\");\n }\n if (lastPacket) {\n // fake drain\n // defer to next tick to allow Socket to clear writeBuffer\n (0, websocket_constructor_js_1.nextTick)(() => {\n this.writable = true;\n this.emitReserved(\"drain\");\n }, this.setTimeoutFn);\n }\n });\n }\n }\n doClose() {\n if (typeof this.ws !== \"undefined\") {\n this.ws.close();\n this.ws = null;\n }\n }\n /**\n * Generates uri for connection.\n *\n * @private\n */\n uri() {\n const schema = this.opts.secure ? \"wss\" : \"ws\";\n const query = this.query || {};\n // append timestamp to URI\n if (this.opts.timestampRequests) {\n query[this.opts.timestampParam] = (0, yeast_js_1.yeast)();\n }\n // communicate binary support capabilities\n if (!this.supportsBinary) {\n query.b64 = 1;\n }\n return this.createUri(schema, query);\n }\n /**\n * Feature detection for WebSocket.\n *\n * @return {Boolean} whether this transport is available.\n * @private\n */\n check() {\n return !!websocket_constructor_js_1.WebSocket;\n }\n}\nexports.WS = WS;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/websocket.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/webtransport.js": +/*!****************************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/webtransport.js ***! + \****************************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.WT = void 0;\nconst transport_js_1 = __webpack_require__(/*! ../transport.js */ \"./node_modules/engine.io-client/build/cjs/transport.js\");\nconst websocket_constructor_js_1 = __webpack_require__(/*! ./websocket-constructor.js */ \"./node_modules/engine.io-client/build/cjs/transports/websocket-constructor.browser.js\");\nconst engine_io_parser_1 = __webpack_require__(/*! engine.io-parser */ \"./node_modules/engine.io-parser/build/cjs/index.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst debug = (0, debug_1.default)(\"engine.io-client:webtransport\"); // debug()\nclass WT extends transport_js_1.Transport {\n get name() {\n return \"webtransport\";\n }\n doOpen() {\n // @ts-ignore\n if (typeof WebTransport !== \"function\") {\n return;\n }\n // @ts-ignore\n this.transport = new WebTransport(this.createUri(\"https\"), this.opts.transportOptions[this.name]);\n this.transport.closed\n .then(() => {\n debug(\"transport closed gracefully\");\n this.onClose();\n })\n .catch((err) => {\n debug(\"transport closed due to %s\", err);\n this.onError(\"webtransport error\", err);\n });\n // note: we could have used async/await, but that would require some additional polyfills\n this.transport.ready.then(() => {\n this.transport.createBidirectionalStream().then((stream) => {\n const decoderStream = (0, engine_io_parser_1.createPacketDecoderStream)(Number.MAX_SAFE_INTEGER, this.socket.binaryType);\n const reader = stream.readable.pipeThrough(decoderStream).getReader();\n const encoderStream = (0, engine_io_parser_1.createPacketEncoderStream)();\n encoderStream.readable.pipeTo(stream.writable);\n this.writer = encoderStream.writable.getWriter();\n const read = () => {\n reader\n .read()\n .then(({ done, value }) => {\n if (done) {\n debug(\"session is closed\");\n return;\n }\n debug(\"received chunk: %o\", value);\n this.onPacket(value);\n read();\n })\n .catch((err) => {\n debug(\"an error occurred while reading: %s\", err);\n });\n };\n read();\n const packet = { type: \"open\" };\n if (this.query.sid) {\n packet.data = `{\"sid\":\"${this.query.sid}\"}`;\n }\n this.writer.write(packet).then(() => this.onOpen());\n });\n });\n }\n write(packets) {\n this.writable = false;\n for (let i = 0; i < packets.length; i++) {\n const packet = packets[i];\n const lastPacket = i === packets.length - 1;\n this.writer.write(packet).then(() => {\n if (lastPacket) {\n (0, websocket_constructor_js_1.nextTick)(() => {\n this.writable = true;\n this.emitReserved(\"drain\");\n }, this.setTimeoutFn);\n }\n });\n }\n }\n doClose() {\n var _a;\n (_a = this.transport) === null || _a === void 0 ? void 0 : _a.close();\n }\n}\nexports.WT = WT;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/webtransport.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/transports/xmlhttprequest.browser.js": +/*!**************************************************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/transports/xmlhttprequest.browser.js ***! + \**************************************************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\n// browser shim for xmlhttprequest module\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.createCookieJar = exports.XHR = void 0;\nconst has_cors_js_1 = __webpack_require__(/*! ../contrib/has-cors.js */ \"./node_modules/engine.io-client/build/cjs/contrib/has-cors.js\");\nconst globalThis_js_1 = __webpack_require__(/*! ../globalThis.js */ \"./node_modules/engine.io-client/build/cjs/globalThis.browser.js\");\nfunction XHR(opts) {\n const xdomain = opts.xdomain;\n // XMLHttpRequest can be disabled on IE\n try {\n if (\"undefined\" !== typeof XMLHttpRequest && (!xdomain || has_cors_js_1.hasCORS)) {\n return new XMLHttpRequest();\n }\n }\n catch (e) { }\n if (!xdomain) {\n try {\n return new globalThis_js_1.globalThisShim[[\"Active\"].concat(\"Object\").join(\"X\")](\"Microsoft.XMLHTTP\");\n }\n catch (e) { }\n }\n}\nexports.XHR = XHR;\nfunction createCookieJar() { }\nexports.createCookieJar = createCookieJar;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/transports/xmlhttprequest.browser.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-client/build/cjs/util.js": +/*!*********************************************************!*\ + !*** ./node_modules/engine.io-client/build/cjs/util.js ***! + \*********************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.byteLength = exports.installTimerFunctions = exports.pick = void 0;\nconst globalThis_js_1 = __webpack_require__(/*! ./globalThis.js */ \"./node_modules/engine.io-client/build/cjs/globalThis.browser.js\");\nfunction pick(obj, ...attr) {\n return attr.reduce((acc, k) => {\n if (obj.hasOwnProperty(k)) {\n acc[k] = obj[k];\n }\n return acc;\n }, {});\n}\nexports.pick = pick;\n// Keep a reference to the real timeout functions so they can be used when overridden\nconst NATIVE_SET_TIMEOUT = globalThis_js_1.globalThisShim.setTimeout;\nconst NATIVE_CLEAR_TIMEOUT = globalThis_js_1.globalThisShim.clearTimeout;\nfunction installTimerFunctions(obj, opts) {\n if (opts.useNativeTimers) {\n obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThis_js_1.globalThisShim);\n obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThis_js_1.globalThisShim);\n }\n else {\n obj.setTimeoutFn = globalThis_js_1.globalThisShim.setTimeout.bind(globalThis_js_1.globalThisShim);\n obj.clearTimeoutFn = globalThis_js_1.globalThisShim.clearTimeout.bind(globalThis_js_1.globalThisShim);\n }\n}\nexports.installTimerFunctions = installTimerFunctions;\n// base64 encoded buffers are about 33% bigger (https://en.wikipedia.org/wiki/Base64)\nconst BASE64_OVERHEAD = 1.33;\n// we could also have used `new Blob([obj]).size`, but it isn't supported in IE9\nfunction byteLength(obj) {\n if (typeof obj === \"string\") {\n return utf8Length(obj);\n }\n // arraybuffer or blob\n return Math.ceil((obj.byteLength || obj.size) * BASE64_OVERHEAD);\n}\nexports.byteLength = byteLength;\nfunction utf8Length(str) {\n let c = 0, length = 0;\n for (let i = 0, l = str.length; i < l; i++) {\n c = str.charCodeAt(i);\n if (c < 0x80) {\n length += 1;\n }\n else if (c < 0x800) {\n length += 2;\n }\n else if (c < 0xd800 || c >= 0xe000) {\n length += 3;\n }\n else {\n i++;\n length += 4;\n }\n }\n return length;\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-client/build/cjs/util.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-parser/build/cjs/commons.js": +/*!************************************************************!*\ + !*** ./node_modules/engine.io-parser/build/cjs/commons.js ***! + \************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.ERROR_PACKET = exports.PACKET_TYPES_REVERSE = exports.PACKET_TYPES = void 0;\nconst PACKET_TYPES = Object.create(null); // no Map = no polyfill\nexports.PACKET_TYPES = PACKET_TYPES;\nPACKET_TYPES[\"open\"] = \"0\";\nPACKET_TYPES[\"close\"] = \"1\";\nPACKET_TYPES[\"ping\"] = \"2\";\nPACKET_TYPES[\"pong\"] = \"3\";\nPACKET_TYPES[\"message\"] = \"4\";\nPACKET_TYPES[\"upgrade\"] = \"5\";\nPACKET_TYPES[\"noop\"] = \"6\";\nconst PACKET_TYPES_REVERSE = Object.create(null);\nexports.PACKET_TYPES_REVERSE = PACKET_TYPES_REVERSE;\nObject.keys(PACKET_TYPES).forEach(key => {\n PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key;\n});\nconst ERROR_PACKET = { type: \"error\", data: \"parser error\" };\nexports.ERROR_PACKET = ERROR_PACKET;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-parser/build/cjs/commons.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.js": +/*!*******************************************************************************!*\ + !*** ./node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.js ***! + \*******************************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.decode = exports.encode = void 0;\n// imported from https://github.com/socketio/base64-arraybuffer\nconst chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n// Use a lookup table to find the index.\nconst lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);\nfor (let i = 0; i < chars.length; i++) {\n lookup[chars.charCodeAt(i)] = i;\n}\nconst encode = (arraybuffer) => {\n let bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = '';\n for (i = 0; i < len; i += 3) {\n base64 += chars[bytes[i] >> 2];\n base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];\n base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];\n base64 += chars[bytes[i + 2] & 63];\n }\n if (len % 3 === 2) {\n base64 = base64.substring(0, base64.length - 1) + '=';\n }\n else if (len % 3 === 1) {\n base64 = base64.substring(0, base64.length - 2) + '==';\n }\n return base64;\n};\nexports.encode = encode;\nconst decode = (base64) => {\n let bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4;\n if (base64[base64.length - 1] === '=') {\n bufferLength--;\n if (base64[base64.length - 2] === '=') {\n bufferLength--;\n }\n }\n const arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer);\n for (i = 0; i < len; i += 4) {\n encoded1 = lookup[base64.charCodeAt(i)];\n encoded2 = lookup[base64.charCodeAt(i + 1)];\n encoded3 = lookup[base64.charCodeAt(i + 2)];\n encoded4 = lookup[base64.charCodeAt(i + 3)];\n bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);\n bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);\n bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);\n }\n return arraybuffer;\n};\nexports.decode = decode;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-parser/build/cjs/decodePacket.browser.js": +/*!*************************************************************************!*\ + !*** ./node_modules/engine.io-parser/build/cjs/decodePacket.browser.js ***! + \*************************************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.decodePacket = void 0;\nconst commons_js_1 = __webpack_require__(/*! ./commons.js */ \"./node_modules/engine.io-parser/build/cjs/commons.js\");\nconst base64_arraybuffer_js_1 = __webpack_require__(/*! ./contrib/base64-arraybuffer.js */ \"./node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.js\");\nconst withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\nconst decodePacket = (encodedPacket, binaryType) => {\n if (typeof encodedPacket !== \"string\") {\n return {\n type: \"message\",\n data: mapBinary(encodedPacket, binaryType)\n };\n }\n const type = encodedPacket.charAt(0);\n if (type === \"b\") {\n return {\n type: \"message\",\n data: decodeBase64Packet(encodedPacket.substring(1), binaryType)\n };\n }\n const packetType = commons_js_1.PACKET_TYPES_REVERSE[type];\n if (!packetType) {\n return commons_js_1.ERROR_PACKET;\n }\n return encodedPacket.length > 1\n ? {\n type: commons_js_1.PACKET_TYPES_REVERSE[type],\n data: encodedPacket.substring(1)\n }\n : {\n type: commons_js_1.PACKET_TYPES_REVERSE[type]\n };\n};\nexports.decodePacket = decodePacket;\nconst decodeBase64Packet = (data, binaryType) => {\n if (withNativeArrayBuffer) {\n const decoded = (0, base64_arraybuffer_js_1.decode)(data);\n return mapBinary(decoded, binaryType);\n }\n else {\n return { base64: true, data }; // fallback for old browsers\n }\n};\nconst mapBinary = (data, binaryType) => {\n switch (binaryType) {\n case \"blob\":\n if (data instanceof Blob) {\n // from WebSocket + binaryType \"blob\"\n return data;\n }\n else {\n // from HTTP long-polling or WebTransport\n return new Blob([data]);\n }\n case \"arraybuffer\":\n default:\n if (data instanceof ArrayBuffer) {\n // from HTTP long-polling (base64) or WebSocket + binaryType \"arraybuffer\"\n return data;\n }\n else {\n // from WebTransport (Uint8Array)\n return data.buffer;\n }\n }\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-parser/build/cjs/decodePacket.browser.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-parser/build/cjs/encodePacket.browser.js": +/*!*************************************************************************!*\ + !*** ./node_modules/engine.io-parser/build/cjs/encodePacket.browser.js ***! + \*************************************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.encodePacket = exports.encodePacketToBinary = void 0;\nconst commons_js_1 = __webpack_require__(/*! ./commons.js */ \"./node_modules/engine.io-parser/build/cjs/commons.js\");\nconst withNativeBlob = typeof Blob === \"function\" ||\n (typeof Blob !== \"undefined\" &&\n Object.prototype.toString.call(Blob) === \"[object BlobConstructor]\");\nconst withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\n// ArrayBuffer.isView method is not defined in IE10\nconst isView = obj => {\n return typeof ArrayBuffer.isView === \"function\"\n ? ArrayBuffer.isView(obj)\n : obj && obj.buffer instanceof ArrayBuffer;\n};\nconst encodePacket = ({ type, data }, supportsBinary, callback) => {\n if (withNativeBlob && data instanceof Blob) {\n if (supportsBinary) {\n return callback(data);\n }\n else {\n return encodeBlobAsBase64(data, callback);\n }\n }\n else if (withNativeArrayBuffer &&\n (data instanceof ArrayBuffer || isView(data))) {\n if (supportsBinary) {\n return callback(data);\n }\n else {\n return encodeBlobAsBase64(new Blob([data]), callback);\n }\n }\n // plain string\n return callback(commons_js_1.PACKET_TYPES[type] + (data || \"\"));\n};\nexports.encodePacket = encodePacket;\nconst encodeBlobAsBase64 = (data, callback) => {\n const fileReader = new FileReader();\n fileReader.onload = function () {\n const content = fileReader.result.split(\",\")[1];\n callback(\"b\" + (content || \"\"));\n };\n return fileReader.readAsDataURL(data);\n};\nfunction toArray(data) {\n if (data instanceof Uint8Array) {\n return data;\n }\n else if (data instanceof ArrayBuffer) {\n return new Uint8Array(data);\n }\n else {\n return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n }\n}\nlet TEXT_ENCODER;\nfunction encodePacketToBinary(packet, callback) {\n if (withNativeBlob && packet.data instanceof Blob) {\n return packet.data\n .arrayBuffer()\n .then(toArray)\n .then(callback);\n }\n else if (withNativeArrayBuffer &&\n (packet.data instanceof ArrayBuffer || isView(packet.data))) {\n return callback(toArray(packet.data));\n }\n encodePacket(packet, false, encoded => {\n if (!TEXT_ENCODER) {\n TEXT_ENCODER = new TextEncoder();\n }\n callback(TEXT_ENCODER.encode(encoded));\n });\n}\nexports.encodePacketToBinary = encodePacketToBinary;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-parser/build/cjs/encodePacket.browser.js?"); + +/***/ }), + +/***/ "./node_modules/engine.io-parser/build/cjs/index.js": +/*!**********************************************************!*\ + !*** ./node_modules/engine.io-parser/build/cjs/index.js ***! + \**********************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.decodePayload = exports.decodePacket = exports.encodePayload = exports.encodePacket = exports.protocol = exports.createPacketDecoderStream = exports.createPacketEncoderStream = void 0;\nconst encodePacket_js_1 = __webpack_require__(/*! ./encodePacket.js */ \"./node_modules/engine.io-parser/build/cjs/encodePacket.browser.js\");\nObject.defineProperty(exports, \"encodePacket\", ({ enumerable: true, get: function () { return encodePacket_js_1.encodePacket; } }));\nconst decodePacket_js_1 = __webpack_require__(/*! ./decodePacket.js */ \"./node_modules/engine.io-parser/build/cjs/decodePacket.browser.js\");\nObject.defineProperty(exports, \"decodePacket\", ({ enumerable: true, get: function () { return decodePacket_js_1.decodePacket; } }));\nconst commons_js_1 = __webpack_require__(/*! ./commons.js */ \"./node_modules/engine.io-parser/build/cjs/commons.js\");\nconst SEPARATOR = String.fromCharCode(30); // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text\nconst encodePayload = (packets, callback) => {\n // some packets may be added to the array while encoding, so the initial length must be saved\n const length = packets.length;\n const encodedPackets = new Array(length);\n let count = 0;\n packets.forEach((packet, i) => {\n // force base64 encoding for binary packets\n (0, encodePacket_js_1.encodePacket)(packet, false, encodedPacket => {\n encodedPackets[i] = encodedPacket;\n if (++count === length) {\n callback(encodedPackets.join(SEPARATOR));\n }\n });\n });\n};\nexports.encodePayload = encodePayload;\nconst decodePayload = (encodedPayload, binaryType) => {\n const encodedPackets = encodedPayload.split(SEPARATOR);\n const packets = [];\n for (let i = 0; i < encodedPackets.length; i++) {\n const decodedPacket = (0, decodePacket_js_1.decodePacket)(encodedPackets[i], binaryType);\n packets.push(decodedPacket);\n if (decodedPacket.type === \"error\") {\n break;\n }\n }\n return packets;\n};\nexports.decodePayload = decodePayload;\nfunction createPacketEncoderStream() {\n return new TransformStream({\n transform(packet, controller) {\n (0, encodePacket_js_1.encodePacketToBinary)(packet, encodedPacket => {\n const payloadLength = encodedPacket.length;\n let header;\n // inspired by the WebSocket format: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#decoding_payload_length\n if (payloadLength < 126) {\n header = new Uint8Array(1);\n new DataView(header.buffer).setUint8(0, payloadLength);\n }\n else if (payloadLength < 65536) {\n header = new Uint8Array(3);\n const view = new DataView(header.buffer);\n view.setUint8(0, 126);\n view.setUint16(1, payloadLength);\n }\n else {\n header = new Uint8Array(9);\n const view = new DataView(header.buffer);\n view.setUint8(0, 127);\n view.setBigUint64(1, BigInt(payloadLength));\n }\n // first bit indicates whether the payload is plain text (0) or binary (1)\n if (packet.data && typeof packet.data !== \"string\") {\n header[0] |= 0x80;\n }\n controller.enqueue(header);\n controller.enqueue(encodedPacket);\n });\n }\n });\n}\nexports.createPacketEncoderStream = createPacketEncoderStream;\nlet TEXT_DECODER;\nfunction totalLength(chunks) {\n return chunks.reduce((acc, chunk) => acc + chunk.length, 0);\n}\nfunction concatChunks(chunks, size) {\n if (chunks[0].length === size) {\n return chunks.shift();\n }\n const buffer = new Uint8Array(size);\n let j = 0;\n for (let i = 0; i < size; i++) {\n buffer[i] = chunks[0][j++];\n if (j === chunks[0].length) {\n chunks.shift();\n j = 0;\n }\n }\n if (chunks.length && j < chunks[0].length) {\n chunks[0] = chunks[0].slice(j);\n }\n return buffer;\n}\nfunction createPacketDecoderStream(maxPayload, binaryType) {\n if (!TEXT_DECODER) {\n TEXT_DECODER = new TextDecoder();\n }\n const chunks = [];\n let state = 0 /* READ_HEADER */;\n let expectedLength = -1;\n let isBinary = false;\n return new TransformStream({\n transform(chunk, controller) {\n chunks.push(chunk);\n while (true) {\n if (state === 0 /* READ_HEADER */) {\n if (totalLength(chunks) < 1) {\n break;\n }\n const header = concatChunks(chunks, 1);\n isBinary = (header[0] & 0x80) === 0x80;\n expectedLength = header[0] & 0x7f;\n if (expectedLength < 126) {\n state = 3 /* READ_PAYLOAD */;\n }\n else if (expectedLength === 126) {\n state = 1 /* READ_EXTENDED_LENGTH_16 */;\n }\n else {\n state = 2 /* READ_EXTENDED_LENGTH_64 */;\n }\n }\n else if (state === 1 /* READ_EXTENDED_LENGTH_16 */) {\n if (totalLength(chunks) < 2) {\n break;\n }\n const headerArray = concatChunks(chunks, 2);\n expectedLength = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length).getUint16(0);\n state = 3 /* READ_PAYLOAD */;\n }\n else if (state === 2 /* READ_EXTENDED_LENGTH_64 */) {\n if (totalLength(chunks) < 8) {\n break;\n }\n const headerArray = concatChunks(chunks, 8);\n const view = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length);\n const n = view.getUint32(0);\n if (n > Math.pow(2, 53 - 32) - 1) {\n // the maximum safe integer in JavaScript is 2^53 - 1\n controller.enqueue(commons_js_1.ERROR_PACKET);\n break;\n }\n expectedLength = n * Math.pow(2, 32) + view.getUint32(4);\n state = 3 /* READ_PAYLOAD */;\n }\n else {\n if (totalLength(chunks) < expectedLength) {\n break;\n }\n const data = concatChunks(chunks, expectedLength);\n controller.enqueue((0, decodePacket_js_1.decodePacket)(isBinary ? data : TEXT_DECODER.decode(data), binaryType));\n state = 0 /* READ_HEADER */;\n }\n if (expectedLength === 0 || expectedLength > maxPayload) {\n controller.enqueue(commons_js_1.ERROR_PACKET);\n break;\n }\n }\n }\n });\n}\nexports.createPacketDecoderStream = createPacketDecoderStream;\nexports.protocol = 4;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/engine.io-parser/build/cjs/index.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/contrib/backo2.js": +/*!*******************************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/contrib/backo2.js ***! + \*******************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\n/**\n * Initialize backoff timer with `opts`.\n *\n * - `min` initial timeout in milliseconds [100]\n * - `max` max timeout [10000]\n * - `jitter` [0]\n * - `factor` [2]\n *\n * @param {Object} opts\n * @api public\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Backoff = void 0;\nfunction Backoff(opts) {\n opts = opts || {};\n this.ms = opts.min || 100;\n this.max = opts.max || 10000;\n this.factor = opts.factor || 2;\n this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;\n this.attempts = 0;\n}\nexports.Backoff = Backoff;\n/**\n * Return the backoff duration.\n *\n * @return {Number}\n * @api public\n */\nBackoff.prototype.duration = function () {\n var ms = this.ms * Math.pow(this.factor, this.attempts++);\n if (this.jitter) {\n var rand = Math.random();\n var deviation = Math.floor(rand * this.jitter * ms);\n ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;\n }\n return Math.min(ms, this.max) | 0;\n};\n/**\n * Reset the number of attempts.\n *\n * @api public\n */\nBackoff.prototype.reset = function () {\n this.attempts = 0;\n};\n/**\n * Set the minimum duration\n *\n * @api public\n */\nBackoff.prototype.setMin = function (min) {\n this.ms = min;\n};\n/**\n * Set the maximum duration\n *\n * @api public\n */\nBackoff.prototype.setMax = function (max) {\n this.max = max;\n};\n/**\n * Set the jitter\n *\n * @api public\n */\nBackoff.prototype.setJitter = function (jitter) {\n this.jitter = jitter;\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/contrib/backo2.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/index.js": +/*!**********************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/index.js ***! + \**********************************************************/ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports[\"default\"] = exports.connect = exports.io = exports.Socket = exports.Manager = exports.protocol = void 0;\nconst url_js_1 = __webpack_require__(/*! ./url.js */ \"./node_modules/socket.io-client/build/cjs/url.js\");\nconst manager_js_1 = __webpack_require__(/*! ./manager.js */ \"./node_modules/socket.io-client/build/cjs/manager.js\");\nObject.defineProperty(exports, \"Manager\", ({ enumerable: true, get: function () { return manager_js_1.Manager; } }));\nconst socket_js_1 = __webpack_require__(/*! ./socket.js */ \"./node_modules/socket.io-client/build/cjs/socket.js\");\nObject.defineProperty(exports, \"Socket\", ({ enumerable: true, get: function () { return socket_js_1.Socket; } }));\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst debug = debug_1.default(\"socket.io-client\"); // debug()\n/**\n * Managers cache.\n */\nconst cache = {};\nfunction lookup(uri, opts) {\n if (typeof uri === \"object\") {\n opts = uri;\n uri = undefined;\n }\n opts = opts || {};\n const parsed = url_js_1.url(uri, opts.path || \"/socket.io\");\n const source = parsed.source;\n const id = parsed.id;\n const path = parsed.path;\n const sameNamespace = cache[id] && path in cache[id][\"nsps\"];\n const newConnection = opts.forceNew ||\n opts[\"force new connection\"] ||\n false === opts.multiplex ||\n sameNamespace;\n let io;\n if (newConnection) {\n debug(\"ignoring socket cache for %s\", source);\n io = new manager_js_1.Manager(source, opts);\n }\n else {\n if (!cache[id]) {\n debug(\"new io instance for %s\", source);\n cache[id] = new manager_js_1.Manager(source, opts);\n }\n io = cache[id];\n }\n if (parsed.query && !opts.query) {\n opts.query = parsed.queryKey;\n }\n return io.socket(parsed.path, opts);\n}\nexports.io = lookup;\nexports.connect = lookup;\nexports[\"default\"] = lookup;\n// so that \"lookup\" can be used both as a function (e.g. `io(...)`) and as a\n// namespace (e.g. `io.connect(...)`), for backward compatibility\nObject.assign(lookup, {\n Manager: manager_js_1.Manager,\n Socket: socket_js_1.Socket,\n io: lookup,\n connect: lookup,\n});\n/**\n * Protocol version.\n *\n * @public\n */\nvar socket_io_parser_1 = __webpack_require__(/*! socket.io-parser */ \"./node_modules/socket.io-parser/build/cjs/index.js\");\nObject.defineProperty(exports, \"protocol\", ({ enumerable: true, get: function () { return socket_io_parser_1.protocol; } }));\n\nmodule.exports = lookup;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/index.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/manager.js": +/*!************************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/manager.js ***! + \************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Manager = void 0;\nconst engine_io_client_1 = __webpack_require__(/*! engine.io-client */ \"./node_modules/engine.io-client/build/cjs/index.js\");\nconst socket_js_1 = __webpack_require__(/*! ./socket.js */ \"./node_modules/socket.io-client/build/cjs/socket.js\");\nconst parser = __importStar(__webpack_require__(/*! socket.io-parser */ \"./node_modules/socket.io-parser/build/cjs/index.js\"));\nconst on_js_1 = __webpack_require__(/*! ./on.js */ \"./node_modules/socket.io-client/build/cjs/on.js\");\nconst backo2_js_1 = __webpack_require__(/*! ./contrib/backo2.js */ \"./node_modules/socket.io-client/build/cjs/contrib/backo2.js\");\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst debug = debug_1.default(\"socket.io-client:manager\"); // debug()\nclass Manager extends component_emitter_1.Emitter {\n constructor(uri, opts) {\n var _a;\n super();\n this.nsps = {};\n this.subs = [];\n if (uri && \"object\" === typeof uri) {\n opts = uri;\n uri = undefined;\n }\n opts = opts || {};\n opts.path = opts.path || \"/socket.io\";\n this.opts = opts;\n engine_io_client_1.installTimerFunctions(this, opts);\n this.reconnection(opts.reconnection !== false);\n this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);\n this.reconnectionDelay(opts.reconnectionDelay || 1000);\n this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);\n this.randomizationFactor((_a = opts.randomizationFactor) !== null && _a !== void 0 ? _a : 0.5);\n this.backoff = new backo2_js_1.Backoff({\n min: this.reconnectionDelay(),\n max: this.reconnectionDelayMax(),\n jitter: this.randomizationFactor(),\n });\n this.timeout(null == opts.timeout ? 20000 : opts.timeout);\n this._readyState = \"closed\";\n this.uri = uri;\n const _parser = opts.parser || parser;\n this.encoder = new _parser.Encoder();\n this.decoder = new _parser.Decoder();\n this._autoConnect = opts.autoConnect !== false;\n if (this._autoConnect)\n this.open();\n }\n reconnection(v) {\n if (!arguments.length)\n return this._reconnection;\n this._reconnection = !!v;\n return this;\n }\n reconnectionAttempts(v) {\n if (v === undefined)\n return this._reconnectionAttempts;\n this._reconnectionAttempts = v;\n return this;\n }\n reconnectionDelay(v) {\n var _a;\n if (v === undefined)\n return this._reconnectionDelay;\n this._reconnectionDelay = v;\n (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMin(v);\n return this;\n }\n randomizationFactor(v) {\n var _a;\n if (v === undefined)\n return this._randomizationFactor;\n this._randomizationFactor = v;\n (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setJitter(v);\n return this;\n }\n reconnectionDelayMax(v) {\n var _a;\n if (v === undefined)\n return this._reconnectionDelayMax;\n this._reconnectionDelayMax = v;\n (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMax(v);\n return this;\n }\n timeout(v) {\n if (!arguments.length)\n return this._timeout;\n this._timeout = v;\n return this;\n }\n /**\n * Starts trying to reconnect if reconnection is enabled and we have not\n * started reconnecting yet\n *\n * @private\n */\n maybeReconnectOnOpen() {\n // Only try to reconnect if it's the first time we're connecting\n if (!this._reconnecting &&\n this._reconnection &&\n this.backoff.attempts === 0) {\n // keeps reconnection from firing twice for the same reconnection loop\n this.reconnect();\n }\n }\n /**\n * Sets the current transport `socket`.\n *\n * @param {Function} fn - optional, callback\n * @return self\n * @public\n */\n open(fn) {\n debug(\"readyState %s\", this._readyState);\n if (~this._readyState.indexOf(\"open\"))\n return this;\n debug(\"opening %s\", this.uri);\n this.engine = new engine_io_client_1.Socket(this.uri, this.opts);\n const socket = this.engine;\n const self = this;\n this._readyState = \"opening\";\n this.skipReconnect = false;\n // emit `open`\n const openSubDestroy = on_js_1.on(socket, \"open\", function () {\n self.onopen();\n fn && fn();\n });\n const onError = (err) => {\n debug(\"error\");\n this.cleanup();\n this._readyState = \"closed\";\n this.emitReserved(\"error\", err);\n if (fn) {\n fn(err);\n }\n else {\n // Only do this if there is no fn to handle the error\n this.maybeReconnectOnOpen();\n }\n };\n // emit `error`\n const errorSub = on_js_1.on(socket, \"error\", onError);\n if (false !== this._timeout) {\n const timeout = this._timeout;\n debug(\"connect attempt will timeout after %d\", timeout);\n // set timer\n const timer = this.setTimeoutFn(() => {\n debug(\"connect attempt timed out after %d\", timeout);\n openSubDestroy();\n onError(new Error(\"timeout\"));\n socket.close();\n }, timeout);\n if (this.opts.autoUnref) {\n timer.unref();\n }\n this.subs.push(() => {\n this.clearTimeoutFn(timer);\n });\n }\n this.subs.push(openSubDestroy);\n this.subs.push(errorSub);\n return this;\n }\n /**\n * Alias for open()\n *\n * @return self\n * @public\n */\n connect(fn) {\n return this.open(fn);\n }\n /**\n * Called upon transport open.\n *\n * @private\n */\n onopen() {\n debug(\"open\");\n // clear old subs\n this.cleanup();\n // mark as open\n this._readyState = \"open\";\n this.emitReserved(\"open\");\n // add new subs\n const socket = this.engine;\n this.subs.push(on_js_1.on(socket, \"ping\", this.onping.bind(this)), on_js_1.on(socket, \"data\", this.ondata.bind(this)), on_js_1.on(socket, \"error\", this.onerror.bind(this)), on_js_1.on(socket, \"close\", this.onclose.bind(this)), on_js_1.on(this.decoder, \"decoded\", this.ondecoded.bind(this)));\n }\n /**\n * Called upon a ping.\n *\n * @private\n */\n onping() {\n this.emitReserved(\"ping\");\n }\n /**\n * Called with data.\n *\n * @private\n */\n ondata(data) {\n try {\n this.decoder.add(data);\n }\n catch (e) {\n this.onclose(\"parse error\", e);\n }\n }\n /**\n * Called when parser fully decodes a packet.\n *\n * @private\n */\n ondecoded(packet) {\n // the nextTick call prevents an exception in a user-provided event listener from triggering a disconnection due to a \"parse error\"\n engine_io_client_1.nextTick(() => {\n this.emitReserved(\"packet\", packet);\n }, this.setTimeoutFn);\n }\n /**\n * Called upon socket error.\n *\n * @private\n */\n onerror(err) {\n debug(\"error\", err);\n this.emitReserved(\"error\", err);\n }\n /**\n * Creates a new socket for the given `nsp`.\n *\n * @return {Socket}\n * @public\n */\n socket(nsp, opts) {\n let socket = this.nsps[nsp];\n if (!socket) {\n socket = new socket_js_1.Socket(this, nsp, opts);\n this.nsps[nsp] = socket;\n }\n else if (this._autoConnect && !socket.active) {\n socket.connect();\n }\n return socket;\n }\n /**\n * Called upon a socket close.\n *\n * @param socket\n * @private\n */\n _destroy(socket) {\n const nsps = Object.keys(this.nsps);\n for (const nsp of nsps) {\n const socket = this.nsps[nsp];\n if (socket.active) {\n debug(\"socket %s is still active, skipping close\", nsp);\n return;\n }\n }\n this._close();\n }\n /**\n * Writes a packet.\n *\n * @param packet\n * @private\n */\n _packet(packet) {\n debug(\"writing packet %j\", packet);\n const encodedPackets = this.encoder.encode(packet);\n for (let i = 0; i < encodedPackets.length; i++) {\n this.engine.write(encodedPackets[i], packet.options);\n }\n }\n /**\n * Clean up transport subscriptions and packet buffer.\n *\n * @private\n */\n cleanup() {\n debug(\"cleanup\");\n this.subs.forEach((subDestroy) => subDestroy());\n this.subs.length = 0;\n this.decoder.destroy();\n }\n /**\n * Close the current socket.\n *\n * @private\n */\n _close() {\n debug(\"disconnect\");\n this.skipReconnect = true;\n this._reconnecting = false;\n this.onclose(\"forced close\");\n if (this.engine)\n this.engine.close();\n }\n /**\n * Alias for close()\n *\n * @private\n */\n disconnect() {\n return this._close();\n }\n /**\n * Called upon engine close.\n *\n * @private\n */\n onclose(reason, description) {\n debug(\"closed due to %s\", reason);\n this.cleanup();\n this.backoff.reset();\n this._readyState = \"closed\";\n this.emitReserved(\"close\", reason, description);\n if (this._reconnection && !this.skipReconnect) {\n this.reconnect();\n }\n }\n /**\n * Attempt a reconnection.\n *\n * @private\n */\n reconnect() {\n if (this._reconnecting || this.skipReconnect)\n return this;\n const self = this;\n if (this.backoff.attempts >= this._reconnectionAttempts) {\n debug(\"reconnect failed\");\n this.backoff.reset();\n this.emitReserved(\"reconnect_failed\");\n this._reconnecting = false;\n }\n else {\n const delay = this.backoff.duration();\n debug(\"will wait %dms before reconnect attempt\", delay);\n this._reconnecting = true;\n const timer = this.setTimeoutFn(() => {\n if (self.skipReconnect)\n return;\n debug(\"attempting reconnect\");\n this.emitReserved(\"reconnect_attempt\", self.backoff.attempts);\n // check again for the case socket closed in above events\n if (self.skipReconnect)\n return;\n self.open((err) => {\n if (err) {\n debug(\"reconnect attempt error\");\n self._reconnecting = false;\n self.reconnect();\n this.emitReserved(\"reconnect_error\", err);\n }\n else {\n debug(\"reconnect success\");\n self.onreconnect();\n }\n });\n }, delay);\n if (this.opts.autoUnref) {\n timer.unref();\n }\n this.subs.push(() => {\n this.clearTimeoutFn(timer);\n });\n }\n }\n /**\n * Called upon successful reconnect.\n *\n * @private\n */\n onreconnect() {\n const attempt = this.backoff.attempts;\n this._reconnecting = false;\n this.backoff.reset();\n this.emitReserved(\"reconnect\", attempt);\n }\n}\nexports.Manager = Manager;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/manager.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/on.js": +/*!*******************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/on.js ***! + \*******************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.on = void 0;\nfunction on(obj, ev, fn) {\n obj.on(ev, fn);\n return function subDestroy() {\n obj.off(ev, fn);\n };\n}\nexports.on = on;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/on.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/socket.js": +/*!***********************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/socket.js ***! + \***********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Socket = void 0;\nconst socket_io_parser_1 = __webpack_require__(/*! socket.io-parser */ \"./node_modules/socket.io-parser/build/cjs/index.js\");\nconst on_js_1 = __webpack_require__(/*! ./on.js */ \"./node_modules/socket.io-client/build/cjs/on.js\");\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst debug = debug_1.default(\"socket.io-client:socket\"); // debug()\n/**\n * Internal events.\n * These events can't be emitted by the user.\n */\nconst RESERVED_EVENTS = Object.freeze({\n connect: 1,\n connect_error: 1,\n disconnect: 1,\n disconnecting: 1,\n // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener\n newListener: 1,\n removeListener: 1,\n});\n/**\n * A Socket is the fundamental class for interacting with the server.\n *\n * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.\n *\n * @example\n * const socket = io();\n *\n * socket.on(\"connect\", () => {\n * console.log(\"connected\");\n * });\n *\n * // send an event to the server\n * socket.emit(\"foo\", \"bar\");\n *\n * socket.on(\"foobar\", () => {\n * // an event was received from the server\n * });\n *\n * // upon disconnection\n * socket.on(\"disconnect\", (reason) => {\n * console.log(`disconnected due to ${reason}`);\n * });\n */\nclass Socket extends component_emitter_1.Emitter {\n /**\n * `Socket` constructor.\n */\n constructor(io, nsp, opts) {\n super();\n /**\n * Whether the socket is currently connected to the server.\n *\n * @example\n * const socket = io();\n *\n * socket.on(\"connect\", () => {\n * console.log(socket.connected); // true\n * });\n *\n * socket.on(\"disconnect\", () => {\n * console.log(socket.connected); // false\n * });\n */\n this.connected = false;\n /**\n * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will\n * be transmitted by the server.\n */\n this.recovered = false;\n /**\n * Buffer for packets received before the CONNECT packet\n */\n this.receiveBuffer = [];\n /**\n * Buffer for packets that will be sent once the socket is connected\n */\n this.sendBuffer = [];\n /**\n * The queue of packets to be sent with retry in case of failure.\n *\n * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.\n * @private\n */\n this._queue = [];\n /**\n * A sequence to generate the ID of the {@link QueuedPacket}.\n * @private\n */\n this._queueSeq = 0;\n this.ids = 0;\n this.acks = {};\n this.flags = {};\n this.io = io;\n this.nsp = nsp;\n if (opts && opts.auth) {\n this.auth = opts.auth;\n }\n this._opts = Object.assign({}, opts);\n if (this.io._autoConnect)\n this.open();\n }\n /**\n * Whether the socket is currently disconnected\n *\n * @example\n * const socket = io();\n *\n * socket.on(\"connect\", () => {\n * console.log(socket.disconnected); // false\n * });\n *\n * socket.on(\"disconnect\", () => {\n * console.log(socket.disconnected); // true\n * });\n */\n get disconnected() {\n return !this.connected;\n }\n /**\n * Subscribe to open, close and packet events\n *\n * @private\n */\n subEvents() {\n if (this.subs)\n return;\n const io = this.io;\n this.subs = [\n on_js_1.on(io, \"open\", this.onopen.bind(this)),\n on_js_1.on(io, \"packet\", this.onpacket.bind(this)),\n on_js_1.on(io, \"error\", this.onerror.bind(this)),\n on_js_1.on(io, \"close\", this.onclose.bind(this)),\n ];\n }\n /**\n * Whether the Socket will try to reconnect when its Manager connects or reconnects.\n *\n * @example\n * const socket = io();\n *\n * console.log(socket.active); // true\n *\n * socket.on(\"disconnect\", (reason) => {\n * if (reason === \"io server disconnect\") {\n * // the disconnection was initiated by the server, you need to manually reconnect\n * console.log(socket.active); // false\n * }\n * // else the socket will automatically try to reconnect\n * console.log(socket.active); // true\n * });\n */\n get active() {\n return !!this.subs;\n }\n /**\n * \"Opens\" the socket.\n *\n * @example\n * const socket = io({\n * autoConnect: false\n * });\n *\n * socket.connect();\n */\n connect() {\n if (this.connected)\n return this;\n this.subEvents();\n if (!this.io[\"_reconnecting\"])\n this.io.open(); // ensure open\n if (\"open\" === this.io._readyState)\n this.onopen();\n return this;\n }\n /**\n * Alias for {@link connect()}.\n */\n open() {\n return this.connect();\n }\n /**\n * Sends a `message` event.\n *\n * This method mimics the WebSocket.send() method.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send\n *\n * @example\n * socket.send(\"hello\");\n *\n * // this is equivalent to\n * socket.emit(\"message\", \"hello\");\n *\n * @return self\n */\n send(...args) {\n args.unshift(\"message\");\n this.emit.apply(this, args);\n return this;\n }\n /**\n * Override `emit`.\n * If the event is in `events`, it's emitted normally.\n *\n * @example\n * socket.emit(\"hello\", \"world\");\n *\n * // all serializable datastructures are supported (no need to call JSON.stringify)\n * socket.emit(\"hello\", 1, \"2\", { 3: [\"4\"], 5: Uint8Array.from([6]) });\n *\n * // with an acknowledgement from the server\n * socket.emit(\"hello\", \"world\", (val) => {\n * // ...\n * });\n *\n * @return self\n */\n emit(ev, ...args) {\n if (RESERVED_EVENTS.hasOwnProperty(ev)) {\n throw new Error('\"' + ev.toString() + '\" is a reserved event name');\n }\n args.unshift(ev);\n if (this._opts.retries && !this.flags.fromQueue && !this.flags.volatile) {\n this._addToQueue(args);\n return this;\n }\n const packet = {\n type: socket_io_parser_1.PacketType.EVENT,\n data: args,\n };\n packet.options = {};\n packet.options.compress = this.flags.compress !== false;\n // event ack callback\n if (\"function\" === typeof args[args.length - 1]) {\n const id = this.ids++;\n debug(\"emitting packet with ack id %d\", id);\n const ack = args.pop();\n this._registerAckCallback(id, ack);\n packet.id = id;\n }\n const isTransportWritable = this.io.engine &&\n this.io.engine.transport &&\n this.io.engine.transport.writable;\n const discardPacket = this.flags.volatile && (!isTransportWritable || !this.connected);\n if (discardPacket) {\n debug(\"discard packet as the transport is not currently writable\");\n }\n else if (this.connected) {\n this.notifyOutgoingListeners(packet);\n this.packet(packet);\n }\n else {\n this.sendBuffer.push(packet);\n }\n this.flags = {};\n return this;\n }\n /**\n * @private\n */\n _registerAckCallback(id, ack) {\n var _a;\n const timeout = (_a = this.flags.timeout) !== null && _a !== void 0 ? _a : this._opts.ackTimeout;\n if (timeout === undefined) {\n this.acks[id] = ack;\n return;\n }\n // @ts-ignore\n const timer = this.io.setTimeoutFn(() => {\n delete this.acks[id];\n for (let i = 0; i < this.sendBuffer.length; i++) {\n if (this.sendBuffer[i].id === id) {\n debug(\"removing packet with ack id %d from the buffer\", id);\n this.sendBuffer.splice(i, 1);\n }\n }\n debug(\"event with ack id %d has timed out after %d ms\", id, timeout);\n ack.call(this, new Error(\"operation has timed out\"));\n }, timeout);\n this.acks[id] = (...args) => {\n // @ts-ignore\n this.io.clearTimeoutFn(timer);\n ack.apply(this, [null, ...args]);\n };\n }\n /**\n * Emits an event and waits for an acknowledgement\n *\n * @example\n * // without timeout\n * const response = await socket.emitWithAck(\"hello\", \"world\");\n *\n * // with a specific timeout\n * try {\n * const response = await socket.timeout(1000).emitWithAck(\"hello\", \"world\");\n * } catch (err) {\n * // the server did not acknowledge the event in the given delay\n * }\n *\n * @return a Promise that will be fulfilled when the server acknowledges the event\n */\n emitWithAck(ev, ...args) {\n // the timeout flag is optional\n const withErr = this.flags.timeout !== undefined || this._opts.ackTimeout !== undefined;\n return new Promise((resolve, reject) => {\n args.push((arg1, arg2) => {\n if (withErr) {\n return arg1 ? reject(arg1) : resolve(arg2);\n }\n else {\n return resolve(arg1);\n }\n });\n this.emit(ev, ...args);\n });\n }\n /**\n * Add the packet to the queue.\n * @param args\n * @private\n */\n _addToQueue(args) {\n let ack;\n if (typeof args[args.length - 1] === \"function\") {\n ack = args.pop();\n }\n const packet = {\n id: this._queueSeq++,\n tryCount: 0,\n pending: false,\n args,\n flags: Object.assign({ fromQueue: true }, this.flags),\n };\n args.push((err, ...responseArgs) => {\n if (packet !== this._queue[0]) {\n // the packet has already been acknowledged\n return;\n }\n const hasError = err !== null;\n if (hasError) {\n if (packet.tryCount > this._opts.retries) {\n debug(\"packet [%d] is discarded after %d tries\", packet.id, packet.tryCount);\n this._queue.shift();\n if (ack) {\n ack(err);\n }\n }\n }\n else {\n debug(\"packet [%d] was successfully sent\", packet.id);\n this._queue.shift();\n if (ack) {\n ack(null, ...responseArgs);\n }\n }\n packet.pending = false;\n return this._drainQueue();\n });\n this._queue.push(packet);\n this._drainQueue();\n }\n /**\n * Send the first packet of the queue, and wait for an acknowledgement from the server.\n * @param force - whether to resend a packet that has not been acknowledged yet\n *\n * @private\n */\n _drainQueue(force = false) {\n debug(\"draining queue\");\n if (!this.connected || this._queue.length === 0) {\n return;\n }\n const packet = this._queue[0];\n if (packet.pending && !force) {\n debug(\"packet [%d] has already been sent and is waiting for an ack\", packet.id);\n return;\n }\n packet.pending = true;\n packet.tryCount++;\n debug(\"sending packet [%d] (try n°%d)\", packet.id, packet.tryCount);\n this.flags = packet.flags;\n this.emit.apply(this, packet.args);\n }\n /**\n * Sends a packet.\n *\n * @param packet\n * @private\n */\n packet(packet) {\n packet.nsp = this.nsp;\n this.io._packet(packet);\n }\n /**\n * Called upon engine `open`.\n *\n * @private\n */\n onopen() {\n debug(\"transport is open - connecting\");\n if (typeof this.auth == \"function\") {\n this.auth((data) => {\n this._sendConnectPacket(data);\n });\n }\n else {\n this._sendConnectPacket(this.auth);\n }\n }\n /**\n * Sends a CONNECT packet to initiate the Socket.IO session.\n *\n * @param data\n * @private\n */\n _sendConnectPacket(data) {\n this.packet({\n type: socket_io_parser_1.PacketType.CONNECT,\n data: this._pid\n ? Object.assign({ pid: this._pid, offset: this._lastOffset }, data)\n : data,\n });\n }\n /**\n * Called upon engine or manager `error`.\n *\n * @param err\n * @private\n */\n onerror(err) {\n if (!this.connected) {\n this.emitReserved(\"connect_error\", err);\n }\n }\n /**\n * Called upon engine `close`.\n *\n * @param reason\n * @param description\n * @private\n */\n onclose(reason, description) {\n debug(\"close (%s)\", reason);\n this.connected = false;\n delete this.id;\n this.emitReserved(\"disconnect\", reason, description);\n }\n /**\n * Called with socket packet.\n *\n * @param packet\n * @private\n */\n onpacket(packet) {\n const sameNamespace = packet.nsp === this.nsp;\n if (!sameNamespace)\n return;\n switch (packet.type) {\n case socket_io_parser_1.PacketType.CONNECT:\n if (packet.data && packet.data.sid) {\n this.onconnect(packet.data.sid, packet.data.pid);\n }\n else {\n this.emitReserved(\"connect_error\", new Error(\"It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)\"));\n }\n break;\n case socket_io_parser_1.PacketType.EVENT:\n case socket_io_parser_1.PacketType.BINARY_EVENT:\n this.onevent(packet);\n break;\n case socket_io_parser_1.PacketType.ACK:\n case socket_io_parser_1.PacketType.BINARY_ACK:\n this.onack(packet);\n break;\n case socket_io_parser_1.PacketType.DISCONNECT:\n this.ondisconnect();\n break;\n case socket_io_parser_1.PacketType.CONNECT_ERROR:\n this.destroy();\n const err = new Error(packet.data.message);\n // @ts-ignore\n err.data = packet.data.data;\n this.emitReserved(\"connect_error\", err);\n break;\n }\n }\n /**\n * Called upon a server event.\n *\n * @param packet\n * @private\n */\n onevent(packet) {\n const args = packet.data || [];\n debug(\"emitting event %j\", args);\n if (null != packet.id) {\n debug(\"attaching ack callback to event\");\n args.push(this.ack(packet.id));\n }\n if (this.connected) {\n this.emitEvent(args);\n }\n else {\n this.receiveBuffer.push(Object.freeze(args));\n }\n }\n emitEvent(args) {\n if (this._anyListeners && this._anyListeners.length) {\n const listeners = this._anyListeners.slice();\n for (const listener of listeners) {\n listener.apply(this, args);\n }\n }\n super.emit.apply(this, args);\n if (this._pid && args.length && typeof args[args.length - 1] === \"string\") {\n this._lastOffset = args[args.length - 1];\n }\n }\n /**\n * Produces an ack callback to emit with an event.\n *\n * @private\n */\n ack(id) {\n const self = this;\n let sent = false;\n return function (...args) {\n // prevent double callbacks\n if (sent)\n return;\n sent = true;\n debug(\"sending ack %j\", args);\n self.packet({\n type: socket_io_parser_1.PacketType.ACK,\n id: id,\n data: args,\n });\n };\n }\n /**\n * Called upon a server acknowlegement.\n *\n * @param packet\n * @private\n */\n onack(packet) {\n const ack = this.acks[packet.id];\n if (\"function\" === typeof ack) {\n debug(\"calling ack %s with %j\", packet.id, packet.data);\n ack.apply(this, packet.data);\n delete this.acks[packet.id];\n }\n else {\n debug(\"bad ack %s\", packet.id);\n }\n }\n /**\n * Called upon server connect.\n *\n * @private\n */\n onconnect(id, pid) {\n debug(\"socket connected with id %s\", id);\n this.id = id;\n this.recovered = pid && this._pid === pid;\n this._pid = pid; // defined only if connection state recovery is enabled\n this.connected = true;\n this.emitBuffered();\n this.emitReserved(\"connect\");\n this._drainQueue(true);\n }\n /**\n * Emit buffered events (received and emitted).\n *\n * @private\n */\n emitBuffered() {\n this.receiveBuffer.forEach((args) => this.emitEvent(args));\n this.receiveBuffer = [];\n this.sendBuffer.forEach((packet) => {\n this.notifyOutgoingListeners(packet);\n this.packet(packet);\n });\n this.sendBuffer = [];\n }\n /**\n * Called upon server disconnect.\n *\n * @private\n */\n ondisconnect() {\n debug(\"server disconnect (%s)\", this.nsp);\n this.destroy();\n this.onclose(\"io server disconnect\");\n }\n /**\n * Called upon forced client/server side disconnections,\n * this method ensures the manager stops tracking us and\n * that reconnections don't get triggered for this.\n *\n * @private\n */\n destroy() {\n if (this.subs) {\n // clean subscriptions to avoid reconnections\n this.subs.forEach((subDestroy) => subDestroy());\n this.subs = undefined;\n }\n this.io[\"_destroy\"](this);\n }\n /**\n * Disconnects the socket manually. In that case, the socket will not try to reconnect.\n *\n * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.\n *\n * @example\n * const socket = io();\n *\n * socket.on(\"disconnect\", (reason) => {\n * // console.log(reason); prints \"io client disconnect\"\n * });\n *\n * socket.disconnect();\n *\n * @return self\n */\n disconnect() {\n if (this.connected) {\n debug(\"performing disconnect (%s)\", this.nsp);\n this.packet({ type: socket_io_parser_1.PacketType.DISCONNECT });\n }\n // remove socket from pool\n this.destroy();\n if (this.connected) {\n // fire events\n this.onclose(\"io client disconnect\");\n }\n return this;\n }\n /**\n * Alias for {@link disconnect()}.\n *\n * @return self\n */\n close() {\n return this.disconnect();\n }\n /**\n * Sets the compress flag.\n *\n * @example\n * socket.compress(false).emit(\"hello\");\n *\n * @param compress - if `true`, compresses the sending data\n * @return self\n */\n compress(compress) {\n this.flags.compress = compress;\n return this;\n }\n /**\n * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not\n * ready to send messages.\n *\n * @example\n * socket.volatile.emit(\"hello\"); // the server may or may not receive it\n *\n * @returns self\n */\n get volatile() {\n this.flags.volatile = true;\n return this;\n }\n /**\n * Sets a modifier for a subsequent event emission that the callback will be called with an error when the\n * given number of milliseconds have elapsed without an acknowledgement from the server:\n *\n * @example\n * socket.timeout(5000).emit(\"my-event\", (err) => {\n * if (err) {\n * // the server did not acknowledge the event in the given delay\n * }\n * });\n *\n * @returns self\n */\n timeout(timeout) {\n this.flags.timeout = timeout;\n return this;\n }\n /**\n * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n * callback.\n *\n * @example\n * socket.onAny((event, ...args) => {\n * console.log(`got ${event}`);\n * });\n *\n * @param listener\n */\n onAny(listener) {\n this._anyListeners = this._anyListeners || [];\n this._anyListeners.push(listener);\n return this;\n }\n /**\n * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n * callback. The listener is added to the beginning of the listeners array.\n *\n * @example\n * socket.prependAny((event, ...args) => {\n * console.log(`got event ${event}`);\n * });\n *\n * @param listener\n */\n prependAny(listener) {\n this._anyListeners = this._anyListeners || [];\n this._anyListeners.unshift(listener);\n return this;\n }\n /**\n * Removes the listener that will be fired when any event is emitted.\n *\n * @example\n * const catchAllListener = (event, ...args) => {\n * console.log(`got event ${event}`);\n * }\n *\n * socket.onAny(catchAllListener);\n *\n * // remove a specific listener\n * socket.offAny(catchAllListener);\n *\n * // or remove all listeners\n * socket.offAny();\n *\n * @param listener\n */\n offAny(listener) {\n if (!this._anyListeners) {\n return this;\n }\n if (listener) {\n const listeners = this._anyListeners;\n for (let i = 0; i < listeners.length; i++) {\n if (listener === listeners[i]) {\n listeners.splice(i, 1);\n return this;\n }\n }\n }\n else {\n this._anyListeners = [];\n }\n return this;\n }\n /**\n * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,\n * e.g. to remove listeners.\n */\n listenersAny() {\n return this._anyListeners || [];\n }\n /**\n * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n * callback.\n *\n * Note: acknowledgements sent to the server are not included.\n *\n * @example\n * socket.onAnyOutgoing((event, ...args) => {\n * console.log(`sent event ${event}`);\n * });\n *\n * @param listener\n */\n onAnyOutgoing(listener) {\n this._anyOutgoingListeners = this._anyOutgoingListeners || [];\n this._anyOutgoingListeners.push(listener);\n return this;\n }\n /**\n * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n * callback. The listener is added to the beginning of the listeners array.\n *\n * Note: acknowledgements sent to the server are not included.\n *\n * @example\n * socket.prependAnyOutgoing((event, ...args) => {\n * console.log(`sent event ${event}`);\n * });\n *\n * @param listener\n */\n prependAnyOutgoing(listener) {\n this._anyOutgoingListeners = this._anyOutgoingListeners || [];\n this._anyOutgoingListeners.unshift(listener);\n return this;\n }\n /**\n * Removes the listener that will be fired when any event is emitted.\n *\n * @example\n * const catchAllListener = (event, ...args) => {\n * console.log(`sent event ${event}`);\n * }\n *\n * socket.onAnyOutgoing(catchAllListener);\n *\n * // remove a specific listener\n * socket.offAnyOutgoing(catchAllListener);\n *\n * // or remove all listeners\n * socket.offAnyOutgoing();\n *\n * @param [listener] - the catch-all listener (optional)\n */\n offAnyOutgoing(listener) {\n if (!this._anyOutgoingListeners) {\n return this;\n }\n if (listener) {\n const listeners = this._anyOutgoingListeners;\n for (let i = 0; i < listeners.length; i++) {\n if (listener === listeners[i]) {\n listeners.splice(i, 1);\n return this;\n }\n }\n }\n else {\n this._anyOutgoingListeners = [];\n }\n return this;\n }\n /**\n * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,\n * e.g. to remove listeners.\n */\n listenersAnyOutgoing() {\n return this._anyOutgoingListeners || [];\n }\n /**\n * Notify the listeners for each packet sent\n *\n * @param packet\n *\n * @private\n */\n notifyOutgoingListeners(packet) {\n if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {\n const listeners = this._anyOutgoingListeners.slice();\n for (const listener of listeners) {\n listener.apply(this, packet.data);\n }\n }\n }\n}\nexports.Socket = Socket;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/socket.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-client/build/cjs/url.js": +/*!********************************************************!*\ + !*** ./node_modules/socket.io-client/build/cjs/url.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; +eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.url = void 0;\nconst engine_io_client_1 = __webpack_require__(/*! engine.io-client */ \"./node_modules/engine.io-client/build/cjs/index.js\");\nconst debug_1 = __importDefault(__webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")); // debug()\nconst debug = debug_1.default(\"socket.io-client:url\"); // debug()\n/**\n * URL parser.\n *\n * @param uri - url\n * @param path - the request path of the connection\n * @param loc - An object meant to mimic window.location.\n * Defaults to window.location.\n * @public\n */\nfunction url(uri, path = \"\", loc) {\n let obj = uri;\n // default to window.location\n loc = loc || (typeof location !== \"undefined\" && location);\n if (null == uri)\n uri = loc.protocol + \"//\" + loc.host;\n // relative path support\n if (typeof uri === \"string\") {\n if (\"/\" === uri.charAt(0)) {\n if (\"/\" === uri.charAt(1)) {\n uri = loc.protocol + uri;\n }\n else {\n uri = loc.host + uri;\n }\n }\n if (!/^(https?|wss?):\\/\\//.test(uri)) {\n debug(\"protocol-less url %s\", uri);\n if (\"undefined\" !== typeof loc) {\n uri = loc.protocol + \"//\" + uri;\n }\n else {\n uri = \"https://\" + uri;\n }\n }\n // parse\n debug(\"parse %s\", uri);\n obj = engine_io_client_1.parse(uri);\n }\n // make sure we treat `localhost:80` and `localhost` equally\n if (!obj.port) {\n if (/^(http|ws)$/.test(obj.protocol)) {\n obj.port = \"80\";\n }\n else if (/^(http|ws)s$/.test(obj.protocol)) {\n obj.port = \"443\";\n }\n }\n obj.path = obj.path || \"/\";\n const ipv6 = obj.host.indexOf(\":\") !== -1;\n const host = ipv6 ? \"[\" + obj.host + \"]\" : obj.host;\n // define unique id\n obj.id = obj.protocol + \"://\" + host + \":\" + obj.port + path;\n // define href\n obj.href =\n obj.protocol +\n \"://\" +\n host +\n (loc && loc.port === obj.port ? \"\" : \":\" + obj.port);\n return obj;\n}\nexports.url = url;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-client/build/cjs/url.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-parser/build/cjs/binary.js": +/*!***********************************************************!*\ + !*** ./node_modules/socket.io-parser/build/cjs/binary.js ***! + \***********************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.reconstructPacket = exports.deconstructPacket = void 0;\nconst is_binary_js_1 = __webpack_require__(/*! ./is-binary.js */ \"./node_modules/socket.io-parser/build/cjs/is-binary.js\");\n/**\n * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.\n *\n * @param {Object} packet - socket.io event packet\n * @return {Object} with deconstructed packet and list of buffers\n * @public\n */\nfunction deconstructPacket(packet) {\n const buffers = [];\n const packetData = packet.data;\n const pack = packet;\n pack.data = _deconstructPacket(packetData, buffers);\n pack.attachments = buffers.length; // number of binary 'attachments'\n return { packet: pack, buffers: buffers };\n}\nexports.deconstructPacket = deconstructPacket;\nfunction _deconstructPacket(data, buffers) {\n if (!data)\n return data;\n if ((0, is_binary_js_1.isBinary)(data)) {\n const placeholder = { _placeholder: true, num: buffers.length };\n buffers.push(data);\n return placeholder;\n }\n else if (Array.isArray(data)) {\n const newData = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n newData[i] = _deconstructPacket(data[i], buffers);\n }\n return newData;\n }\n else if (typeof data === \"object\" && !(data instanceof Date)) {\n const newData = {};\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n newData[key] = _deconstructPacket(data[key], buffers);\n }\n }\n return newData;\n }\n return data;\n}\n/**\n * Reconstructs a binary packet from its placeholder packet and buffers\n *\n * @param {Object} packet - event packet with placeholders\n * @param {Array} buffers - binary buffers to put in placeholder positions\n * @return {Object} reconstructed packet\n * @public\n */\nfunction reconstructPacket(packet, buffers) {\n packet.data = _reconstructPacket(packet.data, buffers);\n delete packet.attachments; // no longer useful\n return packet;\n}\nexports.reconstructPacket = reconstructPacket;\nfunction _reconstructPacket(data, buffers) {\n if (!data)\n return data;\n if (data && data._placeholder === true) {\n const isIndexValid = typeof data.num === \"number\" &&\n data.num >= 0 &&\n data.num < buffers.length;\n if (isIndexValid) {\n return buffers[data.num]; // appropriate buffer (should be natural order anyway)\n }\n else {\n throw new Error(\"illegal attachments\");\n }\n }\n else if (Array.isArray(data)) {\n for (let i = 0; i < data.length; i++) {\n data[i] = _reconstructPacket(data[i], buffers);\n }\n }\n else if (typeof data === \"object\") {\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n data[key] = _reconstructPacket(data[key], buffers);\n }\n }\n }\n return data;\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-parser/build/cjs/binary.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-parser/build/cjs/index.js": +/*!**********************************************************!*\ + !*** ./node_modules/socket.io-parser/build/cjs/index.js ***! + \**********************************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Decoder = exports.Encoder = exports.PacketType = exports.protocol = void 0;\nconst component_emitter_1 = __webpack_require__(/*! @socket.io/component-emitter */ \"./node_modules/@socket.io/component-emitter/index.mjs\");\nconst binary_js_1 = __webpack_require__(/*! ./binary.js */ \"./node_modules/socket.io-parser/build/cjs/binary.js\");\nconst is_binary_js_1 = __webpack_require__(/*! ./is-binary.js */ \"./node_modules/socket.io-parser/build/cjs/is-binary.js\");\nconst debug_1 = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\"); // debug()\nconst debug = (0, debug_1.default)(\"socket.io-parser\"); // debug()\n/**\n * These strings must not be used as event names, as they have a special meaning.\n */\nconst RESERVED_EVENTS = [\n \"connect\",\n \"connect_error\",\n \"disconnect\",\n \"disconnecting\",\n \"newListener\",\n \"removeListener\", // used by the Node.js EventEmitter\n];\n/**\n * Protocol version.\n *\n * @public\n */\nexports.protocol = 5;\nvar PacketType;\n(function (PacketType) {\n PacketType[PacketType[\"CONNECT\"] = 0] = \"CONNECT\";\n PacketType[PacketType[\"DISCONNECT\"] = 1] = \"DISCONNECT\";\n PacketType[PacketType[\"EVENT\"] = 2] = \"EVENT\";\n PacketType[PacketType[\"ACK\"] = 3] = \"ACK\";\n PacketType[PacketType[\"CONNECT_ERROR\"] = 4] = \"CONNECT_ERROR\";\n PacketType[PacketType[\"BINARY_EVENT\"] = 5] = \"BINARY_EVENT\";\n PacketType[PacketType[\"BINARY_ACK\"] = 6] = \"BINARY_ACK\";\n})(PacketType = exports.PacketType || (exports.PacketType = {}));\n/**\n * A socket.io Encoder instance\n */\nclass Encoder {\n /**\n * Encoder constructor\n *\n * @param {function} replacer - custom replacer to pass down to JSON.parse\n */\n constructor(replacer) {\n this.replacer = replacer;\n }\n /**\n * Encode a packet as a single string if non-binary, or as a\n * buffer sequence, depending on packet type.\n *\n * @param {Object} obj - packet object\n */\n encode(obj) {\n debug(\"encoding packet %j\", obj);\n if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {\n if ((0, is_binary_js_1.hasBinary)(obj)) {\n return this.encodeAsBinary({\n type: obj.type === PacketType.EVENT\n ? PacketType.BINARY_EVENT\n : PacketType.BINARY_ACK,\n nsp: obj.nsp,\n data: obj.data,\n id: obj.id,\n });\n }\n }\n return [this.encodeAsString(obj)];\n }\n /**\n * Encode packet as string.\n */\n encodeAsString(obj) {\n // first is type\n let str = \"\" + obj.type;\n // attachments if we have them\n if (obj.type === PacketType.BINARY_EVENT ||\n obj.type === PacketType.BINARY_ACK) {\n str += obj.attachments + \"-\";\n }\n // if we have a namespace other than `/`\n // we append it followed by a comma `,`\n if (obj.nsp && \"/\" !== obj.nsp) {\n str += obj.nsp + \",\";\n }\n // immediately followed by the id\n if (null != obj.id) {\n str += obj.id;\n }\n // json data\n if (null != obj.data) {\n str += JSON.stringify(obj.data, this.replacer);\n }\n debug(\"encoded %j as %s\", obj, str);\n return str;\n }\n /**\n * Encode packet as 'buffer sequence' by removing blobs, and\n * deconstructing packet into object with placeholders and\n * a list of buffers.\n */\n encodeAsBinary(obj) {\n const deconstruction = (0, binary_js_1.deconstructPacket)(obj);\n const pack = this.encodeAsString(deconstruction.packet);\n const buffers = deconstruction.buffers;\n buffers.unshift(pack); // add packet info to beginning of data list\n return buffers; // write all the buffers\n }\n}\nexports.Encoder = Encoder;\n// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript\nfunction isObject(value) {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n/**\n * A socket.io Decoder instance\n *\n * @return {Object} decoder\n */\nclass Decoder extends component_emitter_1.Emitter {\n /**\n * Decoder constructor\n *\n * @param {function} reviver - custom reviver to pass down to JSON.stringify\n */\n constructor(reviver) {\n super();\n this.reviver = reviver;\n }\n /**\n * Decodes an encoded packet string into packet JSON.\n *\n * @param {String} obj - encoded packet\n */\n add(obj) {\n let packet;\n if (typeof obj === \"string\") {\n if (this.reconstructor) {\n throw new Error(\"got plaintext data when reconstructing a packet\");\n }\n packet = this.decodeString(obj);\n const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;\n if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {\n packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;\n // binary packet's json\n this.reconstructor = new BinaryReconstructor(packet);\n // no attachments, labeled binary but no binary data to follow\n if (packet.attachments === 0) {\n super.emitReserved(\"decoded\", packet);\n }\n }\n else {\n // non-binary full packet\n super.emitReserved(\"decoded\", packet);\n }\n }\n else if ((0, is_binary_js_1.isBinary)(obj) || obj.base64) {\n // raw binary data\n if (!this.reconstructor) {\n throw new Error(\"got binary data when not reconstructing a packet\");\n }\n else {\n packet = this.reconstructor.takeBinaryData(obj);\n if (packet) {\n // received final buffer\n this.reconstructor = null;\n super.emitReserved(\"decoded\", packet);\n }\n }\n }\n else {\n throw new Error(\"Unknown type: \" + obj);\n }\n }\n /**\n * Decode a packet String (JSON data)\n *\n * @param {String} str\n * @return {Object} packet\n */\n decodeString(str) {\n let i = 0;\n // look up type\n const p = {\n type: Number(str.charAt(0)),\n };\n if (PacketType[p.type] === undefined) {\n throw new Error(\"unknown packet type \" + p.type);\n }\n // look up attachments if type binary\n if (p.type === PacketType.BINARY_EVENT ||\n p.type === PacketType.BINARY_ACK) {\n const start = i + 1;\n while (str.charAt(++i) !== \"-\" && i != str.length) { }\n const buf = str.substring(start, i);\n if (buf != Number(buf) || str.charAt(i) !== \"-\") {\n throw new Error(\"Illegal attachments\");\n }\n p.attachments = Number(buf);\n }\n // look up namespace (if any)\n if (\"/\" === str.charAt(i + 1)) {\n const start = i + 1;\n while (++i) {\n const c = str.charAt(i);\n if (\",\" === c)\n break;\n if (i === str.length)\n break;\n }\n p.nsp = str.substring(start, i);\n }\n else {\n p.nsp = \"/\";\n }\n // look up id\n const next = str.charAt(i + 1);\n if (\"\" !== next && Number(next) == next) {\n const start = i + 1;\n while (++i) {\n const c = str.charAt(i);\n if (null == c || Number(c) != c) {\n --i;\n break;\n }\n if (i === str.length)\n break;\n }\n p.id = Number(str.substring(start, i + 1));\n }\n // look up json data\n if (str.charAt(++i)) {\n const payload = this.tryParse(str.substr(i));\n if (Decoder.isPayloadValid(p.type, payload)) {\n p.data = payload;\n }\n else {\n throw new Error(\"invalid payload\");\n }\n }\n debug(\"decoded %s as %j\", str, p);\n return p;\n }\n tryParse(str) {\n try {\n return JSON.parse(str, this.reviver);\n }\n catch (e) {\n return false;\n }\n }\n static isPayloadValid(type, payload) {\n switch (type) {\n case PacketType.CONNECT:\n return isObject(payload);\n case PacketType.DISCONNECT:\n return payload === undefined;\n case PacketType.CONNECT_ERROR:\n return typeof payload === \"string\" || isObject(payload);\n case PacketType.EVENT:\n case PacketType.BINARY_EVENT:\n return (Array.isArray(payload) &&\n (typeof payload[0] === \"number\" ||\n (typeof payload[0] === \"string\" &&\n RESERVED_EVENTS.indexOf(payload[0]) === -1)));\n case PacketType.ACK:\n case PacketType.BINARY_ACK:\n return Array.isArray(payload);\n }\n }\n /**\n * Deallocates a parser's resources\n */\n destroy() {\n if (this.reconstructor) {\n this.reconstructor.finishedReconstruction();\n this.reconstructor = null;\n }\n }\n}\nexports.Decoder = Decoder;\n/**\n * A manager of a binary event's 'buffer sequence'. Should\n * be constructed whenever a packet of type BINARY_EVENT is\n * decoded.\n *\n * @param {Object} packet\n * @return {BinaryReconstructor} initialized reconstructor\n */\nclass BinaryReconstructor {\n constructor(packet) {\n this.packet = packet;\n this.buffers = [];\n this.reconPack = packet;\n }\n /**\n * Method to be called when binary data received from connection\n * after a BINARY_EVENT packet.\n *\n * @param {Buffer | ArrayBuffer} binData - the raw binary data received\n * @return {null | Object} returns null if more binary data is expected or\n * a reconstructed packet object if all buffers have been received.\n */\n takeBinaryData(binData) {\n this.buffers.push(binData);\n if (this.buffers.length === this.reconPack.attachments) {\n // done with buffer list\n const packet = (0, binary_js_1.reconstructPacket)(this.reconPack, this.buffers);\n this.finishedReconstruction();\n return packet;\n }\n return null;\n }\n /**\n * Cleans up binary packet reconstruction variables.\n */\n finishedReconstruction() {\n this.reconPack = null;\n this.buffers = [];\n }\n}\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-parser/build/cjs/index.js?"); + +/***/ }), + +/***/ "./node_modules/socket.io-parser/build/cjs/is-binary.js": +/*!**************************************************************!*\ + !*** ./node_modules/socket.io-parser/build/cjs/is-binary.js ***! + \**************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.hasBinary = exports.isBinary = void 0;\nconst withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\nconst isView = (obj) => {\n return typeof ArrayBuffer.isView === \"function\"\n ? ArrayBuffer.isView(obj)\n : obj.buffer instanceof ArrayBuffer;\n};\nconst toString = Object.prototype.toString;\nconst withNativeBlob = typeof Blob === \"function\" ||\n (typeof Blob !== \"undefined\" &&\n toString.call(Blob) === \"[object BlobConstructor]\");\nconst withNativeFile = typeof File === \"function\" ||\n (typeof File !== \"undefined\" &&\n toString.call(File) === \"[object FileConstructor]\");\n/**\n * Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.\n *\n * @private\n */\nfunction isBinary(obj) {\n return ((withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||\n (withNativeBlob && obj instanceof Blob) ||\n (withNativeFile && obj instanceof File));\n}\nexports.isBinary = isBinary;\nfunction hasBinary(obj, toJSON) {\n if (!obj || typeof obj !== \"object\") {\n return false;\n }\n if (Array.isArray(obj)) {\n for (let i = 0, l = obj.length; i < l; i++) {\n if (hasBinary(obj[i])) {\n return true;\n }\n }\n return false;\n }\n if (isBinary(obj)) {\n return true;\n }\n if (obj.toJSON &&\n typeof obj.toJSON === \"function\" &&\n arguments.length === 1) {\n return hasBinary(obj.toJSON(), true);\n }\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {\n return true;\n }\n }\n return false;\n}\nexports.hasBinary = hasBinary;\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/socket.io-parser/build/cjs/is-binary.js?"); + +/***/ }), + +/***/ "./node_modules/@socket.io/component-emitter/index.mjs": +/*!*************************************************************!*\ + !*** ./node_modules/@socket.io/component-emitter/index.mjs ***! + \*************************************************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Emitter: () => (/* binding */ Emitter)\n/* harmony export */ });\n/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nfunction Emitter(obj) {\n if (obj) return mixin(obj);\n}\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n for (var key in Emitter.prototype) {\n obj[key] = Emitter.prototype[key];\n }\n return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\nEmitter.prototype.addEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n .push(fn);\n return this;\n};\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n function on() {\n this.off(event, on);\n fn.apply(this, arguments);\n }\n\n on.fn = fn;\n this.on(event, on);\n return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\nEmitter.prototype.removeListener =\nEmitter.prototype.removeAllListeners =\nEmitter.prototype.removeEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n\n // all\n if (0 == arguments.length) {\n this._callbacks = {};\n return this;\n }\n\n // specific event\n var callbacks = this._callbacks['$' + event];\n if (!callbacks) return this;\n\n // remove all handlers\n if (1 == arguments.length) {\n delete this._callbacks['$' + event];\n return this;\n }\n\n // remove specific handler\n var cb;\n for (var i = 0; i < callbacks.length; i++) {\n cb = callbacks[i];\n if (cb === fn || cb.fn === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n\n // Remove event specific arrays for event types that no\n // one is subscribed for to avoid memory leak.\n if (callbacks.length === 0) {\n delete this._callbacks['$' + event];\n }\n\n return this;\n};\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n this._callbacks = this._callbacks || {};\n\n var args = new Array(arguments.length - 1)\n , callbacks = this._callbacks['$' + event];\n\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n\n if (callbacks) {\n callbacks = callbacks.slice(0);\n for (var i = 0, len = callbacks.length; i < len; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n\n return this;\n};\n\n// alias used for reserved events (protected method)\nEmitter.prototype.emitReserved = Emitter.prototype.emit;\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n this._callbacks = this._callbacks || {};\n return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n return !! this.listeners(event).length;\n};\n\n\n//# sourceURL=webpack://sqlitecloud/./node_modules/@socket.io/component-emitter/index.mjs?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./lib/index.js"); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +}); \ No newline at end of file diff --git a/public/sqlitecloud.drivers.js b/public/sqlitecloud.drivers.js new file mode 100644 index 0000000..6b80076 --- /dev/null +++ b/public/sqlitecloud.drivers.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.sqlitecloud=t():e.sqlitecloud=t()}(this,(()=>(()=>{var e={593:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.SQLiteCloudTlsConnection=void 0;const s=n(906),o=n(480),i=n(1),a=n(73),c=n(1),l=r(n(761)),u=r(n(59));class h extends o.SQLiteCloudConnection{get connected(){return!!this.socket}connectTransport(e,t){console.assert(!this.connected,"Connection already established");const n=e=>{this.socket&&(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),e&&this.close()),null==t||t.call(this,e)};this.config=e;const r=(0,a.getInitializationCommands)(e);if(e.insecure){const s={host:e.host,port:e.port};this.socket=l.default.connect(s,(()=>{console.warn(`TlsConnection.connectTransport - connected to ${e.host}:${e.port} using insecure protocol`),console.assert(this.socket,"Connection already closed"),this.transportCommands(r,(e=>{e&&this.socket&&this.close(),t&&(null==t||t.call(this,e),t=void 0),n(e)}))}))}else this.socket=u.default.connect(this.config.port,this.config.host,this.config.tlsOptions,(()=>{const e=this.socket;if(null==e?void 0:e.authorized){if(null===this.socket)return void n(new s.SQLiteCloudError("Connection was closed before it was done opening"));console.assert(this.socket,"Connection already closed"),this.transportCommands(r,(e=>{e&&this.socket&&this.close(),t&&(null==t||t.call(this,e),t=void 0),n(e)}))}else{const t=(0,a.anonimizeError)(e.authorizationError);console.error("Connection was not authorized",t),this.close(),n(new s.SQLiteCloudError("Connection was not authorized",{cause:t}))}}));return this.socket.on("close",(()=>{this.socket=null,n(new s.SQLiteCloudError("Connection was closed"))})),this.socket.once("error",(e=>{console.error("Connection error",e),n(new s.SQLiteCloudError("Connection error",{cause:e}))})),this}transportCommands(e,t){var n,r,o;if(!this.socket)return null==t||t.call(this,new s.SQLiteCloudError("Connection not established",{errorCode:"ERR_CONNECTION_NOT_ESTABLISHED"})),this;e=(0,i.formatCommand)(e);let l=Buffer.alloc(0);const u=[];let h;const d=(e,n)=>{clearTimeout(h),this.socket&&(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close")),t&&(null==t||t.call(this,e,n),t=void 0)},f=e=>{var t,n;try{let r=0===l.length?e.subarray(0,1).toString():l.subarray(0,1).toString("utf8");if(l=Buffer.concat([l,e]),(0,i.hasCommandLength)(r)){const e=(0,i.parseCommandLength)(l);if(l.length-l.indexOf(" ")-1>=e){if(null===(t=this.config)||void 0===t?void 0:t.verbose){let e=l.toString("utf8");e.length>1e3&&(e=e.substring(0,100)+"..."+e.substring(e.length-40))}if(r===i.CMD_COMPRESSED&&({buffer:l,dataType:r}=(0,i.decompressBuffer)(l)),r!==i.CMD_ROWSET_CHUNK){null===(n=this.socket)||void 0===n||n.off("data",f);const{data:e}=(0,i.popData)(l);d(null,e)}else if((0,i.bufferEndsWith)(l,i.ROWSET_CHUNKS_END)){u.push(l);const e=(0,c.parseRowsetChunks)(u);null==d||d.call(this,null,e)}else u.push(l),l=Buffer.alloc(0)}}else if(" "==l.subarray(l.length-1,l.length).toString("utf8")){const{data:e}=(0,i.popData)(l);d(null,e)}}catch(e){console.assert(e instanceof Error),e instanceof Error&&d(e)}};return null===(n=this.socket)||void 0===n||n.once("close",(()=>{d(new s.SQLiteCloudError("Connection was closed",{cause:(0,a.anonimizeCommand)(e)}))})),null===(r=this.socket)||void 0===r||r.write(e,"utf8",(()=>{var t,n;h=setTimeout((()=>{const t=new s.SQLiteCloudError("Request timed out",{cause:(0,a.anonimizeCommand)(e)});d(t)}),null===(t=this.config)||void 0===t?void 0:t.timeout),null===(n=this.socket)||void 0===n||n.on("data",f)})),null===(o=this.socket)||void 0===o||o.once("error",(e=>{console.error("Socket error",e),this.close(),d(new s.SQLiteCloudError("Socket error",{cause:(0,a.anonimizeError)(e)}))})),this}close(){return console.assert(null!==this.socket,"TlsConnection.close - connection already closed"),this.operations.clear(),this.socket&&(this.socket.destroy(),this.socket=null),this.socket=void 0,this}}t.SQLiteCloudTlsConnection=h,t.default=h},363:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SQLiteCloudWebsocketConnection=void 0;const r=n(906),s=n(825),o=n(480),i=n(46);class a extends o.SQLiteCloudConnection{get connected(){return!!this.socket}connectTransport(e,t){var n;try{if(console.assert(!this.connected,"Connection already established"),!this.socket){this.config=e;const t=this.config.connectionString,r=(null===(n=this.config)||void 0===n?void 0:n.gatewayUrl)||`ws://${this.config.host}:4000`;this.socket=(0,i.io)(r,{auth:{token:t}})}null==t||t.call(this,null)}catch(e){null==t||t.call(this,e)}return this}transportCommands(e,t){return this.socket?(this.socket.emit("v1/sql",{sql:e,row:"array"},(e=>{if(null==e?void 0:e.error){const n=new r.SQLiteCloudError(e.error.detail,Object.assign({},e.error));null==t||t.call(this,n)}else{const{data:n,metadata:r}=e;if(n&&r&&void 0!==r.numberOfRows&&void 0!==r.numberOfColumns&&void 0!==r.columns){console.assert(Array.isArray(n),"SQLiteCloudWebsocketConnection.transportCommands - data is not an array");const e=new s.SQLiteCloudRowset(r,n.flat());return void(null==t||t.call(this,null,e))}null==t||t.call(this,null,null==e?void 0:e.data)}})),this):(null==t||t.call(this,new r.SQLiteCloudError("Connection not established",{errorCode:"ERR_CONNECTION_NOT_ESTABLISHED"})),this)}close(){var e;return console.assert(null!==this.socket,"SQLiteCloudWebsocketConnection.close - connection already closed"),this.socket&&(null===(e=this.socket)||void 0===e||e.close(),this.socket=void 0),this.operations.clear(),this.socket=void 0,this}}t.SQLiteCloudWebsocketConnection=a,t.default=a},480:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SQLiteCloudConnection=void 0;const r=n(906),s=n(73),o=n(39),i=n(73);t.SQLiteCloudConnection=class{constructor(e,t){this.operations=new o.OperationsQueue,this.config="string"==typeof e?(0,s.validateConfiguration)({connectionString:e}):(0,s.validateConfiguration)(e),this.connect(t)}connect(e){return this.operations.enqueue((t=>{this.connectTransport(this.config,(n=>{n&&(console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${n.toString()}`,n),this.close()),null==e||e.call(this,n||null),t(n)}))})),this}log(e,...t){this.config.verbose&&(e=(0,i.anonimizeCommand)(e),console.log(`${(new Date).toISOString()} ${this.config.clientId}: ${e}`,...t))}verbose(){this.config.verbose=!0}sendCommands(e,t){return this.operations.enqueue((n=>{if(!this.connected){const e=new r.SQLiteCloudError("Connection not established",{errorCode:"ERR_CONNECTION_NOT_ESTABLISHED"});null==t||t.call(this,e),n(e)}this.transportCommands(e,((e,r)=>{null==t||t.call(this,e,r),n(e)}))})),this}}},751:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var s=Object.getOwnPropertyDescriptor(t,n);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,s)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return s(t,e),t},i=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(s,o){function i(e){try{c(r.next(e))}catch(e){o(e)}}function a(e){try{c(r.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,a)}c((r=r.apply(e,t||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Database=void 0;const c=n(825),l=n(906),u=n(73),h=n(880),d=a(n(729)),f=n(73);class p extends d.default{constructor(e,t,n){super(),this.connections=[],this.config="string"==typeof e?{connectionString:e}:e,"function"==typeof t&&(n=t,t=void 0),this.getConnection(((e,t)=>{n&&n.call(this,e)}))}getConnection(e){var t,r,s;(null===(t=this.connections)||void 0===t?void 0:t.length)>0?null==e||e.call(this,null,this.connections[0]):f.isBrowser||(null===(r=this.config)||void 0===r?void 0:r.useWebsocket)||(null===(s=this.config)||void 0===s?void 0:s.gatewayUrl)?Promise.resolve().then((()=>o(n(363)))).then((t=>{this.connections.push(new t.default(this.config,(t=>{t?this.handleError(this.connections[0],t,e):(console.assert,null==e||e.call(this,null,this.connections[0]),this.emitEvent("open"))})))})).catch((t=>{this.handleError(null,t,e)})):Promise.resolve().then((()=>o(n(593)))).then((t=>{this.connections.push(new t.default(this.config,(t=>{t?this.handleError(this.connections[0],t,e):(console.assert,null==e||e.call(this,null,this.connections[0]),this.emitEvent("open"))})))})).catch((t=>{this.handleError(null,t,e)}))}handleError(e,t,n){e&&(this.connections=this.connections.filter((t=>t!==e)),e.close()),n?n.call(this,t):this.emitEvent("error",t)}processContext(e){if(e&&Array.isArray(e)&&e.length>0&&e[0]===l.SQLiteCloudArrayType.ARRAY_TYPE_SQLITE_EXEC)return{lastID:e[2],changes:e[3],totalChanges:e[4],finalized:e[5]}}emitEvent(e,...t){setTimeout((()=>{this.emit(e,...t)}),0)}getConfiguration(){return JSON.parse(JSON.stringify(this.config))}verbose(){this.config.verbose=!0;for(const e of this.connections)e.verbose();return this}configure(e,t){return this}run(e,...t){const{args:n,callback:r}=(0,u.popCallback)(t),s=(null==n?void 0:n.length)>0?(0,u.prepareSql)(e,...n):e;return this.getConnection(((e,t)=>{e||!t?this.handleError(null,e,r):t.sendCommands(s,((e,n)=>{if(e)this.handleError(t,e,r);else{const e=this.processContext(n);null==r||r.call(e||this,null,e?void 0:n)}}))})),this}get(e,...t){const{args:n,callback:r}=(0,u.popCallback)(t),s=(null==n?void 0:n.length)>0?(0,u.prepareSql)(e,...n):e;return this.getConnection(((e,t)=>{e||!t?this.handleError(null,e,r):t.sendCommands(s,((e,n)=>{e?this.handleError(t,e,r):n&&n instanceof c.SQLiteCloudRowset&&n.length>0?null==r||r.call(this,null,n[0]):null==r||r.call(this,null)}))})),this}all(e,...t){const{args:n,callback:r}=(0,u.popCallback)(t),s=(null==n?void 0:n.length)>0?(0,u.prepareSql)(e,...n):e;return this.getConnection(((e,t)=>{e||!t?this.handleError(null,e,r):t.sendCommands(s,((e,n)=>{e?this.handleError(t,e,r):n&&n instanceof c.SQLiteCloudRowset?null==r||r.call(this,null,n):null==r||r.call(this,null)}))})),this}each(e,...t){const{args:n,callback:r,complete:s}=(0,u.popCallback)(t),o=(null==n?void 0:n.length)>0?(0,u.prepareSql)(e,...n):e;return this.getConnection(((e,t)=>{e||!t?this.handleError(null,e,r):t.sendCommands(o,((e,n)=>{if(e)this.handleError(t,e,r);else if(n&&n instanceof c.SQLiteCloudRowset){if(r)for(const e of n)r.call(this,null,e);s&&s.call(this,null,n.numberOfRows)}else null==r||r.call(this,new l.SQLiteCloudError("Invalid rowset"))}))})),this}prepare(e,...t){const{args:n,callback:r}=(0,u.popCallback)(t);return new h.Statement(this,e,...n,r)}exec(e,t){return this.getConnection(((n,r)=>{n||!r?this.handleError(null,n,t):r.sendCommands(e,((e,n)=>{if(e)this.handleError(r,e,t);else{const e=this.processContext(n);null==t||t.call(e||this,null)}}))})),this}close(e){var t;if((null===(t=this.connections)||void 0===t?void 0:t.length)>0)for(const e of this.connections)e.close();null==e||e.call(this,null),this.emitEvent("close")}loadExtension(e,t){return t?t.call(this,new Error("Database.loadExtension - Not implemented")):this.emitEvent("error",new Error("Database.loadExtension - Not implemented")),this}interrupt(){}sql(e,...t){return i(this,void 0,void 0,(function*(){let n="";if(Array.isArray(e)&&"raw"in e)e.forEach(((e,r)=>{n+=e+(r0?(0,u.prepareSql)(e,...t):e}return new Promise(((e,t)=>{this.getConnection(((r,s)=>{r||!s?t(r):s.sendCommands(n,((n,r)=>{if(n)t(n);else{const t=this.processContext(r);e(t||r)}}))}))}))}))}}t.Database=p},1:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatCommand=t.popData=t.parseRowsetChunks=t.bufferEndsWith=t.bufferStartsWith=t.parseRowsetHeader=t.parseArray=t.parseError=t.decompressBuffer=t.parseCommandLength=t.hasCommandLength=t.ROWSET_CHUNKS_END=t.CMD_ARRAY=t.CMD_COMMAND=t.CMD_COMPRESSED=t.CMD_BLOB=t.CMD_NULL=t.CMD_JSON=t.CMD_ROWSET_CHUNK=t.CMD_ROWSET=t.CMD_FLOAT=t.CMD_INT=t.CMD_ERROR=t.CMD_ZEROSTRING=t.CMD_STRING=void 0;const r=n(906),s=n(825),o=n(405);function i(e,t){const n=e.subarray(t+1).toString("utf8").split(" ");let s=n.shift()||"0",o="0",i="-1";const a=s.split(":");s=a[0],a.length>1&&(o=a[1],a.length>2&&(i=a[2]));const c=n.join(" "),l=parseInt(s),u=parseInt(o),h=parseInt(i);throw new r.SQLiteCloudError(c,{errorCode:l.toString(),externalErrorCode:u.toString(),offsetCode:h})}function a(e,t){const n=[],r=e.subarray(t+1,e.length),s=parseInt(r.subarray(0,t-2).toString("utf8"));let o=r.subarray(r.indexOf(" ")+1,r.length);for(let e=0;e=t.length&&e.subarray(0,t.length).toString("utf8")===t}function h(e,t){return e.length>=t.length&&e.subarray(e.length-t.length,e.length).toString("utf8")===t}function d(e){function n(t){return{data:t,fwdBuffer:e.subarray(u)}}console.assert(e&&e instanceof Buffer);const r=e.subarray(0,1).toString("utf8");console.assert(r!==t.CMD_COMPRESSED,"Compressed data shouldn't be decompressed before parsing"),console.assert(r!==t.CMD_ROWSET_CHUNK,"Chunked data should be parsed by parseRowsetChunks");let o=e.indexOf(" ");-1===o&&(o=e.length-1);let u=-1;if(r===t.CMD_INT||r===t.CMD_FLOAT||r===t.CMD_NULL)u=o+1;else{const t=parseInt(e.subarray(1,o).toString());u=o+1+t}switch(r){case t.CMD_INT:return n(parseInt(e.subarray(1,o).toString()));case t.CMD_FLOAT:return n(parseFloat(e.subarray(1,o).toString()));case t.CMD_NULL:return n(null);case t.CMD_STRING:return n(e.subarray(o+1,u).toString("utf8"));case t.CMD_ZEROSTRING:return n(e.subarray(o+1,u-1).toString("utf8"));case t.CMD_COMMAND:return n(e.subarray(o+1,u).toString("utf8"));case t.CMD_JSON:return n(JSON.parse(e.subarray(o+1,u).toString("utf8")));case t.CMD_BLOB:return n(e.subarray(o+1,u));case t.CMD_ARRAY:return n(a(e,o));case t.CMD_ROWSET:return n(function(e,t){e=e.subarray(t+1,e.length);const{metadata:n,fwdBuffer:r}=c(e);e=l(r,n);const o=[];for(let t=0;t0&&!u(n,t.ROWSET_CHUNKS_END);){const{index:e,metadata:t,fwdBuffer:s}=c(n);n=s,1===e?(r=t,n=l(n,r)):r.numberOfRows+=t.numberOfRows;for(let e=0;e{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.OperationsQueue=void 0,t.OperationsQueue=class{constructor(){this.queue=[],this.isProcessing=!1}enqueue(e){this.queue.push(e),this.isProcessing||this.processNext()}clear(){this.queue=[],this.isProcessing=!1}processNext(){if(0===this.queue.length)return void(this.isProcessing=!1);this.isProcessing=!0;const e=this.queue.shift();null==e||e((()=>{this.processNext()}))}}},825:function(e,t,n){"use strict";var r,s,o,i,a=this&&this.__classPrivateFieldSet||function(e,t,n,r,s){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!s)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?s.call(e,n):s?s.value=n:t.set(e,n),n},c=this&&this.__classPrivateFieldGet||function(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)};Object.defineProperty(t,"__esModule",{value:!0}),t.SQLiteCloudRowset=t.SQLiteCloudRow=void 0;const l=n(906);class u{constructor(e,t,n){r.set(this,void 0),s.set(this,void 0),a(this,r,e,"f"),a(this,s,n,"f");for(let e=0;er!==t&&e===n[t]))>=0;)n[t]=`${n[t]}_${e}`,e++}for(let r=0,s=0;re.name))}get metadata(){return c(this,o,"f")}getItem(e,t){if(e<0||e>=this.numberOfRows||t<0||t>=this.numberOfColumns)throw new l.SQLiteCloudError(`This rowset has ${this.numberOfColumns} columns by ${this.numberOfRows} rows, requested column ${t} and row ${e} is invalid.`);return c(this,i,"f")[e*this.numberOfColumns+t]}slice(e,t){e=void 0===e?0:e<0?this.numberOfRows+e:e,e=Math.min(Math.max(e,0),this.numberOfRows),t=void 0===t?this.numberOfRows:t<0?this.numberOfRows+t:t,t=Math.min(Math.max(e,t),this.numberOfRows);const n=Object.assign(Object.assign({},c(this,o,"f")),{numberOfRows:t-e}),r=c(this,i,"f").slice(e*this.numberOfColumns,t*this.numberOfColumns);return console.assert(r&&r.length===n.numberOfRows*n.numberOfColumns,"SQLiteCloudRowset.slice - invalid rowset data"),new h(n,r)}map(e){const t=[];for(let n=0;n{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Statement=void 0;const r=n(73);t.Statement=class{constructor(e,t,...n){const{args:s,callback:o}=(0,r.popCallback)(n);this._database=e,this._sql=t,(null==s?void 0:s.length)>0?this.bind(...s,o):null==o||o.call(this,null)}bind(...e){const{args:t,callback:n}=(0,r.popCallback)(e);try{this._preparedSql=(0,r.prepareSql)(this._sql,...t),n&&n.call(this,null)}catch(e){this._preparedSql=void 0,n&&n.call(this,e)}return this}run(...e){const{args:t,callback:n}=(0,r.popCallback)(e||[]);return(null==t?void 0:t.length)>0?this.bind(...t,(e=>{e?null==n||n.call(this,e):this._database.run(this._preparedSql||"",n)})):this._database.run(this._preparedSql||"",n),this}get(...e){const{args:t,callback:n}=(0,r.popCallback)(e||[]);return(null==t?void 0:t.length)>0?this.bind(...t,(e=>{e?null==n||n.call(this,e):this._database.get(this._preparedSql||"",n)})):this._database.get(this._preparedSql||"",n),this}all(...e){const{args:t,callback:n}=(0,r.popCallback)(e||[]);return(null==t?void 0:t.length)>0?this.bind(...t,(e=>{e?null==n||n.call(this,e):this._database.all(this._preparedSql||"",n)})):this._database.all(this._preparedSql||"",n),this}each(...e){const{args:t,callback:n,complete:s}=(0,r.popCallback)(e);return(null==t?void 0:t.length)>0?this.bind(...t,(e=>{e?null==n||n.call(this,e):this._database.each(this._preparedSql||"",n,s)})):this._database.each(this._preparedSql||"",n,s),this}}},906:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SQLiteCloudArrayType=t.SQLiteCloudError=t.DEFAULT_PORT=t.DEFAULT_TIMEOUT=void 0,t.DEFAULT_TIMEOUT=3e5,t.DEFAULT_PORT=9960;class n extends Error{constructor(e,t){super(e),this.name="SQLiteCloudError",t&&Object.assign(this,t)}}var r;t.SQLiteCloudError=n,(r=t.SQLiteCloudArrayType||(t.SQLiteCloudArrayType={}))[r.ARRAY_TYPE_SQLITE_EXEC=10]="ARRAY_TYPE_SQLITE_EXEC",r[r.ARRAY_TYPE_DB_STATUS=11]="ARRAY_TYPE_DB_STATUS",r[r.ARRAY_TYPE_METADATA=12]="ARRAY_TYPE_METADATA",r[r.ARRAY_TYPE_VM_STEP=20]="ARRAY_TYPE_VM_STEP",r[r.ARRAY_TYPE_VM_COMPILE=21]="ARRAY_TYPE_VM_COMPILE",r[r.ARRAY_TYPE_VM_STEP_ONE=22]="ARRAY_TYPE_VM_STEP_ONE",r[r.ARRAY_TYPE_VM_SQL=23]="ARRAY_TYPE_VM_SQL",r[r.ARRAY_TYPE_VM_STATUS=24]="ARRAY_TYPE_VM_STATUS",r[r.ARRAY_TYPE_VM_LIST=25]="ARRAY_TYPE_VM_LIST",r[r.ARRAY_TYPE_BACKUP_INIT=40]="ARRAY_TYPE_BACKUP_INIT",r[r.ARRAY_TYPE_BACKUP_STEP=41]="ARRAY_TYPE_BACKUP_STEP",r[r.ARRAY_TYPE_BACKUP_END=42]="ARRAY_TYPE_BACKUP_END",r[r.ARRAY_TYPE_SQLITE_STATUS=50]="ARRAY_TYPE_SQLITE_STATUS"},73:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parseBoolean=t.parseConnectionString=t.validateConfiguration=t.popCallback=t.prepareSql=t.escapeSqlParameter=t.getInitializationCommands=t.anonimizeError=t.anonimizeCommand=t.isNode=t.isBrowser=void 0;const r=n(906);function s(e){return(e=(e=e.replace(/USER \S+/,"USER ******")).replace(/PASSWORD \S+?(?=;)/,"PASSWORD ******")).replace(/HASH \S+?(?=;)/,"HASH ******")}function o(e){if(null==e)return"NULL";if("string"==typeof e)return`'${e=e.replace(/'/g,"''")}'`;if("number"==typeof e)return e.toString();if("boolean"==typeof e)return e?"1":"0";if(Buffer.isBuffer(e))return`X'${e.toString("hex")}'`;if("object"==typeof e){let t=JSON.stringify(e);return t=t.replace(/'/g,"''"),`'${t}'`}throw new r.SQLiteCloudError("Unsupported parameter type: "+typeof e)}function i(e){try{const t=e.replace("sqlitecloud:","https:"),n=new URL(t),r={};n.searchParams.forEach(((e,t)=>{r[t]=e}));const s=Object.assign({username:n.username,password:n.password,host:n.hostname,port:n.port?parseInt(n.port):void 0},r),o=n.pathname.replace("/","");return o&&(s.database=o),s}catch(t){throw new r.SQLiteCloudError(`Invalid connection string: ${e}`)}}function a(e){return"string"==typeof e?"true"===e.toLowerCase()||"1"===e:!!e}t.isBrowser="undefined"!=typeof window&&void 0!==window.document,t.isNode="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node,t.anonimizeCommand=s,t.anonimizeError=function(e){return(null==e?void 0:e.message)&&(e.message=s(e.message)),e},t.getInitializationCommands=function(e){let t=`AUTH USER ${e.username||""} ${e.passwordHashed?"HASH":"PASSWORD"} ${e.password||""}; `;return e.database&&(e.createDatabase&&!e.dbMemory&&(t+=`CREATE DATABASE ${e.database} IF NOT EXISTS; `),t+=`USE DATABASE ${e.database}; `),e.compression&&(t+="SET CLIENT KEY COMPRESSION TO 1; "),e.nonlinearizable&&(t+="SET CLIENT KEY NONLINEARIZABLE TO 1; "),e.noBlob&&(t+="SET CLIENT KEY NOBLOB TO 1; "),e.maxData&&(t+=`SET CLIENT KEY MAXDATA TO ${e.maxData}; `),e.maxRows&&(t+=`SET CLIENT KEY MAXROWS TO ${e.maxRows}; `),e.maxRowset&&(t+=`SET CLIENT KEY MAXROWSET TO ${e.maxRowset}; `),t},t.escapeSqlParameter=o,t.prepareSql=function(e,...t){1===(null==t?void 0:t.length)&&Array.isArray(t[0])&&(t=t[0]);let n=1,s=e.replace(/\?(\d+)?/g,((e,s)=>{const i=s?parseInt(s):n;let a;if(n++,!t[0]||"object"!=typeof t[0]||t[0]instanceof Buffer||(a=t[0][i]),!a){if(i>t.length)throw new r.SQLiteCloudError("Not enough parameters");a=t[i-1]}return null!=a?o(a):"NULL"}));if(1===(null==t?void 0:t.length)&&t[0]&&"object"==typeof t[0]){const e=t[0];for(const[t,n]of Object.entries(e)){const e=t.charAt(0);if("$"==e||":"==e||"@"==e){const e=o(n);s=s.replace(new RegExp(`\\${t}`,"g"),e)}}}return s},t.popCallback=function(e){const t=e;return e&&e.length>0&&"function"==typeof e[e.length-1]?e.length>1&&"function"==typeof e[e.length-2]?{args:t.slice(0,-2),callback:e[e.length-2],complete:e[e.length-1]}:{args:t.slice(0,-1),callback:e[e.length-1]}:{args:t}},t.validateConfiguration=function(e){if(console.assert(e,"SQLiteCloudConnection.validateConfiguration - missing config"),e.connectionString&&(e=Object.assign(Object.assign(Object.assign({},e),i(e.connectionString)),{connectionString:e.connectionString})),e.port||(e.port=r.DEFAULT_PORT),e.timeout=e.timeout&&e.timeout>0?e.timeout:r.DEFAULT_TIMEOUT,e.clientId||(e.clientId="SQLiteCloud"),e.verbose=a(e.verbose),e.noBlob=a(e.noBlob),e.compression=a(e.compression),e.createDatabase=a(e.createDatabase),e.nonlinearizable=a(e.nonlinearizable),e.insecure=a(e.insecure),!e.username||!e.password||!e.host)throw console.error("SQLiteCloudConnection.validateConfiguration - missing arguments",e),new r.SQLiteCloudError("The user, password and host arguments must be specified.",{errorCode:"ERR_MISSING_ARGS"});return e.connectionString||(e.connectionString=`sqlitecloud://${e.username}:${e.password}@${e.host}:${e.port}/${e.database}`),e},t.parseConnectionString=i,t.parseBoolean=a},227:(e,t,n)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,s=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(s=r))})),t.splice(s,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(447)(t);const{formatters:r}=e.exports;r.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,s,o,i=null;function a(...e){if(!a.enabled)return;const r=a,s=Number(new Date),o=s-(n||s);r.diff=o,r.prev=n,r.curr=s,n=s,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,s)=>{if("%%"===n)return"%";i++;const o=t.formatters[s];if("function"==typeof o){const t=e[i];n=o.call(r,t),e.splice(i,1),i--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=r,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(s!==t.namespaces&&(s=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function s(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(s),...t.skips.map(s).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),s=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t{"use strict";var t=Object.prototype.hasOwnProperty,n="~";function r(){}function s(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function o(e,t,r,o,i){if("function"!=typeof r)throw new TypeError("The listener must be a function");var a=new s(r,o||e,i),c=n?n+t:t;return e._events[c]?e._events[c].fn?e._events[c]=[e._events[c],a]:e._events[c].push(a):(e._events[c]=a,e._eventsCount++),e}function i(e,t){0==--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),a.prototype.eventNames=function(){var e,r,s=[];if(0===this._eventsCount)return s;for(r in e=this._events)t.call(e,r)&&s.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?s.concat(Object.getOwnPropertySymbols(e)):s},a.prototype.listeners=function(e){var t=n?n+e:e,r=this._events[t];if(!r)return[];if(r.fn)return[r.fn];for(var s=0,o=r.length,i=new Array(o);s{var r=n(887),s=n(325),o=65536,i=h(5<<20),a=function(){try{return new Uint32Array(o)}catch(n){for(var e=new Array(o),t=0;t>4&7;if(void 0===u[i])throw new Error("invalid block size "+i);var a=u[i];if(o)return s.readU64(e,t);t++;for(var h=0;;){var d=s.readU32(e,t);if(t+=4,h+=d&l?d&=2147483647:a,0===d)return h;r&&(t+=4),t+=d}},t.makeBuffer=h,t.decompressBlock=function(e,t,n,r,s){var o,i,a,c,l;for(a=n+r;n>4;if(h>0){if(15===h)for(;h+=e[n],255===e[n++];);for(c=n+h;n=a)break;if(o=15&u,i=e[n++]|e[n++]<<8,15===o)for(;o+=e[n],255===e[n++];);for(c=(l=s-i)+(o+=4);l=13)for(var p=67;n+4>>0;if(i=o[g=(g>>16^g)>>>0&65535]-1,o[g]=n+1,i<0||n-i>>>16>0||s.readU32(e,i)!==m)n+=p++>>6;else{for(p=67,u=n-a,l=n-i,i+=4,c=n+=4;n=15){for(t[h++]=240+y,f=u-15;f>=255;f-=255)t[h++]=255;t[h++]=f}else t[h++]=(u<<4)+y;for(var b=0;b>8,c>=15){for(f=c-15;f>=255;f-=255)t[h++]=255;t[h++]=f}a=n}}if(0===a)return 0;if((u=d-a)>=15){for(t[h++]=240,f=u-15;f>=255;f-=255)t[h++]=255;t[h++]=f}else t[h++]=u<<4;for(n=a;n>4&7;if(void 0===u[f])throw new Error("invalid block size");for(i&&(h+=8),h++;;){var p;if(p=s.readU32(e,h),h+=4,0===p)break;if(r&&(h+=4),0!=(p&l)){p&=2147483647;for(var m=0;m>8,l++;var h=u[7],d=e.length,f=0;for(function(e){for(var t=0;t0;){var p,m=d>h?h:d;if((p=t.compressBlock(e,i,f,m,a))>m||0===p){s.writeU32(n,l,2147483648|m),l+=4;for(var g=f+m;f{t.hashU32=function(e){return-1252372727^(e=(e=(e=374761393+(e=-949894596^(e=2127912214+(e|=0)+(e<<12)|0)^e>>>19)+(e<<5)|0)-744332180^e<<9)-42973499+(e<<3)|0)^e>>>16|0},t.readU64=function(e,t){var n=0;return n|=e[t++]<<0,n|=e[t++]<<8,n|=e[t++]<<16,n|=e[t++]<<24,n|=e[t++]<<32,n|=e[t++]<<40,(n|=e[t++]<<48)|e[t++]<<56},t.readU32=function(e,t){var n=0;return n|=e[t++]<<0,n|=e[t++]<<8,(n|=e[t++]<<16)|e[t++]<<24},t.writeU32=function(e,t,n){e[t++]=n>>0&255,e[t++]=n>>8&255,e[t++]=n>>16&255,e[t++]=n>>24&255},t.imul=function(e,t){var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16)|0}},887:(e,t,n)=>{var r=n(325),s=2654435761,o=2246822519,i=3266489917,a=374761393;function c(e,t){return(e|=0)>>>(32-(t|=0)|0)|e<>>(32-t|0)|e<>>(t|=0)^e|0}function h(e,t,n,s,o){return l(r.imul(t,n)+e,s,o)}function d(e,t,n){return l(e+r.imul(t[n],a),11,s)}function f(e,t,n){return h(e,r.readU32(t,n),i,17,668265263)}function p(e,t,n){return[h(e[0],r.readU32(t,n+0),o,13,s),h(e[1],r.readU32(t,n+4),o,13,s),h(e[2],r.readU32(t,n+8),o,13,s),h(e[3],r.readU32(t,n+12),o,13,s)]}t.hash=function(e,t,n,l){var h,m;if(m=l,l>=16){for(h=[e+s+o,e+o,e,e-s];l>=16;)h=p(h,t,n),n+=16,l-=16;h=c(h[0],1)+c(h[1],7)+c(h[2],12)+c(h[3],18)+m}else h=e+a+l>>>0;for(;l>=4;)h=f(h,t,n),n+=4,l-=4;for(;l>0;)h=d(h,t,n),n++,l--;return(h=u(r.imul(u(r.imul(u(h,15),o),13),i),16))>>>0}},824:e=>{var t=1e3,n=60*t,r=60*n,s=24*r;function o(e,t,n,r){var s=t>=1.5*n;return Math.round(e/n)+" "+r+(s?"s":"")}e.exports=function(e,i){i=i||{};var a,c,l=typeof e;if("string"===l&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*s;case"hours":case"hour":case"hrs":case"hr":case"h":return i*r;case"minutes":case"minute":case"mins":case"min":case"m":return i*n;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===l&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=s?o(a,c,s,"day"):c>=r?o(a,c,r,"hour"):c>=n?o(a,c,n,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=s?Math.round(e/s)+"d":o>=r?Math.round(e/r)+"h":o>=n?Math.round(e/n)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},761:()=>{},59:()=>{},419:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasCORS=void 0;let n=!1;try{n="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}t.hasCORS=n},754:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0,t.encode=function(e){let t="";for(let n in e)e.hasOwnProperty(n)&&(t.length&&(t+="&"),t+=encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return t},t.decode=function(e){let t={},n=e.split("&");for(let e=0,r=n.length;e{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;const n=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,r=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.parse=function(e){if(e.length>2e3)throw"URI too long";const t=e,s=e.indexOf("["),o=e.indexOf("]");-1!=s&&-1!=o&&(e=e.substring(0,s)+e.substring(s,o).replace(/:/g,";")+e.substring(o,e.length));let i=n.exec(e||""),a={},c=14;for(;c--;)a[r[c]]=i[c]||"";return-1!=s&&-1!=o&&(a.source=t,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(e,t){const n=t.replace(/\/{2,9}/g,"/").split("/");return"/"!=t.slice(0,1)&&0!==t.length||n.splice(0,1),"/"==t.slice(-1)&&n.splice(n.length-1,1),n}(0,a.path),a.queryKey=function(e,t){const n={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,r){t&&(n[t]=r)})),n}(0,a.query),a}},726:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.yeast=t.decode=t.encode=void 0;const n="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),r={};let s,o=0,i=0;function a(e){let t="";do{t=n[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}for(t.encode=a,t.decode=function(e){let t=0;for(i=0;i{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.globalThisShim=void 0,t.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},679:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.nextTick=t.parse=t.installTimerFunctions=t.transports=t.TransportError=t.Transport=t.protocol=t.Socket=void 0;const r=n(481);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return r.Socket}}),t.protocol=r.Socket.protocol;var s=n(870);Object.defineProperty(t,"Transport",{enumerable:!0,get:function(){return s.Transport}}),Object.defineProperty(t,"TransportError",{enumerable:!0,get:function(){return s.TransportError}});var o=n(385);Object.defineProperty(t,"transports",{enumerable:!0,get:function(){return o.transports}});var i=n(622);Object.defineProperty(t,"installTimerFunctions",{enumerable:!0,get:function(){return i.installTimerFunctions}});var a=n(222);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return a.parse}});var c=n(552);Object.defineProperty(t,"nextTick",{enumerable:!0,get:function(){return c.nextTick}})},481:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const s=n(385),o=n(622),i=n(754),a=n(222),c=r(n(227)),l=n(260),u=n(373),h=n(552),d=(0,c.default)("engine.io-client:socket");class f extends l.Emitter{constructor(e,t={}){super(),this.binaryType=h.defaultBinaryType,this.writeBuffer=[],e&&"object"==typeof e&&(t=e,e=null),e?(e=(0,a.parse)(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=(0,a.parse)(t.host).host),(0,o.installTimerFunctions)(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket","webtransport"],this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!1},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,i.decode)(this.opts.query)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingTimeoutTimer=null,"function"==typeof addEventListener&&(this.opts.closeOnBeforeunload&&(this.beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this.beforeunloadEventListener,!1)),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){d('creating transport "%s"',e);const t=Object.assign({},this.opts.query);t.EIO=u.protocol,t.transport=e,this.id&&(t.sid=this.id);const n=Object.assign({},this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port},this.opts.transportOptions[e]);return d("options: %j",n),new s.transports[e](n)}open(){let e;if(this.opts.rememberUpgrade&&f.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return d("error while creating transport: %s",e),this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){d("setting transport %s",e.name),this.transport&&(d("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){d('probing transport "%s"',e);let t=this.createTransport(e),n=!1;f.priorWebsocketSuccess=!1;const r=()=>{n||(d('probe transport "%s" opened',e),t.send([{type:"ping",data:"probe"}]),t.once("packet",(r=>{if(!n)if("pong"===r.type&&"probe"===r.data){if(d('probe transport "%s" pong',e),this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;f.priorWebsocketSuccess="websocket"===t.name,d('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{n||"closed"!==this.readyState&&(d("changing transport and sending upgrade packet"),l(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{d('probe transport "%s" failed',e);const n=new Error("probe error");n.transport=t.name,this.emitReserved("upgradeError",n)}})))};function s(){n||(n=!0,l(),t.close(),t=null)}const o=n=>{const r=new Error("probe error: "+n);r.transport=t.name,s(),d('probe transport "%s" failed because of error: %s',e,n),this.emitReserved("upgradeError",r)};function i(){o("transport closed")}function a(){o("socket closed")}function c(e){t&&e.name!==t.name&&(d('"%s" works - aborting "%s"',e.name,t.name),s())}const l=()=>{t.removeListener("open",r),t.removeListener("error",o),t.removeListener("close",i),this.off("close",a),this.off("upgrading",c)};t.once("open",r),t.once("error",o),t.once("close",i),this.once("close",a),this.once("upgrading",c),-1!==this.upgrades.indexOf("webtransport")&&"webtransport"!==e?this.setTimeoutFn((()=>{n||t.open()}),200):t.open()}onOpen(){if(d("socket open"),this.readyState="open",f.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){d("starting upgrade probes");let e=0;const t=this.upgrades.length;for(;e{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();d("flushing %d packets in socket",e.length),this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let t=0;t0&&e>this.maxPayload)return d("only send %d out of %d packets",t,this.writeBuffer.length),this.writeBuffer.slice(0,t);e+=2}return d("payload size is %d (max: %d)",e,this.maxPayload),this.writeBuffer}write(e,t,n){return this.sendPacket("message",e,t,n),this}send(e,t,n){return this.sendPacket("message",e,t,n),this}sendPacket(e,t,n,r){if("function"==typeof t&&(r=t,t=void 0),"function"==typeof n&&(r=n,n=null),"closing"===this.readyState||"closed"===this.readyState)return;(n=n||{}).compress=!1!==n.compress;const s={type:e,data:t,options:n};this.emitReserved("packetCreate",s),this.writeBuffer.push(s),r&&this.once("flush",r),this.flush()}close(){const e=()=>{this.onClose("forced close"),d("socket closing - telling transport to close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},n=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?n():e()})):this.upgrading?n():e()),this}onError(e){d("socket error %j",e),f.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(d('socket close with reason: "%s"',e),this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let n=0;const r=e.length;for(;n{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transports=void 0;const r=n(484),s=n(308),o=n(20);t.transports={websocket:s.WS,webtransport:o.WT,polling:r.Polling}},484:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Request=t.Polling=void 0;const s=n(870),o=r(n(227)),i=n(726),a=n(373),c=n(666),l=n(260),u=n(622),h=n(242),d=(0,o.default)("engine.io-client:polling");function f(){}const p=null!=new c.XHR({xdomain:!1}).responseType;class m extends s.Transport{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let n=location.port;n||(n=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||n!==e.port}const t=e&&e.forceBase64;this.supportsBinary=p&&!t,this.opts.withCredentials&&(this.cookieJar=(0,c.createCookieJar)())}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{d("paused"),this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(d("we are currently polling - waiting to pause"),e++,this.once("pollComplete",(function(){d("pre-pause polling complete"),--e||t()}))),this.writable||(d("we are currently writing - waiting to pause"),e++,this.once("drain",(function(){d("pre-pause writing complete"),--e||t()})))}else t()}poll(){d("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){d("polling got data %s",e),(0,a.decodePayload)(e,this.socket.binaryType).forEach((e=>{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():d('ignoring poll - transport state "%s"',this.readyState))}doClose(){const e=()=>{d("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(d("transport open - closing"),e()):(d("transport not open - deferring close"),this.once("open",e))}write(e){this.writable=!1,(0,a.encodePayload)(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){const e=this.opts.secure?"https":"http",t=this.query||{};return!1!==this.opts.timestampRequests&&(t[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||t.sid||(t.b64=1),this.createUri(e,t)}request(e={}){return Object.assign(e,{xd:this.xd,cookieJar:this.cookieJar},this.opts),new g(this.uri(),e)}doWrite(e,t){const n=this.request({method:"POST",data:e});n.on("success",t),n.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){d("xhr poll");const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}t.Polling=m;class g extends l.Emitter{constructor(e,t){super(),(0,u.installTimerFunctions)(this,t),this.opts=t,this.method=t.method||"GET",this.uri=e,this.data=void 0!==t.data?t.data:null,this.create()}create(){var e;const t=(0,u.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");t.xdomain=!!this.opts.xd;const n=this.xhr=new c.XHR(t);try{d("xhr open %s: %s",this.method,this.uri),n.open(this.method,this.uri,!0);try{if(this.opts.extraHeaders){n.setDisableHeaderCheck&&n.setDisableHeaderCheck(!0);for(let e in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(e)&&n.setRequestHeader(e,this.opts.extraHeaders[e])}}catch(e){}if("POST"===this.method)try{n.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}try{n.setRequestHeader("Accept","*/*")}catch(e){}null===(e=this.opts.cookieJar)||void 0===e||e.addCookies(n),"withCredentials"in n&&(n.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(n.timeout=this.opts.requestTimeout),n.onreadystatechange=()=>{var e;3===n.readyState&&(null===(e=this.opts.cookieJar)||void 0===e||e.parseCookies(n)),4===n.readyState&&(200===n.status||1223===n.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof n.status?n.status:0)}),0))},d("xhr data %s",this.data),n.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=g.requestsCount++,g.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=f,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete g.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(t.Request=g,g.requestsCount=0,g.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",y);else if("function"==typeof addEventListener){const e="onpagehide"in h.globalThisShim?"pagehide":"unload";addEventListener(e,y,!1)}function y(){for(let e in g.requests)g.requests.hasOwnProperty(e)&&g.requests[e].abort()}},552:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultBinaryType=t.usingBrowserWebSocket=t.WebSocket=t.nextTick=void 0;const r=n(242);t.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?e=>Promise.resolve().then(e):(e,t)=>t(e,0),t.WebSocket=r.globalThisShim.WebSocket||r.globalThisShim.MozWebSocket,t.usingBrowserWebSocket=!0,t.defaultBinaryType="arraybuffer"},308:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WS=void 0;const s=n(870),o=n(726),i=n(622),a=n(552),c=r(n(227)),l=n(373),u=(0,c.default)("engine.io-client:websocket"),h="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class d extends s.Transport{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,n=h?{}:(0,i.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=a.usingBrowserWebSocket&&!h?t?new a.WebSocket(e,t):new a.WebSocket(e):new a.WebSocket(e,t,n)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t{const t={};!a.usingBrowserWebSocket&&(n.options&&(t.compress=n.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length){this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){const e=this.opts.secure?"wss":"ws",t=this.query||{};return this.opts.timestampRequests&&(t[this.opts.timestampParam]=(0,o.yeast)()),this.supportsBinary||(t.b64=1),this.createUri(e,t)}check(){return!!a.WebSocket}}t.WS=d},20:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WT=void 0;const s=n(870),o=n(552),i=n(373),a=(0,r(n(227)).default)("engine.io-client:webtransport");class c extends s.Transport{get name(){return"webtransport"}doOpen(){"function"==typeof WebTransport&&(this.transport=new WebTransport(this.createUri("https"),this.opts.transportOptions[this.name]),this.transport.closed.then((()=>{a("transport closed gracefully"),this.onClose()})).catch((e=>{a("transport closed due to %s",e),this.onError("webtransport error",e)})),this.transport.ready.then((()=>{this.transport.createBidirectionalStream().then((e=>{const t=(0,i.createPacketDecoderStream)(Number.MAX_SAFE_INTEGER,this.socket.binaryType),n=e.readable.pipeThrough(t).getReader(),r=(0,i.createPacketEncoderStream)();r.readable.pipeTo(e.writable),this.writer=r.writable.getWriter();const s=()=>{n.read().then((({done:e,value:t})=>{e?a("session is closed"):(a("received chunk: %o",t),this.onPacket(t),s())})).catch((e=>{a("an error occurred while reading: %s",e)}))};s();const o={type:"open"};this.query.sid&&(o.data=`{"sid":"${this.query.sid}"}`),this.writer.write(o).then((()=>this.onOpen()))}))})))}write(e){this.writable=!1;for(let t=0;t{r&&(0,o.nextTick)((()=>{this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){var e;null===(e=this.transport)||void 0===e||e.close()}}t.WT=c},666:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createCookieJar=t.XHR=void 0;const r=n(419),s=n(242);t.XHR=function(e){const t=e.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!t||r.hasCORS))return new XMLHttpRequest}catch(e){}if(!t)try{return new(s.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(e){}},t.createCookieJar=function(){}},622:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.byteLength=t.installTimerFunctions=t.pick=void 0;const r=n(242);t.pick=function(e,...t){return t.reduce(((t,n)=>(e.hasOwnProperty(n)&&(t[n]=e[n]),t)),{})};const s=r.globalThisShim.setTimeout,o=r.globalThisShim.clearTimeout;t.installTimerFunctions=function(e,t){t.useNativeTimers?(e.setTimeoutFn=s.bind(r.globalThisShim),e.clearTimeoutFn=o.bind(r.globalThisShim)):(e.setTimeoutFn=r.globalThisShim.setTimeout.bind(r.globalThisShim),e.clearTimeoutFn=r.globalThisShim.clearTimeout.bind(r.globalThisShim))},t.byteLength=function(e){return"string"==typeof e?function(e){let t=0,n=0;for(let r=0,s=e.length;r=57344?n+=3:(r++,n+=4);return n}(e):Math.ceil(1.33*(e.byteLength||e.size))}},87:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_PACKET=t.PACKET_TYPES_REVERSE=t.PACKET_TYPES=void 0;const n=Object.create(null);t.PACKET_TYPES=n,n.open="0",n.close="1",n.ping="2",n.pong="3",n.message="4",n.upgrade="5",n.noop="6";const r=Object.create(null);t.PACKET_TYPES_REVERSE=r,Object.keys(n).forEach((e=>{r[n[e]]=e})),t.ERROR_PACKET={type:"error",data:"parser error"}},469:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0;const n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",r="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let e=0;e<64;e++)r[n.charCodeAt(e)]=e;t.encode=e=>{let t,r=new Uint8Array(e),s=r.length,o="";for(t=0;t>2],o+=n[(3&r[t])<<4|r[t+1]>>4],o+=n[(15&r[t+1])<<2|r[t+2]>>6],o+=n[63&r[t+2]];return s%3==2?o=o.substring(0,o.length-1)+"=":s%3==1&&(o=o.substring(0,o.length-2)+"=="),o},t.decode=e=>{let t,n,s,o,i,a=.75*e.length,c=e.length,l=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);const u=new ArrayBuffer(a),h=new Uint8Array(u);for(t=0;t>4,h[l++]=(15&s)<<4|o>>2,h[l++]=(3&o)<<6|63&i;return u}},572:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePacket=void 0;const r=n(87),s=n(469),o="function"==typeof ArrayBuffer;t.decodePacket=(e,t)=>{if("string"!=typeof e)return{type:"message",data:a(e,t)};const n=e.charAt(0);return"b"===n?{type:"message",data:i(e.substring(1),t)}:r.PACKET_TYPES_REVERSE[n]?e.length>1?{type:r.PACKET_TYPES_REVERSE[n],data:e.substring(1)}:{type:r.PACKET_TYPES_REVERSE[n]}:r.ERROR_PACKET};const i=(e,t)=>{if(o){const n=(0,s.decode)(e);return a(n,t)}return{base64:!0,data:e}},a=(e,t)=>"blob"===t?e instanceof Blob?e:new Blob([e]):e instanceof ArrayBuffer?e:e.buffer},908:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.encodePacket=t.encodePacketToBinary=void 0;const r=n(87),s="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,i=e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer instanceof ArrayBuffer,a=({type:e,data:t},n,a)=>s&&t instanceof Blob?n?a(t):c(t,a):o&&(t instanceof ArrayBuffer||i(t))?n?a(t):c(new Blob([t]),a):a(r.PACKET_TYPES[e]+(t||""));t.encodePacket=a;const c=(e,t)=>{const n=new FileReader;return n.onload=function(){const e=n.result.split(",")[1];t("b"+(e||""))},n.readAsDataURL(e)};function l(e){return e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}let u;t.encodePacketToBinary=function(e,t){return s&&e.data instanceof Blob?e.data.arrayBuffer().then(l).then(t):o&&(e.data instanceof ArrayBuffer||i(e.data))?t(l(e.data)):void a(e,!1,(e=>{u||(u=new TextEncoder),t(u.encode(e))}))}},373:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePayload=t.decodePacket=t.encodePayload=t.encodePacket=t.protocol=t.createPacketDecoderStream=t.createPacketEncoderStream=void 0;const r=n(908);Object.defineProperty(t,"encodePacket",{enumerable:!0,get:function(){return r.encodePacket}});const s=n(572);Object.defineProperty(t,"decodePacket",{enumerable:!0,get:function(){return s.decodePacket}});const o=n(87),i=String.fromCharCode(30);let a;function c(e){return e.reduce(((e,t)=>e+t.length),0)}function l(e,t){if(e[0].length===t)return e.shift();const n=new Uint8Array(t);let r=0;for(let s=0;s{const n=e.length,s=new Array(n);let o=0;e.forEach(((e,a)=>{(0,r.encodePacket)(e,!1,(e=>{s[a]=e,++o===n&&t(s.join(i))}))}))},t.decodePayload=(e,t)=>{const n=e.split(i),r=[];for(let e=0;e{const r=n.length;let s;if(r<126)s=new Uint8Array(1),new DataView(s.buffer).setUint8(0,r);else if(r<65536){s=new Uint8Array(3);const e=new DataView(s.buffer);e.setUint8(0,126),e.setUint16(1,r)}else{s=new Uint8Array(9);const e=new DataView(s.buffer);e.setUint8(0,127),e.setBigUint64(1,BigInt(r))}e.data&&"string"!=typeof e.data&&(s[0]|=128),t.enqueue(s),t.enqueue(n)}))}})},t.createPacketDecoderStream=function(e,t){a||(a=new TextDecoder);const n=[];let r=0,i=-1,u=!1;return new TransformStream({transform(h,d){for(n.push(h);;){if(0===r){if(c(n)<1)break;const e=l(n,1);u=128==(128&e[0]),i=127&e[0],r=i<126?3:126===i?1:2}else if(1===r){if(c(n)<2)break;const e=l(n,2);i=new DataView(e.buffer,e.byteOffset,e.length).getUint16(0),r=3}else if(2===r){if(c(n)<8)break;const e=l(n,8),t=new DataView(e.buffer,e.byteOffset,e.length),s=t.getUint32(0);if(s>Math.pow(2,21)-1){d.enqueue(o.ERROR_PACKET);break}i=s*Math.pow(2,32)+t.getUint32(4),r=3}else{if(c(n)e){d.enqueue(o.ERROR_PACKET);break}}}})},t.protocol=4},159:(e,t)=>{"use strict";function n(e){e=e||{},this.ms=e.min||100,this.max=e.max||1e4,this.factor=e.factor||2,this.jitter=e.jitter>0&&e.jitter<=1?e.jitter:0,this.attempts=0}Object.defineProperty(t,"__esModule",{value:!0}),t.Backoff=void 0,t.Backoff=n,n.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),n=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-n:e+n}return 0|Math.min(e,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(e){this.ms=e},n.prototype.setMax=function(e){this.max=e},n.prototype.setJitter=function(e){this.jitter=e}},46:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.connect=t.io=t.Socket=t.Manager=t.protocol=void 0;const s=n(84),o=n(168);Object.defineProperty(t,"Manager",{enumerable:!0,get:function(){return o.Manager}});const i=n(312);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return i.Socket}});const a=r(n(227)).default("socket.io-client"),c={};function l(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};const n=s.url(e,t.path||"/socket.io"),r=n.source,i=n.id,l=n.path,u=c[i]&&l in c[i].nsps;let h;return t.forceNew||t["force new connection"]||!1===t.multiplex||u?(a("ignoring socket cache for %s",r),h=new o.Manager(r,t)):(c[i]||(a("new io instance for %s",r),c[i]=new o.Manager(r,t)),h=c[i]),n.query&&!t.query&&(t.query=n.queryKey),h.socket(n.path,t)}t.io=l,t.connect=l,t.default=l,Object.assign(l,{Manager:o.Manager,Socket:i.Socket,io:l,connect:l});var u=n(514);Object.defineProperty(t,"protocol",{enumerable:!0,get:function(){return u.protocol}}),e.exports=l},168:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return s(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Manager=void 0;const a=n(679),c=n(312),l=o(n(514)),u=n(149),h=n(159),d=n(260),f=i(n(227)).default("socket.io-client:manager");class p extends d.Emitter{constructor(e,t){var n;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,a.installTimerFunctions(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(n=t.randomizationFactor)&&void 0!==n?n:.5),this.backoff=new h.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const r=t.parser||l;this.encoder=new r.Encoder,this.decoder=new r.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(f("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;f("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const t=this.engine,n=this;this._readyState="opening",this.skipReconnect=!1;const r=u.on(t,"open",(function(){n.onopen(),e&&e()})),s=t=>{f("error"),this.cleanup(),this._readyState="closed",this.emitReserved("error",t),e?e(t):this.maybeReconnectOnOpen()},o=u.on(t,"error",s);if(!1!==this._timeout){const e=this._timeout;f("connect attempt will timeout after %d",e);const n=this.setTimeoutFn((()=>{f("connect attempt timed out after %d",e),r(),s(new Error("timeout")),t.close()}),e);this.opts.autoUnref&&n.unref(),this.subs.push((()=>{this.clearTimeoutFn(n)}))}return this.subs.push(r),this.subs.push(o),this}connect(e){return this.open(e)}onopen(){f("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(u.on(e,"ping",this.onping.bind(this)),u.on(e,"data",this.ondata.bind(this)),u.on(e,"error",this.onerror.bind(this)),u.on(e,"close",this.onclose.bind(this)),u.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(e){this.onclose("parse error",e)}}ondecoded(e){a.nextTick((()=>{this.emitReserved("packet",e)}),this.setTimeoutFn)}onerror(e){f("error",e),this.emitReserved("error",e)}socket(e,t){let n=this.nsps[e];return n?this._autoConnect&&!n.active&&n.connect():(n=new c.Socket(this,e,t),this.nsps[e]=n),n}_destroy(e){const t=Object.keys(this.nsps);for(const e of t)if(this.nsps[e].active)return void f("socket %s is still active, skipping close",e);this._close()}_packet(e){f("writing packet %j",e);const t=this.encoder.encode(e);for(let n=0;ne())),this.subs.length=0,this.decoder.destroy()}_close(){f("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){f("closed due to %s",e),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)f("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();f("will wait %dms before reconnect attempt",t),this._reconnecting=!0;const n=this.setTimeoutFn((()=>{e.skipReconnect||(f("attempting reconnect"),this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(f("reconnect attempt error"),e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):(f("reconnect success"),e.onreconnect())})))}),t);this.opts.autoUnref&&n.unref(),this.subs.push((()=>{this.clearTimeoutFn(n)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}t.Manager=p},149:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.on=void 0,t.on=function(e,t,n){return e.on(t,n),function(){e.off(t,n)}}},312:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const s=n(514),o=n(149),i=n(260),a=r(n(227)).default("socket.io-client:socket"),c=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class l extends i.Emitter{constructor(e,t,n){super(),this.connected=!1,this.recovered=!1,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,n&&n.auth&&(this.auth=n.auth),this._opts=Object.assign({},n),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[o.on(e,"open",this.onopen.bind(this)),o.on(e,"packet",this.onpacket.bind(this)),o.on(e,"error",this.onerror.bind(this)),o.on(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(c.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;const n={type:s.PacketType.EVENT,data:t,options:{}};if(n.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++;a("emitting packet with ack id %d",e);const r=t.pop();this._registerAckCallback(e,r),n.id=e}const r=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||r&&this.connected?this.connected?(this.notifyOutgoingListeners(n),this.packet(n)):this.sendBuffer.push(n):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(e,t){var n;const r=null!==(n=this.flags.timeout)&&void 0!==n?n:this._opts.ackTimeout;if(void 0===r)return void(this.acks[e]=t);const s=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t{this.io.clearTimeoutFn(s),t.apply(this,[null,...e])}}emitWithAck(e,...t){const n=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((r,s)=>{t.push(((e,t)=>n?e?s(e):r(t):r(e))),this.emit(e,...t)}))}_addToQueue(e){let t;"function"==typeof e[e.length-1]&&(t=e.pop());const n={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push(((e,...r)=>{if(n===this._queue[0])return null!==e?n.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",n.id,n.tryCount),this._queue.shift(),t&&t(e)):(a("packet [%d] was successfully sent",n.id),this._queue.shift(),t&&t(null,...r)),n.pending=!1,this._drainQueue()})),this._queue.push(n),this._drainQueue()}_drainQueue(e=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const t=this._queue[0];!t.pending||e?(t.pending=!0,t.tryCount++,a("sending packet [%d] (try n°%d)",t.id,t.tryCount),this.flags=t.flags,this.emit.apply(this,t.args)):a("packet [%d] has already been sent and is waiting for an ack",t.id)}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((e=>{this._sendConnectPacket(e)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:s.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){a("close (%s)",e),this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case s.PacketType.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case s.PacketType.EVENT:case s.PacketType.BINARY_EVENT:this.onevent(e);break;case s.PacketType.ACK:case s.PacketType.BINARY_ACK:this.onack(e);break;case s.PacketType.DISCONNECT:this.ondisconnect();break;case s.PacketType.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];a("emitting event %j",t),null!=e.id&&(a("attaching ack callback to event"),t.push(this.ack(e.id))),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const n of t)n.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&"string"==typeof e[e.length-1]&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let n=!1;return function(...r){n||(n=!0,a("sending ack %j",r),t.packet({type:s.PacketType.ACK,id:e,data:r}))}}onack(e){const t=this.acks[e.id];"function"==typeof t?(a("calling ack %s with %j",e.id,e.data),t.apply(this,e.data),delete this.acks[e.id]):a("bad ack %s",e.id)}onconnect(e,t){a("socket connected with id %s",e),this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:s.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let n=0;n{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.reconstructPacket=t.deconstructPacket=void 0;const r=n(665);function s(e,t){if(!e)return e;if((0,r.isBinary)(e)){const n={_placeholder:!0,num:t.length};return t.push(e),n}if(Array.isArray(e)){const n=new Array(e.length);for(let r=0;r=0&&e.num{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Decoder=t.Encoder=t.PacketType=t.protocol=void 0;const r=n(260),s=n(269),o=n(665),i=(0,n(227).default)("socket.io-parser"),a=["connect","connect_error","disconnect","disconnecting","newListener","removeListener"];var c;function l(e){return"[object Object]"===Object.prototype.toString.call(e)}t.protocol=5,function(e){e[e.CONNECT=0]="CONNECT",e[e.DISCONNECT=1]="DISCONNECT",e[e.EVENT=2]="EVENT",e[e.ACK=3]="ACK",e[e.CONNECT_ERROR=4]="CONNECT_ERROR",e[e.BINARY_EVENT=5]="BINARY_EVENT",e[e.BINARY_ACK=6]="BINARY_ACK"}(c=t.PacketType||(t.PacketType={})),t.Encoder=class{constructor(e){this.replacer=e}encode(e){return i("encoding packet %j",e),e.type!==c.EVENT&&e.type!==c.ACK||!(0,o.hasBinary)(e)?[this.encodeAsString(e)]:this.encodeAsBinary({type:e.type===c.EVENT?c.BINARY_EVENT:c.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id})}encodeAsString(e){let t=""+e.type;return e.type!==c.BINARY_EVENT&&e.type!==c.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),i("encoded %j as %s",e,t),t}encodeAsBinary(e){const t=(0,s.deconstructPacket)(e),n=this.encodeAsString(t.packet),r=t.buffers;return r.unshift(n),r}};class u extends r.Emitter{constructor(e){super(),this.reviver=e}add(e){let t;if("string"==typeof e){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);const n=t.type===c.BINARY_EVENT;n||t.type===c.BINARY_ACK?(t.type=n?c.EVENT:c.ACK,this.reconstructor=new h(t),0===t.attachments&&super.emitReserved("decoded",t)):super.emitReserved("decoded",t)}else{if(!(0,o.isBinary)(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t))}}decodeString(e){let t=0;const n={type:Number(e.charAt(0))};if(void 0===c[n.type])throw new Error("unknown packet type "+n.type);if(n.type===c.BINARY_EVENT||n.type===c.BINARY_ACK){const r=t+1;for(;"-"!==e.charAt(++t)&&t!=e.length;);const s=e.substring(r,t);if(s!=Number(s)||"-"!==e.charAt(t))throw new Error("Illegal attachments");n.attachments=Number(s)}if("/"===e.charAt(t+1)){const r=t+1;for(;++t&&","!==e.charAt(t)&&t!==e.length;);n.nsp=e.substring(r,t)}else n.nsp="/";const r=e.charAt(t+1);if(""!==r&&Number(r)==r){const r=t+1;for(;++t;){const n=e.charAt(t);if(null==n||Number(n)!=n){--t;break}if(t===e.length)break}n.id=Number(e.substring(r,t+1))}if(e.charAt(++t)){const r=this.tryParse(e.substr(t));if(!u.isPayloadValid(n.type,r))throw new Error("invalid payload");n.data=r}return i("decoded %s as %j",e,n),n}tryParse(e){try{return JSON.parse(e,this.reviver)}catch(e){return!1}}static isPayloadValid(e,t){switch(e){case c.CONNECT:return l(t);case c.DISCONNECT:return void 0===t;case c.CONNECT_ERROR:return"string"==typeof t||l(t);case c.EVENT:case c.BINARY_EVENT:return Array.isArray(t)&&("number"==typeof t[0]||"string"==typeof t[0]&&-1===a.indexOf(t[0]));case c.ACK:case c.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}t.Decoder=u;class h{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=(0,s.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasBinary=t.isBinary=void 0;const n="function"==typeof ArrayBuffer,r=Object.prototype.toString,s="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===r.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===r.call(File);function i(e){return n&&(e instanceof ArrayBuffer||(e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||s&&e instanceof Blob||o&&e instanceof File}t.isBinary=i,t.hasBinary=function e(t,n){if(!t||"object"!=typeof t)return!1;if(Array.isArray(t)){for(let n=0,r=t.length;n{"use strict";function r(e){if(e)return function(e){for(var t in r.prototype)e[t]=r.prototype[t];return e}(e)}n.r(t),n.d(t,{Emitter:()=>r}),r.prototype.on=r.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},r.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+e];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var s=0;s{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};return(()=>{"use strict";var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.validateConfiguration=e.parseConnectionString=e.prepareSql=e.escapeSqlParameter=e.SQLiteCloudRow=e.SQLiteCloudRowset=e.SQLiteCloudError=e.SQLiteCloudConnection=e.Statement=e.Database=void 0;var t=n(751);Object.defineProperty(e,"Database",{enumerable:!0,get:function(){return t.Database}});var s=n(880);Object.defineProperty(e,"Statement",{enumerable:!0,get:function(){return s.Statement}});var o=n(480);Object.defineProperty(e,"SQLiteCloudConnection",{enumerable:!0,get:function(){return o.SQLiteCloudConnection}});var i=n(906);Object.defineProperty(e,"SQLiteCloudError",{enumerable:!0,get:function(){return i.SQLiteCloudError}});var a=n(825);Object.defineProperty(e,"SQLiteCloudRowset",{enumerable:!0,get:function(){return a.SQLiteCloudRowset}}),Object.defineProperty(e,"SQLiteCloudRow",{enumerable:!0,get:function(){return a.SQLiteCloudRow}});var c=n(73);Object.defineProperty(e,"escapeSqlParameter",{enumerable:!0,get:function(){return c.escapeSqlParameter}}),Object.defineProperty(e,"prepareSql",{enumerable:!0,get:function(){return c.prepareSql}}),Object.defineProperty(e,"parseConnectionString",{enumerable:!0,get:function(){return c.parseConnectionString}}),Object.defineProperty(e,"validateConfiguration",{enumerable:!0,get:function(){return c.validateConfiguration}})})(),r})())); \ No newline at end of file diff --git a/scripts/gateway-build.sh b/scripts/gateway-build.sh new file mode 100755 index 0000000..c73afc2 --- /dev/null +++ b/scripts/gateway-build.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# gateway-build.sh - build gateway as self contained executable for linux and macos +# If you get an error executing this script run: +# chmod u+x ./scripts/build.sh + +# navigate to the script's directory +#cd "$(dirname "$0")" + +# build bun's one file binary +mkdir -p ./lib/gateway/public +bun build ./src/gateway/gateway.ts --compile --outfile ./lib/gateway/gateway.out + +# copy the public folder to the build folder +cp -r ./public/* ./lib/gateway/public/ +cp ./package.json ./lib/gateway/ diff --git a/scripts/gateway-upgrade.sh b/scripts/gateway-upgrade.sh new file mode 100755 index 0000000..007cd7f --- /dev/null +++ b/scripts/gateway-upgrade.sh @@ -0,0 +1,19 @@ +# +# upgrade.sh - upload gateway builds to a couple of nodes used for development, restart gateway +# + +# upload ./build/ to test nodes +# frankfurt01, frankfurt02, ny01 +rsync -avz -e "ssh -i ~/.ssh/id_ed25519" ./build/ sqlitecloud@y8pbz99zp.sqlite.cloud:gateway +rsync -avz -e "ssh -i ~/.ssh/id_ed25519" ./build/ sqlitecloud@oggdnp3zm.sqlite.cloud:gateway + +# connect to nodes using ssh key +# ssh -i ~/.ssh/id_ed25519 sqlitecloud@y8pbz99zp.sqlite.cloud +# ssh -i ~/.ssh/id_ed25519 sqlitecloud@og0wjec-m.sqlite.cloud + +# restart gateway (locally) +# pkill gateway-linux-x; cd /home/sqlitecloud/gateway; nohup ./gateway-linux-x64.out + +# restart gateway (remotely) +ssh -i ~/.ssh/id_ed25519 sqlitecloud@y8pbz99zp.sqlite.cloud 'pkill gateway-linux-x; cd /home/sqlitecloud/gateway; nohup ./gateway-linux-x64.out > /dev/null 2>&1 &' +ssh -i ~/.ssh/id_ed25519 sqlitecloud@oggdnp3zm.sqlite.cloud 'pkill gateway-linux-x; cd /home/sqlitecloud/gateway; nohup ./gateway-linux-x64.out > /dev/null 2>&1 &' \ No newline at end of file diff --git a/scripts/sqlitecloud-cli b/scripts/sqlitecloud-cli new file mode 100755 index 0000000..8125c00 Binary files /dev/null and b/scripts/sqlitecloud-cli differ diff --git a/src/connection.ts b/src/connection.ts deleted file mode 100644 index bd6004b..0000000 --- a/src/connection.ts +++ /dev/null @@ -1,255 +0,0 @@ -/** - * connection.ts - handles low level communication with sqlitecloud server - */ - -import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback } from './types' -import { validateConfiguration, isBrowser } from './utilities' - -/** - * Base class for SQLiteCloudConnection handles basics and defines methods. - * Actual connection management and communication with the server in concrete classes. - */ -export class SQLiteCloudConnection { - /** Parse and validate provided connectionString or configuration */ - constructor(config: SQLiteCloudConfig | string, callback?: ErrorCallback) { - if (typeof config === 'string') { - this.config = validateConfiguration({ connectionString: config }) - } else { - this.config = validateConfiguration(config) - } - - // connect transport layer to server - this.connect(callback) - } - - /** Configuration passed by client or extracted from connection string */ - protected config: SQLiteCloudConfig - - /** Transport used to communicate with server */ - protected transport?: ConnectionTransport - - /** Operations are serialized by waiting an any pending promises */ - protected operations = new OperationsQueue() - - // - // public properties - // - - /** True if connection is open */ - public get connected(): boolean { - return this.transport?.connected || false - } - - /** Connect will establish a tls or websocket transport to the server based on configuration and environment */ - protected connect(callback?: ErrorCallback): this { - this.operations.enqueue(done => { - // connect using websocket if tls is not supported or if explicitly requested - if (isBrowser || this.config?.useWebsocket || this.config?.gatewayUrl) { - // socket.io transport works in both node.js and browser environments and connects via SQLite Cloud Gateway - import('./transport-ws') - .then(transport => { - this.transport = new transport.WebSocketTransport() - this.transport.connect(this.config, error => { - if (error) { - console.error( - `SQLiteCloudConnection.connect - error while connecting WebSocketTransport: ${error.toString()} to ${this.config.host}:${this.config.port}`, - error - ) - this.close() - } - callback?.call(this, error || null) - done(error) - }) - }) - .catch(error => { - done(error) - }) - } else { - // tls sockets work only in node.js environments - import('./transport-tls') - .then(transport => { - this.transport = new transport.TlsSocketTransport() - this.transport.connect(this.config, error => { - if (error) { - console.error( - `SQLiteCloudConnection.connect - error while connecting TlsSocketTransport: ${error.toString()} to ${this.config.host}:${this.config.port}`, - error - ) - this.close() - } - callback?.call(this, error || null) - done(error) - }) - }) - .catch(error => { - done(error) - }) - } - }) - - return this - } - - // - // private methods - // - - /** Will log to console if verbose mode is enabled */ - protected log(message: string, ...optionalParams: any[]): void { - if (this.config.verbose) { - message = anonimizeCommand(message) - console.log(`${new Date().toISOString()} ${this.config.clientId as string}: ${message}`, ...optionalParams) - } - } - - // - // public methods - // - - /** Enable verbose logging for debug purposes */ - public verbose(): void { - this.config.verbose = true - } - - /** Will enquee a command to be executed and callback with the resulting rowset/result/error */ - public sendCommands(commands: string, callback?: ResultsCallback): this { - this.operations.enqueue(done => { - if (this.transport) { - this.transport.processCommands(commands, (error, result) => { - callback?.call(this, error, result) - done(error) - }) - } else { - const error = new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }) - callback?.call(this, error) - done(error) - } - }) - - return this - } - - /** Disconnect from server, release connection. */ - public close(): this { - this.operations.clear() - this.transport?.close() - this.transport = undefined - return this - } -} - -// -// OperationsQueue - used to linearize operations on the connection -// - -type OperationCallback = (error: Error | null) => void -type Operation = (done: OperationCallback) => void - -export class OperationsQueue { - private queue: Operation[] = [] - private isProcessing = false - - /** Add operations to the queue, process immediately if possible, else wait for previous operations to complete */ - public enqueue(operation: Operation): void { - this.queue.push(operation) - if (!this.isProcessing) { - this.processNext() - } - } - - /** Clear the queue */ - public clear(): void { - this.queue = [] - this.isProcessing = false - } - - /** Process the next operation in the queue */ - private processNext(): void { - if (this.queue.length === 0) { - this.isProcessing = false - return - } - - this.isProcessing = true - const operation = this.queue.shift() - operation?.(() => { - // could receive (error) => { ... - // if (error) { - // console.warn('OperationQueue.processNext - error in operation', error) - // } - - // process the next operation in the queue - this.processNext() - }) - } -} - -// -// utility functions -// - -/** Messages going to the server are sometimes logged when error conditions occour and need to be stripped of user credentials */ -export function anonimizeCommand(message: string): string { - // hide password in AUTH command if needed - message = message.replace(/USER \S+/, 'USER ******') - message = message.replace(/PASSWORD \S+?(?=;)/, 'PASSWORD ******') - message = message.replace(/HASH \S+?(?=;)/, 'HASH ******') - return message -} - -/** Strip message code in error of user credentials */ -export function anonimizeError(error: Error): Error { - if (error?.message) { - error.message = anonimizeCommand(error.message) - } - return error -} - -/** Initialization commands sent to database when connection is established */ -export function getInitializationCommands(config: SQLiteCloudConfig): string { - // first user authentication, then all other commands - let commands = `AUTH USER ${config.username || ''} ${config.passwordHashed ? 'HASH' : 'PASSWORD'} ${config.password || ''}; ` - - if (config.database) { - if (config.createDatabase && !config.dbMemory) { - commands += `CREATE DATABASE ${config.database} IF NOT EXISTS; ` - } - commands += `USE DATABASE ${config.database}; ` - } - if (config.compression) { - commands += 'SET CLIENT KEY COMPRESSION TO 1; ' - } - if (config.nonlinearizable) { - commands += 'SET CLIENT KEY NONLINEARIZABLE TO 1; ' - } - if (config.noBlob) { - commands += 'SET CLIENT KEY NOBLOB TO 1; ' - } - if (config.maxData) { - commands += `SET CLIENT KEY MAXDATA TO ${config.maxData}; ` - } - if (config.maxRows) { - commands += `SET CLIENT KEY MAXROWS TO ${config.maxRows}; ` - } - if (config.maxRowset) { - commands += `SET CLIENT KEY MAXROWSET TO ${config.maxRowset}; ` - } - - return commands -} - -// -// ConnectionTransport -// - -/** ConnectionTransport implements the underlying transport layer for the connection */ -export interface ConnectionTransport { - /** True if connection is currently open */ - get connected(): boolean - /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */ - connect(config: SQLiteCloudConfig, callback?: ErrorCallback): this - /** Send a command, return the rowset/result or throw an error */ - processCommands(commands: string, callback?: ResultsCallback): this - /** Disconnect from server, release transport. */ - close(): this -} diff --git a/src/drivers/connection-tls.ts b/src/drivers/connection-tls.ts new file mode 100644 index 0000000..d59cc06 --- /dev/null +++ b/src/drivers/connection-tls.ts @@ -0,0 +1,258 @@ +/** + * connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol + */ + +import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback } from './types' +import { SQLiteCloudConnection } from './connection' +import { + formatCommand, + hasCommandLength, + parseCommandLength, + popData, + decompressBuffer, + CMD_COMPRESSED, + CMD_ROWSET_CHUNK, + bufferEndsWith, + ROWSET_CHUNKS_END +} from './protocol' +import { getInitializationCommands, anonimizeError, anonimizeCommand } from './utilities' +import { parseRowsetChunks } from './protocol' + +import net from 'net' +import tls from 'tls' + +/** + * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol. + * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified. + * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc. + * A connection socket is established when the connection is created and closed when the connection is closed. + * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed, + * it cannot be reopened and you must create a new connection. + */ +export class SQLiteCloudTlsConnection extends SQLiteCloudConnection { + /** Currently opened tls socket used to communicated with SQLiteCloud server */ + private socket?: tls.TLSSocket | net.Socket | null + + /** True if connection is open */ + get connected(): boolean { + return !!this.socket + } + + /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */ + connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this { + // connection established while we were waiting in line? + console.assert(!this.connected, 'Connection already established') + + // clear all listeners and call done in the operations queue + const finish: ResultsCallback = error => { + if (this.socket) { + this.socket.removeAllListeners('data') + this.socket.removeAllListeners('error') + this.socket.removeAllListeners('close') + if (error) { + this.close() + } + } + callback?.call(this, error) + } + + this.config = config + const initializationCommands = getInitializationCommands(config) + + if (config.insecure) { + // connect to plain socket, without encryption, only if insecure parameter specified + // this option is mainly for testing purposes and is not available on production nodes + // which would need to connect using tls and proper certificates as per code below + const connectionOptions: net.SocketConnectOpts = { + host: config.host, + port: config.port as number + } + this.socket = net.connect(connectionOptions, () => { + console.warn(`TlsConnection.connectTransport - connected to ${config.host as string}:${config.port as number} using insecure protocol`) + // send initialization commands + console.assert(this.socket, 'Connection already closed') + this.transportCommands(initializationCommands, error => { + if (error && this.socket) { + this.close() + } + if (callback) { + callback?.call(this, error) + callback = undefined + } + finish(error) + }) + }) + } else { + // connect to tls socket, initialize connection, setup event handlers + this.socket = tls.connect(this.config.port as number, this.config.host, this.config.tlsOptions, () => { + const tlsSocket = this.socket as tls.TLSSocket + if (!tlsSocket?.authorized) { + const anonimizedError = anonimizeError(tlsSocket.authorizationError) + console.error('Connection was not authorized', anonimizedError) + this.close() + finish(new SQLiteCloudError('Connection was not authorized', { cause: anonimizedError })) + } else { + // the connection was closed before it was even opened, + // eg. client closed the connection before the server accepted it + if (this.socket === null) { + finish(new SQLiteCloudError('Connection was closed before it was done opening')) + return + } + + // send initialization commands + console.assert(this.socket, 'Connection already closed') + this.transportCommands(initializationCommands, error => { + if (error && this.socket) { + this.close() + } + if (callback) { + callback?.call(this, error) + callback = undefined + } + finish(error) + }) + } + }) + } + + this.socket.on('close', () => { + this.socket = null + finish(new SQLiteCloudError('Connection was closed')) + }) + + this.socket.once('error', (error: any) => { + console.error('Connection error', error) + finish(new SQLiteCloudError('Connection error', { cause: error })) + }) + + return this + } + + /** Will send a command immediately (no queueing), return the rowset/result or throw an error */ + transportCommands(commands: string, callback?: ResultsCallback): this { + // connection needs to be established? + if (!this.socket) { + callback?.call(this, new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' })) + return this + } + + // compose commands following SCPC protocol + commands = formatCommand(commands) + + let buffer = Buffer.alloc(0) + const rowsetChunks: Buffer[] = [] + // const startedOn = new Date() + + // define what to do if an answer does not arrive within the set timeout + let socketTimeout: NodeJS.Timeout + + // clear all listeners and call done in the operations queue + const finish: ResultsCallback = (error, result) => { + clearTimeout(socketTimeout) + if (this.socket) { + this.socket.removeAllListeners('data') + this.socket.removeAllListeners('error') + this.socket.removeAllListeners('close') + } + if (callback) { + callback?.call(this, error, result) + callback = undefined + } + } + + // define the Promise that waits for the server response + const readData = (data: Uint8Array) => { + try { + // on first ondata event, dataType is read from data, on subsequent ondata event, is read from buffer that is the concatanations of data received on each ondata event + let dataType = buffer.length === 0 ? data.subarray(0, 1).toString() : buffer.subarray(0, 1).toString('utf8') + buffer = Buffer.concat([buffer, data]) + const commandLength = hasCommandLength(dataType) + + if (commandLength) { + const commandLength = parseCommandLength(buffer) + const hasReceivedEntireCommand = buffer.length - buffer.indexOf(' ') - 1 >= commandLength ? true : false + if (hasReceivedEntireCommand) { + if (this.config?.verbose) { + let bufferString = buffer.toString('utf8') + if (bufferString.length > 1000) { + bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40) + } + // const elapsedMs = new Date().getTime() - startedOn.getTime() + // console.debug(`Receive: ${bufferString} - ${elapsedMs}ms`) + } + + // need to decompress this buffer before decoding? + if (dataType === CMD_COMPRESSED) { + ;({ buffer, dataType } = decompressBuffer(buffer)) + } + + if (dataType !== CMD_ROWSET_CHUNK) { + this.socket?.off('data', readData) + const { data } = popData(buffer) + finish(null, data) + } else { + // check if rowset received the ending chunk + if (bufferEndsWith(buffer, ROWSET_CHUNKS_END)) { + rowsetChunks.push(buffer) + const parsedData = parseRowsetChunks(rowsetChunks) + finish?.call(this, null, parsedData) + } else { + // no ending string? ask server for another chunk + rowsetChunks.push(buffer) + buffer = Buffer.alloc(0) + } + } + } + } else { + // command with no explicit len so make sure that the final character is a space + const lastChar = buffer.subarray(buffer.length - 1, buffer.length).toString('utf8') + if (lastChar == ' ') { + const { data } = popData(buffer) + finish(null, data) + } + } + } catch (error) { + console.assert(error instanceof Error) + if (error instanceof Error) { + finish(error) + } + } + } + + this.socket?.once('close', () => { + finish(new SQLiteCloudError('Connection was closed', { cause: anonimizeCommand(commands) })) + }) + + this.socket?.write(commands, 'utf8', () => { + // @ts-ignore + socketTimeout = setTimeout(() => { + const timeoutError = new SQLiteCloudError('Request timed out', { cause: anonimizeCommand(commands) }) + // console.debug(`Request timed out, config.timeout is ${this.config?.timeout as number}ms`, timeoutError) + finish(timeoutError) + }, this.config?.timeout) + this.socket?.on('data', readData) + }) + + this.socket?.once('error', (error: any) => { + console.error('Socket error', error) + this.close() + finish(new SQLiteCloudError('Socket error', { cause: anonimizeError(error) })) + }) + + return this + } + + /** Disconnect from server, release connection. */ + close(): this { + console.assert(this.socket !== null, 'TlsConnection.close - connection already closed') + this.operations.clear() + if (this.socket) { + this.socket.destroy() + this.socket = null + } + this.socket = undefined + return this + } +} + +export default SQLiteCloudTlsConnection diff --git a/src/transport-ws.ts b/src/drivers/connection-ws.ts similarity index 84% rename from src/transport-ws.ts rename to src/drivers/connection-ws.ts index 0371131..b11cb71 100644 --- a/src/transport-ws.ts +++ b/src/drivers/connection-ws.ts @@ -4,7 +4,7 @@ import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback } from './types' import { SQLiteCloudRowset } from './rowset' -import { ConnectionTransport } from './connection' +import { SQLiteCloudConnection } from './connection' import { io, Socket } from 'socket.io-client' /** @@ -13,9 +13,7 @@ import { io, Socket } from 'socket.io-client' * requests by returning results and rowsets in json format. The gateway handles * connect, disconnect, retries, order of operations, timeouts, etc. */ -export class WebSocketTransport implements ConnectionTransport { - /** Configuration passed to connect */ - private config?: SQLiteCloudConfig +export class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection { /** Socket.io used to communicated with SQLiteCloud server */ private socket?: Socket @@ -25,7 +23,7 @@ export class WebSocketTransport implements ConnectionTransport { } /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */ - connect(config: SQLiteCloudConfig, callback?: ErrorCallback): this { + connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this { try { // connection established while we were waiting in line? console.assert(!this.connected, 'Connection already established') @@ -43,7 +41,7 @@ export class WebSocketTransport implements ConnectionTransport { } /** Will send a command immediately (no queueing), return the rowset/result or throw an error */ - processCommands(commands: string, callback?: ResultsCallback): this { + transportCommands(commands: string, callback?: ResultsCallback): this { // connection needs to be established? if (!this.socket) { callback?.call(this, new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' })) @@ -58,7 +56,7 @@ export class WebSocketTransport implements ConnectionTransport { const { data, metadata } = response if (data && metadata) { if (metadata.numberOfRows !== undefined && metadata.numberOfColumns !== undefined && metadata.columns !== undefined) { - console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.processCommands - data is not an array') + console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.transportCommands - data is not an array') // we can recreate a SQLiteCloudRowset from the response which we know to be an array of arrays // eslint-disable-next-line @typescript-eslint/no-unsafe-call const rowset = new SQLiteCloudRowset(metadata, data.flat()) @@ -75,12 +73,15 @@ export class WebSocketTransport implements ConnectionTransport { /** Disconnect socket.io from server */ public close(): this { - console.assert(this.socket !== null, 'WebsocketTransport.close - connection already closed') + console.assert(this.socket !== null, 'SQLiteCloudWebsocketConnection.close - connection already closed') if (this.socket) { this.socket?.close() this.socket = undefined } + this.operations.clear() this.socket = undefined return this } } + +export default SQLiteCloudWebsocketConnection diff --git a/src/drivers/connection.ts b/src/drivers/connection.ts new file mode 100644 index 0000000..524b811 --- /dev/null +++ b/src/drivers/connection.ts @@ -0,0 +1,101 @@ +/** + * connection.ts - base abstract class for sqlitecloud server connections + */ + +import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback } from './types' +import { validateConfiguration } from './utilities' +import { OperationsQueue } from './queue' +import { anonimizeCommand } from './utilities' + +/** + * Base class for SQLiteCloudConnection handles basics and defines methods. + * Actual connection management and communication with the server in concrete classes. + */ +export abstract class SQLiteCloudConnection { + /** Parse and validate provided connectionString or configuration */ + constructor(config: SQLiteCloudConfig | string, callback?: ErrorCallback) { + if (typeof config === 'string') { + this.config = validateConfiguration({ connectionString: config }) + } else { + this.config = validateConfiguration(config) + } + + // connect transport layer to server + this.connect(callback) + } + + /** Configuration passed by client or extracted from connection string */ + protected config: SQLiteCloudConfig + + /** Operations are serialized by waiting an any pending promises */ + protected operations = new OperationsQueue() + + // + // internal methods (some are implemented in concrete classes using different transport layers) + // + + /** Connect will establish a tls or websocket transport to the server based on configuration and environment */ + protected connect(callback?: ErrorCallback): this { + this.operations.enqueue(done => { + this.connectTransport(this.config, error => { + if (error) { + console.error( + `SQLiteCloudConnection.connect - error connecting ${this.config.host as string}:${this.config.port as number} ${error.toString()}`, + error + ) + this.close() + } + callback?.call(this, error || null) + done(error) + }) + }) + return this + } + + /* Opens a connection with the server and sends the initialization commands */ + protected abstract connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this + + /** Send a command, return the rowset/result or throw an error */ + protected abstract transportCommands(commands: string, callback?: ResultsCallback): this + + /** Will log to console if verbose mode is enabled */ + protected log(message: string, ...optionalParams: any[]): void { + if (this.config.verbose) { + message = anonimizeCommand(message) + console.log(`${new Date().toISOString()} ${this.config.clientId as string}: ${message}`, ...optionalParams) + } + } + + // + // public methods (some are abstract and implemented in concrete classes) + // + + /** Returns true if connection is open */ + public abstract get connected(): boolean + + /** Enable verbose logging for debug purposes */ + public verbose(): void { + this.config.verbose = true + } + + /** Will enquee a command to be executed and callback with the resulting rowset/result/error */ + public sendCommands(commands: string, callback?: ResultsCallback): this { + this.operations.enqueue(done => { + if (!this.connected) { + const error = new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }) + callback?.call(this, error) + done(error) + } + + this.transportCommands(commands, (error, result) => { + callback?.call(this, error, result) + done(error) + }) + }) + + return this + } + + /** Disconnect from server, release transport. */ + public abstract close(): this +} diff --git a/src/database.ts b/src/drivers/database.ts similarity index 91% rename from src/database.ts rename to src/drivers/database.ts index 658a8b0..6c42ab5 100644 --- a/src/database.ts +++ b/src/drivers/database.ts @@ -17,6 +17,7 @@ import { prepareSql, popCallback } from './utilities' import { Statement } from './statement' import { ErrorCallback, ResultsCallback, RowCallback, RowsCallback } from './types' import EventEmitter from 'eventemitter3' +import { isBrowser } from './utilities' // Uses eventemitter3 instead of node events for browser compatibility // https://github.com/primus/eventemitter3 @@ -45,7 +46,11 @@ export class Database extends EventEmitter { // mode is ignored for now // opens first connection to the database automatically - this.getConnection(callback as ResultsCallback) + this.getConnection((error, _connection) => { + if (callback) { + callback.call(this, error) + } + }) } /** Configuration used to open database connections */ @@ -64,17 +69,47 @@ export class Database extends EventEmitter { if (this.connections?.length > 0) { callback?.call(this, null, this.connections[0]) } else { - this.connections.push( - new SQLiteCloudConnection(this.config, error => { - if (error) { - this.handleError(this.connections[0], error, callback) - } else { - console.assert - callback?.call(this, null, this.connections[0]) - this.emitEvent('open') - } - }) - ) + // connect using websocket if tls is not supported or if explicitly requested + const useWebsocket = isBrowser || this.config?.useWebsocket || this.config?.gatewayUrl + if (useWebsocket) { + // socket.io transport works in both node.js and browser environments and connects via SQLite Cloud Gateway + import('./connection-ws') + .then(module => { + this.connections.push( + new module.default(this.config, error => { + if (error) { + this.handleError(this.connections[0], error, callback) + } else { + console.assert + callback?.call(this, null, this.connections[0]) + this.emitEvent('open') + } + }) + ) + }) + .catch(error => { + this.handleError(null, error, callback) + }) + } else { + // tls sockets work only in node.js environments + import('./connection-tls') + .then(module => { + this.connections.push( + new module.default(this.config, error => { + if (error) { + this.handleError(this.connections[0], error, callback) + } else { + console.assert + callback?.call(this, null, this.connections[0]) + this.emitEvent('open') + } + }) + ) + }) + .catch(error => { + this.handleError(null, error, callback) + }) + } } } diff --git a/src/drivers/protocol.ts b/src/drivers/protocol.ts new file mode 100644 index 0000000..79750ad --- /dev/null +++ b/src/drivers/protocol.ts @@ -0,0 +1,321 @@ +// +// protocol.ts - low level protocol handling for SQLiteCloud transport +// + +import { SQLiteCloudError, type SQLCloudRowsetMetadata, type SQLiteCloudDataTypes } from './types' +import { SQLiteCloudRowset } from './rowset' + +const lz4 = require('lz4js') + +// The server communicates with clients via commands defined in +// SQLiteCloud Server Protocol (SCSP), see more at: +// https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md + +export const CMD_STRING = '+' +export const CMD_ZEROSTRING = '!' +export const CMD_ERROR = '-' +export const CMD_INT = ':' +export const CMD_FLOAT = ',' +export const CMD_ROWSET = '*' +export const CMD_ROWSET_CHUNK = '/' +export const CMD_JSON = '#' +export const CMD_NULL = '_' +export const CMD_BLOB = '$' +export const CMD_COMPRESSED = '%' +export const CMD_COMMAND = '^' +export const CMD_ARRAY = '=' +// const CMD_RAWJSON = '{' +// const CMD_PUBSUB = '|' +// const CMD_RECONNECT = '@' + +// To mark the end of the Rowset, the special string /LEN 0 0 0 is sent (LEN is always 6 in this case) +// https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk +export const ROWSET_CHUNKS_END = '/6 0 0 0 ' + +// +// utility functions +// + +/** Analyze first character to check if corresponding data type has LEN */ +export function hasCommandLength(firstCharacter: string): boolean { + return firstCharacter == CMD_INT || firstCharacter == CMD_FLOAT || firstCharacter == CMD_NULL ? false : true +} + +/** Analyze a command with explict LEN and extract it */ +export function parseCommandLength(data: Buffer): number { + return parseInt(data.subarray(1, data.indexOf(' ')).toString('utf8')) +} + +/** Receive a compressed buffer, decompress with lz4, return buffer and datatype */ +export function decompressBuffer(buffer: Buffer): { buffer: Buffer; dataType: string } { + const spaceIndex = buffer.indexOf(' ') + buffer = buffer.subarray(spaceIndex + 1) + + // extract compressed size + const compressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8')) + buffer = buffer.subarray(buffer.indexOf(' ') + 1) + + // extract decompressed size + const decompressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8')) + buffer = buffer.subarray(buffer.indexOf(' ') + 1) + + // extract compressed dataType + const dataType = buffer.subarray(0, 1).toString('utf8') + const decompressedBuffer = Buffer.alloc(decompressedSize) + const compressedBuffer = buffer.subarray(buffer.length - compressedSize) + + // lz4js library is javascript and doesn't have types so we silence the type check + // eslint-disable-next-line + const decompressionResult: number = lz4.decompressBlock(compressedBuffer, decompressedBuffer, 0, compressedSize, 0) + buffer = Buffer.concat([buffer.subarray(0, buffer.length - compressedSize), decompressedBuffer]) + if (decompressionResult <= 0 || decompressionResult !== decompressedSize) { + throw new Error(`lz4 decompression error at offset ${decompressionResult}`) + } + + return { buffer, dataType } +} + +/** Parse error message or extended error message */ +export function parseError(buffer: Buffer, spaceIndex: number): never { + const errorBuffer = buffer.subarray(spaceIndex + 1) + const errorString = errorBuffer.toString('utf8') + const parts = errorString.split(' ') + + let errorCodeStr = parts.shift() || '0' // Default errorCode is '0' if not present + let extErrCodeStr = '0' // Default extended error code + let offsetCodeStr = '-1' // Default offset code + + // Split the errorCode by ':' to check for extended error codes + const errorCodeParts = errorCodeStr.split(':') + errorCodeStr = errorCodeParts[0] + if (errorCodeParts.length > 1) { + extErrCodeStr = errorCodeParts[1] + if (errorCodeParts.length > 2) { + offsetCodeStr = errorCodeParts[2] + } + } + + // Rest of the error string is the error message + const errorMessage = parts.join(' ') + + // Parse error codes to integers safely, defaulting to 0 if NaN + const errorCode = parseInt(errorCodeStr) + const extErrCode = parseInt(extErrCodeStr) + const offsetCode = parseInt(offsetCodeStr) + + // create an Error object and add the custom properties + throw new SQLiteCloudError(errorMessage, { + errorCode: errorCode.toString(), + externalErrorCode: extErrCode.toString(), + offsetCode + }) +} + +/** Parse an array of items (each of which will be parsed by type separately) */ +export function parseArray(buffer: Buffer, spaceIndex: number): SQLiteCloudDataTypes[] { + const parsedData = [] + + const array = buffer.subarray(spaceIndex + 1, buffer.length) + const numberOfItems = parseInt(array.subarray(0, spaceIndex - 2).toString('utf8')) + let arrayItems = array.subarray(array.indexOf(' ') + 1, array.length) + + for (let i = 0; i < numberOfItems; i++) { + const { data, fwdBuffer: buffer } = popData(arrayItems) + parsedData.push(data) + arrayItems = buffer + } + + return parsedData as SQLiteCloudDataTypes[] +} + +/** Parse header in a rowset or chunk of a chunked rowset */ +export function parseRowsetHeader(buffer: Buffer): { index: number; metadata: SQLCloudRowsetMetadata; fwdBuffer: Buffer } { + const index = parseInt(buffer.subarray(0, buffer.indexOf(':') + 1).toString()) + buffer = buffer.subarray(buffer.indexOf(':') + 1) + + // extract rowset header + const { data, fwdBuffer } = popIntegers(buffer, 3) + + return { + index, + metadata: { + version: data[0], + numberOfRows: data[1], + numberOfColumns: data[2], + columns: [] + }, + fwdBuffer + } +} + +/** Extract column names and, optionally, more metadata out of a rowset's header */ +function parseRowsetColumnsMetadata(buffer: Buffer, metadata: SQLCloudRowsetMetadata): Buffer { + function popForward() { + const { data, fwdBuffer: fwdBuffer } = popData(buffer) // buffer in parent scope + buffer = fwdBuffer + return data + } + + for (let i = 0; i < metadata.numberOfColumns; i++) { + metadata.columns.push({ name: popForward() as string }) + } + + // extract additional metadata if rowset has version 2 + if (metadata.version == 2) { + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].type = popForward() as string + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].database = popForward() as string + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].table = popForward() as string + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].column = popForward() as string // original column name + + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].notNull = popForward() as number + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].primaryKey = popForward() as number + for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].autoIncrement = popForward() as number + } + + return buffer +} + +/** Parse a regular rowset (no chunks) */ +function parseRowset(buffer: Buffer, spaceIndex: number): SQLiteCloudRowset { + buffer = buffer.subarray(spaceIndex + 1, buffer.length) + + const { metadata, fwdBuffer } = parseRowsetHeader(buffer) + buffer = parseRowsetColumnsMetadata(fwdBuffer, metadata) + + // decode each rowset item + const data = [] + for (let j = 0; j < metadata.numberOfRows * metadata.numberOfColumns; j++) { + const { data: rowData, fwdBuffer } = popData(buffer) + data.push(rowData) + buffer = fwdBuffer + } + + console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'SQLiteCloudConnection.parseRowset - invalid rowset data') + return new SQLiteCloudRowset(metadata, data) +} + +export function bufferStartsWith(buffer: Buffer, prefix: string): boolean { + return buffer.length >= prefix.length && buffer.subarray(0, prefix.length).toString('utf8') === prefix +} + +export function bufferEndsWith(buffer: Buffer, suffix: string): boolean { + return buffer.length >= suffix.length && buffer.subarray(buffer.length - suffix.length, buffer.length).toString('utf8') === suffix +} + +/** + * Parse a chunk of a chunked rowset command, eg: + * *LEN 0:VERS NROWS NCOLS DATA + * @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk + */ +export function parseRowsetChunks(buffers: Buffer[]): SQLiteCloudRowset { + let buffer = Buffer.concat(buffers) + if (!bufferStartsWith(buffer, CMD_ROWSET_CHUNK) || !bufferEndsWith(buffer, ROWSET_CHUNKS_END)) { + throw new Error('SQLiteCloudConnection.parseRowsetChunks - invalid chunks buffer') + } + + let metadata: SQLCloudRowsetMetadata = { version: 1, numberOfColumns: 0, numberOfRows: 0, columns: [] } + const data: any[] = [] + + // validate and skip data type + const dataType = buffer.subarray(0, 1).toString() + console.assert(dataType === CMD_ROWSET_CHUNK) + buffer = buffer.subarray(buffer.indexOf(' ') + 1) + + while (buffer.length > 0 && !bufferStartsWith(buffer, ROWSET_CHUNKS_END)) { + // chunk header, eg: 0:VERS NROWS NCOLS + const { index: chunkIndex, metadata: chunkMetadata, fwdBuffer } = parseRowsetHeader(buffer) + buffer = fwdBuffer + + // first chunk? extract columns metadata + if (chunkIndex === 1) { + metadata = chunkMetadata + buffer = parseRowsetColumnsMetadata(buffer, metadata) + } else { + metadata.numberOfRows += chunkMetadata.numberOfRows + } + + // extract single rowset row + for (let k = 0; k < chunkMetadata.numberOfRows * metadata.numberOfColumns; k++) { + const { data: itemData, fwdBuffer } = popData(buffer) + data.push(itemData) + buffer = fwdBuffer + } + } + + console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'parseRowsetChunks - invalid rowset data') + const rowset = new SQLiteCloudRowset(metadata, data) + // console.debug(`parseRowsetChunks - ${rowset.numberOfRows} rows, ${rowset.numberOfColumns} columns`) + return rowset +} + +/** Pop one or more space separated integers from beginning of buffer, move buffer forward */ +function popIntegers(buffer: Buffer, numberOfIntegers = 1): { data: number[]; fwdBuffer: Buffer } { + const data: number[] = [] + for (let i = 0; i < numberOfIntegers; i++) { + const spaceIndex = buffer.indexOf(' ') + data[i] = parseInt(buffer.subarray(0, spaceIndex).toString()) + buffer = buffer.subarray(spaceIndex + 1) + } + return { data, fwdBuffer: buffer } +} + +/** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */ +export function popData(buffer: Buffer): { data: SQLiteCloudDataTypes | SQLiteCloudRowset; fwdBuffer: Buffer } { + function popResults(data: any) { + const fwdBuffer = buffer.subarray(commandEnd) + return { data, fwdBuffer } + } + + // first character is the data type + console.assert(buffer && buffer instanceof Buffer) + const dataType: string = buffer.subarray(0, 1).toString('utf8') + console.assert(dataType !== CMD_COMPRESSED, "Compressed data shouldn't be decompressed before parsing") + console.assert(dataType !== CMD_ROWSET_CHUNK, 'Chunked data should be parsed by parseRowsetChunks') + + let spaceIndex = buffer.indexOf(' ') + if (spaceIndex === -1) { + spaceIndex = buffer.length - 1 + } + + let commandEnd = -1 + if (dataType === CMD_INT || dataType === CMD_FLOAT || dataType === CMD_NULL) { + commandEnd = spaceIndex + 1 + } else { + const commandLength = parseInt(buffer.subarray(1, spaceIndex).toString()) + commandEnd = spaceIndex + 1 + commandLength + } + + switch (dataType) { + case CMD_INT: + return popResults(parseInt(buffer.subarray(1, spaceIndex).toString())) + case CMD_FLOAT: + return popResults(parseFloat(buffer.subarray(1, spaceIndex).toString())) + case CMD_NULL: + return popResults(null) + case CMD_STRING: + return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8')) + case CMD_ZEROSTRING: + return popResults(buffer.subarray(spaceIndex + 1, commandEnd - 1).toString('utf8')) + case CMD_COMMAND: + return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8')) + case CMD_JSON: + return popResults(JSON.parse(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8'))) + case CMD_BLOB: + return popResults(buffer.subarray(spaceIndex + 1, commandEnd)) + case CMD_ARRAY: + return popResults(parseArray(buffer, spaceIndex)) + case CMD_ROWSET: + return popResults(parseRowset(buffer, spaceIndex)) + case CMD_ERROR: + parseError(buffer, spaceIndex) // throws custom error + break + } + + throw new TypeError(`Data type: ${dataType} is not defined in SCSP`) +} + +/** Format a command to be sent via SCSP protocol */ +export function formatCommand(command: string): string { + const commandLength = Buffer.byteLength(command, 'utf-8') + return `+${commandLength} ${command}` +} diff --git a/src/drivers/queue.ts b/src/drivers/queue.ts new file mode 100644 index 0000000..9a79973 --- /dev/null +++ b/src/drivers/queue.ts @@ -0,0 +1,45 @@ +// +// queue.ts - simple task queue used to linearize async operations +// + +export type OperationCallback = (error: Error | null) => void +export type Operation = (done: OperationCallback) => void + +export class OperationsQueue { + private queue: Operation[] = [] + private isProcessing = false + + /** Add operations to the queue, process immediately if possible, else wait for previous operations to complete */ + public enqueue(operation: Operation): void { + this.queue.push(operation) + if (!this.isProcessing) { + this.processNext() + } + } + + /** Clear the queue */ + public clear(): void { + this.queue = [] + this.isProcessing = false + } + + /** Process the next operation in the queue */ + private processNext(): void { + if (this.queue.length === 0) { + this.isProcessing = false + return + } + + this.isProcessing = true + const operation = this.queue.shift() + operation?.(() => { + // could receive (error) => { ... + // if (error) { + // console.warn('OperationQueue.processNext - error in operation', error) + // } + + // process the next operation in the queue + this.processNext() + }) + } +} diff --git a/src/rowset.ts b/src/drivers/rowset.ts similarity index 100% rename from src/rowset.ts rename to src/drivers/rowset.ts diff --git a/src/statement.ts b/src/drivers/statement.ts similarity index 100% rename from src/statement.ts rename to src/drivers/statement.ts diff --git a/src/types.ts b/src/drivers/types.ts similarity index 100% rename from src/types.ts rename to src/drivers/types.ts diff --git a/src/utilities.ts b/src/drivers/utilities.ts similarity index 80% rename from src/utilities.ts rename to src/drivers/utilities.ts index 458e078..a6c0ce7 100644 --- a/src/utilities.ts +++ b/src/drivers/utilities.ts @@ -16,6 +16,56 @@ export const isNode: boolean = typeof process !== 'undefined' && process.version // utility methods // +/** Messages going to the server are sometimes logged when error conditions occour and need to be stripped of user credentials */ +export function anonimizeCommand(message: string): string { + // hide password in AUTH command if needed + message = message.replace(/USER \S+/, 'USER ******') + message = message.replace(/PASSWORD \S+?(?=;)/, 'PASSWORD ******') + message = message.replace(/HASH \S+?(?=;)/, 'HASH ******') + return message +} + +/** Strip message code in error of user credentials */ +export function anonimizeError(error: Error): Error { + if (error?.message) { + error.message = anonimizeCommand(error.message) + } + return error +} + +/** Initialization commands sent to database when connection is established */ +export function getInitializationCommands(config: SQLiteCloudConfig): string { + // first user authentication, then all other commands + let commands = `AUTH USER ${config.username || ''} ${config.passwordHashed ? 'HASH' : 'PASSWORD'} ${config.password || ''}; ` + + if (config.database) { + if (config.createDatabase && !config.dbMemory) { + commands += `CREATE DATABASE ${config.database} IF NOT EXISTS; ` + } + commands += `USE DATABASE ${config.database}; ` + } + if (config.compression) { + commands += 'SET CLIENT KEY COMPRESSION TO 1; ' + } + if (config.nonlinearizable) { + commands += 'SET CLIENT KEY NONLINEARIZABLE TO 1; ' + } + if (config.noBlob) { + commands += 'SET CLIENT KEY NOBLOB TO 1; ' + } + if (config.maxData) { + commands += `SET CLIENT KEY MAXDATA TO ${config.maxData}; ` + } + if (config.maxRows) { + commands += `SET CLIENT KEY MAXROWS TO ${config.maxRows}; ` + } + if (config.maxRowset) { + commands += `SET CLIENT KEY MAXROWSET TO ${config.maxRowset}; ` + } + + return commands +} + /** Takes a generic value and escapes it so it can replace ? as a binding in a prepared SQL statement */ export function escapeSqlParameter(param: SQLiteCloudDataTypes): string { if (param === null || param === undefined) { @@ -121,6 +171,7 @@ export function popCallback( /** Validate configuration, apply defaults, throw if something is missing or misconfigured */ export function validateConfiguration(config: SQLiteCloudConfig): SQLiteCloudConfig { + console.assert(config, 'SQLiteCloudConnection.validateConfiguration - missing config') if (config.connectionString) { config = { ...config, diff --git a/src/gateway/connection-bun.test.ts b/src/gateway/connection-bun.test.ts new file mode 100644 index 0000000..a4e2576 --- /dev/null +++ b/src/gateway/connection-bun.test.ts @@ -0,0 +1,246 @@ +// +// gateway.test.ts - bun tests for +// + +// MUST RUN USING BUN TEST RUNNER, EG: +// bun test connection-bun.test.ts --watch + +import { SQLiteCloudError } from '../drivers/types' +import { SQLiteCloudBunConnection } from './connection-bun' +import { expect, test, describe, beforeEach, afterEach } from 'bun:test' + +let CHINOOK_DATABASE_URL = process.env['CHINOOK_DATABASE_URL'] as string +console.assert(CHINOOK_DATABASE_URL, 'CHINOOK_DATABASE_URL is required') + +async function getConnection(): Promise { + return new Promise((resolve, reject) => { + const connection = new SQLiteCloudBunConnection(CHINOOK_DATABASE_URL, error => { + if (error) { + reject(error) + } + resolve(connection) + }) + }) +} + +async function sendCommands(connection: SQLiteCloudBunConnection, command: string): Promise { + return new Promise((resolve, reject) => { + connection.sendCommands(command, (error, result) => { + if (error) { + reject(error) + } + resolve(result) + }) + }) +} + +describe('SQLiteCloudBunConnection', () => { + // test different ways to connect + describe('connecting', () => { + test('can connect using bun socket', done => { + new SQLiteCloudBunConnection(CHINOOK_DATABASE_URL, error => { + if (error) { + console.error('Error connecting to database', error) + } + done(error) + }) + }) + }) + + // test command exercise different data types + describe('test commands', () => { + let chinookConnection: SQLiteCloudBunConnection + + beforeEach(async () => { + chinookConnection = await getConnection() + }) + + afterEach(() => { + if (chinookConnection) { + chinookConnection.close() + } + }) + + test('should test null', async () => { + const results = await sendCommands(chinookConnection, 'TEST NULL') + expect(results).toBeNull() + }) + + test('should test integer', async () => { + const results = await sendCommands(chinookConnection, 'TEST INTEGER') + expect(results).toBe(123456) + }) + + test('should test float', async () => { + const results = await sendCommands(chinookConnection, 'TEST FLOAT') + expect(results).toBe(3.1415926) + }) + + test('should test string', async () => { + const results = await sendCommands(chinookConnection, 'TEST STRING') + expect(results).toBe('Hello World, this is a test string.') + }) + + test('should test zero string', async () => { + const results = await sendCommands(chinookConnection, 'TEST ZERO_STRING') + expect(results).toBe('Hello World, this is a zero-terminated test string.') + }) + + test('should test string0', async () => { + const results = await sendCommands(chinookConnection, 'TEST STRING0') + expect(results).toBe('') + }) + + test('should test command', async () => { + const results = await sendCommands(chinookConnection, 'TEST COMMAND') + expect(results).toBe('PING') + }) + + test('should test json', async () => { + const results = await sendCommands(chinookConnection, 'TEST JSON') + expect(results).toEqual({ + 'msg-from': { class: 'soldier', name: 'Wixilav' }, + 'msg-to': { class: 'supreme-commander', name: '[Redacted]' }, + 'msg-type': ['0xdeadbeef', 'irc log'], + 'msg-log': [ + 'soldier: Boss there is a slight problem with the piece offering to humans', + 'supreme-commander: Explain yourself soldier!', + "soldier: Well they don't seem to move anymore...", + 'supreme-commander: Oh snap, I came here to see them twerk!' + ] + }) + }) + + test('should test blob', async () => { + const results = await sendCommands(chinookConnection, 'TEST BLOB') + expect(typeof results).toBe('object') + expect(results).toBeInstanceOf(Buffer) + const bufferrowset = results as Buffer + expect(bufferrowset.length).toBe(1000) + }) + + test('should test blob0', async () => { + const results = await sendCommands(chinookConnection, 'TEST BLOB0') + expect(typeof results).toBe('object') + expect(results).toBeInstanceOf(Buffer) + const bufferrowset = results as Buffer + expect(bufferrowset.length).toBe(0) + }) + + test('should test error', done => { + chinookConnection.sendCommands('TEST ERROR', (error, results) => { + expect(error).toBeDefined() + expect(error).toBeInstanceOf(SQLiteCloudError) + expect(results).toBeNull() + + const sqliteCloudError = error as SQLiteCloudError + expect(sqliteCloudError.message).toBe('This is a test error message with a devil error code.') + expect(sqliteCloudError.errorCode).toBe('66666') + expect(sqliteCloudError.externalErrorCode).toBe('0') + expect(sqliteCloudError.offsetCode).toBe(-1) + + done() + }) + }) + + test('should test exterror', done => { + chinookConnection.sendCommands('TEST EXTERROR', (error, results) => { + expect(error).toBeDefined() + expect(error).toBeInstanceOf(SQLiteCloudError) + expect(results).toBeNull() + + const sqliteCloudError = error as SQLiteCloudError + expect(sqliteCloudError.message).toBe('This is a test error message with an extcode and a devil error code.') + expect(sqliteCloudError.errorCode).toBe('66666') + expect(sqliteCloudError.externalErrorCode).toBe('333') + expect(sqliteCloudError.offsetCode).toBe(-1) + + done() + }) + }) + + test('should test array', async () => { + const results = await sendCommands(chinookConnection, 'TEST ARRAY') + expect(Array.isArray(results)).toBe(true) + const arrayrowset = results as Array + expect(arrayrowset.length).toBe(5) + expect(arrayrowset[0]).toBe('Hello World') + expect(arrayrowset[1]).toBe(123456) + expect(arrayrowset[2]).toBe(3.1415) + expect(arrayrowset[3]).toBeNull() + }) + + test('should test rowset', async () => { + const results = await sendCommands(chinookConnection, 'TEST ROWSET') + expect(results.numberOfRows).toBe(41) + expect(results.numberOfColumns).toBe(2) + expect(results.version == 1 || results.version == 2).toBeTruthy() + expect(results.columnsNames).toEqual(['key', 'value']) + }) + + test.only('should test chunked rowset', async () => { + const results = await sendCommands(chinookConnection, 'TEST ROWSET_CHUNK') + expect(results.numberOfRows).toBe(147) + expect(results.numberOfColumns).toBe(1) + expect(results.columnsNames).toEqual(['key']) + + expect(results[0]['key']).toBe('REINDEX') + expect(results[1]['key']).toBe('INDEXED') + expect(results[2]['key']).toBe('INDEX') + expect(results[3]['key']).toBe('DESC') + }) + }) + + // various select statements + describe('select', () => { + test('can run simple select', done => { + const connection = new SQLiteCloudBunConnection(CHINOOK_DATABASE_URL, error => { + if (error) { + done(error) + } + connection.sendCommands("SELECT 2 'COLONNA'", (error, result) => { + if (!error) { + expect(result).toEqual([{ COLONNA: 2 }]) + } + done(error) + }) + }) + }) + + test('can list tables', async done => { + const connection = await getConnection() + const results = await sendCommands(connection, 'LIST TABLES') + expect(results.numberOfColumns).toBe(6) + expect(results.numberOfRows).toBe(11) + done() + }) + + test('can repeat commands', async () => { + const connection = await getConnection() + for (let i = 0; i < 50; i++) { + const results = await sendCommands(connection, `SELECT ${i} 'COLONNA'`) + expect(results.numberOfColumns).toBe(1) + expect(results.numberOfRows).toBe(1) + expect(results).toEqual([{ COLONNA: i }]) + } + connection.close() + }) + + test('can send long commands', async () => { + const connection = await getConnection() + + let sql = '' + let i = 0 + for (; i < 250; i++) { + sql += `SELECT ${i} AS counter; ` + } + + // receives only one result for last statement + const results = await sendCommands(connection, sql) + expect(results.numberOfColumns).toBe(1) + expect(results.numberOfRows).toBe(1) + expect(results).toEqual([{ counter: i - 1 }]) + connection.close() + }) + }) +}) diff --git a/src/gateway/connection-bun.ts b/src/gateway/connection-bun.ts new file mode 100644 index 0000000..5703dde --- /dev/null +++ b/src/gateway/connection-bun.ts @@ -0,0 +1,235 @@ +/** + * transport-bun.ts - handles low level communication with sqlitecloud server via specific Bun APIs for tls socket and binary protocol + */ + +import { type SQLiteCloudConfig, SQLiteCloudError, type ErrorCallback, type ResultsCallback } from '../drivers/types' +import { SQLiteCloudConnection } from '../drivers/connection' +import { getInitializationCommands } from '../drivers/utilities' +import { + formatCommand, + hasCommandLength, + parseCommandLength, + popData, + decompressBuffer, + parseRowsetChunks, + CMD_COMPRESSED, + CMD_ROWSET_CHUNK, + bufferEndsWith, + ROWSET_CHUNKS_END +} from '../drivers/protocol' +import type { Socket } from 'bun' + +/** + * Implementation of SQLiteCloudConnection that connects to the database using specific Bun APIs + * that connect to native sockets or tls sockets and communicates via raw, binary protocol. + */ +export class SQLiteCloudBunConnection extends SQLiteCloudConnection { + /** Currently opened bun socket used to communicated with SQLiteCloud server */ + private socket?: Socket + + /** True if connection is open */ + get connected(): boolean { + return !!this.socket + } + + /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */ + /* eslint-disable @typescript-eslint/no-unused-vars */ + connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this { + console.debug(`-> connecting ${config?.host as string}:${config?.port as number}`) + console.assert(!this.connected, 'BunSocketTransport.connect - connection already established') + this.config = config + + void Bun.connect({ + hostname: config.host as string, + port: config.port as number, + tls: config.insecure ? false : true, + + socket: { + open: socket => { + // console.debug('BunSocketTransport.connect - open') + this.socket = socket + + // send initialization commands + const commands = getInitializationCommands(config) + this.transportCommands(commands, error => { + // any results are ignored + if (error) { + console.error('BunSocketTransport.connect - error initializing connection', error) + callback?.call(this, error) + } else { + // console.debug(`<- connected ${config?.host}:${config?.port}`) + callback?.call(this, null) + } + }) + }, + + // connection failed + connectError: (socket, error) => { + console.error('BunTransport.connect - connectError', error) + this.close() + callback?.call(this, error) + }, + + // data received is processed by onData chunk by chunk + data: (socket, data) => { + this.processCommandsData(socket, data) + }, + + // close is received when we call socket.end() or when the server closes the connection + close: socket => { + if (this.socket) { + this.close() + this.processCommandsFinish(new SQLiteCloudError('Connection was closed')) + } + }, + + drain: socket => { + // console.debug('BunTransport.connect - drain') + }, + + error: (socket, error) => { + this.close() + this.processCommandsFinish(new SQLiteCloudError('Connection error', { cause: error })) + }, + + // connection closed by server + end: socket => { + if (this.socket) { + this.close() + this.processCommandsFinish(new SQLiteCloudError('Connection ended')) + } + }, + + // connection timed out + timeout: socket => { + this.close() + this.processCommandsFinish(new SQLiteCloudError('Connection timed out')) + } + } + }) + .catch(error => { + console.debug('BunTransport.connect - error', error) + this.close() + callback?.call(this, error) + }) + .then(socket => { + // connection established + }) + + return this + } + + /** Will send a command immediately (no queueing), return the rowset/result or throw an error */ + transportCommands(commands: string, callback?: ResultsCallback): this { + // connection needs to be established? + if (!this.socket) { + callback?.call(this, new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' })) + return this + } + + // reset buffer and rowset chunks, define response callback + this.buffer = Buffer.alloc(0) + this.startedOn = new Date() + this.processCallback = callback + + // compose commands following SCPC protocol + const formattedCommands = formatCommand(commands) + if (this.config?.verbose) { + console.debug(`-> ${formattedCommands}`) + } + this.socket.write(formattedCommands) + this.socket.flush() + + return this + } + + // processCommands sets up empty buffers, results callback then send the command to the server via socket.write + // onData is called when data is received, it will process the data until all data is retrieved for a response + // when response is complete or there's an error, finish is called to call the results callback set by processCommands... + + // buffer to accumulate incoming data until an whole command is received and can be parsed + private buffer: Buffer = Buffer.alloc(0) + private startedOn: Date = new Date() + + // callback to be called when a command is finished processing + private processCallback?: ResultsCallback + + /** Handles data received in response to an outbound command sent by processCommands */ + private processCommandsData(socket: Socket, data: Buffer) { + try { + // append data to buffer as it arrives + if (data.length && data.length > 0) { + this.buffer = Buffer.concat([this.buffer, data]) + } + + let dataType = this.buffer?.subarray(0, 1).toString() + if (hasCommandLength(dataType)) { + const commandLength = parseCommandLength(this.buffer) + const hasReceivedEntireCommand = this.buffer.length - this.buffer.indexOf(' ') - 1 >= commandLength ? true : false + + if (hasReceivedEntireCommand) { + if (this.config?.verbose) { + let bufferString = this.buffer.toString('utf8') + if (bufferString.length > 1000) { + bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40) + } + const elapsedMs = new Date().getTime() - this.startedOn.getTime() + console.debug(`<- ${bufferString} (${elapsedMs}ms)`) + } + + // need to decompress this buffer before decoding? + if (dataType === CMD_COMPRESSED) { + ;({ buffer: this.buffer, dataType } = decompressBuffer(this.buffer)) + } + + if (dataType !== CMD_ROWSET_CHUNK) { + const { data } = popData(this.buffer) + this.processCommandsFinish?.call(this, null, data) + } else { + // check if rowset received the ending chunk in which case it can be unpacked + if (bufferEndsWith(this.buffer, ROWSET_CHUNKS_END)) { + const parsedData = parseRowsetChunks([this.buffer]) + this.processCommandsFinish?.call(this, null, parsedData) + } + } + } + } else { + // command with no explicit len so make sure that the final character is a space + const lastChar = this.buffer.subarray(this.buffer.length - 1, this.buffer.length).toString('utf8') + if (lastChar == ' ') { + const { data } = popData(this.buffer) + this.processCommandsFinish?.call(this, null, data) + } + } + } catch (error) { + console.assert(error instanceof Error) + if (error instanceof Error) { + this.processCommandsFinish?.call(this, error) + } + } + } + + /** Completes a transaction initiated by processCommands */ + private processCommandsFinish(error: Error | null, result?: any) { + if (error) { + console.error('BunTransport.finish - error', error) + } else { + // console.debug('BunTransport.finish - result', result) + } + if (this.processCallback) { + // console.error(`SQLiteCloudBunConnection.processCommandsFinish - error:${error}, result: ${result}`, error, result) + this.processCallback(error, result) + } + } + + /** Disconnect immediately, release connection. */ + close(): this { + if (this.socket) { + const socket = this.socket + this.socket = undefined + socket.end() + } + this.operations.clear() + return this + } +} diff --git a/src/gateway/gateway.ts b/src/gateway/gateway.ts new file mode 100644 index 0000000..6f5e096 --- /dev/null +++ b/src/gateway/gateway.ts @@ -0,0 +1,286 @@ +// +// gateway.ts - SQLite Cloud Gateway enabling websocket connections and SQL to json queries +// + +import packageJson from '../../package.json' + +// bun specific driver + shared classes +import { SQLiteCloudBunConnection } from './connection-bun' +import { SQLiteCloudRowset, SQLiteCloudError, validateConfiguration } from '../index' +import { type ApiRequest, type ApiResponse, type SqlApiRequest, DEFAULT_PORT_HTTP, DEFAULT_PORT_SOCKET } from './shared' + +// external modules +import { heapStats } from 'bun:jsc' +import { Server } from 'socket.io' +import express from 'express' +import http from 'http' + +// port where socket.io will listen for connections +const SOCKET_PORT = parseInt(process.env['SOCKET_PORT'] || DEFAULT_PORT_SOCKET.toString()) +// port where http server will listen for connections +const HTTP_PORT = parseInt(process.env['HTTP_PORT'] || DEFAULT_PORT_HTTP.toString()) +// should we log verbose messages? +const VERBOSE = process.env['VERBOSE']?.toLowerCase() === 'true' +console.debug(`@sqlitecloud/gateway v${packageJson.version}`) + +// +// express +// + +// Express app for HTTP server +const app = express() +app.use(express.json()) +app.use(express.static('public')) + +// server for socket.io and http endpoints +const server = http.createServer(app) + +// +// websocket server +// + +// Replacing Deno's Server with socket.io's Server +const io = new Server(server, { + cors: { + origin: '*', // specify the client origin + methods: ['GET', 'POST'], // allowed HTTP methods + credentials: true // allow credentials (cookies, session) + } +}) + +// Establish handlers for a socket.io connection +io.on('connection', socket => { + // + // state + // + + // the connection string is passed in the bearer token + // https://socket.io/docs/v4/client-options/#auth + const connectionString = socket.handshake.auth.token as string + let connection: SQLiteCloudBunConnection | null = null + log(`ws | connect socket.id: ${socket.id}`) + + // + // handlers + // + + // received a sql query request from the client socket + socket.on('v1/info', (_request: ApiRequest, callback: (response: ApiResponse) => void) => { + const serverInfo = getServerInfo() + log(`ws | info <- ${JSON.stringify(serverInfo)}`) + return callback(serverInfo) + }) + + // received a sql query request from the client socket + socket.on('v1/sql', async (request: SqlApiRequest, callback: (response: ApiResponse) => void) => { + if (!connectionString) { + callback({ error: { status: '401', title: 'Unauthorized', detail: 'Provide connection string in bearer token' } }) + return + } + + try { + if (!connection) { + const startTime = Date.now() + log('ws | connecting...') + connection = await connectAsync(connectionString) + log(`ws | connected in ${Date.now() - startTime}ms`) + } + + log(`ws | sql -> ${JSON.stringify(request)}`) + const response = await queryAsync(connection, request) + log(`ws | sql <- ${JSON.stringify(response)}`) + return callback(response) + } catch (error) { + callback({ error: { status: '400', title: 'Bad Request', detail: error as string } }) + } + }) + + // received a disconnect request from the client socket + socket.on('disconnect', () => { + log(`ws | disconnect socket.id: ${socket.id}`) + connection?.close() + connection = null + }) +}) + +// Run websocket server +server.listen(SOCKET_PORT, () => { + console.debug(`WebSocket server is running on port ${SOCKET_PORT}`) +}) + +// +// HTTP server +// + +app.listen(HTTP_PORT, () => { + console.debug(`HTTP server is running on port ${HTTP_PORT}`) +}) + +app.get('/v1/info', (req, res) => { + res.json(getServerInfo()) +}) + +app.post('/v1/sql', (req: express.Request, res: express.Response) => { + void (async () => { + try { + log('POST /v1/sql') + const response = await handleHttpSqlRequest(req, res) + res.json(response) + } catch (error) { + log('POST /v1/sql - error', error) + res.status(400).json({ error: { status: '400', title: 'Bad Request', detail: error as string } }) + } + }) +}) + +// +// utilities +// + +/** Handle a stateless sql query request */ +async function handleHttpSqlRequest(request: express.Request, response: express.Response) { + // bearer token is required to connect to sqlitecloud + const connectionString = getBearerToken(request) + if (!connectionString) { + return errorResponse(response, 401, 'Unauthorized') + } + + // ?sql= or json payload with sql property is required + let apiRequest: SqlApiRequest + try { + apiRequest = request.body + } catch (_error) { + apiRequest = { + database: request.query.database as string, + sql: request.query.sql as string, + row: request.query.row as 'array' | 'dictionary' + } + } + if (!(apiRequest.database || apiRequest.sql)) { + return errorResponse(response, 400, 'Bad Request', 'Missing ?sql= query or json payload') + } + + let connection + try { + // request is stateless so we will connect and disconnect for each request + log(`http | sql -> ${JSON.stringify(apiRequest)}`) + connection = await connectAsync(connectionString) + const apiResponse = await queryAsync(connection, apiRequest) + log(`http | sql <- ${JSON.stringify(apiResponse)}`) + response.json(apiResponse) + } catch (error) { + errorResponse(response, 400, 'Bad Request', (error as Error).toString()) + } finally { + connection?.close() + } +} + +/** Server info for /v1/info endpoints */ +function getServerInfo() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { objectTypeCounts, protectedObjectTypeCounts, ...memory } = heapStats() + return { + data: { + name: '@sqlitecloud/gateway', + version: packageJson.version, + bun: { + version: Bun.version, + path: Bun.which('bun'), + main: Bun.main, + uptime: Math.floor(Bun.nanoseconds() / 1e9) // seconds + }, + memory, + cpuUsage: process.cpuUsage(), + date: new Date().toISOString() + } + } +} + +/** Extract and return bearer token from request authorization headers */ +function getBearerToken(request: express.Request): string | null { + const authorization = request.headers['authorization'] as string + // console.debug(`getBearerToken - ${authorization}`, request.headers) + if (authorization && authorization.startsWith('Bearer ')) { + return authorization.substring(7) + } + return null +} + +/** Returns a json api compatibile error response */ +function errorResponse(response: express.Response, status: number, statusText: string, detail?: string) { + response.status(status).json({ error: { status: status.toString(), title: statusText, detail } }) +} + +/** Connects to given database asynchronously */ +async function connectAsync(connectionString: string): Promise { + return await new Promise((resolve, reject) => { + const config = validateConfiguration({ connectionString }) + const connection = new SQLiteCloudBunConnection(config, (error: Error | null) => { + if (error) { + log('connectAsync | error', error) + reject(error) + } else { + resolve(connection) + } + }) + }) +} + +/** Sends given sql commands asynchronously */ +async function sendCommandsAsync(connection: SQLiteCloudBunConnection, sql: string): Promise { + return await new Promise((resolve, reject) => { + connection.sendCommands(sql, (error: Error | null, results) => { + // Explicitly type the 'error' parameter as 'Error' + if (error) { + log('sendCommandsAsync | error', error) + reject(error) + } else { + // console.debug(JSON.stringify(results).substring(0, 140) + '...') + resolve(results) + } + }) + }) +} + +/** Runs query on given connection and returns response payload */ +async function queryAsync(connection: SQLiteCloudBunConnection, apiRequest: SqlApiRequest): Promise { + let result: unknown = 'OK' + try { + if (apiRequest.database) { + result = await sendCommandsAsync(connection, `USE DATABASE ${apiRequest.database}`) + } + + if (apiRequest.sql) { + result = await sendCommandsAsync(connection, apiRequest.sql) + // query returned a rowset? + if (result instanceof SQLiteCloudRowset) { + const rowset = result + const data = apiRequest.row === 'dictionary' ? rowset : rowset.map(rowsetRow => rowsetRow.getData()) // rows as arrays by default + return { data, metadata: rowset.metadata } + } + } + } catch (error) { + log('queryAsync | error', error) + const sqliteError = error as SQLiteCloudError + return { + error: { + status: '400', + title: 'Bad Request', + detail: sqliteError?.message || sqliteError?.toString(), + // SQLiteCloudError additional properties + errorCode: sqliteError?.errorCode, + offsetCode: sqliteError?.offsetCode, + externalErrorCode: sqliteError?.externalErrorCode + } + } + } + + return { data: result } +} + +/** Log only in verbose mode */ +function log(...args: unknown[]) { + if (VERBOSE) { + console.debug(...args) + } +} diff --git a/src/gateway/shared.ts b/src/gateway/shared.ts new file mode 100644 index 0000000..a8c6ca4 --- /dev/null +++ b/src/gateway/shared.ts @@ -0,0 +1,37 @@ +// +// types.ts - shared types for client and server +// + +/** Generic api request as a json dictionary */ +export type ApiRequest = Record + +export interface ApiResponse { + /** Rows are returned as dictionaries or arrays */ + data?: unknown + /** Additional metadata */ + metadata?: unknown + /** Optional error condition */ + error?: { + /** Error status as http code */ + status: string + title?: string + detail?: string + // SQLiteCloudError additional properties + errorCode?: string + externalErrorCode?: string + offsetCode?: number + } +} + +/** An api call to perform a query */ +export interface SqlApiRequest extends ApiRequest { + /** If the optional database name is specified, the connection will perform a USE DATABASE before running the query */ + database?: string + /** The sql query to be executed */ + sql: string + /** Rows can be returned as arrays (default) or dictionaries */ + row?: 'array' | 'dictionary' +} + +export const DEFAULT_PORT_SOCKET = 4000 +export const DEFAULT_PORT_HTTP = 8090 diff --git a/src/index.ts b/src/index.ts index 5ea012d..50215b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,15 @@ // -// index.ts - re-export public APIs +// index.ts - export drivers classes, utilities, types // -export { Database } from './database' -export { Statement } from './statement' -export { SQLiteCloudConfig, SQLCloudRowsetMetadata, SQLiteCloudError, ErrorCallback } from './types' -export { SQLiteCloudRowset, SQLiteCloudRow } from './rowset' -export { SQLiteCloudConnection } from './connection' -export { escapeSqlParameter, prepareSql, parseConnectionString, validateConfiguration } from './utilities' -export { WebSocketTransport } from './transport-ws' -export { TlsSocketTransport } from './transport-tls' +// include ONLY packages used by drivers +// do NOT include anything related to gateway or bun or express +// connection-tls does not want/need to load on browser and is loaded dynamically by Database +// connection-ws does not want/need to load on node and is loaded dynamically by Database + +export { Database } from './drivers/database' +export { Statement } from './drivers/statement' +export { SQLiteCloudConnection } from './drivers/connection' +export { type SQLiteCloudConfig, type SQLCloudRowsetMetadata, SQLiteCloudError, type ErrorCallback } from './drivers/types' +export { SQLiteCloudRowset, SQLiteCloudRow } from './drivers/rowset' +export { escapeSqlParameter, prepareSql, parseConnectionString, validateConfiguration } from './drivers/utilities' diff --git a/src/transport-tls.ts b/src/transport-tls.ts deleted file mode 100644 index e1a15c5..0000000 --- a/src/transport-tls.ts +++ /dev/null @@ -1,532 +0,0 @@ -/** - * transport-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol - */ - -import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback, SQLCloudRowsetMetadata, SQLiteCloudDataTypes } from './types' -import { SQLiteCloudRowset } from './rowset' -import { ConnectionTransport, getInitializationCommands, anonimizeError, anonimizeCommand } from './connection' - -import net from 'net' -import tls from 'tls' -const lz4 = require('lz4js') - -// The server communicates with clients via commands defined in -// SQLiteCloud Server Protocol (SCSP), see more at: -// https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md - -const CMD_STRING = '+' -const CMD_ZEROSTRING = '!' -const CMD_ERROR = '-' -const CMD_INT = ':' -const CMD_FLOAT = ',' -const CMD_ROWSET = '*' -const CMD_ROWSET_CHUNK = '/' -const CMD_JSON = '#' -const CMD_NULL = '_' -const CMD_BLOB = '$' -const CMD_COMPRESSED = '%' -const CMD_COMMAND = '^' -const CMD_ARRAY = '=' -// const CMD_RAWJSON = '{' -// const CMD_PUBSUB = '|' -// const CMD_RECONNECT = '@' - -/** - * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol. - * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified. - * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc. - * A connection socket is established when the connection is created and closed when the connection is closed. - * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed, - * it cannot be reopened and you must create a new connection. - */ -export class TlsSocketTransport implements ConnectionTransport { - /** Configuration passed to connect */ - private config?: SQLiteCloudConfig - /** Currently opened tls socket used to communicated with SQLiteCloud server */ - private socket?: tls.TLSSocket | net.Socket | null - - /** True if connection is open */ - get connected(): boolean { - return !!this.socket - } - - /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */ - connect(config: SQLiteCloudConfig, callback?: ErrorCallback): this { - // connection established while we were waiting in line? - console.assert(!this.connected, 'Connection already established') - - // clear all listeners and call done in the operations queue - const finish: ResultsCallback = error => { - if (this.socket) { - this.socket.removeAllListeners('data') - this.socket.removeAllListeners('error') - this.socket.removeAllListeners('close') - if (error) { - this.close() - } - } - } - - this.config = config - - if (config.insecure) { - // connect to plain socket, without encryption, only if insecure parameter specified - // this option is mainly for testing purposes and is not available on production nodes - // which would need to connect using tls and proper certificates as per code below - const connectionOptions: net.SocketConnectOpts = { - host: config.host, - port: config.port as number - } - this.socket = net.connect(connectionOptions, () => { - console.warn(`TlsTransport.connect - connected to ${config.host}:${config.port} using insecure protocol`) - callback?.call(this, null) - }) - } else { - // connect to tls socket, initialize connection, setup event handlers - this.socket = tls.connect(this.config.port as number, this.config.host, this.config.tlsOptions, () => { - const tlsSocket = this.socket as tls.TLSSocket - if (!tlsSocket?.authorized) { - const anonimizedError = anonimizeError(tlsSocket.authorizationError) - console.error('Connection was not authorized', anonimizedError) - this.close() - finish(new SQLiteCloudError('Connection was not authorized', { cause: anonimizedError })) - } else { - // the connection was closed before it was even opened, - // eg. client closed the connection before the server accepted it - if (this.socket === null) { - finish(new SQLiteCloudError('Connection was closed before it was done opening')) - return - } - - // send initialization commands - console.assert(this.socket, 'Connection already closed') - const commands = getInitializationCommands(config) - this.processCommands(commands, error => { - if (error && this.socket) { - this.close() - } - if (callback) { - callback?.call(this, error) - callback = undefined - } - finish(error) - }) - } - }) - } - - this.socket.on('close', () => { - this.socket = null - finish(new SQLiteCloudError('Connection was closed')) - }) - - this.socket.once('error', (error: any) => { - console.error('Connection error', error) - finish(new SQLiteCloudError('Connection error', { cause: error })) - }) - - return this - } - - /** Will send a command immediately (no queueing), return the rowset/result or throw an error */ - processCommands(commands: string, callback?: ResultsCallback): this { - // connection needs to be established? - if (!this.socket) { - callback?.call(this, new SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' })) - return this - } - - // compose commands following SCPC protocol - commands = formatCommand(commands) - - let buffer = Buffer.alloc(0) - const rowsetChunks: Buffer[] = [] - // const startedOn = new Date() - - // define what to do if an answer does not arrive within the set timeout - let socketTimeout: number - - // clear all listeners and call done in the operations queue - const finish: ResultsCallback = (error, result) => { - clearTimeout(socketTimeout) - if (this.socket) { - this.socket.removeAllListeners('data') - this.socket.removeAllListeners('error') - this.socket.removeAllListeners('close') - } - if (callback) { - callback?.call(this, error, result) - callback = undefined - } - } - - // define the Promise that waits for the server response - const readData = (data: Uint8Array) => { - try { - // on first ondata event, dataType is read from data, on subsequent ondata event, is read from buffer that is the concatanations of data received on each ondata event - let dataType = buffer.length === 0 ? data.subarray(0, 1).toString() : buffer.subarray(0, 1).toString('utf8') - buffer = Buffer.concat([buffer, data]) - const commandLength = hasCommandLength(dataType) - - if (commandLength) { - const commandLength = parseCommandLength(buffer) - const hasReceivedEntireCommand = buffer.length - buffer.indexOf(' ') - 1 >= commandLength ? true : false - if (hasReceivedEntireCommand) { - if (this.config?.verbose) { - let bufferString = buffer.toString('utf8') - if (bufferString.length > 1000) { - bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40) - } - // const elapsedMs = new Date().getTime() - startedOn.getTime() - // console.debug(`Receive: ${bufferString} - ${elapsedMs}ms`) - } - - // need to decompress this buffer before decoding? - if (dataType === CMD_COMPRESSED) { - ;({ buffer, dataType } = decompressBuffer(buffer)) - } - - if (dataType !== CMD_ROWSET_CHUNK) { - this.socket?.off('data', readData) - const { data } = popData(buffer) - finish(null, data) - } else { - // @ts-expect-error - // check if rowset received the ending chunk - if (data.subarray(data.indexOf(' ') + 1, data.length).toString() === '0 0 0 ') { - const parsedData = parseRowsetChunks(rowsetChunks) - finish?.call(this, null, parsedData) - } else { - // no ending string? ask server for another chunk - rowsetChunks.push(buffer) - buffer = Buffer.alloc(0) - - // no longer need to ack the server - // const okCommand = formatCommand('OK') - // this.socket?.write(okCommand) - } - } - } - } else { - // command with no explicit len so make sure that the final character is a space - const lastChar = buffer.subarray(buffer.length - 1, buffer.length).toString('utf8') - if (lastChar == ' ') { - const { data } = popData(buffer) - finish(null, data) - } - } - } catch (error) { - console.assert(error instanceof Error) - if (error instanceof Error) { - finish(error) - } - } - } - - this.socket?.once('close', () => { - finish(new SQLiteCloudError('Connection was closed', { cause: anonimizeCommand(commands) })) - }) - - this.socket?.write(commands, 'utf8', () => { - socketTimeout = setTimeout(() => { - const timeoutError = new SQLiteCloudError('Request timed out', { cause: anonimizeCommand(commands) }) - // console.debug(`Request timed out, config.timeout is ${this.config?.timeout as number}ms`, timeoutError) - finish(timeoutError) - }, this.config?.timeout) - this.socket?.on('data', readData) - }) - - this.socket?.once('error', (error: any) => { - console.error('Socket error', error) - this.close() - finish(new SQLiteCloudError('Socket error', { cause: anonimizeError(error) })) - }) - - return this - } - - /** Disconnect from server, release connection. */ - close(): this { - console.assert(this.socket !== null, 'TlsSocketTransport.close - connection already closed') - if (this.socket) { - this.socket.destroy() - this.socket = null - } - this.socket = undefined - return this - } -} - -// -// utility functions -// - -/** Analyze first character to check if corresponding data type has LEN */ -function hasCommandLength(firstCharacter: string): boolean { - return firstCharacter == CMD_INT || firstCharacter == CMD_FLOAT || firstCharacter == CMD_NULL ? false : true -} - -/** Analyze a command with explict LEN and extract it */ -function parseCommandLength(data: Buffer) { - return parseInt(data.subarray(1, data.indexOf(' ')).toString('utf8')) -} - -/** Receive a compressed buffer, decompress with lz4, return buffer and datatype */ -function decompressBuffer(buffer: Buffer): { buffer: Buffer; dataType: string } { - const spaceIndex = buffer.indexOf(' ') - buffer = buffer.subarray(spaceIndex + 1) - - // extract compressed size - const compressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8')) - buffer = buffer.subarray(buffer.indexOf(' ') + 1) - - // extract decompressed size - const decompressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8')) - buffer = buffer.subarray(buffer.indexOf(' ') + 1) - - // extract compressed dataType - const dataType = buffer.subarray(0, 1).toString('utf8') - const decompressedBuffer = Buffer.alloc(decompressedSize) - const compressedBuffer = buffer.subarray(buffer.length - compressedSize) - - // lz4js library is javascript and doesn't have types so we silence the type check - // eslint-disable-next-line - const decompressionResult: number = lz4.decompressBlock(compressedBuffer, decompressedBuffer, 0, compressedSize, 0) - buffer = Buffer.concat([buffer.subarray(0, buffer.length - compressedSize), decompressedBuffer]) - if (decompressionResult <= 0 || decompressionResult !== decompressedSize) { - throw new Error(`lz4 decompression error at offset ${decompressionResult}`) - } - - return { buffer, dataType: dataType } -} - -/** Parse error message or extended error message */ -function parseError(buffer: Buffer, spaceIndex: number): never { - const errorBuffer = buffer.subarray(spaceIndex + 1) - const errorString = errorBuffer.toString('utf8') - const parts = errorString.split(' ') - - let errorCodeStr = parts.shift() || '0' // Default errorCode is '0' if not present - let extErrCodeStr = '0' // Default extended error code - let offsetCodeStr = '-1' // Default offset code - - // Split the errorCode by ':' to check for extended error codes - const errorCodeParts = errorCodeStr.split(':') - errorCodeStr = errorCodeParts[0] - if (errorCodeParts.length > 1) { - extErrCodeStr = errorCodeParts[1] - if (errorCodeParts.length > 2) { - offsetCodeStr = errorCodeParts[2] - } - } - - // Rest of the error string is the error message - const errorMessage = parts.join(' ') - - // Parse error codes to integers safely, defaulting to 0 if NaN - const errorCode = parseInt(errorCodeStr) - const extErrCode = parseInt(extErrCodeStr) - const offsetCode = parseInt(offsetCodeStr) - - // create an Error object and add the custom properties - throw new SQLiteCloudError(errorMessage, { - errorCode: errorCode.toString(), - externalErrorCode: extErrCode.toString(), - offsetCode - }) -} - -/** Parse an array of items (each of which will be parsed by type separately) */ -function parseArray(buffer: Buffer, spaceIndex: number): SQLiteCloudDataTypes[] { - const parsedData = [] - - const array = buffer.subarray(spaceIndex + 1, buffer.length) - const numberOfItems = parseInt(array.subarray(0, spaceIndex - 2).toString('utf8')) - let arrayItems = array.subarray(array.indexOf(' ') + 1, array.length) - - for (let i = 0; i < numberOfItems; i++) { - const { data, fwdBuffer: buffer } = popData(arrayItems) - parsedData.push(data) - arrayItems = buffer - } - - return parsedData as SQLiteCloudDataTypes[] -} - -/** Parse header in a rowset or chunk of a chunked rowset */ -function parseRowsetHeader(buffer: Buffer): { index: number; metadata: SQLCloudRowsetMetadata; fwdBuffer: Buffer } { - const index = parseInt(buffer.subarray(0, buffer.indexOf(':') + 1).toString()) - buffer = buffer.subarray(buffer.indexOf(':') + 1) - - // extract rowset header - const { data, fwdBuffer } = popIntegers(buffer, 3) - - return { - index, - metadata: { - version: data[0], - numberOfRows: data[1], - numberOfColumns: data[2], - columns: [] - }, - fwdBuffer - } -} - -/** Extract column names and, optionally, more metadata out of a rowset's header */ -function parseRowsetColumnsMetadata(buffer: Buffer, metadata: SQLCloudRowsetMetadata): Buffer { - function popForward() { - const { data, fwdBuffer: fwdBuffer } = popData(buffer) // buffer in parent scope - buffer = fwdBuffer - return data - } - - for (let i = 0; i < metadata.numberOfColumns; i++) { - metadata.columns.push({ name: popForward() as string }) - } - - // extract additional metadata if rowset has version 2 - if (metadata.version == 2) { - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].type = popForward() as string - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].database = popForward() as string - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].table = popForward() as string - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].column = popForward() as string // original column name - - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].notNull = popForward() as number - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].primaryKey = popForward() as number - for (let i = 0; i < metadata.numberOfColumns; i++) metadata.columns[i].autoIncrement = popForward() as number - } - - return buffer -} - -/** Parse a regular rowset (no chunks) */ -function parseRowset(buffer: Buffer, spaceIndex: number): SQLiteCloudRowset { - buffer = buffer.subarray(spaceIndex + 1, buffer.length) - - const { metadata, fwdBuffer } = parseRowsetHeader(buffer) - buffer = parseRowsetColumnsMetadata(fwdBuffer, metadata) - - // decode each rowset item - const data = [] - for (let j = 0; j < metadata.numberOfRows * metadata.numberOfColumns; j++) { - const { data: rowData, fwdBuffer } = popData(buffer) - data.push(rowData) - buffer = fwdBuffer - } - - console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'SQLiteCloudConnection.parseRowset - invalid rowset data') - return new SQLiteCloudRowset(metadata, data) -} - -/** - * Parse a chunk of a chunked rowset command, eg: - * *LEN 0:VERS NROWS NCOLS DATA - */ -export function parseRowsetChunks(buffers: Buffer[]) { - let metadata: SQLCloudRowsetMetadata = { version: 1, numberOfColumns: 0, numberOfRows: 0, columns: [] } - const data: any[] = [] - - for (let i = 0; i < buffers.length; i++) { - let buffer: Buffer = buffers[i] - - // validate and skip data type - const dataType = buffer.subarray(0, 1).toString() - console.assert(dataType === CMD_ROWSET_CHUNK) - buffer = buffer.subarray(buffer.indexOf(' ') + 1) - - // chunk header, eg: 0:VERS NROWS NCOLS - const { index: chunkIndex, metadata: chunkMetadata, fwdBuffer } = parseRowsetHeader(buffer) - buffer = fwdBuffer - - // first chunk? extract columns metadata - if (chunkIndex === 1) { - metadata = chunkMetadata - buffer = parseRowsetColumnsMetadata(buffer, metadata) - } else { - metadata.numberOfRows += chunkMetadata.numberOfRows - } - - // extract single rowset row - for (let k = 0; k < chunkMetadata.numberOfRows * metadata.numberOfColumns; k++) { - const { data: itemData, fwdBuffer } = popData(buffer) - data.push(itemData) - buffer = fwdBuffer - } - } - - console.assert(data && data.length === metadata.numberOfRows * metadata.numberOfColumns, 'SQLiteCloudConnection.parseRowsetChunks - invalid rowset data') - return new SQLiteCloudRowset(metadata, data) -} - -/** Pop one or more space separated integers from beginning of buffer, move buffer forward */ -function popIntegers(buffer: Buffer, numberOfIntegers = 1): { data: number[]; fwdBuffer: Buffer } { - const data: number[] = [] - for (let i = 0; i < numberOfIntegers; i++) { - const spaceIndex = buffer.indexOf(' ') - data[i] = parseInt(buffer.subarray(0, spaceIndex).toString()) - buffer = buffer.subarray(spaceIndex + 1) - } - return { data, fwdBuffer: buffer } -} - -/** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */ -export function popData(buffer: Buffer): { data: SQLiteCloudDataTypes | SQLiteCloudRowset; fwdBuffer: Buffer } { - function popResults(data: any) { - const fwdBuffer = buffer.subarray(commandEnd) - return { data, fwdBuffer } - } - - // first character is the data type - console.assert(buffer && buffer instanceof Buffer) - const dataType: string = buffer.subarray(0, 1).toString('utf8') - console.assert(dataType !== CMD_COMPRESSED, "Compressed data shouldn't be decompressed before parsing") - console.assert(dataType !== CMD_ROWSET_CHUNK, 'Chunked data should be parsed by parseRowsetChunks') - - let spaceIndex = buffer.indexOf(' ') - if (spaceIndex === -1) { - spaceIndex = buffer.length - 1 - } - - let commandEnd = -1 - if (dataType === CMD_INT || dataType === CMD_FLOAT || dataType === CMD_NULL) { - commandEnd = spaceIndex + 1 - } else { - const commandLength = parseInt(buffer.subarray(1, spaceIndex).toString()) - commandEnd = spaceIndex + 1 + commandLength - } - - switch (dataType) { - case CMD_INT: - return popResults(parseInt(buffer.subarray(1, spaceIndex).toString())) - case CMD_FLOAT: - return popResults(parseFloat(buffer.subarray(1, spaceIndex).toString())) - case CMD_NULL: - return popResults(null) - case CMD_STRING: - return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8')) - case CMD_ZEROSTRING: - return popResults(buffer.subarray(spaceIndex + 1, commandEnd - 1).toString('utf8')) - case CMD_COMMAND: - return popResults(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8')) - case CMD_JSON: - return popResults(JSON.parse(buffer.subarray(spaceIndex + 1, commandEnd).toString('utf8'))) - case CMD_BLOB: - return popResults(buffer.subarray(spaceIndex + 1, commandEnd)) - case CMD_ARRAY: - return popResults(parseArray(buffer, spaceIndex)) - case CMD_ROWSET: - return popResults(parseRowset(buffer, spaceIndex)) - case CMD_ERROR: - parseError(buffer, spaceIndex) // throws custom error - break - } - - throw new TypeError(`Data type: ${dataType} is not defined in SCSP`) -} - -/** Format a command to be sent via SCSP protocol */ -export function formatCommand(command: string): string { - const commandLength = Buffer.byteLength(command, 'utf-8') - return `+${commandLength} ${command}` -} diff --git a/test/assets/testing.sql b/test/assets/testing.sql index aa8b9d2..94419c8 100644 --- a/test/assets/testing.sql +++ b/test/assets/testing.sql @@ -31,3 +31,6 @@ INSERT INTO people (name, age, hobby) VALUES ('Harper Jackson', 36, 'Bellybutton lint sculpting'), ('Ditto il Foho', 27, 'Cloud shaping'), ('Benjamin Clark', 39, 'Telepathic cooking'); + +-- Return the number 42 so we can test the query +SELECT 42; diff --git a/test/compare.test.ts b/test/compare.test.ts index acdfa4d..c34105e 100644 --- a/test/compare.test.ts +++ b/test/compare.test.ts @@ -111,8 +111,6 @@ describe('Database.on', () => { describe('Database.run', () => { it('sqlite3: insert with plain sql', done => { - const testingFile = createTestDatabaseFile() - // https://github.com/TryGhost/node-sqlite3/wiki/API#runsql--param---callback function onInsert(error: Error, results: any) { expect(error).toBeNull() @@ -127,12 +125,11 @@ describe('Database.run', () => { done() } + const testingFile = createTestDatabaseFile() testingFile.run(INSERT_SQL, onInsert) }) it('sqlitecloud: insert with plain sql', done => { - const testingCloud = getTestingDatabase() - // https://github.com/TryGhost/node-sqlite3/wiki/API#runsql--param---callback function onInsert(error: Error, results: any) { expect(error).toBeNull() @@ -150,8 +147,10 @@ describe('Database.run', () => { testingCloud.close() done() } - - testingCloud.run(INSERT_SQL, onInsert) + const testingCloud = getTestingDatabase(error => { + expect(error).toBeNull() + testingCloud.run(INSERT_SQL, onInsert) + }) }) // end run diff --git a/test/connection-tls.test.ts b/test/connection-tls.test.ts index 8e2107b..ff42c8b 100644 --- a/test/connection-tls.test.ts +++ b/test/connection-tls.test.ts @@ -3,7 +3,9 @@ */ import { SQLiteCloudError } from '../src/index' -import { SQLiteCloudConnection, anonimizeCommand } from '../src/connection' +import { SQLiteCloudConnection } from '../src/drivers/connection' +import { SQLiteCloudTlsConnection } from '../src/drivers/connection-tls' +import { anonimizeCommand } from '../src/drivers/utilities' import { CHINOOK_DATABASE_URL, INSECURE_DATABASE_URL, @@ -54,7 +56,7 @@ describe('connection-tls', () => { it('should connect with config object string', done => { const configObj = getChinookConfig() - const conn = new SQLiteCloudConnection(configObj, error => { + const conn = new SQLiteCloudTlsConnection(configObj, error => { expect(error).toBeNull() expect(conn.connected).toBe(true) @@ -73,7 +75,7 @@ describe('connection-tls', () => { done() } - const conn = new SQLiteCloudConnection(CHINOOK_DATABASE_URL, error => { + const conn = new SQLiteCloudTlsConnection(CHINOOK_DATABASE_URL, error => { expect(error).toBeNull() expect(conn.connected).toBe(true) @@ -87,9 +89,11 @@ describe('connection-tls', () => { }) it('should connect with insecure connection string', done => { - if (INSECURE_DATABASE_URL) { + if (!INSECURE_DATABASE_URL) { + done() + } else { expect(INSECURE_DATABASE_URL).toBeDefined() - const conn = new SQLiteCloudConnection(INSECURE_DATABASE_URL, error => { + const conn = new SQLiteCloudTlsConnection(INSECURE_DATABASE_URL, error => { expect(error).toBeNull() expect(conn.connected).toBe(true) @@ -100,9 +104,6 @@ describe('connection-tls', () => { }) }) expect(conn).toBeDefined() - } else { - console.warn(`INSECURE_DATABASE_URL is not defined, ?insecure= connection will not be tested`) - done() } }) @@ -113,7 +114,7 @@ describe('connection-tls', () => { delete testingConfig.password try { - const conn = new SQLiteCloudConnection(testingConfig) + const conn = new SQLiteCloudTlsConnection(testingConfig) } catch (error) { expect(error).toBeDefined() expect(error).toBeInstanceOf(SQLiteCloudError) @@ -296,29 +297,7 @@ describe('connection-tls', () => { expect(results[1]['key']).toBe('INDEXED') expect(results[2]['key']).toBe('INDEX') expect(results[3]['key']).toBe('DESC') - - database.close() - done() - }) - }, - LONG_TIMEOUT - ) - - it( - 'should test chunked rowset via ', - done => { - // this operation sends 150 packets, so we need to increase the timeout - const database = getChinookTlsConnection(undefined, { timeout: 60 * 1000 }) - database.sendCommands('TEST ROWSET_CHUNK', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfRows).toBe(147) - expect(results.numberOfColumns).toBe(1) - expect(results.columnsNames).toEqual(['key']) - - expect(results[0]['key']).toBe('REINDEX') - expect(results[1]['key']).toBe('INDEXED') - expect(results[2]['key']).toBe('INDEX') - expect(results[3]['key']).toBe('DESC') + expect(results[146]['key']).toBe('PRIMARY') database.close() done() diff --git a/test/connection-ws.test.ts b/test/connection-ws.test.ts index ad1b6e2..d398b37 100644 --- a/test/connection-ws.test.ts +++ b/test/connection-ws.test.ts @@ -3,8 +3,8 @@ */ import { SQLiteCloudError } from '../src/index' -import { SQLiteCloudConnection, anonimizeCommand } from '../src/connection' -import { parseConnectionString } from '../src/utilities' +import { SQLiteCloudConnection } from '../src/drivers/connection' +import { SQLiteCloudWebsocketConnection } from '../src/drivers/connection-ws' import { // CHINOOK_DATABASE_URL, @@ -14,6 +14,7 @@ import { WARN_SPEED_MS, EXPECT_SPEED_MS } from './shared' +import { error } from 'console' describe('connection-ws', () => { let chinook: SQLiteCloudConnection @@ -36,11 +37,9 @@ describe('connection-ws', () => { it('should connect with config object string', done => { const configObj = getChinookConfig() configObj.useWebsocket = true - const connection = new SQLiteCloudConnection(configObj) - expect(connection).toBeDefined() - connection.sendCommands('TEST STRING', (error, results) => { - connection.close() - expect(connection.connected).toBe(false) + let connection: SQLiteCloudWebsocketConnection | null = null + connection = new SQLiteCloudWebsocketConnection(configObj, error => { + expect(error).toBeNull() done() }) }) @@ -51,237 +50,231 @@ describe('connection-ws', () => { configObj.password = 'wrongpassword' configObj.useWebsocket = true - // should attemp connection and return error - const connection = new SQLiteCloudConnection(configObj) - expect(connection).toBeDefined() - connection.sendCommands('TEST STRING', (error, results) => { + // should attempt connection and return error + const connection = new SQLiteCloudWebsocketConnection(configObj, error => { expect(error).toBeDefined() - expect(error).toBeInstanceOf(SQLiteCloudError) - expect((error as any).message).toBe('SQLiteCloudError: Authentication failed.') - - connection.close() - expect(connection.connected).toBe(false) done() }) }) - + /* TODO RESTORE TEST it('should connect with connection string', done => { if (CHINOOK_DATABASE_URL.indexOf('localhost') > 0) { // skip this test when running locally since it requires a self-signed certificate done() } - const conn = new SQLiteCloudConnection(CHINOOK_DATABASE_URL, error => { + let conn: SQLiteCloudWebsocketConnection | null = null + conn = new SQLiteCloudWebsocketConnection(CHINOOK_DATABASE_URL, error => { expect(error).toBeNull() - expect(conn.connected).toBe(true) - - chinook.sendCommands('TEST STRING', (error, results) => { - conn.close() - expect(conn.connected).toBe(false) + // @ts-ignore + this.sendCommands('TEST STRING', (error, results) => { + expect(error).toBeNull() + conn?.close() + expect(conn?.connected).toBe(false) done() }) }) expect(conn).toBeDefined() }) }) - - describe('send test commands', () => { - it('should test integer', done => { - chinook.sendCommands('TEST INTEGER', (error, results) => { - expect(error).toBeNull() - expect(results).toBe(123456) - done() +*/ + describe('send test commands', () => { + it('should test integer', done => { + chinook.sendCommands('TEST INTEGER', (error, results) => { + expect(error).toBeNull() + expect(results).toBe(123456) + done() + }) }) - }) - it('should test null', done => { - chinook.sendCommands('TEST NULL', (error, results) => { - expect(error).toBeNull() - expect(results).toBeNull() - done() + it('should test null', done => { + chinook.sendCommands('TEST NULL', (error, results) => { + expect(error).toBeNull() + expect(results).toBeNull() + done() + }) }) - }) - it('should test float', done => { - chinook.sendCommands('TEST FLOAT', (error, results) => { - expect(error).toBeNull() - expect(results).toBe(3.1415926) - done() + it('should test float', done => { + chinook.sendCommands('TEST FLOAT', (error, results) => { + expect(error).toBeNull() + expect(results).toBe(3.1415926) + done() + }) }) - }) - it('should test string', done => { - chinook.sendCommands('TEST STRING', (error, results) => { - expect(error).toBeNull() - expect(results).toBe('Hello World, this is a test string.') - done() + it('should test string', done => { + chinook.sendCommands('TEST STRING', (error, results) => { + expect(error).toBeNull() + expect(results).toBe('Hello World, this is a test string.') + done() + }) }) - }) - it('should test zero string', done => { - chinook.sendCommands('TEST ZERO_STRING', (error, results) => { - expect(error).toBeNull() - expect(results).toBe('Hello World, this is a zero-terminated test string.') - done() + it('should test zero string', done => { + chinook.sendCommands('TEST ZERO_STRING', (error, results) => { + expect(error).toBeNull() + expect(results).toBe('Hello World, this is a zero-terminated test string.') + done() + }) }) - }) - it('should test string0', done => { - chinook.sendCommands('TEST STRING0', (error, results) => { - expect(error).toBeNull() - expect(results).toBe('') - done() + it('should test string0', done => { + chinook.sendCommands('TEST STRING0', (error, results) => { + expect(error).toBeNull() + expect(results).toBe('') + done() + }) }) - }) - it('should test command', done => { - chinook.sendCommands('TEST COMMAND', (error, results) => { - expect(error).toBeNull() - expect(results).toBe('PING') - done() + it('should test command', done => { + chinook.sendCommands('TEST COMMAND', (error, results) => { + expect(error).toBeNull() + expect(results).toBe('PING') + done() + }) }) - }) - it('should test json', done => { - chinook.sendCommands('TEST JSON', (error, results) => { - expect(error).toBeNull() - expect(results).toEqual({ - 'msg-from': { class: 'soldier', name: 'Wixilav' }, - 'msg-to': { class: 'supreme-commander', name: '[Redacted]' }, - 'msg-type': ['0xdeadbeef', 'irc log'], - 'msg-log': [ - 'soldier: Boss there is a slight problem with the piece offering to humans', - 'supreme-commander: Explain yourself soldier!', - "soldier: Well they don't seem to move anymore...", - 'supreme-commander: Oh snap, I came here to see them twerk!' - ] + it('should test json', done => { + chinook.sendCommands('TEST JSON', (error, results) => { + expect(error).toBeNull() + expect(results).toEqual({ + 'msg-from': { class: 'soldier', name: 'Wixilav' }, + 'msg-to': { class: 'supreme-commander', name: '[Redacted]' }, + 'msg-type': ['0xdeadbeef', 'irc log'], + 'msg-log': [ + 'soldier: Boss there is a slight problem with the piece offering to humans', + 'supreme-commander: Explain yourself soldier!', + "soldier: Well they don't seem to move anymore...", + 'supreme-commander: Oh snap, I came here to see them twerk!' + ] + }) + done() }) - done() }) - }) - it('should test blob', done => { - chinook.sendCommands('TEST BLOB', (error, results) => { - expect(error).toBeNull() - expect(typeof results).toBe('object') - expect(results).toBeInstanceOf(Buffer) - const bufferrowset = results as any as Buffer - expect(bufferrowset.length).toBe(1000) - done() + it('should test blob', done => { + chinook.sendCommands('TEST BLOB', (error, results) => { + expect(error).toBeNull() + expect(typeof results).toBe('object') + expect(results).toBeInstanceOf(Buffer) + const bufferrowset = results as any as Buffer + expect(bufferrowset.length).toBe(1000) + done() + }) }) - }) - it('should test blob0', done => { - chinook.sendCommands('TEST BLOB0', (error, results) => { - expect(error).toBeNull() - expect(typeof results).toBe('object') - expect(results).toBeInstanceOf(Buffer) - const bufferrowset = results as any as Buffer - expect(bufferrowset.length).toBe(0) - done() + it('should test blob0', done => { + chinook.sendCommands('TEST BLOB0', (error, results) => { + expect(error).toBeNull() + expect(typeof results).toBe('object') + expect(results).toBeInstanceOf(Buffer) + const bufferrowset = results as any as Buffer + expect(bufferrowset.length).toBe(0) + done() + }) }) - }) - it('should test error', done => { - chinook.sendCommands('TEST ERROR', (error, results) => { - expect(error).toBeDefined() - expect(error).toBeInstanceOf(SQLiteCloudError) + it('should test error', done => { + chinook.sendCommands('TEST ERROR', (error, results) => { + expect(error).toBeDefined() + expect(error).toBeInstanceOf(SQLiteCloudError) - const sqliteCloudError = error as SQLiteCloudError - expect(sqliteCloudError.message).toBe('This is a test error message with a devil error code.') - expect(sqliteCloudError.errorCode).toBe('66666') - expect(sqliteCloudError.externalErrorCode).toBe('0') - expect(sqliteCloudError.offsetCode).toBe(-1) + const sqliteCloudError = error as SQLiteCloudError + expect(sqliteCloudError.message).toBe('This is a test error message with a devil error code.') + expect(sqliteCloudError.errorCode).toBe('66666') + expect(sqliteCloudError.externalErrorCode).toBe('0') + expect(sqliteCloudError.offsetCode).toBe(-1) - done() + done() + }) }) - }) - - it('should test exterror', done => { - chinook.sendCommands('TEST EXTERROR', (error, results) => { - expect(error).toBeDefined() - expect(error).toBeInstanceOf(SQLiteCloudError) - const sqliteCloudError = error as SQLiteCloudError - expect(sqliteCloudError.message).toBe('This is a test error message with an extcode and a devil error code.') - expect(sqliteCloudError.errorCode).toBe('66666') - expect(sqliteCloudError.externalErrorCode).toBe('333') - expect(sqliteCloudError.offsetCode).toBe(-1) + it('should test exterror', done => { + chinook.sendCommands('TEST EXTERROR', (error, results) => { + expect(error).toBeDefined() + expect(error).toBeInstanceOf(SQLiteCloudError) - done() - }) - }) + const sqliteCloudError = error as SQLiteCloudError + expect(sqliteCloudError.message).toBe('This is a test error message with an extcode and a devil error code.') + expect(sqliteCloudError.errorCode).toBe('66666') + expect(sqliteCloudError.externalErrorCode).toBe('333') + expect(sqliteCloudError.offsetCode).toBe(-1) - it('should test array', done => { - chinook.sendCommands('TEST ARRAY', (error, results) => { - expect(error).toBeNull() - expect(Array.isArray(results)).toBe(true) - - const arrayrowset = results as any as Array - expect(arrayrowset.length).toBe(5) - expect(arrayrowset[0]).toBe('Hello World') - expect(arrayrowset[1]).toBe(123456) - expect(arrayrowset[2]).toBe(3.1415) - expect(arrayrowset[3]).toBeNull() - done() + done() + }) }) - }) - it('should test rowset', done => { - chinook.sendCommands('TEST ROWSET', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfRows).toBe(41) - expect(results.numberOfColumns).toBe(2) - expect(results.version == 1 || results.version == 2).toBeTruthy() - expect(results.columnsNames).toEqual(['key', 'value']) - done() + it('should test array', done => { + chinook.sendCommands('TEST ARRAY', (error, results) => { + expect(error).toBeNull() + expect(Array.isArray(results)).toBe(true) + + const arrayrowset = results as any as Array + expect(arrayrowset.length).toBe(5) + expect(arrayrowset[0]).toBe('Hello World') + expect(arrayrowset[1]).toBe(123456) + expect(arrayrowset[2]).toBe(3.1415) + expect(arrayrowset[3]).toBeNull() + done() + }) }) - }) - it( - 'should test chunked rowset', - done => { - // this operation sends 150 packets, so we need to increase the timeout - const database = getChinookWebsocketConnection(undefined, { timeout: 60 * 1000 }) - database.sendCommands('TEST ROWSET_CHUNK', (error, results) => { + it('should test rowset', done => { + chinook.sendCommands('TEST ROWSET', (error, results) => { expect(error).toBeNull() - expect(results.numberOfRows).toBe(147) - expect(results.numberOfColumns).toBe(1) - expect(results.columnsNames).toEqual(['key']) - - database.close() + expect(results.numberOfRows).toBe(41) + expect(results.numberOfColumns).toBe(2) + expect(results.version == 1 || results.version == 2).toBeTruthy() + expect(results.columnsNames).toEqual(['key', 'value']) done() }) - }, - LONG_TIMEOUT - ) - }) - - describe('operations', () => { - it( - 'should serialize operations', - done => { - const numQueries = 20 - let completed = 0 + }) - for (let i = 0; i < numQueries; i++) { - chinook.sendCommands(`select ${i} as "count", 'hello' as 'string'`, (error, results) => { + it( + 'should test chunked rowset', + done => { + // this operation sends 150 packets, so we need to increase the timeout + const database = getChinookWebsocketConnection(undefined, { timeout: 60 * 1000 }) + database.sendCommands('TEST ROWSET_CHUNK', (error, results) => { expect(error).toBeNull() - expect(results.numberOfColumns).toBe(2) - expect(results.numberOfRows).toBe(1) - expect(results.version == 1 || results.version == 2).toBeTruthy() - expect(results.columnsNames).toEqual(['count', 'string']) - expect(results.getItem(0, 0)).toBe(i) - - if (++completed >= numQueries) { - done() - } + expect(results.numberOfRows).toBe(147) + expect(results.numberOfColumns).toBe(1) + expect(results.columnsNames).toEqual(['key']) + + database.close() + done() }) - } - }, - LONG_TIMEOUT - ) - /* TODO RESTORE TEST + }, + LONG_TIMEOUT + ) + }) + + describe('operations', () => { + it( + 'should serialize operations', + done => { + const numQueries = 20 + let completed = 0 + + for (let i = 0; i < numQueries; i++) { + chinook.sendCommands(`select ${i} as "count", 'hello' as 'string'`, (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(2) + expect(results.numberOfRows).toBe(1) + expect(results.version == 1 || results.version == 2).toBeTruthy() + expect(results.columnsNames).toEqual(['count', 'string']) + expect(results.getItem(0, 0)).toBe(i) + + if (++completed >= numQueries) { + done() + } + }) + } + }, + LONG_TIMEOUT + ) + /* TODO RESTORE TEST it('should apply short timeout', done => { // apply shorter timeout const configObj = parseConnectionString(CHINOOK_DATABASE_URL + '?timeout=20') @@ -304,163 +297,164 @@ describe('connection-ws', () => { }) }) */ - }) + }) - describe('send select commands', () => { - it('should LIST METADATA', done => { - chinook.sendCommands('LIST METADATA;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(8) - expect(results.numberOfRows).toBe(64) - done() + describe('send select commands', () => { + it('should LIST METADATA', done => { + chinook.sendCommands('LIST METADATA;', (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(8) + expect(results.numberOfRows).toBe(64) + done() + }) }) - }) - it('should select results with no colum names', done => { - chinook.sendCommands("select 42, 'hello'", (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(2) - expect(results.numberOfRows).toBe(1) - expect(results.version == 1 || results.version == 2).toBeTruthy() - expect(results.columnsNames).toEqual(['42', "'hello'"]) // column name should be hello, not 'hello' - expect(results.getItem(0, 0)).toBe(42) - expect(results.getItem(0, 1)).toBe('hello') + it('should select results with no colum names', done => { + chinook.sendCommands("select 42, 'hello'", (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(2) + expect(results.numberOfRows).toBe(1) + expect(results.version == 1 || results.version == 2).toBeTruthy() + expect(results.columnsNames).toEqual(['42', "'hello'"]) // column name should be hello, not 'hello' + expect(results.getItem(0, 0)).toBe(42) + expect(results.getItem(0, 1)).toBe('hello') - done() + done() + }) }) - }) - it('should select long formatted string', done => { - chinook.sendCommands("USE DATABASE :memory:; select printf('%.*c', 1000, 'x') AS DDD", (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(1) - expect(results.numberOfRows).toBe(1) - expect(results.version == 1 || results.version == 2).toBeTruthy() + it('should select long formatted string', done => { + chinook.sendCommands("USE DATABASE :memory:; select printf('%.*c', 1000, 'x') AS DDD", (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(1) + expect(results.numberOfRows).toBe(1) + expect(results.version == 1 || results.version == 2).toBeTruthy() - const stringrowset = results.getItem(0, 0) as string - expect(stringrowset.startsWith('xxxxxxxxxxxxx')).toBeTruthy() - expect(stringrowset).toHaveLength(1000) + const stringrowset = results.getItem(0, 0) as string + expect(stringrowset.startsWith('xxxxxxxxxxxxx')).toBeTruthy() + expect(stringrowset).toHaveLength(1000) - done() + done() + }) }) - }) - it('should select database', done => { - chinook.sendCommands('USE DATABASE chinook.db;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBeUndefined() - expect(results.numberOfRows).toBeUndefined() - expect(results.version).toBeUndefined() - done() + it('should select database', done => { + chinook.sendCommands('USE DATABASE chinook.db;', (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBeUndefined() + expect(results.numberOfRows).toBeUndefined() + expect(results.version).toBeUndefined() + done() + }) }) - }) - it('should select * from tracks limit 10 (no chunks)', done => { - chinook.sendCommands('SELECT * FROM tracks LIMIT 10;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(9) - expect(results.numberOfRows).toBe(10) - done() + it('should select * from tracks limit 10 (no chunks)', done => { + chinook.sendCommands('SELECT * FROM tracks LIMIT 10;', (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(9) + expect(results.numberOfRows).toBe(10) + done() + }) }) - }) - it('should select * from tracks (with chunks)', done => { - chinook.sendCommands('SELECT * FROM tracks;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(9) - expect(results.numberOfRows).toBe(3503) - done() + it('should select * from tracks (with chunks)', done => { + chinook.sendCommands('SELECT * FROM tracks;', (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(9) + expect(results.numberOfRows).toBe(3503) + done() + }) }) - }) - it('should select * from albums', done => { - chinook.sendCommands('SELECT * FROM albums;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(3) - expect(results.numberOfRows).toBe(347) - expect(results.version == 1 || results.version == 2).toBeTruthy() - done() + it('should select * from albums', done => { + chinook.sendCommands('SELECT * FROM albums;', (error, results) => { + expect(error).toBeNull() + expect(results.numberOfColumns).toBe(3) + expect(results.numberOfRows).toBe(347) + expect(results.version == 1 || results.version == 2).toBeTruthy() + done() + }) }) }) - }) - describe('connection stress testing', () => { - it( - '20x test string', - done => { - const numQueries = 20 - let completed = 0 - const startTime = Date.now() - for (let i = 0; i < numQueries; i++) { - chinook.sendCommands('TEST STRING', (error, results) => { - expect(error).toBeNull() - expect(results).toBe('Hello World, this is a test string.') - if (++completed >= numQueries) { - const queryMs = (Date.now() - startTime) / numQueries - if (queryMs > WARN_SPEED_MS) { - console.log(`${numQueries}x test string, ${queryMs.toFixed(0)}ms per query`) - expect(queryMs).toBeLessThan(EXPECT_SPEED_MS) - } - done() - } - }) - } - }, - LONG_TIMEOUT - ) - - it( - '20x individual selects', - done => { - const numQueries = 20 - let completed = 0 - const startTime = Date.now() - for (let i = 0; i < numQueries; i++) { - chinook.sendCommands('SELECT * FROM albums ORDER BY RANDOM() LIMIT 4;', (error, results) => { - expect(error).toBeNull() - expect(results.numberOfColumns).toBe(3) - expect(results.numberOfRows).toBe(4) - if (++completed >= numQueries) { - const queryMs = (Date.now() - startTime) / numQueries - if (queryMs > WARN_SPEED_MS) { - console.log(`${numQueries}x individual selects, ${queryMs.toFixed(0)}ms per query`) - expect(queryMs).toBeLessThan(EXPECT_SPEED_MS) + describe('connection stress testing', () => { + it( + '20x test string', + done => { + const numQueries = 20 + let completed = 0 + const startTime = Date.now() + for (let i = 0; i < numQueries; i++) { + chinook.sendCommands('TEST STRING', (error, results) => { + expect(error).toBeNull() + expect(results).toBe('Hello World, this is a test string.') + if (++completed >= numQueries) { + const queryMs = (Date.now() - startTime) / numQueries + if (queryMs > WARN_SPEED_MS) { + console.log(`${numQueries}x test string, ${queryMs.toFixed(0)}ms per query`) + expect(queryMs).toBeLessThan(EXPECT_SPEED_MS) + } + done() } - done() - } - }) - } - }, - LONG_TIMEOUT - ) - - it( - '20x batched selects', - done => { - const numQueries = 20 - let completed = 0 - const startTime = Date.now() - for (let i = 0; i < numQueries; i++) { - chinook.sendCommands( - 'SELECT * FROM albums ORDER BY RANDOM() LIMIT 16; SELECT * FROM albums ORDER BY RANDOM() LIMIT 12; SELECT * FROM albums ORDER BY RANDOM() LIMIT 8; SELECT * FROM albums ORDER BY RANDOM() LIMIT 4;', - (error, results) => { + }) + } + }, + LONG_TIMEOUT + ) + + it( + '20x individual selects', + done => { + const numQueries = 20 + let completed = 0 + const startTime = Date.now() + for (let i = 0; i < numQueries; i++) { + chinook.sendCommands('SELECT * FROM albums ORDER BY RANDOM() LIMIT 4;', (error, results) => { expect(error).toBeNull() - // server only returns the last rowset? expect(results.numberOfColumns).toBe(3) expect(results.numberOfRows).toBe(4) if (++completed >= numQueries) { const queryMs = (Date.now() - startTime) / numQueries if (queryMs > WARN_SPEED_MS) { - console.log(`${numQueries}x batched selects, ${queryMs.toFixed(0)}ms per query`) + console.log(`${numQueries}x individual selects, ${queryMs.toFixed(0)}ms per query`) expect(queryMs).toBeLessThan(EXPECT_SPEED_MS) } done() } - } - ) - } - }, - LONG_TIMEOUT - ) + }) + } + }, + LONG_TIMEOUT + ) + + it( + '20x batched selects', + done => { + const numQueries = 20 + let completed = 0 + const startTime = Date.now() + for (let i = 0; i < numQueries; i++) { + chinook.sendCommands( + 'SELECT * FROM albums ORDER BY RANDOM() LIMIT 16; SELECT * FROM albums ORDER BY RANDOM() LIMIT 12; SELECT * FROM albums ORDER BY RANDOM() LIMIT 8; SELECT * FROM albums ORDER BY RANDOM() LIMIT 4;', + (error, results) => { + expect(error).toBeNull() + // server only returns the last rowset? + expect(results.numberOfColumns).toBe(3) + expect(results.numberOfRows).toBe(4) + if (++completed >= numQueries) { + const queryMs = (Date.now() - startTime) / numQueries + if (queryMs > WARN_SPEED_MS) { + console.log(`${numQueries}x batched selects, ${queryMs.toFixed(0)}ms per query`) + expect(queryMs).toBeLessThan(EXPECT_SPEED_MS) + } + done() + } + } + ) + } + }, + LONG_TIMEOUT + ) + }) }) }) diff --git a/test/database.test.ts b/test/database.test.ts index bc3d4a4..cfff5bc 100644 --- a/test/database.test.ts +++ b/test/database.test.ts @@ -4,8 +4,8 @@ import { SQLiteCloudRowset, SQLiteCloudRow, SQLiteCloudError } from '../src/index' import { getTestingDatabase, getTestingDatabaseAsync, getChinookDatabase, removeDatabase, removeDatabaseAsync, LONG_TIMEOUT } from './shared' -import { RowCountCallback } from '../src/types' -import { finished } from 'stream' +import { RowCountCallback } from '../src/drivers/types' +import e from 'express' // // utility methods to setup and destroy temporary test databases @@ -38,8 +38,10 @@ describe('Database.run', () => { }) } - const database = getTestingDatabase() - database.run(updateSql, plainCallbackNotALambda) + const database = getTestingDatabase(error => { + expect(error).toBeNull() + database.run(updateSql, plainCallbackNotALambda) + }) }, LONG_TIMEOUT ) @@ -85,8 +87,10 @@ describe('Database.run', () => { }) } - const database = getTestingDatabase() - database.run(insertSql, plainCallbackNotALambdaOne) + const database = getTestingDatabase(error => { + expect(error).toBeNull() + database.run(insertSql, plainCallbackNotALambdaOne) + }) }, LONG_TIMEOUT ) @@ -269,7 +273,7 @@ describe('Database.sql (async)', () => { it('should work with regular function parameters', async () => { let database try { - database = await getTestingDatabase() + database = await getTestingDatabaseAsync() const results = await database.sql('SELECT * FROM people WHERE name = ?', 'Emma Johnson') expect(results).toHaveLength(1) } finally { @@ -280,7 +284,7 @@ describe('Database.sql (async)', () => { it('should select and return multiple rows', async () => { let database try { - database = await getTestingDatabase() + database = await getTestingDatabaseAsync() const results = await database.sql('SELECT * FROM people ORDER BY id') expect(results).toBeDefined() diff --git a/test/protocol.test.ts b/test/protocol.test.ts new file mode 100644 index 0000000..c332c0d --- /dev/null +++ b/test/protocol.test.ts @@ -0,0 +1,31 @@ +// +// protocol.test.ts +// + +import { parseRowsetChunks } from '../src/drivers/protocol' + +// response sent by the server when we TEST ROWSET_CHUNK +const CHUNKED_RESPONSE = Buffer.from( + '/24 1:1 1 1 +3 key+7 REINDEX/18 2:1 1 1 +7 INDEXED/16 3:1 1 1 +5 INDEX/15 4:1 1 1 +4 DESC/17 5:1 1 1 +6 ESCAPE/15 6:1 1 1 +4 EACH/16 7:1 1 1 +5 CHECK/14 8:1 1 1 +3 KEY/17 9:1 1 1 +6 BEFORE/19 10:1 1 1 +7 FOREIGN/15 11:1 1 1 +3 FOR/18 12:1 1 1 +6 IGNORE/18 13:1 1 1 +6 REGEXP/19 14:1 1 1 +7 EXPLAIN/19 15:1 1 1 +7 INSTEAD/15 16:1 1 1 +3 ADD/20 17:1 1 1 +8 DATABASE/14 18:1 1 1 +2 AS/18 19:1 1 1 +6 SELECT/17 20:1 1 1 +5 TABLE/16 21:1 1 1 +4 LEFT/16 22:1 1 1 +4 THEN/15 23:1 1 1 +3 END/23 24:1 1 1 +10 DEFERRABLE/16 25:1 1 1 +4 ELSE/19 26:1 1 1 +7 EXCLUDE/18 27:1 1 1 +6 DELETE/21 28:1 1 1 +9 TEMPORARY/16 29:1 1 1 +4 TEMP/14 30:1 1 1 +2 OR/18 31:1 1 1 +6 ISNULL/17 32:1 1 1 +5 NULLS/21 33:1 1 1 +9 SAVEPOINT/21 34:1 1 1 +9 INTERSECT/16 35:1 1 1 +4 TIES/19 36:1 1 1 +7 NOTNULL/15 37:1 1 1 +3 NOT/14 38:1 1 1 +2 NO/16 39:1 1 1 +4 NULL/16 40:1 1 1 +4 LIKE/18 41:1 1 1 +6 EXCEPT/24 42:1 1 1 +11 TRANSACTION/18 43:1 1 1 +6 ACTION/14 44:1 1 1 +2 ON/19 45:1 1 1 +7 NATURAL/17 46:1 1 1 +5 ALTER/17 47:1 1 1 +5 RAISE/21 48:1 1 1 +9 EXCLUSIVE/18 49:1 1 1 +6 EXISTS/23 50:1 1 1 +10 CONSTRAINT/16 51:1 1 1 +4 INTO/18 52:1 1 1 +6 OFFSET/14 53:1 1 1 +2 OF/15 54:1 1 1 +3 SET/19 55:1 1 1 +7 TRIGGER/17 56:1 1 1 +5 RANGE/21 57:1 1 1 +9 GENERATED/18 58:1 1 1 +6 DETACH/18 59:1 1 1 +6 HAVING/16 60:1 1 1 +4 GLOB/17 61:1 1 1 +5 BEGIN/17 62:1 1 1 +5 INNER/23 63:1 1 1 +10 REFERENCES/18 64:1 1 1 +6 UNIQUE/17 65:1 1 1 +5 QUERY/19 66:1 1 1 +7 WITHOUT/16 67:1 1 1 +4 WITH/17 68:1 1 1 +5 OUTER/19 69:1 1 1 +7 RELEASE/18 70:1 1 1 +6 ATTACH/19 71:1 1 1 +7 BETWEEN/19 72:1 1 1 +7 NOTHING/18 73:1 1 1 +6 GROUPS/17 74:1 1 1 +5 GROUP/19 75:1 1 1 +7 CASCADE/15 76:1 1 1 +3 ASC/19 77:1 1 1 +7 DEFAULT/16 78:1 1 1 +4 CASE/19 79:1 1 1 +7 COLLATE/18 80:1 1 1 +6 CREATE/25 81:1 1 1 +12 CURRENT_DATE/21 82:1 1 1 +9 IMMEDIATE/16 83:1 1 1 +4 JOIN/18 84:1 1 1 +6 INSERT/17 85:1 1 1 +5 MATCH/16 86:1 1 1 +4 PLAN/19 87:1 1 1 +7 ANALYZE/18 88:1 1 1 +6 PRAGMA/25 89:1 1 1 +12 MATERIALIZED/20 90:1 1 1 +8 DEFERRED/20 91:1 1 1 +8 DISTINCT/14 92:1 1 1 +2 IS/18 93:1 1 1 +6 UPDATE/18 94:1 1 1 +6 VALUES/19 95:1 1 1 +7 VIRTUAL/18 96:1 1 1 +6 ALWAYS/16 97:1 1 1 +4 WHEN/17 98:1 1 1 +5 WHERE/21 99:1 1 1 +9 RECURSIVE/18 100:1 1 1 +5 ABORT/18 101:1 1 1 +5 AFTER/19 102:1 1 1 +6 RENAME/16 103:1 1 1 +3 AND/17 104:1 1 1 +4 DROP/22 105:1 1 1 +9 PARTITION/27 106:1 1 1 +13 AUTOINCREMENT/15 107:1 1 1 +2 TO/15 108:1 1 1 +2 IN/17 109:1 1 1 +4 CAST/19 110:1 1 1 +6 COLUMN/19 111:1 1 1 +6 COMMIT/21 112:1 1 1 +8 CONFLICT/18 113:1 1 1 +5 CROSS/31 114:1 1 1 +17 CURRENT_TIMESTAMP/26 115:1 1 1 +12 CURRENT_TIME/20 116:1 1 1 +7 CURRENT/22 117:1 1 1 +9 PRECEDING/17 118:1 1 1 +4 FAIL/17 119:1 1 1 +4 LAST/19 120:1 1 1 +6 FILTER/20 121:1 1 1 +7 REPLACE/18 122:1 1 1 +5 FIRST/22 123:1 1 1 +9 FOLLOWING/17 124:1 1 1 +4 FROM/17 125:1 1 1 +4 FULL/18 126:1 1 1 +5 LIMIT/15 127:1 1 1 +2 IF/18 128:1 1 1 +5 ORDER/21 129:1 1 1 +8 RESTRICT/19 130:1 1 1 +6 OTHERS/17 131:1 1 1 +4 OVER/22 132:1 1 1 +9 RETURNING/18 133:1 1 1 +5 RIGHT/21 134:1 1 1 +8 ROLLBACK/17 135:1 1 1 +4 ROWS/16 136:1 1 1 +3 ROW/22 137:1 1 1 +9 UNBOUNDED/18 138:1 1 1 +5 UNION/18 139:1 1 1 +5 USING/19 140:1 1 1 +6 VACUUM/17 141:1 1 1 +4 VIEW/19 142:1 1 1 +6 WINDOW/15 143:1 1 1 +2 DO/15 144:1 1 1 +2 BY/22 145:1 1 1 +9 INITIALLY/16 146:1 1 1 +3 ALL/20 147:1 1 1 +7 PRIMARY/6 0 0 0 ' +) + +describe('parseRowsetChunks', () => { + it('should extract rowset from single buffer', () => { + const rowset = parseRowsetChunks([CHUNKED_RESPONSE]) + expect(rowset.length).toBe(147) + expect(rowset[0]['key']).toBe('REINDEX') + expect(rowset[146]['key']).toBe('PRIMARY') + }) + + it('should extract rowset from segmented buffers', () => { + // split CHUNKED_RESPONSE into 3 random sized buffers + const buffer1 = CHUNKED_RESPONSE.slice(0, 100) + const buffer2 = CHUNKED_RESPONSE.slice(100, 200) + const buffer3 = CHUNKED_RESPONSE.slice(200) + + const rowset = parseRowsetChunks([buffer1, buffer2, buffer3]) + expect(rowset.length).toBe(147) + expect(rowset[0]['key']).toBe('REINDEX') + expect(rowset[146]['key']).toBe('PRIMARY') + }) +}) diff --git a/test/shared.ts b/test/shared.ts index c3a17c6..3b1e7a4 100644 --- a/test/shared.ts +++ b/test/shared.ts @@ -4,12 +4,16 @@ import { join } from 'path' import { readFileSync } from 'fs' -import { Database } from '../src/database' -import { ResultsCallback, SQLiteCloudConfig } from '../src/types' -import { parseConnectionString } from '../src/utilities' +import { Database } from '../src/drivers/database' +import { ResultsCallback, SQLiteCloudConfig, SQLiteCloudError } from '../src/drivers/types' +import { parseConnectionString } from '../src/drivers/utilities' + +import { SQLiteCloudTlsConnection } from '../src/drivers/connection-tls' +import { SQLiteCloudWebsocketConnection } from '../src/drivers/connection-ws' import * as dotenv from 'dotenv' -import { SQLiteCloudConnection } from '../src' +import { SQLiteCloudConnection, SQLiteCloudRowset } from '../src' +import e from 'express' dotenv.config() export const LONG_TIMEOUT = 1 * 60 * 1000 // 1 minute @@ -21,7 +25,7 @@ export const WARN_SPEED_MS = 500 export const EXPECT_SPEED_MS = 6 * 1000 /** Number of times or size of stress (when repeated in sequence) */ -export const SEQUENCE_TEST_SIZE = 75 +export const SEQUENCE_TEST_SIZE = 150 /** Concurrency size for multiple connection tests */ export const SIMULTANEOUS_TEST_SIZE = 150 @@ -100,13 +104,13 @@ export function getChinookWebsocketConnection(callback?: ResultsCallback, extraC useWebsocket: true, gatewayUrl: GATEWAY_URL } - const chinookConnection = new SQLiteCloudConnection(chinookConfig, callback) + const chinookConnection = new SQLiteCloudWebsocketConnection(chinookConfig, callback) return chinookConnection } export function getChinookTlsConnection(callback?: ResultsCallback, extraConfig?: Partial): SQLiteCloudConnection { const chinookConfig = getChinookConfig(CHINOOK_DATABASE_URL, extraConfig) - return new SQLiteCloudConnection(chinookConfig, callback) + return new SQLiteCloudTlsConnection(chinookConfig, callback) } /** Returns a chinook.db connection, caller is responsible for closing the database */ @@ -157,18 +161,42 @@ export function getTestingConfig(url = TESTING_DATABASE_URL): SQLiteCloudConfig export function getTestingDatabase(callback?: ResultsCallback): Database { const testingConfig = getTestingConfig() - const database = new Database(testingConfig) + const database = new Database(testingConfig, error => { + if (error) { + console.error(`getTestingDatabase - connection error: ${error}`) + callback?.call(database, error) + } + database.run(TESTING_SQL, (error: SQLiteCloudError, results: SQLiteCloudRowset) => { + if (error) { + console.error(`getTestingDatabase - setup error: ${error}`) + callback?.call(database, error) + } + expect(results).toBeDefined() + expect(results[0][42]).toBe(42) + callback?.call(database, null) + }) + }) + // database.verbose() - database.exec(TESTING_SQL, callback) return database } export async function getTestingDatabaseAsync(): Promise { const testingConfig = getTestingConfig() - const database = new Database(testingConfig) - // database.verbose() - await database.sql(TESTING_SQL) - return database + return new Promise((resolve, reject) => { + const database = new Database(testingConfig, error => { + if (error) { + reject(error) + } + database.run(TESTING_SQL, (error: SQLiteCloudError, results: SQLiteCloudRowset) => { + if (error) { + reject(error) + } + expect(results[0]['42']).toBe(42) + resolve(database) + }) + }) + }) } /** Drop databases that are no longer in use */ diff --git a/test/statement.test.ts b/test/statement.test.ts index 4797270..ae7d621 100644 --- a/test/statement.test.ts +++ b/test/statement.test.ts @@ -3,7 +3,7 @@ */ import { SQLiteCloudRowset } from '../src' -import { RowCallback, RowCountCallback, SQLiteCloudError } from '../src/types' +import { RowCallback, RowCountCallback, SQLiteCloudError } from '../src/drivers/types' import { getChinookDatabase } from './shared' describe('Database.prepare', () => { diff --git a/test/utilities.test.ts b/test/utilities.test.ts index be9d78c..5036a27 100644 --- a/test/utilities.test.ts +++ b/test/utilities.test.ts @@ -3,7 +3,7 @@ // import { SQLiteCloudError } from '../src/index' -import { prepareSql, parseConnectionString } from '../src/utilities' +import { prepareSql, parseConnectionString } from '../src/drivers/utilities' describe('prepareSql', () => { it('should replace single ? parameter', () => { diff --git a/tsconfig.build.json b/tsconfig.build.json index 8a42a1a..439689a 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["test/"] + "exclude": ["test/", "src/gateway/"] } diff --git a/tsconfig.json b/tsconfig.json index 084a1ef..92a9299 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -66,7 +66,10 @@ /* Advanced Options */ "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + + /** Loaders for json files */ + "resolveJsonModule": true }, "include": ["src/**/*.ts", "test/**/*.ts"], diff --git a/webpack.config.js b/webpack.config.js index b9df8df..0fa2435 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,7 +11,7 @@ const productionConfig = { // Output configuration output: { path: path.resolve(__dirname, 'lib'), - filename: `sqlitecloud.v${packageJson.version}.js`, + filename: `sqlitecloud.drivers.js`, library: 'sqlitecloud', libraryTarget: 'umd', globalObject: 'this' @@ -35,6 +35,7 @@ const productionConfig = { const devConfig = JSON.parse(JSON.stringify(productionConfig)) devConfig.mode = 'development' devConfig.optimization.minimize = false -devConfig.output.filename = `sqlitecloud.v${packageJson.version}.dev.js` +devConfig.output.filename = `sqlitecloud.drivers.dev.js` +// devConfig.output.filename = `sqlitecloud.v${packageJson.version}.dev.js` module.exports = [productionConfig, devConfig]