mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
Use datalake storage (#6310)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
2caa8590f9
commit
9df6ba218c
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -103,14 +103,15 @@
|
|||||||
"ACCOUNTS_URL": "http://localhost:3000",
|
"ACCOUNTS_URL": "http://localhost:3000",
|
||||||
"UPLOAD_URL": "/files",
|
"UPLOAD_URL": "/files",
|
||||||
"SERVER_PORT": "8087",
|
"SERVER_PORT": "8087",
|
||||||
"VERSION": null,
|
|
||||||
"COLLABORATOR_URL": "ws://localhost:3078",
|
"COLLABORATOR_URL": "ws://localhost:3078",
|
||||||
"COLLABORATOR_API_URL": "http://localhost:3078",
|
"COLLABORATOR_API_URL": "http://localhost:3078",
|
||||||
"CALENDAR_URL": "http://localhost:8095",
|
"CALENDAR_URL": "http://localhost:8095",
|
||||||
"GMAIL_URL": "http://localhost:8088",
|
"GMAIL_URL": "http://localhost:8088",
|
||||||
"TELEGRAM_URL": "http://localhost:8086",
|
"TELEGRAM_URL": "http://localhost:8086",
|
||||||
"MODEL_VERSION": ""
|
"MODEL_VERSION": "",
|
||||||
|
"VERSION": ""
|
||||||
},
|
},
|
||||||
|
"runtimeVersion": "20",
|
||||||
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
|
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
|
||||||
"showAsyncStacks": true,
|
"showAsyncStacks": true,
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
@ -127,7 +128,6 @@
|
|||||||
"SECRET": "secret",
|
"SECRET": "secret",
|
||||||
"METRICS_CONSOLE": "true",
|
"METRICS_CONSOLE": "true",
|
||||||
"ACCOUNTS_URL": "http://localhost:3000",
|
"ACCOUNTS_URL": "http://localhost:3000",
|
||||||
"UPLOAD_URL": "/files",
|
|
||||||
"MONGO_URL": "mongodb://localhost:27017",
|
"MONGO_URL": "mongodb://localhost:27017",
|
||||||
"MINIO_ACCESS_KEY": "minioadmin",
|
"MINIO_ACCESS_KEY": "minioadmin",
|
||||||
"MINIO_SECRET_KEY": "minioadmin",
|
"MINIO_SECRET_KEY": "minioadmin",
|
||||||
|
@ -176,6 +176,9 @@ dependencies:
|
|||||||
'@rush-temp/core':
|
'@rush-temp/core':
|
||||||
specifier: file:./projects/core.tgz
|
specifier: file:./projects/core.tgz
|
||||||
version: file:projects/core.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
version: file:projects/core.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||||
|
'@rush-temp/datalake':
|
||||||
|
specifier: file:./projects/datalake.tgz
|
||||||
|
version: file:projects/datalake.tgz(esbuild@0.20.1)(ts-node@10.9.2)
|
||||||
'@rush-temp/desktop':
|
'@rush-temp/desktop':
|
||||||
specifier: file:./projects/desktop.tgz
|
specifier: file:./projects/desktop.tgz
|
||||||
version: file:projects/desktop.tgz(bufferutil@4.0.8)(sass@1.71.1)(utf-8-validate@6.0.4)
|
version: file:projects/desktop.tgz(bufferutil@4.0.8)(sass@1.71.1)(utf-8-validate@6.0.4)
|
||||||
@ -1313,6 +1316,9 @@ dependencies:
|
|||||||
'@types/web-push':
|
'@types/web-push':
|
||||||
specifier: ~3.6.3
|
specifier: ~3.6.3
|
||||||
version: 3.6.3
|
version: 3.6.3
|
||||||
|
'@types/ws':
|
||||||
|
specifier: ^8.5.11
|
||||||
|
version: 8.5.11
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^6.11.0
|
specifier: ^6.11.0
|
||||||
version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||||
@ -1511,6 +1517,9 @@ dependencies:
|
|||||||
eslint-plugin-svelte:
|
eslint-plugin-svelte:
|
||||||
specifier: ^2.35.1
|
specifier: ^2.35.1
|
||||||
version: 2.35.1(eslint@8.56.0)(svelte@4.2.12)(ts-node@10.9.2)
|
version: 2.35.1(eslint@8.56.0)(svelte@4.2.12)(ts-node@10.9.2)
|
||||||
|
express:
|
||||||
|
specifier: ^4.19.2
|
||||||
|
version: 4.19.2
|
||||||
express-fileupload:
|
express-fileupload:
|
||||||
specifier: ^1.5.1
|
specifier: ^1.5.1
|
||||||
version: 1.5.1
|
version: 1.5.1
|
||||||
@ -1538,6 +1547,9 @@ dependencies:
|
|||||||
fork-ts-checker-webpack-plugin:
|
fork-ts-checker-webpack-plugin:
|
||||||
specifier: ~7.3.0
|
specifier: ~7.3.0
|
||||||
version: 7.3.0(typescript@5.3.3)(webpack@5.90.3)
|
version: 7.3.0(typescript@5.3.3)(webpack@5.90.3)
|
||||||
|
form-data:
|
||||||
|
specifier: ^4.0.0
|
||||||
|
version: 4.0.0
|
||||||
gaxios:
|
gaxios:
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.1.3
|
version: 5.1.3
|
||||||
@ -1835,6 +1847,9 @@ dependencies:
|
|||||||
winston-daily-rotate-file:
|
winston-daily-rotate-file:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.0(winston@3.13.1)
|
version: 5.0.0(winston@3.13.1)
|
||||||
|
ws:
|
||||||
|
specifier: ^8.18.0
|
||||||
|
version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
y-prosemirror:
|
y-prosemirror:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.2(prosemirror-model@1.19.4)(y-protocols@1.0.6)(yjs@13.6.12)
|
version: 1.2.2(prosemirror-model@1.19.4)(y-protocols@1.0.6)(yjs@13.6.12)
|
||||||
@ -2604,7 +2619,7 @@ packages:
|
|||||||
'@babel/traverse': 7.23.9
|
'@babel/traverse': 7.23.9
|
||||||
'@babel/types': 7.23.9
|
'@babel/types': 7.23.9
|
||||||
convert-source-map: 2.0.0
|
convert-source-map: 2.0.0
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
gensync: 1.0.0-beta.2
|
gensync: 1.0.0-beta.2
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
@ -3827,7 +3842,7 @@ packages:
|
|||||||
'@babel/helper-split-export-declaration': 7.22.6
|
'@babel/helper-split-export-declaration': 7.22.6
|
||||||
'@babel/parser': 7.23.9
|
'@babel/parser': 7.23.9
|
||||||
'@babel/types': 7.23.9
|
'@babel/types': 7.23.9
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
globals: 11.12.0
|
globals: 11.12.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -3949,7 +3964,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==}
|
resolution: {integrity: sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
fs-extra: 9.1.0
|
fs-extra: 9.1.0
|
||||||
promise-retry: 2.0.1
|
promise-retry: 2.0.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -3973,7 +3988,7 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
compare-version: 0.1.2
|
compare-version: 0.1.2
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
isbinaryfile: 4.0.10
|
isbinaryfile: 4.0.10
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
@ -3988,7 +4003,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@electron/asar': 3.2.10
|
'@electron/asar': 3.2.10
|
||||||
'@malept/cross-spawn-promise': 1.1.1
|
'@malept/cross-spawn-promise': 1.1.1
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
dir-compare: 3.3.0
|
dir-compare: 3.3.0
|
||||||
fs-extra: 9.1.0
|
fs-extra: 9.1.0
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
@ -4637,7 +4652,7 @@ packages:
|
|||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
espree: 9.6.1
|
espree: 9.6.1
|
||||||
globals: 13.24.0
|
globals: 13.24.0
|
||||||
ignore: 5.3.1
|
ignore: 5.3.1
|
||||||
@ -4654,7 +4669,7 @@ packages:
|
|||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
espree: 9.6.1
|
espree: 9.6.1
|
||||||
globals: 13.24.0
|
globals: 13.24.0
|
||||||
ignore: 5.3.1
|
ignore: 5.3.1
|
||||||
@ -4809,7 +4824,7 @@ packages:
|
|||||||
engines: {node: '>=10.10.0'}
|
engines: {node: '>=10.10.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@humanwhocodes/object-schema': 2.0.2
|
'@humanwhocodes/object-schema': 2.0.2
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -4820,7 +4835,7 @@ packages:
|
|||||||
engines: {node: '>=10.10.0'}
|
engines: {node: '>=10.10.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@humanwhocodes/object-schema': 1.2.1
|
'@humanwhocodes/object-schema': 1.2.1
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -5579,7 +5594,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
|
resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
fs-extra: 9.1.0
|
fs-extra: 9.1.0
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
tmp-promise: 3.0.3
|
tmp-promise: 3.0.3
|
||||||
@ -9540,7 +9555,7 @@ packages:
|
|||||||
'@typescript-eslint/scope-manager': 5.62.0
|
'@typescript-eslint/scope-manager': 5.62.0
|
||||||
'@typescript-eslint/type-utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/type-utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.1
|
ignore: 5.3.1
|
||||||
@ -9594,7 +9609,7 @@ packages:
|
|||||||
'@typescript-eslint/scope-manager': 5.62.0
|
'@typescript-eslint/scope-manager': 5.62.0
|
||||||
'@typescript-eslint/types': 5.62.0
|
'@typescript-eslint/types': 5.62.0
|
||||||
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3)
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -9650,7 +9665,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
tsutils: 3.21.0(typescript@5.3.3)
|
tsutils: 3.21.0(typescript@5.3.3)
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
@ -9670,7 +9685,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
ts-api-utils: 1.2.1(typescript@5.3.3)
|
ts-api-utils: 1.2.1(typescript@5.3.3)
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
@ -9699,7 +9714,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.62.0
|
'@typescript-eslint/types': 5.62.0
|
||||||
'@typescript-eslint/visitor-keys': 5.62.0
|
'@typescript-eslint/visitor-keys': 5.62.0
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
semver: 7.6.3
|
semver: 7.6.3
|
||||||
@ -9720,7 +9735,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 6.21.0
|
'@typescript-eslint/types': 6.21.0
|
||||||
'@typescript-eslint/visitor-keys': 6.21.0
|
'@typescript-eslint/visitor-keys': 6.21.0
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 9.0.3
|
minimatch: 9.0.3
|
||||||
@ -10257,7 +10272,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -10266,7 +10281,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
|
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -10475,7 +10490,7 @@ packages:
|
|||||||
builder-util: 24.13.1
|
builder-util: 24.13.1
|
||||||
builder-util-runtime: 9.2.4
|
builder-util-runtime: 9.2.4
|
||||||
chromium-pickle-js: 0.2.0
|
chromium-pickle-js: 0.2.0
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
dmg-builder: 24.13.3
|
dmg-builder: 24.13.3
|
||||||
ejs: 3.1.9
|
ejs: 3.1.9
|
||||||
electron-publish: 24.13.1
|
electron-publish: 24.13.1
|
||||||
@ -11323,7 +11338,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==}
|
resolution: {integrity: sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
sax: 1.3.0
|
sax: 1.3.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -11339,7 +11354,7 @@ packages:
|
|||||||
builder-util-runtime: 9.2.4
|
builder-util-runtime: 9.2.4
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
http-proxy-agent: 5.0.0
|
http-proxy-agent: 5.0.0
|
||||||
https-proxy-agent: 5.0.1
|
https-proxy-agent: 5.0.1
|
||||||
@ -12449,7 +12464,7 @@ packages:
|
|||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
object.assign: 4.1.5
|
object.assign: 4.1.5
|
||||||
regexp.prototype.flags: 1.5.2
|
regexp.prototype.flags: 1.5.2
|
||||||
side-channel: 1.0.5
|
side-channel: 1.0.6
|
||||||
which-boxed-primitive: 1.0.2
|
which-boxed-primitive: 1.0.2
|
||||||
which-collection: 1.0.1
|
which-collection: 1.0.1
|
||||||
which-typed-array: 1.1.14
|
which-typed-array: 1.1.14
|
||||||
@ -12617,7 +12632,7 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
address: 1.2.2
|
address: 1.2.2
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -13264,7 +13279,7 @@ packages:
|
|||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
has-proto: 1.0.3
|
has-proto: 1.0.3
|
||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
hasown: 2.0.1
|
hasown: 2.0.2
|
||||||
internal-slot: 1.0.7
|
internal-slot: 1.0.7
|
||||||
is-array-buffer: 3.0.4
|
is-array-buffer: 3.0.4
|
||||||
is-callable: 1.2.7
|
is-callable: 1.2.7
|
||||||
@ -13410,13 +13425,13 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic: 1.2.4
|
get-intrinsic: 1.2.4
|
||||||
has-tostringtag: 1.0.2
|
has-tostringtag: 1.0.2
|
||||||
hasown: 2.0.1
|
hasown: 2.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/es-shim-unscopables@1.0.2:
|
/es-shim-unscopables@1.0.2:
|
||||||
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
|
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
hasown: 2.0.1
|
hasown: 2.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/es-to-primitive@1.2.1:
|
/es-to-primitive@1.2.1:
|
||||||
@ -13498,7 +13513,7 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
esbuild: '>=0.12 <1'
|
esbuild: '>=0.12 <1'
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
esbuild: 0.18.20
|
esbuild: 0.18.20
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -13990,7 +14005,7 @@ packages:
|
|||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
enquirer: 2.4.1
|
enquirer: 2.4.1
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
@ -14976,7 +14991,7 @@ packages:
|
|||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
has-proto: 1.0.3
|
has-proto: 1.0.3
|
||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
hasown: 2.0.1
|
hasown: 2.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/get-nonce@1.0.1:
|
/get-nonce@1.0.1:
|
||||||
@ -15667,7 +15682,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tootallnate/once': 2.0.0
|
'@tootallnate/once': 2.0.0
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -15730,7 +15745,7 @@ packages:
|
|||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 5.1.1
|
agent-base: 5.1.1
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -15740,7 +15755,7 @@ packages:
|
|||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -15750,7 +15765,7 @@ packages:
|
|||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.1
|
agent-base: 7.1.1
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@ -15897,8 +15912,8 @@ packages:
|
|||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
hasown: 2.0.1
|
hasown: 2.0.2
|
||||||
side-channel: 1.0.5
|
side-channel: 1.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/interpret@3.1.1:
|
/interpret@3.1.1:
|
||||||
@ -16422,7 +16437,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
|
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
istanbul-lib-coverage: 3.2.2
|
istanbul-lib-coverage: 3.2.2
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -19877,7 +19892,7 @@ packages:
|
|||||||
engines: {node: '>=8.16.0'}
|
engines: {node: '>=8.16.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/mime-types': 2.1.4
|
'@types/mime-types': 2.1.4
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
extract-zip: 1.7.0
|
extract-zip: 1.7.0
|
||||||
https-proxy-agent: 4.0.0
|
https-proxy-agent: 4.0.0
|
||||||
mime: 2.6.0
|
mime: 2.6.0
|
||||||
@ -19930,7 +19945,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
|
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.0.5
|
side-channel: 1.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/qs@6.11.2:
|
/qs@6.11.2:
|
||||||
@ -20344,7 +20359,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==}
|
resolution: {integrity: sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
module-details-from-path: 1.0.3
|
module-details-from-path: 1.0.3
|
||||||
resolve: 1.22.8
|
resolve: 1.22.8
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -21149,7 +21164,7 @@ packages:
|
|||||||
/spdy-transport@3.0.0:
|
/spdy-transport@3.0.0:
|
||||||
resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==}
|
resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
detect-node: 2.1.0
|
detect-node: 2.1.0
|
||||||
hpack.js: 2.1.6
|
hpack.js: 2.1.6
|
||||||
obuf: 1.1.2
|
obuf: 1.1.2
|
||||||
@ -21163,7 +21178,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==}
|
resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
handle-thing: 2.0.1
|
handle-thing: 2.0.1
|
||||||
http-deceiver: 1.2.7
|
http-deceiver: 1.2.7
|
||||||
select-hose: 2.0.0
|
select-hose: 2.0.0
|
||||||
@ -21586,7 +21601,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
component-emitter: 1.3.1
|
component-emitter: 1.3.1
|
||||||
cookiejar: 2.1.4
|
cookiejar: 2.1.4
|
||||||
debug: 4.3.4
|
debug: 4.3.5
|
||||||
fast-safe-stringify: 2.1.1
|
fast-safe-stringify: 2.1.1
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
formidable: 2.1.2
|
formidable: 2.1.2
|
||||||
@ -25338,6 +25353,40 @@ packages:
|
|||||||
- ts-node
|
- ts-node
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
file:projects/datalake.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
||||||
|
resolution: {integrity: sha512-pqgfJAfjDTa3AWRK263xljvkd1GLinDFrjTGW7res8krRskMMJ3K6gj3kfnLjyKmWeAesJQ5CSnFybPnPSJq/Q==, tarball: file:projects/datalake.tgz}
|
||||||
|
id: file:projects/datalake.tgz
|
||||||
|
name: '@rush-temp/datalake'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@types/jest': 29.5.12
|
||||||
|
'@types/node': 20.11.19
|
||||||
|
'@types/node-fetch': 2.6.11
|
||||||
|
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||||
|
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
|
eslint: 8.56.0
|
||||||
|
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||||
|
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||||
|
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||||
|
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||||
|
form-data: 4.0.0
|
||||||
|
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||||
|
node-fetch: 2.7.0
|
||||||
|
prettier: 3.2.5
|
||||||
|
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||||
|
typescript: 5.3.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@babel/core'
|
||||||
|
- '@jest/types'
|
||||||
|
- babel-jest
|
||||||
|
- babel-plugin-macros
|
||||||
|
- encoding
|
||||||
|
- esbuild
|
||||||
|
- node-notifier
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
dev: false
|
||||||
|
|
||||||
file:projects/desktop-1.tgz(webpack@5.90.3):
|
file:projects/desktop-1.tgz(webpack@5.90.3):
|
||||||
resolution: {integrity: sha512-Fkk5uNa4NwlCVU5yJUf4X3FcGljXj0qUH7iyoCEAk8EKQ/Mi3OfG/KqK03kEeuM1KP8T1CtArtUhWDsM66/AFQ==, tarball: file:projects/desktop-1.tgz}
|
resolution: {integrity: sha512-Fkk5uNa4NwlCVU5yJUf4X3FcGljXj0qUH7iyoCEAk8EKQ/Mi3OfG/KqK03kEeuM1KP8T1CtArtUhWDsM66/AFQ==, tarball: file:projects/desktop-1.tgz}
|
||||||
id: file:projects/desktop-1.tgz
|
id: file:projects/desktop-1.tgz
|
||||||
@ -27110,7 +27159,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/model-all.tgz:
|
file:projects/model-all.tgz:
|
||||||
resolution: {integrity: sha512-iZAri5sHzRIutIt2bdrG1zI/QAu/lt1KC14lDRvHKLCaEtThF4RLlBqYHQ/rZM8aZyHIiGLwVztxvzR8D5EnZA==, tarball: file:projects/model-all.tgz}
|
resolution: {integrity: sha512-GYOekXK7++TNstTuTVtmUp1crs2chkWBmgdMBGzWaKVnuYbvHCKSfaNhaZfnAKV3ZnXc4nrbFbq6MUZgu97hnQ==, tarball: file:projects/model-all.tgz}
|
||||||
name: '@rush-temp/model-all'
|
name: '@rush-temp/model-all'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -29515,7 +29564,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/pod-server.tgz:
|
file:projects/pod-server.tgz:
|
||||||
resolution: {integrity: sha512-91Ac7EN5mpCKBG8sIWUljU+qSb6mtEJNVt9TynP8U0++Bhlmyvcryd4k2rMC5S+M/GvmlikUpAZ+MdIBsqUM+g==, tarball: file:projects/pod-server.tgz}
|
resolution: {integrity: sha512-cbeFqSKcEIP6H/55Ux47qcZ1os7nwgBryGQGIF3DILmB/1J7wc6dlbJizE6S7/f3PON5c3H5s7VY2NmpVzhD5g==, tarball: file:projects/pod-server.tgz}
|
||||||
name: '@rush-temp/pod-server'
|
name: '@rush-temp/pod-server'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -29650,7 +29699,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/pod-telegram-bot.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
file:projects/pod-telegram-bot.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
resolution: {integrity: sha512-T7EdAT4nMEnEDROxVBBAwOD7ssjiSl6eOr96YFwfZvHlbaR6wJm/XYNzwOM61oc0+rjfnmkmM+FzOwTSifePEA==, tarball: file:projects/pod-telegram-bot.tgz}
|
resolution: {integrity: sha512-nHK8VvEEKMela0QxFYFIFHgIjnQj8A01bct7tu+T54i9PP0bgk1zuS+6neAPX45/su+hRG+oiXjdXnuAPMYv3w==, tarball: file:projects/pod-telegram-bot.tgz}
|
||||||
id: file:projects/pod-telegram-bot.tgz
|
id: file:projects/pod-telegram-bot.tgz
|
||||||
name: '@rush-temp/pod-telegram-bot'
|
name: '@rush-temp/pod-telegram-bot'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -29835,13 +29884,14 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/presentation.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2):
|
file:projects/presentation.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2):
|
||||||
resolution: {integrity: sha512-qkCAH3xI1PgIlcZMYba7hsH3mpizW9nfMF13DaxgTu7glkC4ycPl+CHxhiqUadpHPfPQXNk6g7mNj2fS9ZyuGw==, tarball: file:projects/presentation.tgz}
|
resolution: {integrity: sha512-r+NP0EMgEeKbfaa4v8P1Iho0cfYqe9PhOBfV6SPd/9xnNPt42nK9Gu4r5so1LTolhEUzbFiKh7zSX1ADL5e/3g==, tarball: file:projects/presentation.tgz}
|
||||||
id: file:projects/presentation.tgz
|
id: file:projects/presentation.tgz
|
||||||
name: '@rush-temp/presentation'
|
name: '@rush-temp/presentation'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/jest': 29.5.12
|
'@types/jest': 29.5.12
|
||||||
'@types/png-chunks-extract': 1.0.2
|
'@types/png-chunks-extract': 1.0.2
|
||||||
|
'@types/uuid': 8.3.4
|
||||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
@ -29863,6 +29913,7 @@ packages:
|
|||||||
svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.12)(typescript@5.3.3)
|
svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.12)(typescript@5.3.3)
|
||||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
|
uuid: 8.3.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- '@jest/types'
|
- '@jest/types'
|
||||||
@ -30161,7 +30212,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/qms-doc-import-tool.tgz:
|
file:projects/qms-doc-import-tool.tgz:
|
||||||
resolution: {integrity: sha512-mzTjks1peZbU8165Sd1xaoYs9H9f37XszY2zoxtggnaJrP1GeEktuX0TtNTz1XJRsMOg0+0K3s3CRYUEM9+cYw==, tarball: file:projects/qms-doc-import-tool.tgz}
|
resolution: {integrity: sha512-5CfQNuO9R7VNOvU84mR2y/EPQW9tQFUOJ1hX+BWtAGu0TIyO7fHfj57SqGMV8yFqGxjDfBpDpPigZnCM6OUN8A==, tarball: file:projects/qms-doc-import-tool.tgz}
|
||||||
name: '@rush-temp/qms-doc-import-tool'
|
name: '@rush-temp/qms-doc-import-tool'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -30746,7 +30797,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/s3.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
file:projects/s3.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
||||||
resolution: {integrity: sha512-m3PN2etEQkB2hQVrl2Bd5QgHzOQ+1C4e/zk30MuQoIqQiCDR3Uf6/ok0hqza3H69KWkkKjIC5rPihVEfkNt8aA==, tarball: file:projects/s3.tgz}
|
resolution: {integrity: sha512-K8tCIa7XhsCfCud4PK5ap0pAoF4fGanurF5AJ7Otx97p6m170W2DJIkiplk2x41Ksy9+Zw9dEF2VWRgdDrWX5A==, tarball: file:projects/s3.tgz}
|
||||||
id: file:projects/s3.tgz
|
id: file:projects/s3.tgz
|
||||||
name: '@rush-temp/s3'
|
name: '@rush-temp/s3'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -32056,7 +32107,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/server-notification.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
file:projects/server-notification.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
||||||
resolution: {integrity: sha512-jGABHblqLJRd4EjN6dDbXqUJQxr88DjqFkyTva4La4HBrK1ge4g0v6xF450nn7BSOPxLtTZs+60UzaY9lLi0qg==, tarball: file:projects/server-notification.tgz}
|
resolution: {integrity: sha512-aTPQrWC0ymA+iBGLDS9+d8HJvvXCXRdj+XdAe6irRywRPzKjc+niHzm+wVMLRTELYR3RWt/HTGZBVeRSMRgS4g==, tarball: file:projects/server-notification.tgz}
|
||||||
id: file:projects/server-notification.tgz
|
id: file:projects/server-notification.tgz
|
||||||
name: '@rush-temp/server-notification'
|
name: '@rush-temp/server-notification'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -32087,7 +32138,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/server-pipeline.tgz:
|
file:projects/server-pipeline.tgz:
|
||||||
resolution: {integrity: sha512-VMd/X1M3HotOPN51cVDAHjKrHhNm8/5GMMiZ4WklnQVtDfmDHocXKsC+FgOLXpb9RHYhtsz0Arwi7pW7xIar5A==, tarball: file:projects/server-pipeline.tgz}
|
resolution: {integrity: sha512-qGocP2RKEaAspOP4lJZzIYkjIk/hbsYMGGyC4oO62GgWyfBw3O6o2u2R9sU/Jtkkeu2/GBIxkkAc9XEzQ4LbDQ==, tarball: file:projects/server-pipeline.tgz}
|
||||||
name: '@rush-temp/server-pipeline'
|
name: '@rush-temp/server-pipeline'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -32338,7 +32389,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/server-storage.tgz(esbuild@0.20.1):
|
file:projects/server-storage.tgz(esbuild@0.20.1):
|
||||||
resolution: {integrity: sha512-nuggpJP7L/8s3sSJ393e8cISWODMQoCKtqyewY8lN7+n8gnL7RHlVDdinb4N9qvUACoSoExtK41dqAHoTnZxlQ==, tarball: file:projects/server-storage.tgz}
|
resolution: {integrity: sha512-8Vd7+fEnqGcQHOUD4gWdMOlB6X3Ka7kOji7RfrZdlD6es58ykSk5MXH5pPXE0hWJptxlJ0DgLXAAYdptrKCFQQ==, tarball: file:projects/server-storage.tgz}
|
||||||
id: file:projects/server-storage.tgz
|
id: file:projects/server-storage.tgz
|
||||||
name: '@rush-temp/server-storage'
|
name: '@rush-temp/server-storage'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -34157,7 +34208,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/tool.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
file:projects/tool.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
resolution: {integrity: sha512-lU7I2J+om0YHTY8FtcR2DtsEo4wSjZFP7FxAmpPgzFRSz7SwPtvdNDiXlM5zdMLiDszCXxUE/fNluCcxOeO8rg==, tarball: file:projects/tool.tgz}
|
resolution: {integrity: sha512-eZQ8XE+deR+AVtEVrG2p1xfsPLpLfDF4HkcWFNK9SXarUz05pP5xp2KPLXLiVYBbG81Qx56t5jjWi6bMaboTwQ==, tarball: file:projects/tool.tgz}
|
||||||
id: file:projects/tool.tgz
|
id: file:projects/tool.tgz
|
||||||
name: '@rush-temp/tool'
|
name: '@rush-temp/tool'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
|
@ -201,6 +201,7 @@ export async function configurePlatform (): Promise<void> {
|
|||||||
|
|
||||||
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
||||||
setMetadata(presentation.metadata.UploadURL, config.UPLOAD_URL)
|
setMetadata(presentation.metadata.UploadURL, config.UPLOAD_URL)
|
||||||
|
setMetadata(presentation.metadata.FilesURL, config.FILES_URL)
|
||||||
setMetadata(presentation.metadata.CollaboratorUrl, config.COLLABORATOR_URL)
|
setMetadata(presentation.metadata.CollaboratorUrl, config.COLLABORATOR_URL)
|
||||||
setMetadata(presentation.metadata.CollaboratorApiUrl, config.COLLABORATOR_API_URL)
|
setMetadata(presentation.metadata.CollaboratorApiUrl, config.COLLABORATOR_API_URL)
|
||||||
setMetadata(presentation.metadata.PreviewConfig, parsePreviewConfig(config.PREVIEW_CONFIG))
|
setMetadata(presentation.metadata.PreviewConfig, parsePreviewConfig(config.PREVIEW_CONFIG))
|
||||||
|
@ -70,7 +70,9 @@ const expose: IPCMainExposed = {
|
|||||||
...serverConfig,
|
...serverConfig,
|
||||||
...mainConfig,
|
...mainConfig,
|
||||||
INITIAL_URL: openArg ?? '',
|
INITIAL_URL: openArg ?? '',
|
||||||
UPLOAD_URL: concatLink(mainConfig.FRONT_URL, serverConfig.UPLOAD_URL),
|
UPLOAD_URL: (serverConfig.UPLOAD_URL as string).includes('://')
|
||||||
|
? serverConfig.UPLOAD_URL
|
||||||
|
: concatLink(mainConfig.FRONT_URL, serverConfig.UPLOAD_URL),
|
||||||
MODEL_VERSION: mainConfig.MODEL_VERSION,
|
MODEL_VERSION: mainConfig.MODEL_VERSION,
|
||||||
VERSION: mainConfig.VERSION
|
VERSION: mainConfig.VERSION
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ export interface Config {
|
|||||||
COLLABORATOR_URL: string
|
COLLABORATOR_URL: string
|
||||||
COLLABORATOR_API_URL: string
|
COLLABORATOR_API_URL: string
|
||||||
FRONT_URL: string
|
FRONT_URL: string
|
||||||
|
FILES_URL: string
|
||||||
UPLOAD_URL: string
|
UPLOAD_URL: string
|
||||||
MODEL_VERSION?: string
|
MODEL_VERSION?: string
|
||||||
VERSION?: string
|
VERSION?: string
|
||||||
|
@ -77,7 +77,6 @@ services:
|
|||||||
- COLLABORATOR_PORT=3078
|
- COLLABORATOR_PORT=3078
|
||||||
- SECRET=secret
|
- SECRET=secret
|
||||||
- ACCOUNTS_URL=http://account:3000
|
- ACCOUNTS_URL=http://account:3000
|
||||||
- UPLOAD_URL=/files
|
|
||||||
- MONGO_URL=mongodb://mongodb:27017?compressors=snappy
|
- MONGO_URL=mongodb://mongodb:27017?compressors=snappy
|
||||||
- 'MONGO_OPTIONS={"appName":"collaborator","maxPoolSize":2}'
|
- 'MONGO_OPTIONS={"appName":"collaborator","maxPoolSize":2}'
|
||||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||||
@ -100,7 +99,7 @@ services:
|
|||||||
- MONGO_URL=mongodb://mongodb:27017?compressors=snappy
|
- MONGO_URL=mongodb://mongodb:27017?compressors=snappy
|
||||||
- 'MONGO_OPTIONS={"appName":"front","maxPoolSize":1}'
|
- 'MONGO_OPTIONS={"appName":"front","maxPoolSize":1}'
|
||||||
- ACCOUNTS_URL=http://localhost:3000
|
- ACCOUNTS_URL=http://localhost:3000
|
||||||
- UPLOAD_URL=/files
|
- UPLOAD_URL=/files
|
||||||
- ELASTIC_URL=http://elastic:9200
|
- ELASTIC_URL=http://elastic:9200
|
||||||
- GMAIL_URL=http://localhost:8088
|
- GMAIL_URL=http://localhost:8088
|
||||||
- CALENDAR_URL=http://localhost:8095
|
- CALENDAR_URL=http://localhost:8095
|
||||||
@ -116,7 +115,7 @@ services:
|
|||||||
- DESKTOP_UPDATES_URL=https://dist.huly.io
|
- DESKTOP_UPDATES_URL=https://dist.huly.io
|
||||||
- DESKTOP_UPDATES_CHANNEL=dev
|
- DESKTOP_UPDATES_CHANNEL=dev
|
||||||
- BRANDING_URL=http://localhost:8087/branding.json
|
- BRANDING_URL=http://localhost:8087/branding.json
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
transactor:
|
transactor:
|
||||||
image: hardcoreeng/transactor
|
image: hardcoreeng/transactor
|
||||||
links:
|
links:
|
||||||
@ -145,7 +144,6 @@ services:
|
|||||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||||
- REKONI_URL=http://rekoni:4004
|
- REKONI_URL=http://rekoni:4004
|
||||||
- FRONT_URL=http://localhost:8087
|
- FRONT_URL=http://localhost:8087
|
||||||
- UPLOAD_URL=http://localhost:8087/files
|
|
||||||
# - APM_SERVER_URL=http://apm-server:8200
|
# - APM_SERVER_URL=http://apm-server:8200
|
||||||
- SES_URL=''
|
- SES_URL=''
|
||||||
- ACCOUNTS_URL=http://account:3000
|
- ACCOUNTS_URL=http://account:3000
|
||||||
|
@ -120,6 +120,7 @@ import { Analytics } from '@hcengineering/analytics'
|
|||||||
export interface Config {
|
export interface Config {
|
||||||
ACCOUNTS_URL: string
|
ACCOUNTS_URL: string
|
||||||
UPLOAD_URL: string
|
UPLOAD_URL: string
|
||||||
|
FILES_URL: string
|
||||||
MODEL_VERSION: string
|
MODEL_VERSION: string
|
||||||
VERSION: string
|
VERSION: string
|
||||||
COLLABORATOR_URL: string
|
COLLABORATOR_URL: string
|
||||||
@ -284,6 +285,7 @@ export async function configurePlatform() {
|
|||||||
// tryOpenInDesktopApp(config.APP_PROTOCOL ?? 'huly://')
|
// tryOpenInDesktopApp(config.APP_PROTOCOL ?? 'huly://')
|
||||||
|
|
||||||
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
||||||
|
setMetadata(presentation.metadata.FilesURL, config.FILES_URL)
|
||||||
setMetadata(presentation.metadata.UploadURL, config.UPLOAD_URL)
|
setMetadata(presentation.metadata.UploadURL, config.UPLOAD_URL)
|
||||||
setMetadata(presentation.metadata.CollaboratorUrl, config.COLLABORATOR_URL)
|
setMetadata(presentation.metadata.CollaboratorUrl, config.COLLABORATOR_URL)
|
||||||
setMetadata(presentation.metadata.CollaboratorApiUrl, config.COLLABORATOR_API_URL)
|
setMetadata(presentation.metadata.CollaboratorApiUrl, config.COLLABORATOR_API_URL)
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
"ts-jest": "^29.1.1",
|
"ts-jest": "^29.1.1",
|
||||||
"@types/jest": "^29.5.5",
|
"@types/jest": "^29.5.5",
|
||||||
"svelte-eslint-parser": "^0.33.1",
|
"svelte-eslint-parser": "^0.33.1",
|
||||||
"@types/png-chunks-extract": "^1.0.2"
|
"@types/png-chunks-extract": "^1.0.2",
|
||||||
|
"@types/uuid": "^8.3.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hcengineering/platform": "^0.6.11",
|
"@hcengineering/platform": "^0.6.11",
|
||||||
@ -52,7 +53,8 @@
|
|||||||
"@hcengineering/client": "^0.6.18",
|
"@hcengineering/client": "^0.6.18",
|
||||||
"@hcengineering/collaborator-client": "^0.6.4",
|
"@hcengineering/collaborator-client": "^0.6.4",
|
||||||
"fast-equals": "^5.0.1",
|
"fast-equals": "^5.0.1",
|
||||||
"png-chunks-extract": "^1.0.0"
|
"png-chunks-extract": "^1.0.0",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"repository": "https://github.com/hcengineering/platform",
|
"repository": "https://github.com/hcengineering/platform",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
import presentation from '../plugin'
|
import presentation from '../plugin'
|
||||||
|
|
||||||
import { getPreviewType, previewTypes } from '../file'
|
import { getFileUrl } from '../file'
|
||||||
|
import { getPreviewType, previewTypes } from '../filetypes'
|
||||||
import { BlobMetadata, FilePreviewExtension } from '../types'
|
import { BlobMetadata, FilePreviewExtension } from '../types'
|
||||||
import { getFileUrl } from '../utils'
|
|
||||||
|
|
||||||
export let file: Ref<Blob>
|
export let file: Ref<Blob>
|
||||||
export let name: string
|
export let name: string
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
import presentation from '../plugin'
|
import presentation from '../plugin'
|
||||||
|
|
||||||
|
import { getFileUrl } from '../file'
|
||||||
import { BlobMetadata } from '../types'
|
import { BlobMetadata } from '../types'
|
||||||
import { getFileUrl } from '../utils'
|
|
||||||
|
|
||||||
import ActionContext from './ActionContext.svelte'
|
import ActionContext from './ActionContext.svelte'
|
||||||
import FilePreview from './FilePreview.svelte'
|
import FilePreview from './FilePreview.svelte'
|
||||||
|
@ -14,26 +14,78 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { concatLink, type Blob, type Ref } from '@hcengineering/core'
|
import { concatLink, type Blob, type Ref } from '@hcengineering/core'
|
||||||
import { PlatformError, Severity, Status, getMetadata, getResource } from '@hcengineering/platform'
|
import { PlatformError, Severity, Status, getMetadata } from '@hcengineering/platform'
|
||||||
import { type PopupAlignment } from '@hcengineering/ui'
|
import { v4 as uuid } from 'uuid'
|
||||||
import { writable } from 'svelte/store'
|
|
||||||
|
|
||||||
import plugin from './plugin'
|
import plugin from './plugin'
|
||||||
import type { BlobMetadata, FileOrBlob, FilePreviewExtension } from './types'
|
import { decodeTokenPayload } from './utils'
|
||||||
import { createQuery } from './utils'
|
|
||||||
|
interface FileUploadError {
|
||||||
|
key: string
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileUploadSuccess {
|
||||||
|
key: string
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileUploadResult = FileUploadSuccess | FileUploadError
|
||||||
|
|
||||||
|
const defaultUploadUrl = '/files'
|
||||||
|
const defaultFilesUrl = '/files/:workspace/:filename?file=:blobId&workspace=:workspace'
|
||||||
|
|
||||||
|
function getFilesUrl (): string {
|
||||||
|
const filesUrl = getMetadata(plugin.metadata.FilesURL) ?? defaultFilesUrl
|
||||||
|
const frontUrl = getMetadata(plugin.metadata.FrontUrl) ?? window.location.origin
|
||||||
|
|
||||||
|
return filesUrl.includes('://') ? filesUrl : concatLink(frontUrl, filesUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCurrentWorkspace (): string {
|
||||||
|
return decodeTokenPayload(getMetadata(plugin.metadata.Token) ?? '').workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function generateFileId (): string {
|
||||||
|
return uuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function getUploadUrl (): string {
|
||||||
|
const template = getMetadata(plugin.metadata.UploadURL) ?? defaultUploadUrl
|
||||||
|
|
||||||
|
return template.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function getFileUrl (file: string, filename?: string): string {
|
||||||
|
if (file.includes('://')) {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = getFilesUrl()
|
||||||
|
return template
|
||||||
|
.replaceAll(':filename', encodeURIComponent(filename ?? ''))
|
||||||
|
.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
|
||||||
|
.replaceAll(':blobId', encodeURIComponent(file))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export async function uploadFile (file: File): Promise<Ref<Blob>> {
|
export async function uploadFile (file: File): Promise<Ref<Blob>> {
|
||||||
const uploadUrl = getMetadata(plugin.metadata.UploadURL)
|
const uploadUrl = getUploadUrl()
|
||||||
|
|
||||||
if (uploadUrl === undefined) {
|
|
||||||
throw Error('UploadURL is not defined')
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const id = generateFileId()
|
||||||
const data = new FormData()
|
const data = new FormData()
|
||||||
data.append('file', file)
|
data.append('file', file, id)
|
||||||
|
|
||||||
const resp = await fetch(uploadUrl, {
|
const resp = await fetch(uploadUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -51,17 +103,25 @@ export async function uploadFile (file: File): Promise<Ref<Blob>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await resp.text()) as Ref<Blob>
|
const result = (await resp.json()) as FileUploadResult[]
|
||||||
|
if (result.length !== 1) {
|
||||||
|
throw Error('Bad upload response')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('error' in result[0]) {
|
||||||
|
throw Error(`Failed to upload file: ${result[0].error}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return id as Ref<Blob>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export async function deleteFile (id: string): Promise<void> {
|
export async function deleteFile (id: string): Promise<void> {
|
||||||
const uploadUrl = getMetadata(plugin.metadata.UploadURL) ?? ''
|
const fileUrl = getFileUrl(id)
|
||||||
|
|
||||||
const url = concatLink(uploadUrl, `?file=${id}`)
|
const resp = await fetch(fileUrl, {
|
||||||
const resp = await fetch(url, {
|
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer ' + (getMetadata(plugin.metadata.Token) as string)
|
Authorization: 'Bearer ' + (getMetadata(plugin.metadata.Token) as string)
|
||||||
@ -72,108 +132,3 @@ export async function deleteFile (id: string): Promise<void> {
|
|||||||
throw new Error('Failed to delete file')
|
throw new Error('Failed to delete file')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export async function getFileMetadata (file: FileOrBlob, uuid: Ref<Blob>): Promise<BlobMetadata | undefined> {
|
|
||||||
const previewType = await getPreviewType(file.type, $previewTypes)
|
|
||||||
if (previewType?.metadataProvider === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadataProvider = await getResource(previewType.metadataProvider)
|
|
||||||
if (metadataProvider === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return await metadataProvider(file, uuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export const previewTypes = writable<FilePreviewExtension[]>([])
|
|
||||||
const previewTypesQuery = createQuery(true)
|
|
||||||
previewTypesQuery.query(plugin.class.FilePreviewExtension, {}, (result) => {
|
|
||||||
previewTypes.set(result)
|
|
||||||
})
|
|
||||||
|
|
||||||
let $previewTypes: FilePreviewExtension[] = []
|
|
||||||
previewTypes.subscribe((it) => {
|
|
||||||
$previewTypes = it
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export async function canPreviewFile (contentType: string, _previewTypes: FilePreviewExtension[]): Promise<boolean> {
|
|
||||||
for (const previewType of _previewTypes) {
|
|
||||||
if (await isApplicableType(previewType, contentType)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export async function getPreviewType (
|
|
||||||
contentType: string,
|
|
||||||
_previewTypes: FilePreviewExtension[]
|
|
||||||
): Promise<FilePreviewExtension | undefined> {
|
|
||||||
const applicableTypes: FilePreviewExtension[] = []
|
|
||||||
for (const previewType of _previewTypes) {
|
|
||||||
if (await isApplicableType(previewType, contentType)) {
|
|
||||||
applicableTypes.push(previewType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return applicableTypes.sort(comparePreviewTypes)[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export function getPreviewAlignment (contentType: string): PopupAlignment {
|
|
||||||
if (contentType.startsWith('image/')) {
|
|
||||||
return 'centered'
|
|
||||||
} else if (contentType.startsWith('video/')) {
|
|
||||||
return 'centered'
|
|
||||||
} else {
|
|
||||||
return 'float'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPreviewTypeRegExp (type: string): RegExp {
|
|
||||||
return new RegExp(`^${type.replaceAll('/', '\\/').replaceAll('*', '.*')}$`)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isApplicableType (
|
|
||||||
{ contentType, availabilityChecker }: FilePreviewExtension,
|
|
||||||
_contentType: string
|
|
||||||
): Promise<boolean> {
|
|
||||||
const checkAvailability = availabilityChecker !== undefined ? await getResource(availabilityChecker) : undefined
|
|
||||||
const isAvailable: boolean = checkAvailability === undefined || (await checkAvailability())
|
|
||||||
|
|
||||||
return (
|
|
||||||
isAvailable &&
|
|
||||||
(Array.isArray(contentType) ? contentType : [contentType]).some((type) =>
|
|
||||||
getPreviewTypeRegExp(type).test(_contentType)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function comparePreviewTypes (a: FilePreviewExtension, b: FilePreviewExtension): number {
|
|
||||||
if (a.order === undefined && b.order === undefined) {
|
|
||||||
return 0
|
|
||||||
} else if (a.order === undefined) {
|
|
||||||
return -1
|
|
||||||
} else if (b.order === undefined) {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return a.order - b.order
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
128
packages/presentation/src/filetypes.ts
Normal file
128
packages/presentation/src/filetypes.ts
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2024 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { type Blob, type Ref } from '@hcengineering/core'
|
||||||
|
import { getResource } from '@hcengineering/platform'
|
||||||
|
import { type PopupAlignment } from '@hcengineering/ui'
|
||||||
|
import { writable } from 'svelte/store'
|
||||||
|
|
||||||
|
import plugin from './plugin'
|
||||||
|
import type { BlobMetadata, FileOrBlob, FilePreviewExtension } from './types'
|
||||||
|
import { createQuery } from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function getFileMetadata (file: FileOrBlob, uuid: Ref<Blob>): Promise<BlobMetadata | undefined> {
|
||||||
|
const previewType = await getPreviewType(file.type, $previewTypes)
|
||||||
|
if (previewType?.metadataProvider === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadataProvider = await getResource(previewType.metadataProvider)
|
||||||
|
if (metadataProvider === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return await metadataProvider(file, uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const previewTypes = writable<FilePreviewExtension[]>([])
|
||||||
|
const previewTypesQuery = createQuery(true)
|
||||||
|
previewTypesQuery.query(plugin.class.FilePreviewExtension, {}, (result) => {
|
||||||
|
previewTypes.set(result)
|
||||||
|
})
|
||||||
|
|
||||||
|
let $previewTypes: FilePreviewExtension[] = []
|
||||||
|
previewTypes.subscribe((it) => {
|
||||||
|
$previewTypes = it
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function canPreviewFile (contentType: string, _previewTypes: FilePreviewExtension[]): Promise<boolean> {
|
||||||
|
for (const previewType of _previewTypes) {
|
||||||
|
if (await isApplicableType(previewType, contentType)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function getPreviewType (
|
||||||
|
contentType: string,
|
||||||
|
_previewTypes: FilePreviewExtension[]
|
||||||
|
): Promise<FilePreviewExtension | undefined> {
|
||||||
|
const applicableTypes: FilePreviewExtension[] = []
|
||||||
|
for (const previewType of _previewTypes) {
|
||||||
|
if (await isApplicableType(previewType, contentType)) {
|
||||||
|
applicableTypes.push(previewType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicableTypes.sort(comparePreviewTypes)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function getPreviewAlignment (contentType: string): PopupAlignment {
|
||||||
|
if (contentType.startsWith('image/')) {
|
||||||
|
return 'centered'
|
||||||
|
} else if (contentType.startsWith('video/')) {
|
||||||
|
return 'centered'
|
||||||
|
} else {
|
||||||
|
return 'float'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPreviewTypeRegExp (type: string): RegExp {
|
||||||
|
return new RegExp(`^${type.replaceAll('/', '\\/').replaceAll('*', '.*')}$`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isApplicableType (
|
||||||
|
{ contentType, availabilityChecker }: FilePreviewExtension,
|
||||||
|
_contentType: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
const checkAvailability = availabilityChecker !== undefined ? await getResource(availabilityChecker) : undefined
|
||||||
|
const isAvailable: boolean = checkAvailability === undefined || (await checkAvailability())
|
||||||
|
|
||||||
|
return (
|
||||||
|
isAvailable &&
|
||||||
|
(Array.isArray(contentType) ? contentType : [contentType]).some((type) =>
|
||||||
|
getPreviewTypeRegExp(type).test(_contentType)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function comparePreviewTypes (a: FilePreviewExtension, b: FilePreviewExtension): number {
|
||||||
|
if (a.order === undefined && b.order === undefined) {
|
||||||
|
return 0
|
||||||
|
} else if (a.order === undefined) {
|
||||||
|
return -1
|
||||||
|
} else if (b.order === undefined) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return a.order - b.order
|
||||||
|
}
|
||||||
|
}
|
@ -51,6 +51,7 @@ export { default } from './plugin'
|
|||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
export * from './file'
|
export * from './file'
|
||||||
|
export * from './filetypes'
|
||||||
export * from './drafts'
|
export * from './drafts'
|
||||||
export { presentationId }
|
export { presentationId }
|
||||||
export * from './collaborator'
|
export * from './collaborator'
|
||||||
|
@ -130,10 +130,12 @@ export default plugin(presentationId, {
|
|||||||
FrontVersion: '' as Metadata<string>,
|
FrontVersion: '' as Metadata<string>,
|
||||||
Draft: '' as Metadata<Record<string, any>>,
|
Draft: '' as Metadata<Record<string, any>>,
|
||||||
UploadURL: '' as Metadata<string>,
|
UploadURL: '' as Metadata<string>,
|
||||||
|
FilesURL: '' as Metadata<string>,
|
||||||
CollaboratorUrl: '' as Metadata<string>,
|
CollaboratorUrl: '' as Metadata<string>,
|
||||||
CollaboratorApiUrl: '' as Metadata<string>,
|
CollaboratorApiUrl: '' as Metadata<string>,
|
||||||
Token: '' as Metadata<string>,
|
Token: '' as Metadata<string>,
|
||||||
Endpoint: '' as Metadata<string>,
|
Endpoint: '' as Metadata<string>,
|
||||||
|
Workspace: '' as Metadata<string>,
|
||||||
FrontUrl: '' as Asset,
|
FrontUrl: '' as Asset,
|
||||||
PreviewConfig: '' as Metadata<PreviewConfig | undefined>,
|
PreviewConfig: '' as Metadata<PreviewConfig | undefined>,
|
||||||
ClientHook: '' as Metadata<ClientHook>,
|
ClientHook: '' as Metadata<ClientHook>,
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import type { Blob, Ref } from '@hcengineering/core'
|
import type { Blob, Ref } from '@hcengineering/core'
|
||||||
import { concatLink } from '@hcengineering/core'
|
import { concatLink } from '@hcengineering/core'
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import { getCurrentWorkspaceUrl, getFileUrl } from '.'
|
|
||||||
|
import { getFileUrl, getCurrentWorkspace } from './file'
|
||||||
import presentation from './plugin'
|
import presentation from './plugin'
|
||||||
|
|
||||||
export interface PreviewConfig {
|
export interface PreviewConfig {
|
||||||
previewUrl: string
|
previewUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPreview = (): string => `/files/${getCurrentWorkspaceUrl()}?file=:blobId&size=:size`
|
const defaultPreview = (): string => `/files/${getCurrentWorkspace()}?file=:blobId&size=:size`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -53,7 +54,7 @@ export function getSrcSet (_blob: Ref<Blob>, width?: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function blobToSrcSet (cfg: PreviewConfig, blob: Ref<Blob>, width: number | undefined): string {
|
function blobToSrcSet (cfg: PreviewConfig, blob: Ref<Blob>, width: number | undefined): string {
|
||||||
let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspaceUrl()))
|
let url = cfg.previewUrl.replaceAll(':workspace', encodeURIComponent(getCurrentWorkspace()))
|
||||||
const downloadUrl = getFileUrl(blob)
|
const downloadUrl = getFileUrl(blob)
|
||||||
|
|
||||||
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin
|
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin
|
||||||
@ -74,7 +75,7 @@ function blobToSrcSet (cfg: PreviewConfig, blob: Ref<Blob>, width: number | unde
|
|||||||
fu.replaceAll(':size', `${width * 3}`) +
|
fu.replaceAll(':size', `${width * 3}`) +
|
||||||
' 3x'
|
' 3x'
|
||||||
} else {
|
} else {
|
||||||
result += fu.replaceAll(':size', `${-1}`)
|
result += downloadUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -18,7 +18,6 @@ import { Analytics } from '@hcengineering/analytics'
|
|||||||
import core, {
|
import core, {
|
||||||
TxOperations,
|
TxOperations,
|
||||||
TxProcessor,
|
TxProcessor,
|
||||||
concatLink,
|
|
||||||
getCurrentAccount,
|
getCurrentAccount,
|
||||||
reduceCalls,
|
reduceCalls,
|
||||||
type AnyAttribute,
|
type AnyAttribute,
|
||||||
@ -34,7 +33,6 @@ import core, {
|
|||||||
type Hierarchy,
|
type Hierarchy,
|
||||||
type Mixin,
|
type Mixin,
|
||||||
type Obj,
|
type Obj,
|
||||||
type Blob as PlatformBlob,
|
|
||||||
type Ref,
|
type Ref,
|
||||||
type RefTo,
|
type RefTo,
|
||||||
type SearchOptions,
|
type SearchOptions,
|
||||||
@ -457,22 +455,6 @@ export function getCurrentWorkspaceUrl (): string {
|
|||||||
return wsId
|
return wsId
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export function getFileUrl (file: Ref<PlatformBlob>, filename?: string, useToken?: boolean): string {
|
|
||||||
if (file.includes('://')) {
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
const frontUrl = getMetadata(plugin.metadata.FrontUrl) ?? window.location.origin
|
|
||||||
let uploadUrl = getMetadata(plugin.metadata.UploadURL) ?? ''
|
|
||||||
if (!uploadUrl.includes('://')) {
|
|
||||||
uploadUrl = concatLink(frontUrl ?? '', uploadUrl)
|
|
||||||
}
|
|
||||||
const token = getMetadata(plugin.metadata.Token) ?? ''
|
|
||||||
return `${uploadUrl}/${getCurrentWorkspaceUrl()}${filename !== undefined ? '/' + encodeURIComponent(filename) : ''}?file=${file}${useToken === true ? `&token=${token}` : ''}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sizeToWidth (size: string): number | undefined {
|
export function sizeToWidth (size: string): number | undefined {
|
||||||
let width: number | undefined
|
let width: number | undefined
|
||||||
switch (size) {
|
switch (size) {
|
||||||
|
@ -64,6 +64,8 @@ export interface StorageAdapter {
|
|||||||
offset: number,
|
offset: number,
|
||||||
length?: number
|
length?: number
|
||||||
) => Promise<Readable>
|
) => Promise<Readable>
|
||||||
|
|
||||||
|
getUrl: (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string) => Promise<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StorageAdapterEx extends StorageAdapter {
|
export interface StorageAdapterEx extends StorageAdapter {
|
||||||
@ -161,6 +163,10 @@ export class DummyStorageAdapter implements StorageAdapter, StorageAdapterEx {
|
|||||||
): Promise<UploadedObjectInfo> {
|
): Promise<UploadedObjectInfo> {
|
||||||
throw new Error('not implemented')
|
throw new Error('not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<string> {
|
||||||
|
throw new Error('not implemented')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDummyStorageAdapter (): StorageAdapter {
|
export function createDummyStorageAdapter (): StorageAdapter {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
async function doSync (): Promise<void> {
|
async function doSync (): Promise<void> {
|
||||||
loading = true
|
loading = true
|
||||||
const uploadUrl = window.location.origin + getMetadata(presentation.metadata.UploadURL)
|
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin
|
||||||
const token = (getMetadata(presentation.metadata.Token) as string) ?? ''
|
const token = (getMetadata(presentation.metadata.Token) as string) ?? ''
|
||||||
|
|
||||||
const mappedFilter: Record<string, any> = {}
|
const mappedFilter: Record<string, any> = {}
|
||||||
@ -75,7 +75,7 @@
|
|||||||
email: '',
|
email: '',
|
||||||
endpoint: ''
|
endpoint: ''
|
||||||
},
|
},
|
||||||
frontUrl: uploadUrl,
|
frontUrl,
|
||||||
monitor: (total: number) => {
|
monitor: (total: number) => {
|
||||||
docsProcessed++
|
docsProcessed++
|
||||||
state = `processed: ${docsProcessed}/${total ?? 1}`
|
state = `processed: ${docsProcessed}/${total ?? 1}`
|
||||||
|
@ -12,7 +12,6 @@ import core, {
|
|||||||
import login, { loginId } from '@hcengineering/login'
|
import login, { loginId } from '@hcengineering/login'
|
||||||
import { getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
import { getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
||||||
import presentation, { closeClient, refreshClient, setClient, setPresentationCookie } from '@hcengineering/presentation'
|
import presentation, { closeClient, refreshClient, setClient, setPresentationCookie } from '@hcengineering/presentation'
|
||||||
import { getCurrentWorkspaceUrl } from '@hcengineering/presentation/src/utils'
|
|
||||||
import { fetchMetadataLocalStorage, getCurrentLocation, navigate, setMetadataLocalStorage } from '@hcengineering/ui'
|
import { fetchMetadataLocalStorage, getCurrentLocation, navigate, setMetadataLocalStorage } from '@hcengineering/ui'
|
||||||
import { writable } from 'svelte/store'
|
import { writable } from 'svelte/store'
|
||||||
|
|
||||||
@ -35,8 +34,6 @@ export async function connect (title: string): Promise<Client | undefined> {
|
|||||||
}
|
}
|
||||||
setMetadata(presentation.metadata.Token, token)
|
setMetadata(presentation.metadata.Token, token)
|
||||||
|
|
||||||
setPresentationCookie(token, getCurrentWorkspaceUrl())
|
|
||||||
|
|
||||||
const selectWorkspace = await getResource(login.function.SelectWorkspace)
|
const selectWorkspace = await getResource(login.function.SelectWorkspace)
|
||||||
const workspaceLoginInfo = (await selectWorkspace(ws, token))[1]
|
const workspaceLoginInfo = (await selectWorkspace(ws, token))[1]
|
||||||
if (workspaceLoginInfo == null) {
|
if (workspaceLoginInfo == null) {
|
||||||
@ -46,7 +43,10 @@ export async function connect (title: string): Promise<Client | undefined> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPresentationCookie(token, workspaceLoginInfo.workspaceId)
|
||||||
|
|
||||||
setMetadata(presentation.metadata.Token, token)
|
setMetadata(presentation.metadata.Token, token)
|
||||||
|
setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace)
|
||||||
setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint)
|
setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint)
|
||||||
|
|
||||||
if (_token !== token && _client !== undefined) {
|
if (_token !== token && _client !== undefined) {
|
||||||
@ -178,9 +178,13 @@ function clearMetadata (ws: string): void {
|
|||||||
delete tokens[loc.path[1]]
|
delete tokens[loc.path[1]]
|
||||||
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
||||||
}
|
}
|
||||||
|
const currentWorkspace = getMetadata(presentation.metadata.Workspace)
|
||||||
|
if (currentWorkspace !== undefined) {
|
||||||
|
setPresentationCookie('', currentWorkspace)
|
||||||
|
}
|
||||||
|
|
||||||
setMetadata(presentation.metadata.Token, null)
|
setMetadata(presentation.metadata.Token, null)
|
||||||
setMetadataLocalStorage(login.metadata.LastToken, null)
|
setMetadataLocalStorage(login.metadata.LastToken, null)
|
||||||
setPresentationCookie('', getCurrentWorkspaceUrl())
|
|
||||||
setMetadataLocalStorage(login.metadata.LoginEmail, null)
|
setMetadataLocalStorage(login.metadata.LoginEmail, null)
|
||||||
void closeClient()
|
void closeClient()
|
||||||
}
|
}
|
||||||
|
@ -440,6 +440,7 @@ export function navigateToWorkspace (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setMetadata(presentation.metadata.Token, loginInfo.token)
|
setMetadata(presentation.metadata.Token, loginInfo.token)
|
||||||
|
setMetadata(presentation.metadata.Workspace, loginInfo.workspace)
|
||||||
setLoginInfo(loginInfo)
|
setLoginInfo(loginInfo)
|
||||||
|
|
||||||
if (navigateUrl !== undefined) {
|
if (navigateUrl !== undefined) {
|
||||||
@ -894,6 +895,7 @@ export async function afterConfirm (clearQuery = false): Promise<void> {
|
|||||||
const result = (await selectWorkspace(joinedWS[0].workspace, null))[1]
|
const result = (await selectWorkspace(joinedWS[0].workspace, null))[1]
|
||||||
if (result !== undefined) {
|
if (result !== undefined) {
|
||||||
setMetadata(presentation.metadata.Token, result.token)
|
setMetadata(presentation.metadata.Token, result.token)
|
||||||
|
setMetadata(presentation.metadata.Workspace, result.workspace)
|
||||||
setMetadataLocalStorage(login.metadata.LastToken, result.token)
|
setMetadataLocalStorage(login.metadata.LastToken, result.token)
|
||||||
setLoginInfo(result)
|
setLoginInfo(result)
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ export interface Workspace {
|
|||||||
*/
|
*/
|
||||||
export interface WorkspaceLoginInfo extends LoginInfo {
|
export interface WorkspaceLoginInfo extends LoginInfo {
|
||||||
workspace: string
|
workspace: string
|
||||||
|
workspaceId: string
|
||||||
creating?: boolean
|
creating?: boolean
|
||||||
createProgress?: number
|
createProgress?: number
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ export const ImageUploadExtension = Extension.create<ImageUploadOptions>({
|
|||||||
for (const uri of uris) {
|
for (const uri of uris) {
|
||||||
if (uri !== '') {
|
if (uri !== '') {
|
||||||
const url = new URL(uri)
|
const url = new URL(uri)
|
||||||
|
// TODO datalake support
|
||||||
const _file = (url.searchParams.get('file') ?? '').split('/').join('')
|
const _file = (url.searchParams.get('file') ?? '').split('/').join('')
|
||||||
|
|
||||||
if (_file.trim().length === 0) {
|
if (_file.trim().length === 0) {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import { type Blob, type Ref, generateId } from '@hcengineering/core'
|
import { type Blob, type Ref, generateId } from '@hcengineering/core'
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import presentation, { getFileMetadata } from '@hcengineering/presentation'
|
import presentation, { generateFileId, getFileMetadata, getUploadUrl } from '@hcengineering/presentation'
|
||||||
import { getCurrentLanguage } from '@hcengineering/theme'
|
import { getCurrentLanguage } from '@hcengineering/theme'
|
||||||
import type { FileUploadCallback, FileUploadOptions } from '@hcengineering/uploader'
|
import type { FileUploadCallback, FileUploadOptions } from '@hcengineering/uploader'
|
||||||
|
|
||||||
@ -72,14 +72,26 @@ export function getUppy (options: FileUploadOptions, onFileUploaded?: FileUpload
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uppy = new Uppy<UppyMeta, UppyBody>(uppyOptions).use(XHR, {
|
const uppy = new Uppy<UppyMeta, UppyBody>(uppyOptions).use(XHR, {
|
||||||
endpoint: getMetadata(presentation.metadata.UploadURL) ?? '',
|
endpoint: getUploadUrl(),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer ' + (getMetadata(presentation.metadata.Token) as string)
|
Authorization: 'Bearer ' + (getMetadata(presentation.metadata.Token) as string)
|
||||||
},
|
}
|
||||||
getResponseData: (body: string): UppyBody => {
|
// getResponseData: (body: string): UppyBody => {
|
||||||
return {
|
// const data = JSON.parse(body)
|
||||||
uuid: body
|
// return {
|
||||||
|
// uuid: data[0].id
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
uppy.addPreProcessor(async (fileIds: string[]) => {
|
||||||
|
for (const fileId of fileIds) {
|
||||||
|
const file = uppy.getFile(fileId)
|
||||||
|
if (file != null) {
|
||||||
|
const uuid = generateFileId()
|
||||||
|
file.meta.uuid = uuid
|
||||||
|
file.meta.name = uuid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -88,7 +100,7 @@ export function getUppy (options: FileUploadOptions, onFileUploaded?: FileUpload
|
|||||||
uppy.addPostProcessor(async (fileIds: string[]) => {
|
uppy.addPostProcessor(async (fileIds: string[]) => {
|
||||||
for (const fileId of fileIds) {
|
for (const fileId of fileIds) {
|
||||||
const file = uppy.getFile(fileId)
|
const file = uppy.getFile(fileId)
|
||||||
const uuid = file?.response?.body?.uuid as Ref<Blob>
|
const uuid = file.meta.uuid as Ref<Blob>
|
||||||
if (uuid !== undefined) {
|
if (uuid !== undefined) {
|
||||||
const metadata = await getFileMetadata(file.data, uuid)
|
const metadata = await getFileMetadata(file.data, uuid)
|
||||||
await onFileUploaded(uuid, file.name, file.data, file.meta.relativePath, metadata)
|
await onFileUploaded(uuid, file.name, file.data, file.meta.relativePath, metadata)
|
||||||
|
@ -37,13 +37,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<img
|
<img
|
||||||
on:load={(evt) => {
|
on:load={() => {
|
||||||
loading = false
|
loading = false
|
||||||
}}
|
}}
|
||||||
class="object-contain mx-auto"
|
class="object-contain mx-auto"
|
||||||
style:max-width={width}
|
style:max-width={width}
|
||||||
style:max-height={height}
|
style:max-height={height}
|
||||||
src={blobRef.src}
|
src={blobRef.src}
|
||||||
|
srcset={blobRef.srcset}
|
||||||
alt={name}
|
alt={name}
|
||||||
style:height={loading ? '0' : ''}
|
style:height={loading ? '0' : ''}
|
||||||
/>
|
/>
|
||||||
|
@ -17,7 +17,6 @@ import login, { loginId } from '@hcengineering/login'
|
|||||||
import { broadcastEvent, getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
import { broadcastEvent, getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
||||||
import presentation, {
|
import presentation, {
|
||||||
closeClient,
|
closeClient,
|
||||||
getCurrentWorkspaceUrl,
|
|
||||||
purgeClient,
|
purgeClient,
|
||||||
refreshClient,
|
refreshClient,
|
||||||
setClient,
|
setClient,
|
||||||
@ -77,6 +76,7 @@ export async function connect (title: string): Promise<Client | undefined> {
|
|||||||
tokens[ws] = workspaceLoginInfo.token
|
tokens[ws] = workspaceLoginInfo.token
|
||||||
token = workspaceLoginInfo.token
|
token = workspaceLoginInfo.token
|
||||||
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
||||||
|
setMetadata(presentation.metadata.Workspace, workspaceLoginInfo.workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
setMetadata(presentation.metadata.Token, token)
|
setMetadata(presentation.metadata.Token, token)
|
||||||
@ -106,7 +106,9 @@ export async function connect (title: string): Promise<Client | undefined> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPresentationCookie(token, getCurrentWorkspaceUrl())
|
if (workspaceLoginInfo !== undefined) {
|
||||||
|
setPresentationCookie(token, workspaceLoginInfo.workspaceId)
|
||||||
|
}
|
||||||
|
|
||||||
setMetadataLocalStorage(login.metadata.LoginEndpoint, workspaceLoginInfo?.endpoint)
|
setMetadataLocalStorage(login.metadata.LoginEndpoint, workspaceLoginInfo?.endpoint)
|
||||||
|
|
||||||
@ -344,9 +346,14 @@ function clearMetadata (ws: string): void {
|
|||||||
delete tokens[loc.path[1]]
|
delete tokens[loc.path[1]]
|
||||||
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
|
||||||
}
|
}
|
||||||
|
const currentWorkspace = getMetadata(presentation.metadata.Workspace)
|
||||||
|
if (currentWorkspace !== undefined) {
|
||||||
|
setPresentationCookie('', currentWorkspace)
|
||||||
|
}
|
||||||
|
|
||||||
setMetadata(presentation.metadata.Token, null)
|
setMetadata(presentation.metadata.Token, null)
|
||||||
|
setMetadata(presentation.metadata.Workspace, null)
|
||||||
setMetadataLocalStorage(login.metadata.LastToken, null)
|
setMetadataLocalStorage(login.metadata.LastToken, null)
|
||||||
setPresentationCookie('', getCurrentWorkspaceUrl())
|
|
||||||
setMetadataLocalStorage(login.metadata.LoginEndpoint, null)
|
setMetadataLocalStorage(login.metadata.LoginEndpoint, null)
|
||||||
setMetadataLocalStorage(login.metadata.LoginEmail, null)
|
setMetadataLocalStorage(login.metadata.LoginEmail, null)
|
||||||
void closeClient()
|
void closeClient()
|
||||||
|
@ -47,7 +47,7 @@ const storageConfig: StorageConfiguration = storageConfigFromEnv()
|
|||||||
const lastNameFirst = process.env.LAST_NAME_FIRST === 'true'
|
const lastNameFirst = process.env.LAST_NAME_FIRST === 'true'
|
||||||
setMetadata(contactPlugin.metadata.LastNameFirst, lastNameFirst)
|
setMetadata(contactPlugin.metadata.LastNameFirst, lastNameFirst)
|
||||||
setMetadata(serverCore.metadata.FrontUrl, config.frontUrl)
|
setMetadata(serverCore.metadata.FrontUrl, config.frontUrl)
|
||||||
setMetadata(serverCore.metadata.UploadURL, config.uploadUrl)
|
setMetadata(serverCore.metadata.FilesUrl, config.filesUrl)
|
||||||
setMetadata(serverToken.metadata.Secret, config.serverSecret)
|
setMetadata(serverToken.metadata.Secret, config.serverSecret)
|
||||||
setMetadata(serverNotification.metadata.SesUrl, config.sesUrl ?? '')
|
setMetadata(serverNotification.metadata.SesUrl, config.sesUrl ?? '')
|
||||||
setMetadata(notification.metadata.PushPublicKey, config.pushPublicKey)
|
setMetadata(notification.metadata.PushPublicKey, config.pushPublicKey)
|
||||||
|
@ -59,7 +59,6 @@ export async function configurePlatform() {
|
|||||||
const config = await (await fetch('/config.json')).json()
|
const config = await (await fetch('/config.json')).json()
|
||||||
console.log('loading configuration', config)
|
console.log('loading configuration', config)
|
||||||
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
setMetadata(login.metadata.AccountsUrl, config.ACCOUNTS_URL)
|
||||||
setMetadata(login.metadata.UploadUrl, config.UPLOAD_URL)
|
|
||||||
|
|
||||||
if (config.MODEL_VERSION != null) {
|
if (config.MODEL_VERSION != null) {
|
||||||
console.log('Minimal Model version requirement', config.MODEL_VERSION)
|
console.log('Minimal Model version requirement', config.MODEL_VERSION)
|
||||||
|
@ -1487,6 +1487,11 @@
|
|||||||
"projectFolder": "server/s3",
|
"projectFolder": "server/s3",
|
||||||
"shouldPublish": false
|
"shouldPublish": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@hcengineering/datalake",
|
||||||
|
"projectFolder": "server/datalake",
|
||||||
|
"shouldPublish": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"packageName": "@hcengineering/bitrix",
|
"packageName": "@hcengineering/bitrix",
|
||||||
"projectFolder": "plugins/bitrix",
|
"projectFolder": "plugins/bitrix",
|
||||||
|
@ -69,7 +69,7 @@ import notification, {
|
|||||||
PushSubscription
|
PushSubscription
|
||||||
} from '@hcengineering/notification'
|
} from '@hcengineering/notification'
|
||||||
import { getMetadata, getResource, translate } from '@hcengineering/platform'
|
import { getMetadata, getResource, translate } from '@hcengineering/platform'
|
||||||
import type { TriggerControl } from '@hcengineering/server-core'
|
import { type TriggerControl } from '@hcengineering/server-core'
|
||||||
import serverCore from '@hcengineering/server-core'
|
import serverCore from '@hcengineering/server-core'
|
||||||
import serverNotification, {
|
import serverNotification, {
|
||||||
getPersonAccount,
|
getPersonAccount,
|
||||||
@ -539,7 +539,6 @@ export async function createPushNotification (
|
|||||||
data.tag = _id
|
data.tag = _id
|
||||||
}
|
}
|
||||||
const front = control.branding?.front ?? getMetadata(serverCore.metadata.FrontUrl) ?? ''
|
const front = control.branding?.front ?? getMetadata(serverCore.metadata.FrontUrl) ?? ''
|
||||||
const uploadUrl = getMetadata(serverCore.metadata.UploadURL) ?? ''
|
|
||||||
const domainPath = `${workbenchId}/${control.workspace.workspaceUrl}`
|
const domainPath = `${workbenchId}/${control.workspace.workspaceUrl}`
|
||||||
data.domain = concatLink(front, domainPath)
|
data.domain = concatLink(front, domainPath)
|
||||||
if (path !== undefined) {
|
if (path !== undefined) {
|
||||||
@ -548,7 +547,10 @@ export async function createPushNotification (
|
|||||||
if (senderAvatar != null) {
|
if (senderAvatar != null) {
|
||||||
const provider = getAvatarProviderId(senderAvatar.avatarType)
|
const provider = getAvatarProviderId(senderAvatar.avatarType)
|
||||||
if (provider === contact.avatarProvider.Image) {
|
if (provider === contact.avatarProvider.Image) {
|
||||||
data.icon = concatLink(uploadUrl, `?file=${senderAvatar.avatar}`)
|
if (senderAvatar.avatar != null) {
|
||||||
|
const url = await control.storageAdapter.getUrl(control.ctx, control.workspace, senderAvatar.avatar)
|
||||||
|
data.icon = url.includes('://') ? url : concatLink(front, url)
|
||||||
|
}
|
||||||
} else if (provider === contact.avatarProvider.Gravatar && senderAvatar.avatarProps?.url !== undefined) {
|
} else if (provider === contact.avatarProvider.Gravatar && senderAvatar.avatarProps?.url !== undefined) {
|
||||||
data.icon = getGravatarUrl(senderAvatar.avatarProps?.url, 512)
|
data.icon = getGravatarUrl(senderAvatar.avatarProps?.url, 512)
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,8 @@ export interface WorkspaceLoginInfo extends LoginInfo {
|
|||||||
workspace: string
|
workspace: string
|
||||||
productId: string
|
productId: string
|
||||||
|
|
||||||
|
workspaceId: string
|
||||||
|
|
||||||
creating?: boolean
|
creating?: boolean
|
||||||
createProgress?: number
|
createProgress?: number
|
||||||
}
|
}
|
||||||
@ -635,6 +637,7 @@ export async function selectWorkspace (
|
|||||||
email,
|
email,
|
||||||
token,
|
token,
|
||||||
workspace: workspaceUrl,
|
workspace: workspaceUrl,
|
||||||
|
workspaceId: workspaceInfo.workspace,
|
||||||
productId,
|
productId,
|
||||||
creating: workspaceInfo.creating,
|
creating: workspaceInfo.creating,
|
||||||
createProgress: workspaceInfo.createProgress
|
createProgress: workspaceInfo.createProgress
|
||||||
@ -667,6 +670,7 @@ export async function selectWorkspace (
|
|||||||
email,
|
email,
|
||||||
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace, productId), getExtra(accountInfo)),
|
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace, productId), getExtra(accountInfo)),
|
||||||
workspace: workspaceUrl,
|
workspace: workspaceUrl,
|
||||||
|
workspaceId: workspaceInfo.workspace,
|
||||||
productId,
|
productId,
|
||||||
creating: workspaceInfo.creating,
|
creating: workspaceInfo.creating,
|
||||||
createProgress: workspaceInfo.createProgress
|
createProgress: workspaceInfo.createProgress
|
||||||
@ -689,6 +693,7 @@ export async function selectWorkspace (
|
|||||||
email,
|
email,
|
||||||
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace, productId), getExtra(accountInfo)),
|
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace, productId), getExtra(accountInfo)),
|
||||||
workspace: workspaceUrl,
|
workspace: workspaceUrl,
|
||||||
|
workspaceId: workspaceInfo.workspace,
|
||||||
productId,
|
productId,
|
||||||
creating: workspaceInfo.creating,
|
creating: workspaceInfo.creating,
|
||||||
createProgress: workspaceInfo.createProgress
|
createProgress: workspaceInfo.createProgress
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright © 2022 Hardcore Engineering Inc.
|
// Copyright © 2022, 2024 Hardcore Engineering Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License. You may
|
// you may not use this file except in compliance with the License. You may
|
||||||
@ -26,7 +26,6 @@ export interface Config {
|
|||||||
|
|
||||||
AccountsUrl: string
|
AccountsUrl: string
|
||||||
MongoUrl: string
|
MongoUrl: string
|
||||||
UploadUrl: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const envMap: { [key in keyof Config]: string } = {
|
const envMap: { [key in keyof Config]: string } = {
|
||||||
@ -35,8 +34,7 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
Interval: 'INTERVAL',
|
Interval: 'INTERVAL',
|
||||||
Port: 'COLLABORATOR_PORT',
|
Port: 'COLLABORATOR_PORT',
|
||||||
AccountsUrl: 'ACCOUNTS_URL',
|
AccountsUrl: 'ACCOUNTS_URL',
|
||||||
MongoUrl: 'MONGO_URL',
|
MongoUrl: 'MONGO_URL'
|
||||||
UploadUrl: 'UPLOAD_URL'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const required: Array<keyof Config> = ['Secret', 'ServiceID', 'Port', 'AccountsUrl', 'MongoUrl']
|
const required: Array<keyof Config> = ['Secret', 'ServiceID', 'Port', 'AccountsUrl', 'MongoUrl']
|
||||||
@ -48,8 +46,7 @@ const config: Config = (() => {
|
|||||||
Interval: parseInt(process.env[envMap.Interval] ?? '30000'),
|
Interval: parseInt(process.env[envMap.Interval] ?? '30000'),
|
||||||
Port: parseInt(process.env[envMap.Port] ?? '3078'),
|
Port: parseInt(process.env[envMap.Port] ?? '3078'),
|
||||||
AccountsUrl: process.env[envMap.AccountsUrl],
|
AccountsUrl: process.env[envMap.AccountsUrl],
|
||||||
MongoUrl: process.env[envMap.MongoUrl],
|
MongoUrl: process.env[envMap.MongoUrl]
|
||||||
UploadUrl: process.env[envMap.UploadUrl] ?? '/files'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key])
|
const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key])
|
||||||
|
@ -34,6 +34,7 @@ import { simpleClientFactory } from './platform'
|
|||||||
import { RpcErrorResponse, RpcRequest, RpcResponse, methods } from './rpc'
|
import { RpcErrorResponse, RpcRequest, RpcResponse, methods } from './rpc'
|
||||||
import { PlatformStorageAdapter } from './storage/platform'
|
import { PlatformStorageAdapter } from './storage/platform'
|
||||||
import { MarkupTransformer } from './transformers/markup'
|
import { MarkupTransformer } from './transformers/markup'
|
||||||
|
import { TransformerFactory } from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -57,23 +58,22 @@ export async function start (
|
|||||||
const app = express()
|
const app = express()
|
||||||
app.use(cors())
|
app.use(cors())
|
||||||
app.use(bp.json())
|
app.use(bp.json())
|
||||||
const extensions = [
|
|
||||||
ServerKit.configure({
|
|
||||||
image: {
|
|
||||||
getBlobRef: async (fileId, name, size) => {
|
|
||||||
const sz = size !== undefined ? `&size=${size}` : ''
|
|
||||||
return {
|
|
||||||
src: `${config.UploadUrl}?file=${fileId}`,
|
|
||||||
srcset: `${config.UploadUrl}?file=${fileId}${sz}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
|
|
||||||
const extensionsCtx = ctx.newChild('extensions', {})
|
const extensionsCtx = ctx.newChild('extensions', {})
|
||||||
|
|
||||||
const transformer = new MarkupTransformer(extensions)
|
const transformerFactory: TransformerFactory = (workspaceId) => {
|
||||||
|
const extensions = [
|
||||||
|
ServerKit.configure({
|
||||||
|
image: {
|
||||||
|
getBlobRef: async (fileId, name, size) => {
|
||||||
|
const src = await storageAdapter.getUrl(ctx, workspaceId, fileId)
|
||||||
|
return { src, srcset: '' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
return new MarkupTransformer(extensions)
|
||||||
|
}
|
||||||
|
|
||||||
const hocuspocus = new Hocuspocus({
|
const hocuspocus = new Hocuspocus({
|
||||||
address: '0.0.0.0',
|
address: '0.0.0.0',
|
||||||
@ -116,7 +116,7 @@ export async function start (
|
|||||||
}),
|
}),
|
||||||
new StorageExtension({
|
new StorageExtension({
|
||||||
ctx: extensionsCtx.newChild('storage', {}),
|
ctx: extensionsCtx.newChild('storage', {}),
|
||||||
adapter: new PlatformStorageAdapter(storageAdapter, mongo, transformer)
|
adapter: new PlatformStorageAdapter(storageAdapter, mongo, transformerFactory)
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -178,6 +178,7 @@ export async function start (
|
|||||||
rpcCtx.info('rpc', { method: request.method, connectionId: context.connectionId, mode: token.extra?.mode ?? '' })
|
rpcCtx.info('rpc', { method: request.method, connectionId: context.connectionId, mode: token.extra?.mode ?? '' })
|
||||||
await rpcCtx.with('/rpc', { method: request.method }, async (ctx) => {
|
await rpcCtx.with('/rpc', { method: request.method }, async (ctx) => {
|
||||||
try {
|
try {
|
||||||
|
const transformer = transformerFactory(token.workspace)
|
||||||
const response: RpcResponse = await rpcCtx.with(request.method, {}, async (ctx) => {
|
const response: RpcResponse = await rpcCtx.with(request.method, {}, async (ctx) => {
|
||||||
return await method(ctx, context, request.payload, { hocuspocus, storageAdapter, transformer })
|
return await method(ctx, context, request.payload, { hocuspocus, storageAdapter, transformer })
|
||||||
})
|
})
|
||||||
|
@ -35,10 +35,10 @@ import core, {
|
|||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { StorageAdapter } from '@hcengineering/server-core'
|
import { StorageAdapter } from '@hcengineering/server-core'
|
||||||
import { areEqualMarkups } from '@hcengineering/text'
|
import { areEqualMarkups } from '@hcengineering/text'
|
||||||
import { Transformer } from '@hocuspocus/transformer'
|
|
||||||
import { MongoClient } from 'mongodb'
|
import { MongoClient } from 'mongodb'
|
||||||
import { Doc as YDoc } from 'yjs'
|
import { Doc as YDoc } from 'yjs'
|
||||||
import { Context } from '../context'
|
import { Context } from '../context'
|
||||||
|
import { TransformerFactory } from '../types'
|
||||||
|
|
||||||
import { CollabStorageAdapter } from './adapter'
|
import { CollabStorageAdapter } from './adapter'
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
constructor (
|
constructor (
|
||||||
private readonly storage: StorageAdapter,
|
private readonly storage: StorageAdapter,
|
||||||
private readonly mongodb: MongoClient,
|
private readonly mongodb: MongoClient,
|
||||||
private readonly transformer: Transformer
|
private readonly transformerFactory: TransformerFactory
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async loadDocument (ctx: MeasureContext, documentId: DocumentId, context: Context): Promise<YDoc | undefined> {
|
async loadDocument (ctx: MeasureContext, documentId: DocumentId, context: Context): Promise<YDoc | undefined> {
|
||||||
@ -208,18 +208,18 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
platformDocumentId: PlatformDocumentId,
|
platformDocumentId: PlatformDocumentId,
|
||||||
context: Context
|
context: Context
|
||||||
): Promise<YDoc | undefined> {
|
): Promise<YDoc | undefined> {
|
||||||
const { mongodb, transformer } = this
|
|
||||||
const { workspaceId } = context
|
const { workspaceId } = context
|
||||||
const { objectDomain, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
const { objectDomain, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
||||||
|
|
||||||
const doc = await ctx.with('query', {}, async () => {
|
const doc = await ctx.with('query', {}, async () => {
|
||||||
const db = mongodb.db(toWorkspaceString(workspaceId))
|
const db = this.mongodb.db(toWorkspaceString(workspaceId))
|
||||||
return await db.collection<Doc>(objectDomain).findOne({ _id: objectId }, { projection: { [objectAttr]: 1 } })
|
return await db.collection<Doc>(objectDomain).findOne({ _id: objectId }, { projection: { [objectAttr]: 1 } })
|
||||||
})
|
})
|
||||||
|
|
||||||
const content = doc !== null && objectAttr in doc ? ((doc as any)[objectAttr] as string) : ''
|
const content = doc !== null && objectAttr in doc ? ((doc as any)[objectAttr] as string) : ''
|
||||||
if (content.startsWith('{') && content.endsWith('}')) {
|
if (content.startsWith('{') && content.endsWith('}')) {
|
||||||
return await ctx.with('transform', {}, () => {
|
return await ctx.with('transform', {}, () => {
|
||||||
|
const transformer = this.transformerFactory(workspaceId)
|
||||||
return transformer.toYdoc(content, objectAttr)
|
return transformer.toYdoc(content, objectAttr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -237,6 +237,7 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
snapshot: YDocVersion | undefined,
|
snapshot: YDocVersion | undefined,
|
||||||
context: Context
|
context: Context
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { workspaceId } = context
|
||||||
const { objectClass, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
const { objectClass, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
||||||
|
|
||||||
const attribute = client.getHierarchy().findAttribute(objectClass, objectAttr)
|
const attribute = client.getHierarchy().findAttribute(objectClass, objectAttr)
|
||||||
@ -267,7 +268,8 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
} else if (hierarchy.isDerived(attribute.type._class, core.class.TypeCollaborativeMarkup)) {
|
} else if (hierarchy.isDerived(attribute.type._class, core.class.TypeCollaborativeMarkup)) {
|
||||||
// TODO a temporary solution while we are keeping Markup in Mongo
|
// TODO a temporary solution while we are keeping Markup in Mongo
|
||||||
const content = await ctx.with('transform', {}, () => {
|
const content = await ctx.with('transform', {}, () => {
|
||||||
return this.transformer.fromYdoc(document, objectAttr)
|
const transformer = this.transformerFactory(workspaceId)
|
||||||
|
return transformer.fromYdoc(document, objectAttr)
|
||||||
})
|
})
|
||||||
if (!areEqualMarkups(content, (current as any)[objectAttr])) {
|
if (!areEqualMarkups(content, (current as any)[objectAttr])) {
|
||||||
await ctx.with('update', {}, async () => {
|
await ctx.with('update', {}, async () => {
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import type { Class, Doc, Domain, Ref } from '@hcengineering/core'
|
import type { Class, Doc, Domain, Ref, WorkspaceId } from '@hcengineering/core'
|
||||||
|
import { Transformer } from '@hocuspocus/transformer'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface DocumentId {
|
export interface DocumentId {
|
||||||
@ -29,3 +30,6 @@ export interface PlatformDocumentId {
|
|||||||
objectId: Ref<Doc>
|
objectId: Ref<Doc>
|
||||||
objectAttr: string
|
objectAttr: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export type TransformerFactory = (workspaceId: WorkspaceId) => Transformer
|
||||||
|
@ -147,6 +147,10 @@ export class MemStorageAdapter implements StorageAdapter {
|
|||||||
// Partial are not supported by
|
// Partial are not supported by
|
||||||
throw new Error('NoSuchKey')
|
throw new Error('NoSuchKey')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<string> {
|
||||||
|
return '/files/' + objectName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MemRawDBAdapter implements RawDBAdapter {
|
export class MemRawDBAdapter implements RawDBAdapter {
|
||||||
|
@ -41,7 +41,7 @@ const serverCore = plugin(serverCoreId, {
|
|||||||
},
|
},
|
||||||
metadata: {
|
metadata: {
|
||||||
FrontUrl: '' as Metadata<string>,
|
FrontUrl: '' as Metadata<string>,
|
||||||
UploadURL: '' as Metadata<string>,
|
FilesUrl: '' as Metadata<string>,
|
||||||
ElasticIndexName: '' as Metadata<string>,
|
ElasticIndexName: '' as Metadata<string>,
|
||||||
ElasticIndexVersion: '' as Metadata<string>
|
ElasticIndexVersion: '' as Metadata<string>
|
||||||
}
|
}
|
||||||
|
@ -253,8 +253,12 @@ export class AggregatorStorageAdapter implements StorageAdapter, StorageAdapterE
|
|||||||
|
|
||||||
@withContext('aggregator-get', {})
|
@withContext('aggregator-get', {})
|
||||||
async get (ctx: MeasureContext, workspaceId: WorkspaceId, name: string): Promise<Readable> {
|
async get (ctx: MeasureContext, workspaceId: WorkspaceId, name: string): Promise<Readable> {
|
||||||
const { provider, stat } = await this.findProvider(ctx, workspaceId, name)
|
// const { provider, stat } = await this.findProvider(ctx, workspaceId, name)
|
||||||
return await provider.get(ctx, workspaceId, stat.storageId)
|
const provider = this.adapters.get(this.defaultAdapter)
|
||||||
|
if (provider === undefined) {
|
||||||
|
throw new NoSuchKeyError('No such provider found')
|
||||||
|
}
|
||||||
|
return await provider.get(ctx, workspaceId, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@withContext('find-provider', {})
|
@withContext('find-provider', {})
|
||||||
@ -353,12 +357,19 @@ export class AggregatorStorageAdapter implements StorageAdapter, StorageAdapterE
|
|||||||
|
|
||||||
// If the file is already stored in different provider, we need to remove it.
|
// If the file is already stored in different provider, we need to remove it.
|
||||||
if (stat !== undefined && stat.provider !== provider) {
|
if (stat !== undefined && stat.provider !== provider) {
|
||||||
const adapter = this.adapters.get(stat.provider)
|
// TODO temporary not needed
|
||||||
await adapter?.remove(ctx, workspaceId, [stat._id])
|
// const adapter = this.adapters.get(stat.provider)
|
||||||
|
// await adapter?.remove(ctx, workspaceId, [stat._id])
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@withContext('aggregator-getUrl', {})
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, name: string): Promise<string> {
|
||||||
|
const { provider, stat } = await this.findProvider(ctx, workspaceId, name)
|
||||||
|
return await provider.getUrl(ctx, workspaceId, stat.storageId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
7
server/datalake/.eslintrc.js
Normal file
7
server/datalake/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@hcengineering/platform-rig/profiles/node/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
server/datalake/.npmignore
Normal file
4
server/datalake/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
5
server/datalake/config/rig.json
Normal file
5
server/datalake/config/rig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
"rigPackageName": "@hcengineering/platform-rig",
|
||||||
|
"rigProfile": "node"
|
||||||
|
}
|
7
server/datalake/jest.config.js
Normal file
7
server/datalake/jest.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||||
|
roots: ["./src"],
|
||||||
|
coverageReporters: ["text-summary", "html"]
|
||||||
|
}
|
44
server/datalake/package.json
Normal file
44
server/datalake/package.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "@hcengineering/datalake",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"svelte": "src/index.ts",
|
||||||
|
"types": "types/index.d.ts",
|
||||||
|
"author": "Anticrm Platform Contributors",
|
||||||
|
"template": "@hcengineering/node-package",
|
||||||
|
"license": "EPL-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "compile",
|
||||||
|
"build:watch": "compile",
|
||||||
|
"test": "jest --passWithNoTests --silent --forceExit",
|
||||||
|
"format": "format src",
|
||||||
|
"_phase:build": "compile transpile src",
|
||||||
|
"_phase:test": "jest --passWithNoTests --silent --forceExit",
|
||||||
|
"_phase:format": "format src",
|
||||||
|
"_phase:validate": "compile validate"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@hcengineering/platform-rig": "^0.6.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||||
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
|
"eslint-plugin-n": "^15.4.0",
|
||||||
|
"eslint": "^8.54.0",
|
||||||
|
"@typescript-eslint/parser": "^6.11.0",
|
||||||
|
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||||
|
"prettier": "^3.1.0",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"@types/node": "~20.11.16",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"ts-jest": "^29.1.1",
|
||||||
|
"@types/jest": "^29.5.5",
|
||||||
|
"@types/node-fetch": "~2.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@hcengineering/core": "^0.6.32",
|
||||||
|
"@hcengineering/platform": "^0.6.11",
|
||||||
|
"@hcengineering/server-core": "^0.6.1",
|
||||||
|
"node-fetch": "^2.6.6",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
127
server/datalake/src/client.ts
Normal file
127
server/datalake/src/client.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2024 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { type MeasureContext, type WorkspaceId, concatLink } from '@hcengineering/core'
|
||||||
|
import FormData from 'form-data'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
import { Readable } from 'stream'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface ObjectMetadata {
|
||||||
|
lastModified: number
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
size?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface PutObjectOutput {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlobUploadError {
|
||||||
|
key: string
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlobUploadSuccess {
|
||||||
|
key: string
|
||||||
|
id: string
|
||||||
|
metadata: ObjectMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlobUploadResult = BlobUploadSuccess | BlobUploadError
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export class Client {
|
||||||
|
constructor (private readonly endpoint: string) {}
|
||||||
|
|
||||||
|
getObjectUrl (ctx: MeasureContext, workspace: WorkspaceId, objectName: string): string {
|
||||||
|
const path = `/blob/${workspace.name}/${objectName}`
|
||||||
|
return concatLink(this.endpoint, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getObject (ctx: MeasureContext, workspace: WorkspaceId, objectName: string): Promise<Readable> {
|
||||||
|
const url = this.getObjectUrl(ctx, workspace, objectName)
|
||||||
|
const response = await fetch(url)
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('HTTP error ' + response.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.body == null) {
|
||||||
|
ctx.error('bad datalake response', { objectName })
|
||||||
|
throw new Error('Missing response body')
|
||||||
|
}
|
||||||
|
|
||||||
|
return Readable.from(response.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteObject (ctx: MeasureContext, workspace: WorkspaceId, objectName: string): Promise<void> {
|
||||||
|
const url = this.getObjectUrl(ctx, workspace, objectName)
|
||||||
|
|
||||||
|
const response = await fetch(url, { method: 'DELETE' })
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('HTTP error ' + response.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async putObject (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
workspace: WorkspaceId,
|
||||||
|
objectName: string,
|
||||||
|
stream: Readable | Buffer | string,
|
||||||
|
metadata: ObjectMetadata
|
||||||
|
): Promise<PutObjectOutput> {
|
||||||
|
const path = `/upload/form-data/${workspace.name}`
|
||||||
|
const url = concatLink(this.endpoint, path)
|
||||||
|
|
||||||
|
const form = new FormData()
|
||||||
|
const options: FormData.AppendOptions = {
|
||||||
|
filename: objectName,
|
||||||
|
contentType: metadata.type,
|
||||||
|
knownLength: metadata.size,
|
||||||
|
header: {
|
||||||
|
'Last-Modified': metadata.lastModified
|
||||||
|
}
|
||||||
|
}
|
||||||
|
form.append('file', stream, options)
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: form
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('HTTP error ' + response.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = (await response.json()) as BlobUploadResult[]
|
||||||
|
if (result.length !== 1) {
|
||||||
|
ctx.error('bad datalake response', { objectName, result })
|
||||||
|
throw new Error('Bad datalake response')
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadResult = result[0]
|
||||||
|
|
||||||
|
if ('error' in uploadResult) {
|
||||||
|
ctx.error('error during blob upload', { objectName, error: uploadResult.error })
|
||||||
|
throw new Error('Upload failed: ' + uploadResult.error)
|
||||||
|
} else {
|
||||||
|
return { id: uploadResult.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
server/datalake/src/index.ts
Normal file
170
server/datalake/src/index.ts
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2024 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { withContext, type Blob, type MeasureContext, type WorkspaceId } from '@hcengineering/core'
|
||||||
|
|
||||||
|
import {
|
||||||
|
type BlobStorageIterator,
|
||||||
|
type BucketInfo,
|
||||||
|
type StorageAdapter,
|
||||||
|
type StorageConfig,
|
||||||
|
type StorageConfiguration,
|
||||||
|
type UploadedObjectInfo
|
||||||
|
} from '@hcengineering/server-core'
|
||||||
|
import { type Readable } from 'stream'
|
||||||
|
import { type ObjectMetadata, Client } from './client'
|
||||||
|
|
||||||
|
export interface DatalakeConfig extends StorageConfig {
|
||||||
|
kind: 'datalake'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export class DatalakeService implements StorageAdapter {
|
||||||
|
static config = 'datalake'
|
||||||
|
client: Client
|
||||||
|
constructor (readonly opt: DatalakeConfig) {
|
||||||
|
this.client = new Client(opt.endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize (ctx: MeasureContext, workspaceId: WorkspaceId): Promise<void> {}
|
||||||
|
|
||||||
|
async close (): Promise<void> {}
|
||||||
|
|
||||||
|
async exists (ctx: MeasureContext, workspaceId: WorkspaceId): Promise<boolean> {
|
||||||
|
// workspace/buckets not supported, assume that always exist
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('make')
|
||||||
|
async make (ctx: MeasureContext, workspaceId: WorkspaceId): Promise<void> {
|
||||||
|
// workspace/buckets not supported, assume that always exist
|
||||||
|
}
|
||||||
|
|
||||||
|
async listBuckets (ctx: MeasureContext, productId: string): Promise<BucketInfo[]> {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('remove')
|
||||||
|
async remove (ctx: MeasureContext, workspaceId: WorkspaceId, objectNames: string[]): Promise<void> {
|
||||||
|
await Promise.all(
|
||||||
|
objectNames.map(async (objectName) => {
|
||||||
|
await this.client.deleteObject(ctx, workspaceId, objectName)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('delete')
|
||||||
|
async delete (ctx: MeasureContext, workspaceId: WorkspaceId): Promise<void> {
|
||||||
|
// not supported, just do nothing and pretend we deleted the workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('listStream')
|
||||||
|
async listStream (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
workspaceId: WorkspaceId,
|
||||||
|
prefix?: string | undefined
|
||||||
|
): Promise<BlobStorageIterator> {
|
||||||
|
throw new Error('not supported')
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('stat')
|
||||||
|
async stat (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<Blob | undefined> {
|
||||||
|
// not supported
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('get')
|
||||||
|
async get (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<Readable> {
|
||||||
|
return await this.client.getObject(ctx, workspaceId, objectName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('put')
|
||||||
|
async put (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
workspaceId: WorkspaceId,
|
||||||
|
objectName: string,
|
||||||
|
stream: Readable | Buffer | string,
|
||||||
|
contentType: string,
|
||||||
|
size?: number
|
||||||
|
): Promise<UploadedObjectInfo> {
|
||||||
|
const metadata: ObjectMetadata = {
|
||||||
|
lastModified: Date.now(),
|
||||||
|
name: objectName,
|
||||||
|
type: contentType,
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.with('put', {}, async () => {
|
||||||
|
return await this.client.putObject(ctx, workspaceId, objectName, stream, metadata)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
etag: '',
|
||||||
|
versionId: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('read')
|
||||||
|
async read (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<Buffer[]> {
|
||||||
|
const data = await this.client.getObject(ctx, workspaceId, objectName)
|
||||||
|
const chunks: Buffer[] = []
|
||||||
|
|
||||||
|
for await (const chunk of data) {
|
||||||
|
chunks.push(chunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
@withContext('partial')
|
||||||
|
async partial (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
workspaceId: WorkspaceId,
|
||||||
|
objectName: string,
|
||||||
|
offset: number,
|
||||||
|
length?: number
|
||||||
|
): Promise<Readable> {
|
||||||
|
throw new Error('not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<string> {
|
||||||
|
return this.client.getObjectUrl(ctx, workspaceId, objectName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function processConfigFromEnv (storageConfig: StorageConfiguration): string | undefined {
|
||||||
|
let endpoint = process.env.DATALAKE_ENDPOINT
|
||||||
|
if (endpoint === undefined) {
|
||||||
|
return 'DATALAKE_ENDPOINT'
|
||||||
|
}
|
||||||
|
|
||||||
|
let port = 80
|
||||||
|
const sp = endpoint.split(':')
|
||||||
|
if (sp.length > 1) {
|
||||||
|
endpoint = sp[0]
|
||||||
|
port = parseInt(sp[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
const config: DatalakeConfig = {
|
||||||
|
kind: 'datalake',
|
||||||
|
name: 'datalake',
|
||||||
|
endpoint,
|
||||||
|
port
|
||||||
|
}
|
||||||
|
storageConfig.storages.push(config)
|
||||||
|
storageConfig.default = 'datalake'
|
||||||
|
}
|
10
server/datalake/tsconfig.json
Normal file
10
server/datalake/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@hcengineering/platform-rig/profiles/node/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib",
|
||||||
|
"declarationDir": "./types",
|
||||||
|
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||||
|
}
|
||||||
|
}
|
@ -44,18 +44,17 @@ async function storageUpload (
|
|||||||
workspace: WorkspaceId,
|
workspace: WorkspaceId,
|
||||||
file: UploadedFile
|
file: UploadedFile
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const id = uuid()
|
const uuid = file.name
|
||||||
|
|
||||||
const data = file.tempFilePath !== undefined ? fs.createReadStream(file.tempFilePath) : file.data
|
const data = file.tempFilePath !== undefined ? fs.createReadStream(file.tempFilePath) : file.data
|
||||||
const resp = await ctx.with(
|
const resp = await ctx.with(
|
||||||
'storage upload',
|
'storage upload',
|
||||||
{ workspace: workspace.name },
|
{ workspace: workspace.name },
|
||||||
async (ctx) => await storageAdapter.put(ctx, workspace, id, data, file.mimetype, file.size),
|
async (ctx) => await storageAdapter.put(ctx, workspace, uuid, data, file.mimetype, file.size),
|
||||||
{ file: file.name, contentType: file.mimetype }
|
{ file: file.name, contentType: file.mimetype }
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx.info('minio upload', resp)
|
ctx.info('storage upload', resp)
|
||||||
return id
|
return uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRange (range: string, size: number): [number, number] {
|
function getRange (range: string, size: number): [number, number] {
|
||||||
@ -84,6 +83,7 @@ async function getFileRange (
|
|||||||
workspace: WorkspaceId,
|
workspace: WorkspaceId,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const uuid = stat._id
|
||||||
const size: number = stat.size
|
const size: number = stat.size
|
||||||
|
|
||||||
const [start, end] = getRange(range, size)
|
const [start, end] = getRange(range, size)
|
||||||
@ -240,6 +240,7 @@ export function start (
|
|||||||
storageAdapter: StorageAdapter
|
storageAdapter: StorageAdapter
|
||||||
accountsUrl: string
|
accountsUrl: string
|
||||||
uploadUrl: string
|
uploadUrl: string
|
||||||
|
filesUrl: string
|
||||||
modelVersion: string
|
modelVersion: string
|
||||||
version: string
|
version: string
|
||||||
rekoniUrl: string
|
rekoniUrl: string
|
||||||
@ -290,6 +291,7 @@ export function start (
|
|||||||
const data = {
|
const data = {
|
||||||
ACCOUNTS_URL: config.accountsUrl,
|
ACCOUNTS_URL: config.accountsUrl,
|
||||||
UPLOAD_URL: config.uploadUrl,
|
UPLOAD_URL: config.uploadUrl,
|
||||||
|
FILES_URL: config.filesUrl,
|
||||||
MODEL_VERSION: config.modelVersion,
|
MODEL_VERSION: config.modelVersion,
|
||||||
VERSION: config.version,
|
VERSION: config.version,
|
||||||
REKONI_URL: config.rekoniUrl,
|
REKONI_URL: config.rekoniUrl,
|
||||||
@ -511,7 +513,12 @@ export function start (
|
|||||||
const payload = decodeToken(token)
|
const payload = decodeToken(token)
|
||||||
const uuid = await storageUpload(ctx, config.storageAdapter, payload.workspace, file)
|
const uuid = await storageUpload(ctx, config.storageAdapter, payload.workspace, file)
|
||||||
|
|
||||||
res.status(200).send(uuid)
|
res.status(200).send([
|
||||||
|
{
|
||||||
|
key: 'file',
|
||||||
|
id: uuid
|
||||||
|
}
|
||||||
|
])
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
ctx.error('error-post-files', error)
|
ctx.error('error-post-files', error)
|
||||||
res.status(500).send()
|
res.status(500).send()
|
||||||
@ -606,7 +613,7 @@ export function start (
|
|||||||
const buffer = Buffer.concat(data)
|
const buffer = Buffer.concat(data)
|
||||||
config.storageAdapter
|
config.storageAdapter
|
||||||
.put(ctx, payload.workspace, id, buffer, contentType, buffer.length)
|
.put(ctx, payload.workspace, id, buffer, contentType, buffer.length)
|
||||||
.then(async (objInfo) => {
|
.then(async () => {
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
id,
|
id,
|
||||||
contentType,
|
contentType,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||||
// Copyright © 2021 Hardcore Engineering Inc.
|
// Copyright © 2021, 2024 Hardcore Engineering Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License. You may
|
// you may not use this file except in compliance with the License. You may
|
||||||
@ -106,12 +106,16 @@ export function startFront (ctx: MeasureContext, extraConfig?: Record<string, st
|
|||||||
}
|
}
|
||||||
|
|
||||||
let previewConfig = process.env.PREVIEW_CONFIG
|
let previewConfig = process.env.PREVIEW_CONFIG
|
||||||
|
|
||||||
if (previewConfig === undefined) {
|
if (previewConfig === undefined) {
|
||||||
// Use universal preview config
|
// Use universal preview config
|
||||||
previewConfig = `${uploadUrl}/:workspace?file=:blobId&size=:size`
|
previewConfig = `${uploadUrl}/:workspace?file=:blobId&size=:size`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let filesUrl = process.env.FILES_URL
|
||||||
|
if (filesUrl === undefined) {
|
||||||
|
filesUrl = `${uploadUrl}/:workspace/:filename?file=:blobId&workspace=:workspace`
|
||||||
|
}
|
||||||
|
|
||||||
const pushPublicKey = process.env.PUSH_PUBLIC_KEY
|
const pushPublicKey = process.env.PUSH_PUBLIC_KEY
|
||||||
|
|
||||||
const brandingUrl = process.env.BRANDING_URL
|
const brandingUrl = process.env.BRANDING_URL
|
||||||
@ -123,6 +127,7 @@ export function startFront (ctx: MeasureContext, extraConfig?: Record<string, st
|
|||||||
storageAdapter,
|
storageAdapter,
|
||||||
accountsUrl,
|
accountsUrl,
|
||||||
uploadUrl,
|
uploadUrl,
|
||||||
|
filesUrl,
|
||||||
modelVersion,
|
modelVersion,
|
||||||
version,
|
version,
|
||||||
gmailUrl,
|
gmailUrl,
|
||||||
|
@ -23,8 +23,8 @@ import core, {
|
|||||||
type Ref,
|
type Ref,
|
||||||
type WorkspaceId
|
type WorkspaceId
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import {
|
import serverCore, {
|
||||||
removeAllObjects,
|
removeAllObjects,
|
||||||
type BlobStorageIterator,
|
type BlobStorageIterator,
|
||||||
type BucketInfo,
|
type BucketInfo,
|
||||||
@ -363,6 +363,12 @@ export class MinioService implements StorageAdapter {
|
|||||||
length
|
length
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@withContext('getUrl')
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<string> {
|
||||||
|
const filesUrl = getMetadata(serverCore.metadata.FilesUrl) ?? ''
|
||||||
|
return filesUrl.replaceAll(':workspace', workspaceId.name).replaceAll(':blobId', objectName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processConfigFromEnv (storageConfig: StorageConfiguration): string | undefined {
|
export function processConfigFromEnv (storageConfig: StorageConfiguration): string | undefined {
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hcengineering/core": "^0.6.32",
|
"@hcengineering/core": "^0.6.32",
|
||||||
|
"@hcengineering/platform": "^0.6.11",
|
||||||
"@hcengineering/server-core": "^0.6.1",
|
"@hcengineering/server-core": "^0.6.1",
|
||||||
"@hcengineering/storage": "^0.6.0",
|
"@hcengineering/storage": "^0.6.0",
|
||||||
"@aws-sdk/client-s3": "^3.575.0",
|
"@aws-sdk/client-s3": "^3.575.0",
|
||||||
|
@ -24,8 +24,8 @@ import core, {
|
|||||||
type Ref,
|
type Ref,
|
||||||
type WorkspaceId
|
type WorkspaceId
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import {
|
import serverCore, {
|
||||||
type BlobStorageIterator,
|
type BlobStorageIterator,
|
||||||
type ListBlobResult,
|
type ListBlobResult,
|
||||||
type StorageAdapter,
|
type StorageAdapter,
|
||||||
@ -433,6 +433,12 @@ export class S3Service implements StorageAdapter {
|
|||||||
const range = length !== undefined ? `bytes=${offset}-${offset + length}` : `bytes=${offset}-`
|
const range = length !== undefined ? `bytes=${offset}-${offset + length}` : `bytes=${offset}-`
|
||||||
return await this.doGet(ctx, workspaceId, objectName, range)
|
return await this.doGet(ctx, workspaceId, objectName, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@withContext('getUrl')
|
||||||
|
async getUrl (ctx: MeasureContext, workspaceId: WorkspaceId, objectName: string): Promise<string> {
|
||||||
|
const filesUrl = getMetadata(serverCore.metadata.FilesUrl) ?? ''
|
||||||
|
return filesUrl.replaceAll(':workspace', workspaceId.name).replaceAll(':blobId', objectName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processConfigFromEnv (storageConfig: StorageConfiguration): string | undefined {
|
export function processConfigFromEnv (storageConfig: StorageConfiguration): string | undefined {
|
||||||
@ -450,7 +456,7 @@ export function processConfigFromEnv (storageConfig: StorageConfiguration): stri
|
|||||||
return 'S3_SECRET_KEY'
|
return 'S3_SECRET_KEY'
|
||||||
}
|
}
|
||||||
|
|
||||||
const minioConfig: S3Config = {
|
const config: S3Config = {
|
||||||
kind: 's3',
|
kind: 's3',
|
||||||
name: 's3',
|
name: 's3',
|
||||||
region: 'auto',
|
region: 'auto',
|
||||||
@ -458,6 +464,6 @@ export function processConfigFromEnv (storageConfig: StorageConfiguration): stri
|
|||||||
accessKey,
|
accessKey,
|
||||||
secretKey
|
secretKey
|
||||||
}
|
}
|
||||||
storageConfig.storages.push(minioConfig)
|
storageConfig.storages.push(config)
|
||||||
storageConfig.default = 's3'
|
storageConfig.default = 's3'
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
"@hcengineering/mongo": "^0.6.1",
|
"@hcengineering/mongo": "^0.6.1",
|
||||||
"@hcengineering/minio": "^0.6.0",
|
"@hcengineering/minio": "^0.6.0",
|
||||||
"@hcengineering/s3": "^0.6.0",
|
"@hcengineering/s3": "^0.6.0",
|
||||||
|
"@hcengineering/datalake": "^0.6.0",
|
||||||
"elastic-apm-node": "~3.26.0",
|
"elastic-apm-node": "~3.26.0",
|
||||||
"@hcengineering/server-token": "^0.6.11"
|
"@hcengineering/server-token": "^0.6.11"
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { type DatalakeConfig, DatalakeService } from '@hcengineering/datalake'
|
||||||
import { MinioConfig, MinioService, addMinioFallback } from '@hcengineering/minio'
|
import { MinioConfig, MinioService, addMinioFallback } from '@hcengineering/minio'
|
||||||
import { createRawMongoDBAdapter } from '@hcengineering/mongo'
|
import { createRawMongoDBAdapter } from '@hcengineering/mongo'
|
||||||
import { S3Service, type S3Config } from '@hcengineering/s3'
|
import { S3Service, type S3Config } from '@hcengineering/s3'
|
||||||
@ -96,6 +97,12 @@ export function createStorageFromConfig (config: StorageConfig): StorageAdapter
|
|||||||
throw new Error('One of endpoint/accessKey/secretKey values are not specified')
|
throw new Error('One of endpoint/accessKey/secretKey values are not specified')
|
||||||
}
|
}
|
||||||
return new S3Service(c)
|
return new S3Service(c)
|
||||||
|
} else if (kind === DatalakeService.config) {
|
||||||
|
const c = config as DatalakeConfig
|
||||||
|
if (c.endpoint == null) {
|
||||||
|
throw new Error('Endpoint value is not specified')
|
||||||
|
}
|
||||||
|
return new DatalakeService(c)
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported storage kind:' + kind)
|
throw new Error('Unsupported storage kind:' + kind)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ export interface ServerEnv {
|
|||||||
serverSecret: string
|
serverSecret: string
|
||||||
rekoniUrl: string
|
rekoniUrl: string
|
||||||
frontUrl: string
|
frontUrl: string
|
||||||
uploadUrl: string
|
filesUrl: string | undefined
|
||||||
sesUrl: string | undefined
|
sesUrl: string | undefined
|
||||||
accountsUrl: string
|
accountsUrl: string
|
||||||
serverPort: number
|
serverPort: number
|
||||||
@ -55,12 +55,7 @@ export function serverConfigFromEnv (): ServerEnv {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadUrl = process.env.UPLOAD_URL
|
const filesUrl = process.env.FILES_URL
|
||||||
if (uploadUrl === undefined) {
|
|
||||||
console.log('Please provide UPLOAD_URL url')
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const sesUrl = process.env.SES_URL
|
const sesUrl = process.env.SES_URL
|
||||||
|
|
||||||
const accountsUrl = process.env.ACCOUNTS_URL
|
const accountsUrl = process.env.ACCOUNTS_URL
|
||||||
@ -81,7 +76,7 @@ export function serverConfigFromEnv (): ServerEnv {
|
|||||||
serverSecret,
|
serverSecret,
|
||||||
rekoniUrl,
|
rekoniUrl,
|
||||||
frontUrl,
|
frontUrl,
|
||||||
uploadUrl,
|
filesUrl,
|
||||||
sesUrl,
|
sesUrl,
|
||||||
accountsUrl,
|
accountsUrl,
|
||||||
serverPort,
|
serverPort,
|
||||||
|
@ -163,6 +163,7 @@ export class GithubWorker implements IntegrationManager {
|
|||||||
}
|
}
|
||||||
const frontUrl = this.getBranding()?.front ?? config.FrontURL
|
const frontUrl = this.getBranding()?.front ?? config.FrontURL
|
||||||
const refUrl = concatLink(frontUrl, `/browse/?workspace=${this.workspace.name}`)
|
const refUrl = concatLink(frontUrl, `/browse/?workspace=${this.workspace.name}`)
|
||||||
|
// TODO storage URL
|
||||||
const imageUrl = concatLink(frontUrl ?? config.FrontURL, `/files?workspace=${this.workspace.name}&file=`)
|
const imageUrl = concatLink(frontUrl ?? config.FrontURL, `/files?workspace=${this.workspace.name}&file=`)
|
||||||
const guestUrl = getPublicLinkUrl(this.workspace, frontUrl)
|
const guestUrl = getPublicLinkUrl(this.workspace, frontUrl)
|
||||||
const json = parseMessageMarkdown(text ?? '', refUrl, imageUrl, guestUrl)
|
const json = parseMessageMarkdown(text ?? '', refUrl, imageUrl, guestUrl)
|
||||||
@ -177,6 +178,7 @@ export class GithubWorker implements IntegrationManager {
|
|||||||
return await markupToMarkdown(
|
return await markupToMarkdown(
|
||||||
text ?? '',
|
text ?? '',
|
||||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/browse/?workspace=${this.workspace.name}`),
|
concatLink(this.getBranding()?.front ?? config.FrontURL, `/browse/?workspace=${this.workspace.name}`),
|
||||||
|
// TODO storage URL
|
||||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/files?workspace=${this.workspace.name}&file=`),
|
concatLink(this.getBranding()?.front ?? config.FrontURL, `/files?workspace=${this.workspace.name}&file=`),
|
||||||
preprocessor
|
preprocessor
|
||||||
)
|
)
|
||||||
|
@ -101,7 +101,6 @@ services:
|
|||||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||||
- REKONI_URL=http://rekoni:7
|
- REKONI_URL=http://rekoni:7
|
||||||
- FRONT_URL=http://localhost:8083
|
- FRONT_URL=http://localhost:8083
|
||||||
- UPLOAD_URL=http://localhost:8083/files
|
|
||||||
- ACCOUNTS_URL=http://account:3003
|
- ACCOUNTS_URL=http://account:3003
|
||||||
- LAST_NAME_FIRST=true
|
- LAST_NAME_FIRST=true
|
||||||
- ELASTIC_INDEX_NAME=local_storage_index
|
- ELASTIC_INDEX_NAME=local_storage_index
|
||||||
@ -118,7 +117,6 @@ services:
|
|||||||
- COLLABORATOR_PORT=3078
|
- COLLABORATOR_PORT=3078
|
||||||
- SECRET=secret
|
- SECRET=secret
|
||||||
- ACCOUNTS_URL=http://account:3003
|
- ACCOUNTS_URL=http://account:3003
|
||||||
- UPLOAD_URL=/files
|
|
||||||
- MONGO_URL=mongodb://mongodb:27018
|
- MONGO_URL=mongodb://mongodb:27018
|
||||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
Loading…
Reference in New Issue
Block a user