Added remote storage based on rest server
This commit is contained in:
parent
b0fc58825e
commit
e0307d4cbf
12 changed files with 586 additions and 8 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
.venv
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM node
|
||||
|
||||
ADD . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install
|
||||
|
||||
EXPOSE 5001
|
||||
CMD npm run storageserver
|
11
README.md
11
README.md
|
@ -42,9 +42,20 @@ const storage = tkStorage.getLocalStorage("myapp");
|
|||
Use
|
||||
---
|
||||
|
||||
To get a storage locally persistent (saved in browser data or on disk for Node.js):
|
||||
|
||||
```javascript
|
||||
const storage = getLocalStorage("myapp");
|
||||
await storage.get("key"); // => null
|
||||
await storage.set("key", "value");
|
||||
await storage.get("key"); // => "value"
|
||||
```
|
||||
|
||||
To get a storage remotely persistent (saved on a compliant server):
|
||||
|
||||
```javascript
|
||||
const storage = getRemoteStorage("myapp", "https://tk-storage.example.io/", { shared: true });
|
||||
await storage.get("key"); // => null
|
||||
await storage.set("key", "value");
|
||||
await storage.get("key"); // => "value"
|
||||
```
|
||||
|
|
11
dist/index.html
vendored
Normal file
11
dist/index.html
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="tk-storage.umd.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
342
package-lock.json
generated
342
package-lock.json
generated
|
@ -1155,12 +1155,61 @@
|
|||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/body-parser": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz",
|
||||
"integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/connect": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/connect": {
|
||||
"version": "3.4.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
|
||||
"integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/cors": {
|
||||
"version": "2.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.6.tgz",
|
||||
"integrity": "sha512-invOmosX0DqbpA+cE2yoHGUlF/blyf7nB0OGYBBiH27crcVm5NmFaZkLP4Ta1hGaesckCi5lVLlydNJCxkTOSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
|
||||
"integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.0.tgz",
|
||||
"integrity": "sha512-Xnub7w57uvcBqFdIGoRg1KhNOeEj0vB6ykUM7uFWyxvbdE89GFyqgmUcanAriMr4YOxNFZBAWkfcWIb4WBPt3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
|
||||
|
@ -1201,6 +1250,12 @@
|
|||
"integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
|
||||
"integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.12.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.6.tgz",
|
||||
|
@ -1213,6 +1268,12 @@
|
|||
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/resolve": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
|
||||
|
@ -1222,6 +1283,16 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/serve-static": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
|
||||
"integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/mime": "*"
|
||||
}
|
||||
},
|
||||
"@types/stack-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
|
@ -1401,6 +1472,12 @@
|
|||
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
|
||||
"dev": true
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
|
||||
"dev": true
|
||||
},
|
||||
"array-unique": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
|
||||
|
@ -1675,6 +1752,51 @@
|
|||
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
|
||||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bytes": "3.1.0",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "~2.3.0",
|
||||
"qs": "6.7.0",
|
||||
"raw-body": "2.4.0",
|
||||
"type-is": "~1.6.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-errors": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
|
||||
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.0"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
|
@ -1793,6 +1915,12 @@
|
|||
"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
|
||||
"dev": true
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
|
||||
"dev": true
|
||||
},
|
||||
"cache-base": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
|
||||
|
@ -2076,6 +2204,21 @@
|
|||
"utils-merge": "1.0.1"
|
||||
}
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"dev": true
|
||||
},
|
||||
"convert-source-map": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
|
||||
|
@ -2085,6 +2228,18 @@
|
|||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
|
||||
"dev": true
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
|
||||
"dev": true
|
||||
},
|
||||
"copy-descriptor": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
|
||||
|
@ -2903,6 +3058,52 @@
|
|||
"jest-regex-util": "^24.9.0"
|
||||
}
|
||||
},
|
||||
"express": {
|
||||
"version": "4.17.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"accepts": "~1.3.7",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.19.0",
|
||||
"content-disposition": "0.5.3",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "~1.1.2",
|
||||
"fresh": "0.5.2",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "~2.0.5",
|
||||
"qs": "6.7.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"send": "0.17.1",
|
||||
"serve-static": "1.14.1",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": "~1.5.0",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
|
@ -3129,6 +3330,12 @@
|
|||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
|
||||
"dev": true
|
||||
},
|
||||
"fragment-cache": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||
|
@ -3736,6 +3943,15 @@
|
|||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-port": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-port/-/get-port-5.0.0.tgz",
|
||||
"integrity": "sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
|
@ -3844,9 +4060,9 @@
|
|||
}
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz",
|
||||
"integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==",
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"neo-async": "^2.6.0",
|
||||
|
@ -4112,6 +4328,12 @@
|
|||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
|
||||
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-absolute-url": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
|
||||
|
@ -5102,6 +5324,14 @@
|
|||
"proxy-middleware": "^0.15.0",
|
||||
"send": "^0.17.1",
|
||||
"serve-index": "^1.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
|
@ -5332,18 +5562,36 @@
|
|||
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
|
||||
"dev": true
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
|
||||
"dev": true
|
||||
},
|
||||
"memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
|
||||
"dev": true
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
|
||||
"dev": true
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
|
||||
"dev": true
|
||||
},
|
||||
"microbundle": {
|
||||
"version": "0.12.0-next.6",
|
||||
"resolved": "https://registry.npmjs.org/microbundle/-/microbundle-0.12.0-next.6.tgz",
|
||||
|
@ -5974,6 +6222,12 @@
|
|||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
|
||||
"dev": true
|
||||
},
|
||||
"path-type": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
|
@ -6717,6 +6971,16 @@
|
|||
"sisteransi": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
|
||||
"integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"forwarded": "~0.1.2",
|
||||
"ipaddr.js": "1.9.0"
|
||||
}
|
||||
},
|
||||
"proxy-middleware": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz",
|
||||
|
@ -6763,6 +7027,39 @@
|
|||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"dev": true
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bytes": "3.1.0",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-errors": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
|
||||
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.0"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz",
|
||||
|
@ -7431,6 +7728,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
|
||||
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.17.1"
|
||||
}
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
|
@ -8205,6 +8514,22 @@
|
|||
"prelude-ls": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
|
||||
"integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
|
||||
|
@ -8212,9 +8537,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.8",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.8.tgz",
|
||||
"integrity": "sha512-XhHJ3S3ZyMwP8kY1Gkugqx3CJh2C3O0y8NPiSxtm1tyD/pktLAkFZsFGpuNfTZddKDQ/bbDBLAd2YyA1pbi8HQ==",
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.0.tgz",
|
||||
"integrity": "sha512-PC/ee458NEMITe1OufAjal65i6lB58R1HWMRcxwvdz1UopW0DYqlRL3xdu3IcTvTXsB02CRHykidkTRL+A3hQA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
|
@ -8569,6 +8894,11 @@
|
|||
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"xmlhttprequest": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
|
||||
"integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
|
|
|
@ -13,12 +13,21 @@
|
|||
"dev": "run-p dev:*",
|
||||
"dev:test": "jest --watchAll",
|
||||
"dev:build": "microbundle watch -f modern,umd",
|
||||
"storageserver": "ts-node src/server.ts",
|
||||
"prepare": "npm run build",
|
||||
"prepublishOnly": "npm test",
|
||||
"dev:serve": "live-server --host=localhost --port=5000 --no-browser --ignorePattern='.*\\.d\\.ts' dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"xmlhttprequest": "^1.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/express": "^4.17.2",
|
||||
"@types/uuid": "^3.4.6",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"get-port": "^5.0.0",
|
||||
"tk-base": "^0.2.5",
|
||||
"uuid": "^3.3.3"
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { getLocalStorage, getMemoryStorage } from ".";
|
||||
import { getLocalStorage, getMemoryStorage, getRemoteStorage } from ".";
|
||||
import { MemoryStorage, ScopedStorage } from "./basic";
|
||||
import { BrowserLocalStorage } from "./browser";
|
||||
import { NodeDirectoryStorage } from "./node";
|
||||
import { forceNodeStoragesInTempDir } from "./node.test";
|
||||
import { startTestServer } from "./remote.test";
|
||||
|
||||
const localStorage = (window as any).localStorage;
|
||||
|
||||
|
@ -42,6 +43,27 @@ describe(getLocalStorage, () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(getRemoteStorage, () => {
|
||||
const server = startTestServer();
|
||||
|
||||
it("returns a scoped storage", async () => {
|
||||
let storage = getRemoteStorage("app1", `http://localhost:${server.port()}`);
|
||||
|
||||
await storage.set("testkey", "testvalue");
|
||||
expect(await storage.get("testkey")).toBe("testvalue");
|
||||
|
||||
storage = getRemoteStorage("app1", `http://localhost:${server.port()}`);
|
||||
expect(await storage.get("testkey")).toBe("testvalue");
|
||||
|
||||
storage = getRemoteStorage("app2", `http://localhost:${server.port()}`);
|
||||
expect(await storage.get("testkey")).toBeNull();
|
||||
});
|
||||
|
||||
it("scopes in a private namespace on shared mode", async () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe(getMemoryStorage, () => {
|
||||
it("returns a memory storage", () => {
|
||||
const storage = getMemoryStorage();
|
||||
|
|
22
src/index.ts
22
src/index.ts
|
@ -1,12 +1,18 @@
|
|||
import { KeyValueStorage, MemoryStorage, ScopedStorage } from "./basic";
|
||||
import { KeyValueStorage, MemoryStorage, RefScopedStorage, ScopedStorage } from "./basic";
|
||||
import { BrowserLocalStorage } from "./browser";
|
||||
import { NodeDirectoryStorage } from "./node";
|
||||
import { RestRemoteStorage } from "./remote";
|
||||
|
||||
/**
|
||||
* Base type for storage usage
|
||||
*/
|
||||
export type TKStorage = KeyValueStorage
|
||||
|
||||
/**
|
||||
* Exposed classes
|
||||
*/
|
||||
export { MemoryStorage, ScopedStorage, RefScopedStorage, BrowserLocalStorage, NodeDirectoryStorage, RestRemoteStorage };
|
||||
|
||||
/**
|
||||
* Get the best "local" storage available
|
||||
*/
|
||||
|
@ -23,6 +29,20 @@ export function getLocalStorage(appname: string): TKStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a remote storage, based on an URI
|
||||
*
|
||||
* If *shared* is set to true, a namespace will be used to avoid collisions, using getLocalStorage to persist it
|
||||
*/
|
||||
export function getRemoteStorage(appname: string, uri: string, options = { shared: false }): TKStorage {
|
||||
let storage: TKStorage = new RestRemoteStorage(appname, uri);
|
||||
storage = new ScopedStorage(storage, appname);
|
||||
if (options.shared) {
|
||||
storage = new RefScopedStorage(getLocalStorage(appname), storage);
|
||||
}
|
||||
return storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a in-memory volatile storage
|
||||
*/
|
||||
|
|
33
src/remote.test.ts
Normal file
33
src/remote.test.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import getPort from "get-port";
|
||||
import { MemoryStorage } from "./basic";
|
||||
import { basicCheck } from "./basic.test";
|
||||
import { RestRemoteStorage } from "./remote";
|
||||
import { startRestServer } from "./server";
|
||||
|
||||
export function startTestServer(): { port: () => number } {
|
||||
let app: { close: Function } | undefined;
|
||||
let port: number;
|
||||
|
||||
beforeEach(async () => {
|
||||
port = await getPort();
|
||||
app = await startRestServer(port, new MemoryStorage());
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (app) {
|
||||
await app.close();
|
||||
app = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
return { port: () => port };
|
||||
}
|
||||
|
||||
describe(RestRemoteStorage, () => {
|
||||
const server = startTestServer();
|
||||
|
||||
it("communicates with the server", async () => {
|
||||
const storage = new RestRemoteStorage("test", `http://localhost:${server.port()}`);
|
||||
await basicCheck(storage);
|
||||
});
|
||||
});
|
64
src/remote.ts
Normal file
64
src/remote.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { KeyValueStorage } from "./basic";
|
||||
|
||||
function protectKey(key: string): string {
|
||||
return encodeURIComponent(key);
|
||||
}
|
||||
|
||||
type RestClient = (method: "GET" | "POST" | "PUT" | "DELETE", uri: string, body?: string) => Promise<string | null>
|
||||
export const HEADER_REQUESTER = "X-TK-Storage-App"
|
||||
export const HEADER_REPLYIER = "X-TK-Storage-Control"
|
||||
|
||||
/**
|
||||
* Storage on a remote server, directly usable using HTTP REST verbs
|
||||
*/
|
||||
export class RestRemoteStorage implements KeyValueStorage {
|
||||
readonly appname: string
|
||||
readonly base_url: string
|
||||
readonly client: RestClient
|
||||
|
||||
constructor(appname: string, url: string) {
|
||||
this.appname = appname;
|
||||
this.base_url = (url[url.length - 1] != "/") ? url + "/" : url;
|
||||
this.client = this.createClient();
|
||||
}
|
||||
|
||||
async get(key: string): Promise<string | null> {
|
||||
key = protectKey(key);
|
||||
return await this.client("GET", key);
|
||||
}
|
||||
|
||||
async set(key: string, value: string | null): Promise<void> {
|
||||
key = protectKey(key);
|
||||
if (value === null) {
|
||||
await this.client("DELETE", key);
|
||||
} else {
|
||||
await this.client("PUT", key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private createClient(): RestClient {
|
||||
const Request: typeof XMLHttpRequest = (typeof XMLHttpRequest === "undefined") ? require("xmlhttprequest").XMLHttpRequest : XMLHttpRequest;
|
||||
const client: RestClient = (method, path, body?) => new Promise((resolve, reject) => {
|
||||
const xhr = new Request();
|
||||
xhr.open(method, `${this.base_url}${path}`);
|
||||
xhr.responseType = 'text';
|
||||
xhr.setRequestHeader(HEADER_REQUESTER, this.appname);
|
||||
xhr.onload = function () {
|
||||
if (xhr.getResponseHeader(HEADER_REPLYIER) != "ok") {
|
||||
reject("storage not compatible with tk-storage");
|
||||
} else if (xhr.status == 200) {
|
||||
resolve(xhr.responseText);
|
||||
} else if (xhr.status == 404) {
|
||||
resolve(null);
|
||||
} else {
|
||||
reject(`http error ${xhr.status}: ${xhr.statusText}`);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
reject("unknown error");
|
||||
};
|
||||
xhr.send(body);
|
||||
});
|
||||
return client;
|
||||
}
|
||||
}
|
64
src/server.ts
Normal file
64
src/server.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import bodyParser from "body-parser";
|
||||
import cors from "cors";
|
||||
import express from "express";
|
||||
import { getLocalStorage } from ".";
|
||||
import { KeyValueStorage } from "./basic";
|
||||
import { HEADER_REPLYIER, HEADER_REQUESTER } from "./remote";
|
||||
|
||||
type Server = {
|
||||
close: () => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a server compliant with RestRemoteStorage
|
||||
*/
|
||||
export function startRestServer(port: number, storage: KeyValueStorage): Promise<Server> {
|
||||
const app = express();
|
||||
app.use(
|
||||
cors({ exposedHeaders: [HEADER_REPLYIER] }),
|
||||
bodyParser.text(),
|
||||
(req, res, next) => {
|
||||
if (req.header(HEADER_REQUESTER)) {
|
||||
res.set(HEADER_REPLYIER, "ok");
|
||||
next();
|
||||
} else {
|
||||
res.status(400).send();
|
||||
}
|
||||
},
|
||||
);
|
||||
app.get("*", (req, res, next) => {
|
||||
storage.get(req.path).then(result => {
|
||||
if (result === null) {
|
||||
res.status(404).send();
|
||||
} else {
|
||||
res.send(result);
|
||||
}
|
||||
}).catch(next);
|
||||
});
|
||||
app.put("*", (req, res, next) => {
|
||||
storage.set(req.path, req.body).then(() => {
|
||||
res.send();
|
||||
}).catch(next);
|
||||
});
|
||||
app.delete("*", (req, res, next) => {
|
||||
storage.set(req.path, null).then(() => {
|
||||
res.send();
|
||||
}).catch(next);
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const server = app.listen(port, () => {
|
||||
resolve({
|
||||
close: () => new Promise((resolve, reject) => {
|
||||
server.close((err) => err ? reject(err) : resolve());
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof require !== "undefined" && require.main === module) {
|
||||
startRestServer(5001, getLocalStorage("tk-storage-server")).then(() => {
|
||||
console.log(`Server running on port 5001`);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue