bun -> rush (#62)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina
2025-06-04 20:57:18 +04:00
committed by GitHub
parent 9ac61516bf
commit 235ee8ffff
128 changed files with 9838 additions and 1889 deletions
+14
View File
@@ -0,0 +1,14 @@
# Don't allow people to merge changes to these generated files, because the result
# may be invalid. You need to run "rush update" again.
pnpm-lock.yaml merge=text
shrinkwrap.yaml merge=binary
npm-shrinkwrap.json merge=binary
yarn.lock merge=binary
# Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic
# syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor
# may also require a special configuration to allow comments in JSON.
#
# For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088
#
*.json linguist-language=JSON-with-Comments
+15 -21
View File
@@ -34,32 +34,26 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Set up bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.9
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
registry-url: 'https://npm.pkg.github.com'
scope: '@hcengineering'
- name: Prepare deps
- name: Prepare .npmrc for GitHub Packages
run: |
echo "@hcengineering:registry=https://npm.pkg.github.com" > .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc
- name: Install dependencies
run: bun install
- name: Build
run: bun run build
- name: Check format
run: bun run format:check
- name: Lint
run: bun run lint
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Rush Install
run: node common/scripts/install-run-rush.js update
- name: Rush rebuild
run: node common/scripts/install-run-rush.js build
- name: Rush validate
run: node common/scripts/install-run-rush.js validate
- name: Linting
run: node common/scripts/install-run-rush.js lint
- name: Formatting
run: node common/scripts/install-run-rush.js format
+125 -14
View File
@@ -1,6 +1,129 @@
# build output
dist/
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
rush-logs/
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov/
# Coverage directory used by tools like istanbul
coverage/
# nyc test coverage
.nyc_output/
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt/
# Bower dependency directory (https://bower.io/)
bower_components/
# node-waf configuration
.lock-wscript/
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release/
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm/
# Optional eslint cache
.eslintcache/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# next.js build output
.next/
# Docusaurus cache and generated files
.docusaurus/
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# yarn v2
.yarn/cache/
.yarn/unplugged/
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# OS X temporary files
.DS_Store
# IntelliJ IDEA project files; if you want to commit IntelliJ settings, this recipe may be helpful:
# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
.idea/
*.iml
# Visual Studio Code
.vscode/
!.vscode/tasks.json
!.vscode/launch.json
# Rush temporary files
common/deploy/
common/temp/
common/autoinstallers/*/.npmrc
**/.rush/temp/
*.lock
# Common toolchain intermediate files
temp/
lib/
lib-amd/
lib-es6/
lib-esnext/
lib-commonjs/
lib-shim/
dist/
dist-storybook/
# Heft temporary files
.cache/
.heft/
.rush/
.validate
# build output
.turbo/
**/types/
@@ -9,21 +132,9 @@ lib/
# VS Code settings
.vscode/settings.json
# Jetbrains setting folder
.idea/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
+13 -6
View File
@@ -1,27 +1,34 @@
## 📡 Platform Communication Package
A modular communication package for platform-level messaging —
built with [Bun](https://bun.sh).
built with [Rush](https://rushjs.io/).
---
### 📦 Installation
Install dependencies using Bun:
Install rush:
```bash
bun install
npm install -g @microsoft/rush
```
Install dependencies:
```bash
rush update
```
### Build packages
```bash
bun run build
rush build
rush validate
```
### Lint & format
```bash
bun run lint
bun run format
rush lint
rush format
```
-643
View File
@@ -1,643 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "@hcengineering/communication",
"devDependencies": {
"@eslint/js": "^9.28.0",
"@types/bun": "^1.2.15",
"bun-types": "^1.2.15",
"eslint": "^9.28.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.4.1",
"prettier": "^3.5.3",
"turbo": "^2.5.4",
"typescript-eslint": "^8.33.1",
},
},
"packages/client-query": {
"name": "@hcengineering/communication-client-query",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-query": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"fast-equals": "^5.0.1",
},
"devDependencies": {
"@types/bun": "^1.1.14",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/cockroach": {
"name": "@hcengineering/communication-cockroach",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"postgres": "^3.4.4",
"uuid": "^11.1.0",
},
"devDependencies": {
"@types/bun": "^1.1.14",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/query": {
"name": "@hcengineering/communication-query",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-yaml": "workspace:*",
"fast-equals": "^5.0.1",
"uuid": "^11.1.0",
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/crypto-js": "^4.2.2",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/rest-client": {
"name": "@hcengineering/communication-rest-client",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/core": "^0.7.88",
"snappyjs": "^0.7.0",
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/snappyjs": "^0.7.1",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/sdk-types": {
"name": "@hcengineering/communication-sdk-types",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/core": "^0.7.88",
},
"devDependencies": {
"@types/bun": "^1.1.14",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/server": {
"name": "@hcengineering/communication-server",
"version": "0.1.0",
"dependencies": {
"@hcengineering/account-client": "^0.7.88",
"@hcengineering/communication-cockroach": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-yaml": "workspace:*",
"@hcengineering/core": "^0.7.88",
"@hcengineering/platform": "^0.7.88",
"@hcengineering/server-token": "^0.7.88",
"@hcengineering/text-core": "^0.7.88",
"@hcengineering/text-markdown": "^0.7.88",
"zod": "^3.24.2",
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/ws": "^8.5.13",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/shared": {
"name": "@hcengineering/communication-shared",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
},
"devDependencies": {
"@types/bun": "^1.1.14",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/types": {
"name": "@hcengineering/communication-types",
"version": "0.1.0",
"dependencies": {
"@hcengineering/card": "^0.7.88",
"@hcengineering/core": "^0.7.88",
"@hcengineering/tags": "^0.7.88",
},
"devDependencies": {
"@types/bun": "^1.1.14",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
"packages/yaml": {
"name": "@hcengineering/communication-yaml",
"version": "0.1.0",
"dependencies": {
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"js-yaml": "^4.1.0",
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/js-yaml": "^4.0.9",
},
"peerDependencies": {
"typescript": "^5.6.3",
},
},
},
"packages": {
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
"@babel/runtime": ["@babel/runtime@7.26.9", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/config-array": ["@eslint/config-array@0.20.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.2.1", "", {}, "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw=="],
"@eslint/core": ["@eslint/core@0.14.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
"@eslint/js": ["@eslint/js@9.28.0", "", {}, "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.1", "", { "dependencies": { "@eslint/core": "^0.14.0", "levn": "^0.4.1" } }, "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w=="],
"@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.3", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.6", "@formatjs/intl-localematcher": "0.6.0", "decimal.js": "10", "tslib": "2" } }, "sha512-pJT1OkhplSmvvr6i3CWTPvC/FGC06MbN5TNBfRO6Ox62AEz90eMq+dVvtX9Bl3jxCEkS0tATzDarRZuOLw7oFg=="],
"@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.6", "", { "dependencies": { "tslib": "2" } }, "sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw=="],
"@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.1", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.3", "@formatjs/icu-skeleton-parser": "1.8.13", "tslib": "2" } }, "sha512-o0AhSNaOfKoic0Sn1GkFCK4MxdRsw7mPJ5/rBpIqdvcC7MIuyUSW8WChUEvrK78HhNpYOgqCQbINxCTumJLzZA=="],
"@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.13", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.3", "tslib": "2" } }, "sha512-N/LIdTvVc1TpJmMt2jVg0Fr1F7Q1qJPdZSCs19unMskCmVQ/sa0H9L8PWt13vq+gLdLg1+pPsvBLydL1Apahjg=="],
"@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.0", "", { "dependencies": { "tslib": "2" } }, "sha512-4rB4g+3hESy1bHSBG3tDFaMY2CH67iT7yne1e+0CLTsGLDcmoEWWpJjjpWVaYgYfYuohIRuo0E+N536gd2ZHZA=="],
"@hcengineering/account-client": ["@hcengineering/account-client@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/account-client/0.7.88/57caa95e62fecc4ca22a32c76bcdc900b0384f04", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88" } }, "sha512-CZWOJT/JZAUy+FuYuX0QcJQYDnVDNAB0QHU4RxKc7gSlYAYleibL7qJC0vRGL4rNkvDVZfJMKDPUQW4AauGqtA=="],
"@hcengineering/analytics": ["@hcengineering/analytics@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/analytics/0.7.88/385c2ae512bbcae39189d63e53ea527aa21a662f", { "dependencies": { "@hcengineering/platform": "^0.7.88" } }, "sha512-3jT3h2Y85awrgG0JWZSrpWOXaX1J3dpq8zouo3QMw8OVO1RgHCwPEqrBPOALnB+gc9cZL02p6Aq4J+fnTZ2fww=="],
"@hcengineering/card": ["@hcengineering/card@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/card/0.7.88/e39b9e182325945494f162f2dd6f16ef9bea0f3e", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "@hcengineering/ui": "^0.7.88" } }, "sha512-3JDgocHFSGmQuKsrtQ5CTTm4rpd/PHahIx6oNX8sshDGpS2hnvNtrHNkJf39seIKiq0NNKmJ//Etl4I21h4c6w=="],
"@hcengineering/communication-client-query": ["@hcengineering/communication-client-query@workspace:packages/client-query"],
"@hcengineering/communication-cockroach": ["@hcengineering/communication-cockroach@workspace:packages/cockroach"],
"@hcengineering/communication-query": ["@hcengineering/communication-query@workspace:packages/query"],
"@hcengineering/communication-rest-client": ["@hcengineering/communication-rest-client@workspace:packages/rest-client"],
"@hcengineering/communication-sdk-types": ["@hcengineering/communication-sdk-types@workspace:packages/sdk-types"],
"@hcengineering/communication-server": ["@hcengineering/communication-server@workspace:packages/server"],
"@hcengineering/communication-shared": ["@hcengineering/communication-shared@workspace:packages/shared"],
"@hcengineering/communication-types": ["@hcengineering/communication-types@workspace:packages/types"],
"@hcengineering/communication-yaml": ["@hcengineering/communication-yaml@workspace:packages/yaml"],
"@hcengineering/core": ["@hcengineering/core@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/core/0.7.88/ca01c3ccd43c85ea44b189d995b0693c5465956c", { "dependencies": { "@hcengineering/analytics": "^0.7.88", "@hcengineering/platform": "^0.7.88", "fast-equals": "^5.2.2" } }, "sha512-c3GRTGAZYARu1kMt4TqkugmnuprYesZ4XZUeakReRtZdYei9tAF+i9xPpDKb4J3hvMC3u82LlEiV8iK26iXpTA=="],
"@hcengineering/platform": ["@hcengineering/platform@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/platform/0.7.88/b3fbe09d6b849f7eb3641792682bf133103037f0", { "dependencies": { "intl-messageformat": "^10.7.14" } }, "sha512-iFAwYQZjGox1NqEgUh8hiT1mRHdSJqYmYux0lkeIFyt8Nn/BAZOVXe0br0Dx7wXiueFPWhSZSeWVhxvBb78zoA=="],
"@hcengineering/preference": ["@hcengineering/preference@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/preference/0.7.88/e1181dae3cb2eaf53fed66ddd3d5c4854717ccf0", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "@hcengineering/ui": "^0.7.88" } }, "sha512-idzAlphM/HyNJfFMFwbpyKg6KvFTJ6rTaqgduNNJqkO4DsUCEF5/1WLNQMmiAeoFDY9y5+/mHJrx+1Ztq1XIuw=="],
"@hcengineering/server-token": ["@hcengineering/server-token@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/server-token/0.7.88/11b3a8247869a50037fcbb13572e16545116ff93", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "jwt-simple": "^0.5.6" } }, "sha512-UQfW0E+v+PTwR7ICR+kSTQqAokpiV008ukqsxRSQJkCM4vmNYciUgd/7Y/ifDMFhKDvNyODb+wgAQs3QxkSbkA=="],
"@hcengineering/tags": ["@hcengineering/tags@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/tags/0.7.88/f3f0de35b1be71d1f3f6711b8e4f161e0cf857eb", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "@hcengineering/ui": "^0.7.88", "@hcengineering/view": "^0.7.88" } }, "sha512-wpnVX/1Y8E4YPYnUcw+ZyVOpZvXYpboZC9D1btMqFs34CoMGc4tW1XT3YfsS8KxlkH6tsQjsAUvtWOPy2J46dg=="],
"@hcengineering/text-core": ["@hcengineering/text-core@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/text-core/0.7.88/7e53b0da9622709b2d1071049ead3843e0c45764", { "dependencies": { "@hcengineering/core": "^0.7.88", "fast-equals": "^5.2.2" } }, "sha512-mFri9SMzD99uR3/H0gZ4KEekYf3lEmJ2bqEQrjIVmi9z7+CzDTxmKnXeHKzcFpvQaLt5kmbPIoXM4MyxpK7ZXA=="],
"@hcengineering/text-html": ["@hcengineering/text-html@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/text-html/0.7.88/e48beced20921d9e1e9c84548c3caf5c9770bac1", { "dependencies": { "@hcengineering/text-core": "^0.7.88", "htmlparser2": "^9.0.0" } }, "sha512-Wj0gYv0JEUIKpuaDFmRn7/60/SXGg0CZVmzbux0XlUzayly+C4Pkfj5U3G/ZEUyDBtAtyeBdWtnkzgQgN6qOuQ=="],
"@hcengineering/text-markdown": ["@hcengineering/text-markdown@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/text-markdown/0.7.88/86938b13b0bdd81941a22378e3b2e92998f71d80", { "dependencies": { "@hcengineering/text-core": "^0.7.88", "@hcengineering/text-html": "^0.7.88", "fast-equals": "^5.2.2", "markdown-it": "^14.0.0" } }, "sha512-066WeD/6EI5VmFQZ/Cv6eEOFXBd+fA+YPxX5fb0ytlZr5bLpQs6/AifpyqJoZ5gqQzfAf/HmtDVxDl5QU95FGw=="],
"@hcengineering/theme": ["@hcengineering/theme@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/theme/0.7.88/d939d1e2a9047def2795dc5124653e49ca522cfc", { "dependencies": { "@hcengineering/analytics": "^0.7.88", "@hcengineering/platform": "^0.7.88", "svelte": "^4.2.19" } }, "sha512-PCt9bFuGPYOf1kQgjzxPSZgGXU4G14Z1XZJfgGu71u/zHxG6fu6nls35aSrEjy2Ks6oR+OCqqvpDh6RTf6utrg=="],
"@hcengineering/ui": ["@hcengineering/ui@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/ui/0.7.88/fce3392a59f706c248ba4b17714163e5725d5f01", { "dependencies": { "@hcengineering/analytics": "^0.7.88", "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "@hcengineering/theme": "^0.7.88", "autolinker": "4.0.0", "date-fns": "^2.30.0", "date-fns-tz": "^2.0.0", "dompurify": "^3.1.6", "emojibase": "^16.0.0", "fast-equals": "^5.2.2", "hls.js": "^1.5.20", "plyr": "^3.7.8", "svelte": "^4.2.19" } }, "sha512-mzHXcX3aBC/OXUaV9F2hnB6+irwMfEYM5J1CnfqiHqgv3Hza20BZR6BrYe/nQCLb44DuHkXojbwL94AKK3QW6w=="],
"@hcengineering/view": ["@hcengineering/view@0.7.88", "https://npm.pkg.github.com/download/@hcengineering/view/0.7.88/8a13ddff0178ac3b705ebed683d0c1cc328c8e1c", { "dependencies": { "@hcengineering/core": "^0.7.88", "@hcengineering/platform": "^0.7.88", "@hcengineering/preference": "^0.7.88", "@hcengineering/ui": "^0.7.88" } }, "sha512-W3/OgCu9W+OGZ8v8hoT0bjoCNflvIcWFwFafk40FtWFxvqzObm41e5ZWNj3yGWFdlVsyN/Nqdjkyz0txWUXQAA=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@pkgr/core": ["@pkgr/core@0.2.7", "", {}, "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg=="],
"@types/body-parser": ["@types/body-parser@1.19.5", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg=="],
"@types/bun": ["@types/bun@1.2.15", "", { "dependencies": { "bun-types": "1.2.15" } }, "sha512-U1ljPdBEphF0nw1MIk0hI7kPg7dFdPyM7EenHsp6W5loNHl7zqy6JQf/RKCgnUn2KDzUpkBwHPnEJEjII594bA=="],
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
"@types/cors": ["@types/cors@2.8.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA=="],
"@types/crypto-js": ["@types/crypto-js@4.2.2", "", {}, "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
"@types/express": ["@types/express@5.0.0", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ=="],
"@types/express-serve-static-core": ["@types/express-serve-static-core@5.0.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA=="],
"@types/http-errors": ["@types/http-errors@2.0.4", "", {}, "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="],
"@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="],
"@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
"@types/qs": ["@types/qs@6.9.18", "", {}, "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA=="],
"@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="],
"@types/send": ["@types/send@0.17.4", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA=="],
"@types/serve-static": ["@types/serve-static@1.15.7", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "*" } }, "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw=="],
"@types/snappyjs": ["@types/snappyjs@0.7.1", "", {}, "sha512-OxjzJ6cQZstysMh6PEwZWmK9qlKZyezHJKOkcUkZDooSFuog2votUEKkxMaTq51UQF3cJkXKQ+XGlj4FSl8JQQ=="],
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
"@types/ws": ["@types/ws@8.18.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.33.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/type-utils": "8.33.1", "@typescript-eslint/utils": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.33.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.33.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/types": "^8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1" } }, "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.33.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/utils": "8.33.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.33.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ=="],
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
"autolinker": ["autolinker@4.0.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-fl5Kh6BmEEZx+IWBfEirnRUU5+cOiV0OK7PEt0RBKvJMJ8GaRseIOeDU3FKf4j3CE5HVefcjHmhYPOcaVt0bZw=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"bun-types": ["bun-types@1.2.15", "", { "dependencies": { "@types/node": "*" } }, "sha512-NarRIaS+iOaQU1JPfyKhZm4AsUOrwUOqRNHY0XxI8GI8jYxiLXLcdjYMG9UKS+fwWasc1uw1htV9AX24dD+p4w=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"code-red": ["code-red@1.0.4", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", "acorn": "^8.10.0", "estree-walker": "^3.0.3", "periscopic": "^3.1.0" } }, "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"core-js": ["core-js@3.41.0", "", {}, "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="],
"custom-event-polyfill": ["custom-event-polyfill@1.0.7", "", {}, "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w=="],
"date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="],
"date-fns-tz": ["date-fns-tz@2.0.1", "", { "peerDependencies": { "date-fns": "2.x" } }, "sha512-fJCG3Pwx8HUoLhkepdsP7Z5RsucUi+ZBOxyM5d0ZZ6c4SdYustq0VMmOu6Wf7bli+yS/Jwp91TOCqn9jMcVrUA=="],
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
"dompurify": ["dompurify@3.2.4", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg=="],
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
"emojibase": ["emojibase@16.0.0", "", {}, "sha512-Nw2m7JLIO4Ou2X/yZPRNscHQXVbbr6SErjkJ7EooG7MbR3yDZszCv9KTizsXFc7yZl0n3WF+qUKIC/Lw6H9xaQ=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.28.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.28.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ=="],
"eslint-config-prettier": ["eslint-config-prettier@9.1.0", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw=="],
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.4.1", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg=="],
"eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
"espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
"fast-equals": ["fast-equals@5.2.2", "", {}, "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"hls.js": ["hls.js@1.5.20", "", {}, "sha512-uu0VXUK52JhihhnN/MVVo1lvqNNuhoxkonqgO3IpjvQiGpJBdIXMGkofjQb/j9zvV7a1SW8U9g1FslWx/1HOiQ=="],
"htmlparser2": ["htmlparser2@9.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "entities": "^4.5.0" } }, "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"intl-messageformat": ["intl-messageformat@10.7.15", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.3", "@formatjs/fast-memoize": "2.2.6", "@formatjs/icu-messageformat-parser": "2.11.1", "tslib": "2" } }, "sha512-LRyExsEsefQSBjU2p47oAheoKz+EOJxSLDdjOaEjdriajfHsMXOmV/EhMvYSg9bAgCUHasuAC+mcUBe/95PfIg=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"jwt-simple": ["jwt-simple@0.5.6", "", {}, "sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="],
"loadjs": ["loadjs@4.3.0", "", {}, "sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ=="],
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
"markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="],
"mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="],
"mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"periscopic": ["periscopic@3.1.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", "is-reference": "^3.0.0" } }, "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"plyr": ["plyr@3.7.8", "", { "dependencies": { "core-js": "^3.26.1", "custom-event-polyfill": "^1.0.7", "loadjs": "^4.2.0", "rangetouch": "^2.0.1", "url-polyfill": "^1.1.12" } }, "sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA=="],
"postgres": ["postgres@3.4.5", "", {}, "sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"rangetouch": ["rangetouch@2.0.1", "", {}, "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA=="],
"regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"snappyjs": ["snappyjs@0.7.0", "", {}, "sha512-u5iEEXkMe2EInQio6Wv9LWHOQYRDbD2O9hzS27GpT/lwfIQhTCnHCTqedqHIHe9ZcvQo+9au6vngQayipz1NYw=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"svelte": ["svelte@4.2.19", "", { "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/trace-mapping": "^0.3.18", "@types/estree": "^1.0.1", "acorn": "^8.9.0", "aria-query": "^5.3.0", "axobject-query": "^4.0.0", "code-red": "^1.0.3", "css-tree": "^2.3.1", "estree-walker": "^3.0.3", "is-reference": "^3.0.1", "locate-character": "^3.0.0", "magic-string": "^0.30.4", "periscopic": "^3.1.0" } }, "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw=="],
"synckit": ["synckit@0.11.8", "", { "dependencies": { "@pkgr/core": "^0.2.4" } }, "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"turbo": ["turbo@2.5.4", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.4", "turbo-darwin-arm64": "2.5.4", "turbo-linux-64": "2.5.4", "turbo-linux-arm64": "2.5.4", "turbo-windows-64": "2.5.4", "turbo-windows-arm64": "2.5.4" }, "bin": { "turbo": "bin/turbo" } }, "sha512-kc8ZibdRcuWUG1pbYSBFWqmIjynlD8Lp7IB6U3vIzvOv9VG+6Sp8bzyeBWE3Oi8XV5KsQrznyRTBPvrf99E4mA=="],
"turbo-darwin-64": ["turbo-darwin-64@2.5.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ah6YnH2dErojhFooxEzmvsoZQTMImaruZhFPfMKPBq8sb+hALRdvBNLqfc8NWlZq576FkfRZ/MSi4SHvVFT9PQ=="],
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2+Nx6LAyuXw2MdXb7pxqle3MYignLvS7OwtsP9SgtSBaMlnNlxl9BovzqdYAgkUW3AsYiQMJ/wBRb7d+xemM5A=="],
"turbo-linux-64": ["turbo-linux-64@2.5.4", "", { "os": "linux", "cpu": "x64" }, "sha512-5May2kjWbc8w4XxswGAl74GZ5eM4Gr6IiroqdLhXeXyfvWEdm2mFYCSWOzz0/z5cAgqyGidF1jt1qzUR8hTmOA=="],
"turbo-linux-arm64": ["turbo-linux-arm64@2.5.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-/2yqFaS3TbfxV3P5yG2JUI79P7OUQKOUvAnx4MV9Bdz6jqHsHwc9WZPpO4QseQm+NvmgY6ICORnoVPODxGUiJg=="],
"turbo-windows-64": ["turbo-windows-64@2.5.4", "", { "os": "win32", "cpu": "x64" }, "sha512-EQUO4SmaCDhO6zYohxIjJpOKRN3wlfU7jMAj3CgcyTPvQR/UFLEKAYHqJOnJtymbQmiiM/ihX6c6W6Uq0yC7mA=="],
"turbo-windows-arm64": ["turbo-windows-arm64@2.5.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-oQ8RrK1VS8lrxkLriotFq+PiF7iiGgkZtfLKF4DDKsmdbPo0O9R2mQxm7jHLuXraRCuIQDWMIw6dpcr7Iykf4A=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"typescript-eslint": ["typescript-eslint@8.33.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.33.1", "@typescript-eslint/parser": "8.33.1", "@typescript-eslint/utils": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A=="],
"uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"url-polyfill": ["url-polyfill@1.1.13", "", {}, "sha512-tXzkojrv2SujumYthZ/WjF7jaSfNhSXlYMpE5AYdL2I3D7DCeo+mch8KtW2rUuKjDg+3VXODXHVgipt8yGY/eQ=="],
"uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.4", "", {}, "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
}
}
+35
View File
@@ -0,0 +1,35 @@
# Rush uses this file to configure the NPM package registry during installation. It is applicable
# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install",
# "rush update", and the "install-run.js" scripts.
#
# NOTE: The "rush publish" command uses .npmrc-publish instead.
#
# Before invoking the package manager, Rush will generate an .npmrc in the folder where installation
# is performed. This generated file will omit any config lines that reference environment variables
# that are undefined in that session; this avoids problems that would otherwise result due to
# a missing variable being replaced by an empty string.
#
# If "subspacesEnabled" is true in subspaces.json, the generated file will merge settings from
# "common/config/rush/.npmrc" and "common/config/subspaces/<name>/.npmrc", with the latter taking
# precedence.
#
# * * * SECURITY WARNING * * *
#
# It is NOT recommended to store authentication tokens in a text file on a lab machine, because
# other unrelated processes may be able to read that file. Also, the file may persist indefinitely,
# for example if the machine loses power. A safer practice is to pass the token via an
# environment variable, which can be referenced from .npmrc using ${} expansion. For example:
#
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
#
# Explicitly specify the NPM registry that "rush install" and "rush update" will use by default:
registry=https://registry.npmjs.org/
# Optionally provide an authentication token for the above registry URL (if it is a private registry):
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
# Change this to "true" if your registry requires authentication for read-only operations:
@hcengineering:registry=https://npm.pkg.github.com
always-auth=false
+26
View File
@@ -0,0 +1,26 @@
# This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish
# is used by the "rush publish" command, as publishing often involves different credentials
# and registries than other operations.
#
# Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc"
# and then temporarily map that folder as the "home directory" for the current user account.
# This enables the same settings to apply for each project folder that gets published. The copied file
# will omit any config lines that reference environment variables that are undefined in that session;
# this avoids problems that would otherwise result due to a missing variable being replaced by
# an empty string.
#
# * * * SECURITY WARNING * * *
#
# It is NOT recommended to store authentication tokens in a text file on a lab machine, because
# other unrelated processes may be able to read the file. Also, the file may persist indefinitely,
# for example if the machine loses power. A safer practice is to pass the token via an
# environment variable, which can be referenced from .npmrc using ${} expansion. For example:
#
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
#
# Explicitly specify the NPM registry that "rush publish" will use by default:
registry=https://registry.npmjs.org/
# Provide an authentication token for the above registry URL:
# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
+38
View File
@@ -0,0 +1,38 @@
'use strict';
/**
* When using the PNPM package manager, you can use pnpmfile.js to workaround
* dependencies that have mistakes in their package.json file. (This feature is
* functionally similar to Yarn's "resolutions".)
*
* For details, see the PNPM documentation:
* https://pnpm.io/pnpmfile#hooks
*
* IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE
* ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run
* "rush update --full" so that PNPM will recalculate all version selections.
*/
module.exports = {
hooks: {
readPackage
}
};
/**
* This hook is invoked during installation before a package's dependencies
* are selected.
* The `packageJson` parameter is the deserialized package.json
* contents for the package that is about to be installed.
* The `context` parameter provides a log() function.
* The return value is the updated object.
*/
function readPackage(packageJson, context) {
// // The karma types have a missing dependency on typings from the log4js package.
// if (packageJson.name === '@types/karma') {
// context.log('Fixed up dependencies for @types/karma');
// packageJson.dependencies['log4js'] = '0.6.38';
// }
return packageJson;
}
+109
View File
@@ -0,0 +1,109 @@
/**
* This configuration file manages Rush integration with JFrog Artifactory services.
* More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json",
"packageRegistry": {
/**
* (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry.
* When enabled, "rush install" will automatically detect when the user's ~/.npmrc
* authentication token is missing or expired. And "rush setup" will prompt the user to
* renew their token.
*
* The default value is false.
*/
"enabled": false,
/**
* (Required) Specify the URL of your NPM registry. This is the same URL that appears in
* your .npmrc file. It should look something like this example:
*
* https://your-company.jfrog.io/your-project/api/npm/npm-private/
*/
"registryUrl": "",
/**
* A list of custom strings that "rush setup" should add to the user's ~/.npmrc file at the time
* when the token is updated. This could be used for example to configure the company registry
* to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush
* operations like "rush add" and "rush install", which get their mappings from the monorepo's
* common/config/rush/.npmrc file).
*
* NOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful
* about adding settings that may interfere with other work outside the monorepo.
*/
"userNpmrcLinesToAdd": [
// "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/"
],
/**
* (Required) Specifies the URL of the Artifactory control panel where the user can generate
* an API key. This URL is printed after the "visitWebsite" message.
* It should look something like this example: https://your-company.jfrog.io/
* Specify an empty string to suppress this line entirely.
*/
"artifactoryWebsiteUrl": "",
/**
* Uncomment this line to specify the type of credential to save in the user's ~/.npmrc file.
* The default is "password", which means the user's API token will be traded in for an
* npm password specific to that registry. Optionally you can specify "authToken", which
* will save the user's API token as credentials instead.
*/
// "credentialType": "password",
/**
* These settings allow the "rush setup" interactive prompts to be customized, for
* example with messages specific to your team or configuration. Specify an empty string
* to suppress that message entirely.
*/
"messageOverrides": {
/**
* Overrides the message that normally says:
* "This monorepo consumes packages from an Artifactory private NPM registry."
*/
// "introduction": "",
/**
* Overrides the message that normally says:
* "Please contact the repository maintainers for help with setting up an Artifactory user account."
*/
// "obtainAnAccount": "",
/**
* Overrides the message that normally says:
* "Please open this URL in your web browser:"
*
* The "artifactoryWebsiteUrl" string is printed after this message.
*/
// "visitWebsite": "",
/**
* Overrides the message that normally says:
* "Your user name appears in the upper-right corner of the JFrog website."
*/
// "locateUserName": "",
/**
* Overrides the message that normally says:
* "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key'
* button if you haven't already done so previously."
*/
// "locateApiKey": ""
/**
* Overrides the message that normally prompts:
* "What is your Artifactory user name?"
*/
// "userNamePrompt": ""
/**
* Overrides the message that normally prompts:
* "What is your Artifactory API key?"
*/
// "apiKeyPrompt": ""
}
}
}
+160
View File
@@ -0,0 +1,160 @@
/**
* This configuration file manages Rush's build cache feature.
* More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json",
/**
* (Required) EXPERIMENTAL - Set this to true to enable the build cache feature.
*
* See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature.
*/
"buildCacheEnabled": false,
/**
* (Required) Choose where project build outputs will be cached.
*
* Possible values: "local-only", "azure-blob-storage", "amazon-s3"
*/
"cacheProvider": "local-only",
/**
* Setting this property overrides the cache entry ID. If this property is set, it must contain
* a [hash] token.
*
* Other available tokens:
* - [projectName] Example: "@my-scope/my-project"
* - [projectName:normalize] Example: "my-scope+my-project"
* - [phaseName] Example: "_phase:test/api"
* - [phaseName:normalize] Example: "_phase:test+api"
* - [phaseName:trimPrefix] Example: "test/api"
* - [os] Example: "win32"
* - [arch] Example: "x64"
*/
// "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]"
/**
* (Optional) Salt to inject during calculation of the cache key. This can be used to invalidate the cache for all projects when the salt changes.
*/
// "cacheHashSalt": "1",
/**
* Use this configuration with "cacheProvider"="azure-blob-storage"
*/
"azureBlobStorageConfiguration": {
/**
* (Required) The name of the the Azure storage account to use for build cache.
*/
// "storageAccountName": "example",
/**
* (Required) The name of the container in the Azure storage account to use for build cache.
*/
// "storageContainerName": "my-container",
/**
* The Azure environment the storage account exists in. Defaults to AzurePublicCloud.
*
* Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment"
*/
// "azureEnvironment": "AzurePublicCloud",
/**
* An optional prefix for cache item blob names.
*/
// "blobPrefix": "my-prefix",
/**
* If set to true, allow writing to the cache. Defaults to false.
*/
// "isCacheWriteAllowed": true,
/**
* The Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'InteractiveBrowser' otherwise.
*/
// "loginFlow": "InteractiveBrowser",
/**
* If set to true, reading the cache requires authentication. Defaults to false.
*/
// "readRequiresAuthentication": true
},
/**
* Use this configuration with "cacheProvider"="amazon-s3"
*/
"amazonS3Configuration": {
/**
* (Required unless s3Endpoint is specified) The name of the bucket to use for build cache.
* Example: "my-bucket"
*/
// "s3Bucket": "my-bucket",
/**
* (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache.
* This should not include any path; use the s3Prefix to set the path.
* Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000"
*/
// "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com",
/**
* (Required) The Amazon S3 region of the bucket to use for build cache.
* Example: "us-east-1"
*/
// "s3Region": "us-east-1",
/**
* An optional prefix ("folder") for cache items. It should not start with "/".
*/
// "s3Prefix": "my-prefix",
/**
* If set to true, allow writing to the cache. Defaults to false.
*/
// "isCacheWriteAllowed": true
},
/**
* Use this configuration with "cacheProvider"="http"
*/
"httpConfiguration": {
/**
* (Required) The URL of the server that stores the caches.
* Example: "https://build-cacches.example.com/"
*/
// "url": "https://build-cacches.example.com/",
/**
* (Optional) The HTTP method to use when writing to the cache (defaults to PUT).
* Should be one of PUT, POST, or PATCH.
* Example: "PUT"
*/
// "uploadMethod": "PUT",
/**
* (Optional) HTTP headers to pass to the cache server.
* Example: { "X-HTTP-Company-Id": "109283" }
*/
// "headers": {},
/**
* (Optional) Shell command that prints the authorization token needed to communicate with the
* cache server, and exits with exit code 0. This command will be executed from the root of
* the monorepo.
* Example: { "exec": "node", "args": ["common/scripts/auth.js"] }
*/
// "tokenHandler": { "exec": "node", "args": ["common/scripts/auth.js"] },
/**
* (Optional) Prefix for cache keys.
* Example: "my-company-"
*/
// "cacheKeyPrefix": "",
/**
* (Optional) If set to true, allow writing to the cache. Defaults to false.
*/
// "isCacheWriteAllowed": true
}
}
+22
View File
@@ -0,0 +1,22 @@
/**
* This configuration file manages Rush's cobuild feature.
* More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json",
/**
* (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature.
* RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string,
* otherwise the cobuild feature will be disabled.
*/
"cobuildFeatureEnabled": false,
/**
* (Required) Choose where cobuild lock will be acquired.
*
* The lock provider is registered by the rush plugins.
* For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider.
*/
"cobuildLockProvider": "redis"
}
+230
View File
@@ -0,0 +1,230 @@
/**
* This configuration file defines custom commands for the "rush" command-line.
* More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json",
"phases": [
{
"name": "_phase:build",
"dependencies": {
"upstream": ["_phase:build"]
},
"ignoreMissingScript": true,
"allowWarningsOnSuccess": false
},
{
"name": "_phase:validate",
"dependencies": {
"self": ["_phase:build"],
"upstream": ["_phase:validate", "_phase:build"]
},
"ignoreMissingScript": true,
"allowWarningsOnSuccess": false
},
{
"name": "_phase:bundle",
"dependencies": {
"self": ["_phase:build"]
},
"ignoreMissingScript": true,
"allowWarningsOnSuccess": false
},
],
"commands": [
{
"commandKind": "phased",
"name": "build",
"summary": "build",
"phases": ["_phase:build"],
"enableParallelism": true,
"incremental": true,
"watchOptions": {
"alwaysWatch": false,
"watchPhases": ["_phase:build"]
}
},
{
"commandKind": "phased",
"name": "validate",
"phases": ["_phase:validate"],
"summary": "validate",
"enableParallelism": true,
"incremental": true
},
{
"commandKind": "bulk",
"name": "format",
"summary": "Format",
"description": "Perform a formatting",
"enableParallelism": true,
"incremental": false,
"ignoreMissingScript": true,
"safeForSimultaneousRushProcesses": true,
"disableBuildCache": true
},
{
"commandKind": "bulk",
"name": "lint",
"summary": "Lint",
"description": "Linting",
"enableParallelism": true,
"incremental": false,
"ignoreMissingScript": true,
"safeForSimultaneousRushProcesses": true,
"disableBuildCache": true
},
{
"commandKind": "bulk",
"name": "lint:fix",
"summary": "Lint & fix",
"description": "Linting and fixing",
"enableParallelism": true,
"incremental": false,
"ignoreMissingScript": true,
"safeForSimultaneousRushProcesses": true,
"disableBuildCache": true
}
],
/**
* Custom "parameters" introduce new parameters for specified Rush command-line commands.
* For example, you might define a "--production" parameter for the "rush build" command.
*/
"parameters": [
{
"parameterKind": "flag",
"longName": "--lite",
"shortName": "-l",
"description": "Enable Heft lite building option, will skip some phases.",
"associatedCommands": ["build"]
},
{
"parameterKind": "flag",
"longName": "--clean",
"description": "Enable Heft clean building option",
"associatedCommands": ["build"]
},
// {
// /**
// * (Required) Determines the type of custom parameter.
// * A "flag" is a custom command-line parameter whose presence acts as an on/off switch.
// */
// "parameterKind": "flag",
//
// /**
// * (Required) The long name of the parameter. It must be lower-case and use dash delimiters.
// */
// "longName": "--my-flag",
//
// /**
// * An optional alternative short name for the parameter. It must be a dash followed by a single
// * lower-case or upper-case letter, which is case-sensitive.
// *
// * NOTE: The Rush developers recommend that automation scripts should always use the long name
// * to improve readability. The short name is only intended as a convenience for humans.
// * The alphabet letters run out quickly, and are difficult to memorize, so *only* use
// * a short name if you expect the parameter to be needed very often in everyday operations.
// */
// "shortName": "-m",
//
// /**
// * (Required) A long description to be shown in the command-line help.
// *
// * Whenever you introduce commands/parameters, taking a little time to write meaningful
// * documentation can make a big difference for the developer experience in your repo.
// */
// "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects",
//
// /**
// * (Required) A list of custom commands and/or built-in Rush commands that this parameter may
// * be used with. The parameter will be appended to the shell command that Rush invokes.
// */
// "associatedCommands": ["build", "rebuild"]
// },
//
// {
// /**
// * (Required) Determines the type of custom parameter.
// * A "string" is a custom command-line parameter whose value is a simple text string.
// */
// "parameterKind": "string",
// "longName": "--my-string",
// "description": "A custom string parameter for the \"my-global-command\" custom command",
//
// "associatedCommands": ["my-global-command"],
//
// /**
// * The name of the argument, which will be shown in the command-line help.
// *
// * For example, if the parameter name is '--count" and the argument name is "NUMBER",
// * then the command-line help would display "--count NUMBER". The argument name must
// * be comprised of upper-case letters, numbers, and underscores. It should be kept short.
// */
// "argumentName": "SOME_TEXT",
//
// /**
// * If true, this parameter must be included with the command. The default is false.
// */
// "required": false
// },
//
// {
// /**
// * (Required) Determines the type of custom parameter.
// * A "choice" is a custom command-line parameter whose argument must be chosen from a list of
// * allowable alternatives.
// */
// "parameterKind": "choice",
// "longName": "--my-choice",
// "description": "A custom choice parameter for the \"my-global-command\" custom command",
//
// "associatedCommands": ["my-global-command"],
//
// /**
// * If true, this parameter must be included with the command. The default is false.
// */
// "required": false,
//
// /**
// * Normally if a parameter is omitted from the command line, it will not be passed
// * to the shell command. this value will be inserted by default. Whereas if a "defaultValue"
// * is defined, the parameter will always be passed to the shell command, and will use the
// * default value if unspecified. The value must be one of the defined alternatives.
// */
// "defaultValue": "vanilla",
//
// /**
// * (Required) A list of alternative argument values that can be chosen for this parameter.
// */
// "alternatives": [
// {
// /**
// * A token that is one of the alternatives that can be used with the choice parameter,
// * e.g. "vanilla" in "--flavor vanilla".
// */
// "name": "vanilla",
//
// /**
// * A detailed description for the alternative that can be shown in the command-line help.
// *
// * Whenever you introduce commands/parameters, taking a little time to write meaningful
// * documentation can make a big difference for the developer experience in your repo.
// */
// "description": "Use the vanilla flavor (the default)"
// },
//
// {
// "name": "chocolate",
// "description": "Use the chocolate flavor"
// },
//
// {
// "name": "strawberry",
// "description": "Use the strawberry flavor"
// }
// ]
// }
]
}
+77
View File
@@ -0,0 +1,77 @@
/**
* This configuration file specifies NPM dependency version selections that affect all projects
* in a Rush repo. More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json",
/**
* A table that specifies a "preferred version" for a given NPM package. This feature is typically used
* to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies.
*
* The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into
* the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager
* will calculate versions. The specific effect depends on your package manager. Generally it will have no
* effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be
* achieved using the pnpmfile.js hook. See the Rush documentation for more details.
*
* After modifying this field, it's recommended to run "rush update --full" so that the package manager
* will recalculate all version selections.
*/
"preferredVersions": {
/**
* When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo,
* instead of the latest version.
*/
// "some-library": "1.2.3"
},
/**
* When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions,
* except in cases where different projects specify different version ranges for a given dependency. For older
* package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause
* trouble for indirect dependencies with incompatible peerDependencies ranges.
*
* The default value is true. If you're encountering installation errors related to peer dependencies,
* it's recommended to set this to false.
*
* After modifying this field, it's recommended to run "rush update --full" so that the package manager
* will recalculate all version selections.
*/
// "implicitlyPreferredVersions": false,
/**
* If you would like the version specifiers for your dependencies to be consistent, then
* uncomment this line. This is effectively similar to running "rush check" before any
* of the following commands:
*
* rush install, rush update, rush link, rush version, rush publish
*
* In some cases you may want this turned on, but need to allow certain packages to use a different
* version. In those cases, you will need to add an entry to the "allowedAlternativeVersions"
* section of the common-versions.json.
*
* In the case that subspaces is enabled, this setting will take effect at a subspace level.
*/
// "ensureConsistentVersions": true,
/**
* The "rush check" command can be used to enforce that every project in the repo must specify
* the same SemVer range for a given dependency. However, sometimes exceptions are needed.
* The allowedAlternativeVersions table allows you to list other SemVer ranges that will be
* accepted by "rush check" for a given dependency.
*
* IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE
* USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO).
* This design avoids unnecessary churn in this file.
*/
"allowedAlternativeVersions": {
/**
* For example, allow some projects to use an older TypeScript compiler
* (in addition to whatever "usual" version is being used by other projects in the repo):
*/
// "typescript": [
// "~2.4.0"
// ]
}
}
+29
View File
@@ -0,0 +1,29 @@
/**
* This configuration file allows repo maintainers to configure extra details to be
* printed alongside certain Rush messages. More documentation is available on the
* Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json",
/**
* Custom tips allow you to annotate Rush's console messages with advice tailored for
* your specific monorepo.
*/
"customTips": [
// {
// /**
// * (REQUIRED) An identifier indicating a message that may be printed by Rush.
// * If that message is printed, then this custom tip will be shown.
// * The list of available tip identifiers can be found on this page:
// * https://rushjs.io/pages/maintainer/custom_tips/
// */
// "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS",
//
// /**
// * (REQUIRED) The message text to be displayed for this tip.
// */
// "message": "For additional troubleshooting information, refer this wiki article:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch"
// }
]
}
+121
View File
@@ -0,0 +1,121 @@
/**
* This configuration file allows repo maintainers to enable and disable experimental
* Rush features. More documentation is available on the Rush website: https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json",
/**
* By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'.
* Set this option to true to pass '--frozen-lockfile' instead for faster installs.
*/
// "usePnpmFrozenLockfileForRushInstall": true,
/**
* By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'.
* Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes.
*/
// "usePnpmPreferFrozenLockfileForRushUpdate": true,
/**
* By default, 'rush update' runs as a single operation.
* Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install.
* Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs.
*/
// "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate": true,
/**
* If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies.
* Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not
* cause hash changes.
*/
// "omitImportersFromPreventManualShrinkwrapChanges": true,
/**
* If true, the chmod field in temporary project tar headers will not be normalized.
* This normalization can help ensure consistent tarball integrity across platforms.
*/
// "noChmodFieldInTarHeaderNormalization": true,
/**
* If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings.
* This will not replay warnings from the cached build.
*/
// "buildCacheWithAllowWarningsInSuccessfulBuild": true,
/**
* If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings.
* This will not replay warnings from the skipped build.
*/
// "buildSkipWithAllowWarningsInSuccessfulBuild": true,
/**
* If true, perform a clean install after when running `rush install` or `rush update` if the
* `.npmrc` file has changed since the last install.
*/
// "cleanInstallAfterNpmrcChanges": true,
/**
* If true, print the outputs of shell commands defined in event hooks to the console.
*/
// "printEventHooksOutputToConsole": true,
/**
* If true, Rush will not allow node_modules in the repo folder or in parent folders.
*/
// "forbidPhantomResolvableNodeModulesFolders": true,
/**
* (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot
* correctly satisfy versioning requirements without installing duplicate copies of a package inside the
* node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally
* installed by making a symlink to the local project source folder. PNPM's "injected dependencies"
* feature provides a model for copying the local project folder into node_modules, however copying
* must occur AFTER the dependency project is built and BEFORE the consuming project starts to build.
* The "pnpm-sync" tool manages this operation; see its documentation for details.
* Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies
* by invoking "pnpm-sync" during the build.
*/
// "usePnpmSyncForInjectedDependencies": true,
/**
* If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`.
*/
// "generateProjectImpactGraphDuringRushUpdate": true,
/**
* If true, when running in watch mode, Rush will check for phase scripts named `_phase:<name>:ipc` and run them instead
* of `_phase:<name>` if they exist. The created child process will be provided with an IPC channel and expected to persist
* across invocations.
*/
// "useIPCScriptsInWatchMode": true,
/**
* (UNDER DEVELOPMENT) The Rush alerts feature provides a way to send announcements to engineers
* working in the monorepo, by printing directly in the user's shell window when they invoke Rush commands.
* This ensures that important notices will be seen by anyone doing active development, since people often
* ignore normal discussion group messages or don't know to subscribe.
*/
// "rushAlerts": true,
/**
* When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache.
*/
// "allowCobuildWithoutCache": true,
/**
* By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes.
* When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations.
*/
// "enableSubpathScan": true,
/**
* Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending
* on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies`
* in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different
* subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume
* each other's packages via the NPM registry.
*/
// "exemptDecoupledDependenciesBetweenSubspaces": false
}
+331
View File
@@ -0,0 +1,331 @@
/**
* This configuration file provides settings specific to the PNPM package manager.
* More documentation is available on the Rush website: https://rushjs.io
*
* Rush normally looks for this file in `common/config/rush/pnpm-config.json`. However,
* if `subspacesEnabled` is true in subspaces.json, then Rush will instead first look
* for `common/config/subspaces/<name>/pnpm-config.json`. (If the file exists in both places,
* then the file under `common/config/rush` is ignored.)
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json",
/**
* If true, then `rush install` and `rush update` will use the PNPM workspaces feature
* to perform the install, instead of the old model where Rush generated the symlinks
* for each projects's node_modules folder.
*
* When using workspaces, Rush will generate a `common/temp/pnpm-workspace.yaml` file referencing
* all local projects to install. Rush will also generate a `.pnpmfile.cjs` shim which implements
* Rush-specific features such as preferred versions. The user's `common/config/rush/.pnpmfile.cjs`
* is invoked by the shim.
*
* This option is strongly recommended. The default value is false.
*/
"useWorkspaces": true,
/**
* This setting determines how PNPM chooses version numbers during `rush update`.
* For example, suppose `lib-x@3.0.0` depends on `"lib-y": "^1.2.3"` whose latest major
* releases are `1.8.9` and `2.3.4`. The resolution mode `lowest-direct` might choose
* `lib-y@1.2.3`, wheres `highest` will choose 1.8.9, and `time-based` will pick the
* highest compatible version at the time when `lib-x@3.0.0` itself was published (ensuring
* that the version could have been tested by the maintainer of "lib-x"). For local workspace
* projects, `time-based` instead works like `lowest-direct`, avoiding upgrades unless
* they are explicitly requested. Although `time-based` is the most robust option, it may be
* slightly slower with registries such as npmjs.com that have not implemented an optimization.
*
* IMPORTANT: Be aware that PNPM 8.0.0 initially defaulted to `lowest-direct` instead of
* `highest`, but PNPM reverted this decision in 8.6.12 because it caused confusion for users.
* Rush version 5.106.0 and newer avoids this confusion by consistently defaulting to
* `highest` when `resolutionMode` is not explicitly set in pnpm-config.json or .npmrc,
* regardless of your PNPM version.
*
* PNPM documentation: https://pnpm.io/npmrc#resolution-mode
*
* Possible values are: `highest`, `time-based`, and `lowest-direct`.
* The default is `highest`.
*/
// "resolutionMode": "time-based",
/**
* This setting determines whether PNPM will automatically install (non-optional)
* missing peer dependencies instead of reporting an error. Doing so conveniently
* avoids the need to specify peer versions in package.json, but in a large monorepo
* this often creates worse problems. The reason is that peer dependency behavior
* is inherently complicated, and it is easier to troubleshoot consequences of an explicit
* version than an invisible heuristic. The original NPM RFC discussion pointed out
* some other problems with this feature: https://github.com/npm/rfcs/pull/43
* IMPORTANT: Without Rush, the setting defaults to true for PNPM 8 and newer; however,
* as of Rush version 5.109.0 the default is always false unless `autoInstallPeers`
* is specified in pnpm-config.json or .npmrc, regardless of your PNPM version.
* PNPM documentation: https://pnpm.io/npmrc#auto-install-peers
* The default value is false.
*/
// "autoInstallPeers": false,
/**
* If true, then Rush will add the `--strict-peer-dependencies` command-line parameter when
* invoking PNPM. This causes `rush update` to fail if there are unsatisfied peer dependencies,
* which is an invalid state that can cause build failures or incompatible dependency versions.
* (For historical reasons, JavaScript package managers generally do not treat this invalid
* state as an error.)
*
* PNPM documentation: https://pnpm.io/npmrc#strict-peer-dependencies
*
* The default value is false to avoid legacy compatibility issues.
* It is strongly recommended to set `strictPeerDependencies=true`.
*/
// "strictPeerDependencies": true,
/**
* Environment variables that will be provided to PNPM.
*/
// "environmentVariables": {
// "NODE_OPTIONS": {
// "value": "--max-old-space-size=4096",
// "override": false
// }
// },
/**
* Specifies the location of the PNPM store. There are two possible values:
*
* - `local` - use the `pnpm-store` folder in the current configured temp folder:
* `common/temp/pnpm-store` by default.
* - `global` - use PNPM's global store, which has the benefit of being shared
* across multiple repo folders, but the disadvantage of less isolation for builds
* (for example, bugs or incompatibilities when two repos use different releases of PNPM)
*
* In both cases, the store path can be overridden by the environment variable `RUSH_PNPM_STORE_PATH`.
*
* The default value is `local`.
*/
// "pnpmStore": "global",
/**
* If true, then `rush install` will report an error if manual modifications
* were made to the PNPM shrinkwrap file without running `rush update` afterwards.
*
* This feature protects against accidental inconsistencies that may be introduced
* if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this
* feature is enabled, `rush update` will append a hash to the file as a YAML comment,
* and then `rush update` and `rush install` will validate the hash. Note that this
* does not prohibit manual modifications, but merely requires `rush update` be run
* afterwards, ensuring that PNPM can report or repair any potential inconsistencies.
*
* To temporarily disable this validation when invoking `rush install`, use the
* `--bypass-policy` command-line parameter.
*
* The default value is false.
*/
// "preventManualShrinkwrapChanges": true,
/**
* When a project uses `workspace:` to depend on another Rush project, PNPM normally installs
* it by creating a symlink under `node_modules`. This generally works well, but in certain
* cases such as differing `peerDependencies` versions, symlinking may cause trouble
* such as incorrectly satisfied versions. For such cases, the dependency can be declared
* as "injected", causing PNPM to copy its built output into `node_modules` like a real
* install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/
*
* When using Rush subspaces, these sorts of versioning problems are much more likely if
* `workspace:` refers to a project from a different subspace. This is because the symlink
* would point to a separate `node_modules` tree installed by a different PNPM lockfile.
* A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`,
* which automatically treats all projects from other subspaces as injected dependencies
* without having to manually configure them.
*
* NOTE: Use carefully -- excessive file copying can slow down the `rush install` and
* `pnpm-sync` operations if too many dependencies become injected.
*
* The default value is false.
*/
// "alwaysInjectDependenciesFromOtherSubspaces": false,
/**
* Defines the policies to be checked for the `pnpm-lock.yaml` file.
*/
"pnpmLockfilePolicies": {
/**
* This policy will cause "rush update" to report an error if `pnpm-lock.yaml` contains
* any SHA1 integrity hashes.
*
* For each NPM dependency, `pnpm-lock.yaml` normally stores an `integrity` hash. Although
* its main purpose is to detect corrupted or truncated network requests, this hash can also
* serve as a security fingerprint to protect against attacks that would substitute a
* malicious tarball, for example if a misconfigured .npmrc caused a machine to accidentally
* download a matching package name+version from npmjs.com instead of the private NPM registry.
* NPM originally used a SHA1 hash; this was insecure because an attacker can too easily craft
* a tarball with a matching fingerprint. For this reason, NPM later deprecated SHA1 and
* instead adopted a cryptographically strong SHA512 hash. Nonetheless, SHA1 hashes can
* occasionally reappear during "rush update", for example due to missing metadata fallbacks
* (https://github.com/orgs/pnpm/discussions/6194) or an incompletely migrated private registry.
* The `disallowInsecureSha1` policy prevents this, avoiding potential security/compliance alerts.
*/
// "disallowInsecureSha1": {
// /**
// * Enables the "disallowInsecureSha1" policy. The default value is false.
// */
// "enabled": true,
//
// /**
// * In rare cases, a private NPM registry may continue to serve SHA1 hashes for very old
// * package versions, perhaps due to a caching issue or database migration glitch. To avoid
// * having to disable the "disallowInsecureSha1" policy for the entire monorepo, the problematic
// * package versions can be individually ignored. The "exemptPackageVersions" key is the
// * package name, and the array value lists exact version numbers to be ignored.
// */
// "exemptPackageVersions": {
// "example1": ["1.0.0"],
// "example2": ["2.0.0", "2.0.1"]
// }
// }
},
/**
* The "globalOverrides" setting provides a simple mechanism for overriding version selections
* for all dependencies of all projects in the monorepo workspace. The settings are copied
* into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated
* by Rush during installation.
*
* Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by
* `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`,
* and `globalOverrides` has lowest precedence.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmoverrides
*/
"globalOverrides": {
// "example1": "^1.0.0",
// "example2": "npm:@company/example2@^1.0.0"
},
/**
* The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors
* that are reported during installation with `strictPeerDependencies=true`. The settings are copied
* into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated
* by Rush during installation.
*
* Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by
* `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`,
* and `globalOverrides` has lowest precedence.
*
* https://pnpm.io/package_json#pnpmpeerdependencyrules
*/
"globalPeerDependencyRules": {
// "ignoreMissing": ["@eslint/*"],
// "allowedVersions": { "react": "17" },
// "allowAny": ["@babel/*"]
},
/**
* The `globalPackageExtension` setting provides a way to patch arbitrary package.json fields
* for any PNPM dependency of the monorepo. The settings are copied into the `pnpm.packageExtensions`
* field of the `common/temp/package.json` file that is generated by Rush during installation.
* The `globalPackageExtension` setting has similar capabilities as `.pnpmfile.cjs` but without
* the downsides of an executable script (nondeterminism, unreliable caching, performance concerns).
*
* Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by
* `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`,
* and `globalOverrides` has lowest precedence.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions
*/
"globalPackageExtensions": {
// "fork-ts-checker-webpack-plugin": {
// "dependencies": {
// "@babel/core": "1"
// },
// "peerDependencies": {
// "eslint": ">= 6"
// },
// "peerDependenciesMeta": {
// "eslint": {
// "optional": true
// }
// }
// }
},
/**
* The `globalNeverBuiltDependencies` setting suppresses the `preinstall`, `install`, and `postinstall`
* lifecycle events for the specified NPM dependencies. This is useful for scripts with poor practices
* such as downloading large binaries without retries or attempting to invoke OS tools such as
* a C++ compiler. (PNPM's terminology refers to these lifecycle events as "building" a package;
* it has nothing to do with build system operations such as `rush build` or `rushx build`.)
* The settings are copied into the `pnpm.neverBuiltDependencies` field of the `common/temp/package.json`
* file that is generated by Rush during installation.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies
*/
"globalNeverBuiltDependencies": [
// "fsevents"
],
/**
* The `globalIgnoredOptionalDependencies` setting suppresses the installation of optional NPM
* dependencies specified in the list. This is useful when certain optional dependencies are
* not needed in your environment, such as platform-specific packages or dependencies that
* fail during installation but are not critical to your project.
* These settings are copied into the `pnpm.overrides` field of the `common/temp/package.json`
* file that is generated by Rush during installation, instructing PNPM to ignore the specified
* optional dependencies.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmignoredoptionaldependencies
*/
"globalIgnoredOptionalDependencies": [
// "fsevents"
],
/**
* The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package
* versions that the NPM registry reports as being deprecated. This is useful if the
* deprecated package is an indirect dependency of an external package that has not released a fix.
* The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json`
* file that is generated by Rush during installation.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions
*
* If you are working to eliminate a deprecated version, it's better to specify `allowedDeprecatedVersions`
* in the package.json file for individual Rush projects.
*/
"globalAllowedDeprecatedVersions": {
// "request": "*"
},
/**
* (THIS FIELD IS MACHINE GENERATED) The "globalPatchedDependencies" field is updated automatically
* by the `rush-pnpm patch-commit` command. It is a dictionary, where the key is an NPM package name
* and exact version, and the value is a relative path to the associated patch file.
*
* PNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies
*/
"globalPatchedDependencies": { },
/**
* (USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into
* the `common/temp/package.json` file that is generated by Rush during installation.
* This provides a way to experiment with new PNPM features. These settings will override
* any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`.
*
* USAGE OF THIS SETTING IS NOT SUPPORTED BY THE RUSH MAINTAINERS AND MAY CAUSE RUSH
* TO MALFUNCTION. If you encounter a missing PNPM setting that you believe should
* be supported, please create a GitHub issue or PR. Note that Rush does not aim to
* support every possible PNPM setting, but rather to promote a battle-tested installation
* strategy that is known to provide a good experience for large teams with lots of projects.
*/
"unsupportedPackageJsonSettings": {
// "dependencies": {
// "not-a-good-practice": "*"
// },
// "scripts": {
// "do-something": "echo Also not a good practice"
// },
// "pnpm": { "futurePnpmFeature": true }
}
}
+5866
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f"
}
+29
View File
@@ -0,0 +1,29 @@
/**
* This configuration file manages Rush's plugin feature.
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json",
"plugins": [
/**
* Each item configures a plugin to be loaded by Rush.
*/
// {
// /**
// * The name of the NPM package that provides the plugin.
// */
// "packageName": "@scope/my-rush-plugin",
// /**
// * The name of the plugin. This can be found in the "pluginName"
// * field of the "rush-plugin-manifest.json" file in the NPM package folder.
// */
// "pluginName": "my-plugin-name",
// /**
// * The name of a Rush autoinstaller that will be used for installation, which
// * can be created using "rush init-autoinstaller". Add the plugin's NPM package
// * to the package.json "dependencies" of your autoinstaller, then run
// * "rush update-autoinstaller".
// */
// "autoinstallerName": "rush-plugins"
// }
]
}
+35
View File
@@ -0,0 +1,35 @@
/**
* This configuration file manages the experimental "subspaces" feature for Rush,
* which allows multiple PNPM lockfiles to be used in a single Rush workspace.
* For full documentation, please see https://rushjs.io
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json",
/**
* Set this flag to "true" to enable usage of subspaces.
*/
"subspacesEnabled": false,
/**
* (DEPRECATED) This is a temporary workaround for migrating from an earlier prototype
* of this feature: https://github.com/microsoft/rushstack/pull/3481
* It allows subspaces with only one project to store their config files in the project folder.
*/
"splitWorkspaceCompatibility": false,
/**
* When a command such as "rush update" is invoked without the "--subspace" or "--to"
* parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces,
* this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this
* mistake by always requiring selection parameters for commands such as "rush update".
*/
"preventSelectingAllSubspaces": false,
/**
* The list of subspace names, which should be lowercase alphanumeric words separated by
* hyphens, for example "my-subspace". The corresponding config files will have paths
* such as "common/config/subspaces/my-subspace/package-lock.yaml".
*/
"subspaceNames": []
}
+102
View File
@@ -0,0 +1,102 @@
/**
* This is configuration file is used for advanced publishing configurations with Rush.
* More documentation is available on the Rush website: https://rushjs.io
*/
/**
* A list of version policy definitions. A "version policy" is a custom package versioning
* strategy that affects "rush change", "rush version", and "rush publish". The strategy applies
* to a set of projects that are specified using the "versionPolicyName" field in rush.json.
*/
[
// {
// /**
// * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion").
// *
// * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This
// * strategy is appropriate for a set of packages that act as selectable components of a
// * unified product. The entire set of packages are always published together, and always share
// * the same NPM version number. When the packages depend on other packages in the set, the
// * SemVer range is usually restricted to a single version.
// */
// "definitionName": "lockStepVersion",
//
// /**
// * (Required) The name that will be used for the "versionPolicyName" field in rush.json.
// * This name is also used command-line parameters such as "--version-policy"
// * and "--to-version-policy".
// */
// "policyName": "MyBigFramework",
//
// /**
// * (Required) The current version. All packages belonging to the set should have this version
// * in the current branch. When bumping versions, Rush uses this to determine the next version.
// * (The "version" field in package.json is NOT considered.)
// */
// "version": "1.0.0",
//
// /**
// * (Required) The type of bump that will be performed when publishing the next release.
// * When creating a release branch in Git, this field should be updated according to the
// * type of release.
// *
// * Valid values are: "prerelease", "preminor", "minor", "patch", "major"
// */
// "nextBump": "prerelease",
//
// /**
// * (Optional) If specified, all packages in the set share a common CHANGELOG.md file.
// * This file is stored with the specified "main" project, which must be a member of the set.
// *
// * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each
// * package in the set.
// */
// "mainProject": "my-app",
//
// /**
// * (Optional) If enabled, the "rush change" command will prompt the user for their email address
// * and include it in the JSON change files. If an organization maintains multiple repos, tracking
// * this contact information may be useful for a service that automatically upgrades packages and
// * needs to notify engineers whose change may be responsible for a downstream build break. It might
// * also be useful for crediting contributors. Rush itself does not do anything with the collected
// * email addresses. The default value is "false".
// */
// // "includeEmailInChangeFile": true
// },
//
// {
// /**
// * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion").
// *
// * The "individualVersion" mode specifies that the projects will use "individual versioning".
// * This is the typical NPM model where each package has an independent version number
// * and CHANGELOG.md file. Although a single CI definition is responsible for publishing the
// * packages, they otherwise don't have any special relationship. The version bumping will
// * depend on how developers answer the "rush change" questions for each package that
// * is changed.
// */
// "definitionName": "individualVersion",
//
// "policyName": "MyRandomLibraries",
//
// /**
// * (Optional) This can be used to enforce that all packages in the set must share a common
// * major version number, e.g. because they are from the same major release branch.
// * It can also be used to discourage people from accidentally making "MAJOR" SemVer changes
// * inappropriately. The minor/patch version parts will be bumped independently according
// * to the types of changes made to each project, according to the "rush change" command.
// */
// "lockedMajor": 3,
//
// /**
// * (Optional) When publishing is managed by Rush, by default the "rush change" command will
// * request changes for any projects that are modified by a pull request. These change entries
// * will produce a CHANGELOG.md file. If you author your CHANGELOG.md manually or announce updates
// * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects
// * belonging to this version policy.
// */
// "exemptFromRushChange": false,
//
// // "includeEmailInChangeFile": true
// }
]
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
#
# This is an example Git hook for use with Rush. To enable this hook, rename this file
# to "commit-msg" and then run "rush install", which will copy it from common/git-hooks
# to the .git/hooks folder.
#
# TO LEARN MORE ABOUT GIT HOOKS
#
# The Git documentation is here: https://git-scm.com/docs/githooks
# Some helpful resources: https://githooks.com
#
# ABOUT THIS EXAMPLE
#
# The commit-msg hook is called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero status after issuing
# an appropriate message if it wants to stop the commit. The hook is allowed to edit
# the commit message file.
# This example enforces that commit message should contain a minimum amount of
# description text.
if [ `cat $1 | wc -w` -lt 3 ]; then
echo ""
echo "Invalid commit message: The message must contain at least 3 words."
exit 1
fi
+31
View File
@@ -0,0 +1,31 @@
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
//
// This script is intended for usage in an automated build environment where the Rush command may not have
// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush
// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the
// rush-pnpm command.
//
// An example usage would be:
//
// node common/scripts/install-run-rush-pnpm.js pnpm-command
//
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
//
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See the @microsoft/rush package's LICENSE file for details.
/******/ (() => { // webpackBootstrap
/******/ "use strict";
var __webpack_exports__ = {};
/*!*****************************************************!*\
!*** ./lib-esnext/scripts/install-run-rush-pnpm.js ***!
\*****************************************************/
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
require('./install-run-rush');
//# sourceMappingURL=install-run-rush-pnpm.js.map
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=install-run-rush-pnpm.js.map
+218
View File
@@ -0,0 +1,218 @@
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
//
// This script is intended for usage in an automated build environment where the Rush command may not have
// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush
// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it.
// An example usage would be:
//
// node common/scripts/install-run-rush.js install
//
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
//
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See the @microsoft/rush package's LICENSE file for details.
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 16928:
/*!***********************!*\
!*** external "path" ***!
\***********************/
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 179896:
/*!*********************!*\
!*** external "fs" ***!
\*********************/
/***/ ((module) => {
module.exports = require("fs");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
(() => {
/*!************************************************!*\
!*** ./lib-esnext/scripts/install-run-rush.js ***!
\************************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! path */ 16928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 179896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
/* eslint-disable no-console */
const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run');
const PACKAGE_NAME = '@microsoft/rush';
const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION';
const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH';
function _getRushVersion(logger) {
const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION];
if (rushPreviewVersion !== undefined) {
logger.info(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`);
return rushPreviewVersion;
}
const rushJsonFolder = findRushJsonFolder();
const rushJsonPath = path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME);
try {
const rushJsonContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(rushJsonPath, 'utf-8');
// Use a regular expression to parse out the rushVersion value because rush.json supports comments,
// but JSON.parse does not and we don't want to pull in more dependencies than we need to in this script.
const rushJsonMatches = rushJsonContents.match(/\"rushVersion\"\s*\:\s*\"([0-9a-zA-Z.+\-]+)\"/);
return rushJsonMatches[1];
}
catch (e) {
throw new Error(`Unable to determine the required version of Rush from ${RUSH_JSON_FILENAME} (${rushJsonFolder}). ` +
`The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` +
'using an unexpected syntax.');
}
}
function _getBin(scriptName) {
switch (scriptName.toLowerCase()) {
case 'install-run-rush-pnpm.js':
return 'rush-pnpm';
case 'install-run-rushx.js':
return 'rushx';
default:
return 'rush';
}
}
function _run() {
const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv;
// Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the
// appropriate binary inside the rush package to run
const scriptName = path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath);
const bin = _getBin(scriptName);
if (!nodePath || !scriptPath) {
throw new Error('Unexpected exception: could not detect node path or script path');
}
let commandFound = false;
let logger = { info: console.log, error: console.error };
for (const arg of packageBinArgs) {
if (arg === '-q' || arg === '--quiet') {
// The -q/--quiet flag is supported by both `rush` and `rushx`, and will suppress
// any normal informational/diagnostic information printed during startup.
//
// To maintain the same user experience, the install-run* scripts pass along this
// flag but also use it to suppress any diagnostic information normally printed
// to stdout.
logger = {
info: () => { },
error: console.error
};
}
else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') {
// We either found something that looks like a command (i.e. - doesn't start with a "-"),
// or we found the -h/--help flag, which can be run without a command
commandFound = true;
}
}
if (!commandFound) {
console.log(`Usage: ${scriptName} <command> [args...]`);
if (scriptName === 'install-run-rush-pnpm.js') {
console.log(`Example: ${scriptName} pnpm-command`);
}
else if (scriptName === 'install-run-rush.js') {
console.log(`Example: ${scriptName} build --to myproject`);
}
else {
console.log(`Example: ${scriptName} custom-command`);
}
process.exit(1);
}
runWithErrorAndStatusCode(logger, () => {
const version = _getRushVersion(logger);
logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`);
const lockFilePath = process.env[INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE];
if (lockFilePath) {
logger.info(`Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.`);
}
return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath);
});
}
_run();
//# sourceMappingURL=install-run-rush.js.map
})();
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=install-run-rush.js.map
+31
View File
@@ -0,0 +1,31 @@
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
//
// This script is intended for usage in an automated build environment where the Rush command may not have
// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush
// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the
// rushx command.
//
// An example usage would be:
//
// node common/scripts/install-run-rushx.js custom-command
//
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
//
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See the @microsoft/rush package's LICENSE file for details.
/******/ (() => { // webpackBootstrap
/******/ "use strict";
var __webpack_exports__ = {};
/*!*************************************************!*\
!*** ./lib-esnext/scripts/install-run-rushx.js ***!
\*************************************************/
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
require('./install-run-rush');
//# sourceMappingURL=install-run-rushx.js.map
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=install-run-rushx.js.map
+778
View File
@@ -0,0 +1,778 @@
// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.
//
// This script is intended for usage in an automated build environment where a Node tool may not have
// been preinstalled, or may have an unpredictable version. This script will automatically install the specified
// version of the specified tool (if not already installed), and then pass a command-line to it.
// An example usage would be:
//
// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io
//
// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/
//
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See the @microsoft/rush package's LICENSE file for details.
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 16928:
/*!***********************!*\
!*** external "path" ***!
\***********************/
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 179896:
/*!*********************!*\
!*** external "fs" ***!
\*********************/
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ 370857:
/*!*********************!*\
!*** external "os" ***!
\*********************/
/***/ ((module) => {
module.exports = require("os");
/***/ }),
/***/ 535317:
/*!********************************!*\
!*** external "child_process" ***!
\********************************/
/***/ ((module) => {
module.exports = require("child_process");
/***/ }),
/***/ 832286:
/*!************************************************!*\
!*** ./lib-esnext/utilities/npmrcUtilities.js ***!
\************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ isVariableSetInNpmrcFile: () => (/* binding */ isVariableSetInNpmrcFile),
/* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc),
/* harmony export */ trimNpmrcFileLines: () => (/* binding */ trimNpmrcFileLines)
/* harmony export */ });
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 179896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ 16928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
// IMPORTANT - do not use any non-built-in libraries in this file
/**
* This function reads the content for given .npmrc file path, and also trims
* unusable lines from the .npmrc file.
*
* @returns
* The text of the the .npmrc.
*/
// create a global _combinedNpmrc for cache purpose
const _combinedNpmrcMap = new Map();
function _trimNpmrcFile(options) {
const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax } = options;
const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath);
if (combinedNpmrcFromCache !== undefined) {
return combinedNpmrcFromCache;
}
let npmrcFileLines = [];
if (linesToPrepend) {
npmrcFileLines.push(...linesToPrepend);
}
if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) {
npmrcFileLines.push(...fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n'));
}
if (linesToAppend) {
npmrcFileLines.push(...linesToAppend);
}
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
const resultLines = trimNpmrcFileLines(npmrcFileLines, process.env, supportEnvVarFallbackSyntax);
const combinedNpmrc = resultLines.join('\n');
//save the cache
_combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc);
return combinedNpmrc;
}
/**
*
* @param npmrcFileLines The npmrc file's lines
* @param env The environment variables object
* @param supportEnvVarFallbackSyntax Whether to support fallback values in the form of `${VAR_NAME:-fallback}`
* @returns
*/
function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax) {
var _a;
const resultLines = [];
// This finds environment variable tokens that look like "${VAR_NAME}"
const expansionRegExp = /\$\{([^\}]+)\}/g;
// Comment lines start with "#" or ";"
const commentRegExp = /^\s*[#;]/;
// Trim out lines that reference environment variables that aren't defined
for (let line of npmrcFileLines) {
let lineShouldBeTrimmed = false;
//remove spaces before or after key and value
line = line
.split('=')
.map((lineToTrim) => lineToTrim.trim())
.join('=');
// Ignore comment lines
if (!commentRegExp.test(line)) {
const environmentVariables = line.match(expansionRegExp);
if (environmentVariables) {
for (const token of environmentVariables) {
/**
* Remove the leading "${" and the trailing "}" from the token
*
* ${nameString} -> nameString
* ${nameString-fallbackString} -> name-fallbackString
* ${nameString:-fallbackString} -> name:-fallbackString
*/
const nameWithFallback = token.substring(2, token.length - 1);
let environmentVariableName;
let fallback;
if (supportEnvVarFallbackSyntax) {
/**
* Get the environment variable name and fallback value.
*
* name fallback
* nameString -> nameString undefined
* nameString-fallbackString -> nameString fallbackString
* nameString:-fallbackString -> nameString fallbackString
*/
const matched = nameWithFallback.match(/^([^:-]+)(?:\:?-(.+))?$/);
// matched: [originStr, variableName, fallback]
environmentVariableName = (_a = matched === null || matched === void 0 ? void 0 : matched[1]) !== null && _a !== void 0 ? _a : nameWithFallback;
fallback = matched === null || matched === void 0 ? void 0 : matched[2];
}
else {
environmentVariableName = nameWithFallback;
}
// Is the environment variable and fallback value defined.
if (!env[environmentVariableName] && !fallback) {
// No, so trim this line
lineShouldBeTrimmed = true;
break;
}
}
}
}
if (lineShouldBeTrimmed) {
// Example output:
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
}
else {
resultLines.push(line);
}
}
return resultLines;
}
function _copyAndTrimNpmrcFile(options) {
const { logger, sourceNpmrcPath, targetNpmrcPath } = options;
logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose
logger.info(` --> "${targetNpmrcPath}"`);
const combinedNpmrc = _trimNpmrcFile(options);
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc);
return combinedNpmrc;
}
function syncNpmrc(options) {
const { sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish, logger = {
// eslint-disable-next-line no-console
info: console.log,
// eslint-disable-next-line no-console
error: console.error
}, createIfMissing = false } = options;
const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish');
const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc');
try {
if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) {
// Ensure the target folder exists
if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) {
fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true });
}
return _copyAndTrimNpmrcFile({
sourceNpmrcPath,
targetNpmrcPath,
logger,
...options
});
}
else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) {
// If the source .npmrc doesn't exist and there is one in the target, delete the one in the target
logger.info(`Deleting ${targetNpmrcPath}`); // Verbose
fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath);
}
}
catch (e) {
throw new Error(`Error syncing .npmrc file: ${e}`);
}
}
function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarFallbackSyntax) {
const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`;
//if .npmrc file does not exist, return false directly
if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) {
return false;
}
const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath, supportEnvVarFallbackSyntax });
const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm');
return trimmedNpmrcFile.match(variableKeyRegExp) !== null;
}
//# sourceMappingURL=npmrcUtilities.js.map
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
(() => {
/*!*******************************************!*\
!*** ./lib-esnext/scripts/install-run.js ***!
\*******************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ RUSH_JSON_FILENAME: () => (/* binding */ RUSH_JSON_FILENAME),
/* harmony export */ findRushJsonFolder: () => (/* binding */ findRushJsonFolder),
/* harmony export */ getNpmPath: () => (/* binding */ getNpmPath),
/* harmony export */ installAndRun: () => (/* binding */ installAndRun),
/* harmony export */ runWithErrorAndStatusCode: () => (/* binding */ runWithErrorAndStatusCode)
/* harmony export */ });
/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! child_process */ 535317);
/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 179896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ 370857);
/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! path */ 16928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 832286);
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
/* eslint-disable no-console */
const RUSH_JSON_FILENAME = 'rush.json';
const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER';
const INSTALL_RUN_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_LOCKFILE_PATH';
const INSTALLED_FLAG_FILENAME = 'installed.flag';
const NODE_MODULES_FOLDER_NAME = 'node_modules';
const PACKAGE_JSON_FILENAME = 'package.json';
/**
* Parse a package specifier (in the form of name\@version) into name and version parts.
*/
function _parsePackageSpecifier(rawPackageSpecifier) {
rawPackageSpecifier = (rawPackageSpecifier || '').trim();
const separatorIndex = rawPackageSpecifier.lastIndexOf('@');
let name;
let version = undefined;
if (separatorIndex === 0) {
// The specifier starts with a scope and doesn't have a version specified
name = rawPackageSpecifier;
}
else if (separatorIndex === -1) {
// The specifier doesn't have a version
name = rawPackageSpecifier;
}
else {
name = rawPackageSpecifier.substring(0, separatorIndex);
version = rawPackageSpecifier.substring(separatorIndex + 1);
}
if (!name) {
throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`);
}
return { name, version };
}
let _npmPath = undefined;
/**
* Get the absolute path to the npm executable
*/
function getNpmPath() {
if (!_npmPath) {
try {
if (_isWindows()) {
// We're on Windows
const whereOutput = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('where npm', { stdio: [] }).toString();
const lines = whereOutput.split(os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line);
// take the last result, we are looking for a .cmd command
// see https://github.com/microsoft/rushstack/issues/759
_npmPath = lines[lines.length - 1];
}
else {
// We aren't on Windows - assume we're on *NIX or Darwin
_npmPath = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('command -v npm', { stdio: [] }).toString();
}
}
catch (e) {
throw new Error(`Unable to determine the path to the NPM tool: ${e}`);
}
_npmPath = _npmPath.trim();
if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) {
throw new Error('The NPM executable does not exist');
}
}
return _npmPath;
}
function _ensureFolder(folderPath) {
if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) {
const parentDir = path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath);
_ensureFolder(parentDir);
fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath);
}
}
/**
* Create missing directories under the specified base directory, and return the resolved directory.
*
* Does not support "." or ".." path segments.
* Assumes the baseFolder exists.
*/
function _ensureAndJoinPath(baseFolder, ...pathSegments) {
let joinedPath = baseFolder;
try {
for (let pathSegment of pathSegments) {
pathSegment = pathSegment.replace(/[\\\/]/g, '+');
joinedPath = path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment);
if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) {
fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath);
}
}
}
catch (e) {
throw new Error(`Error building local installation folder (${path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`);
}
return joinedPath;
}
function _getRushTempFolder(rushCommonFolder) {
const rushTempFolder = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME];
if (rushTempFolder !== undefined) {
_ensureFolder(rushTempFolder);
return rushTempFolder;
}
else {
return _ensureAndJoinPath(rushCommonFolder, 'temp');
}
}
/**
* Compare version strings according to semantic versioning.
* Returns a positive integer if "a" is a later version than "b",
* a negative integer if "b" is later than "a",
* and 0 otherwise.
*/
function _compareVersionStrings(a, b) {
const aParts = a.split(/[.-]/);
const bParts = b.split(/[.-]/);
const numberOfParts = Math.max(aParts.length, bParts.length);
for (let i = 0; i < numberOfParts; i++) {
if (aParts[i] !== bParts[i]) {
return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0);
}
}
return 0;
}
/**
* Resolve a package specifier to a static version
*/
function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) {
if (!version) {
version = '*'; // If no version is specified, use the latest version
}
if (version.match(/^[a-zA-Z0-9\-\+\.]+$/)) {
// If the version contains only characters that we recognize to be used in static version specifiers,
// pass the version through
return version;
}
else {
// version resolves to
try {
const rushTempFolder = _getRushTempFolder(rushCommonFolder);
const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush');
(0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({
sourceNpmrcFolder,
targetNpmrcFolder: rushTempFolder,
logger,
supportEnvVarFallbackSyntax: false
});
const npmPath = getNpmPath();
// This returns something that looks like:
// ```
// [
// "3.0.0",
// "3.0.1",
// ...
// "3.0.20"
// ]
// ```
//
// if multiple versions match the selector, or
//
// ```
// "3.0.0"
// ```
//
// if only a single version matches.
const spawnSyncOptions = {
cwd: rushTempFolder,
stdio: [],
shell: _isWindows()
};
const platformNpmPath = _getPlatformPath(npmPath);
const npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], spawnSyncOptions);
if (npmVersionSpawnResult.status !== 0) {
throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`);
}
const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString();
const parsedVersionOutput = JSON.parse(npmViewVersionOutput);
const versions = Array.isArray(parsedVersionOutput)
? parsedVersionOutput
: [parsedVersionOutput];
let latestVersion = versions[0];
for (let i = 1; i < versions.length; i++) {
const latestVersionCandidate = versions[i];
if (_compareVersionStrings(latestVersionCandidate, latestVersion) > 0) {
latestVersion = latestVersionCandidate;
}
}
if (!latestVersion) {
throw new Error('No versions found for the specified version range.');
}
return latestVersion;
}
catch (e) {
throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`);
}
}
}
let _rushJsonFolder;
/**
* Find the absolute path to the folder containing rush.json
*/
function findRushJsonFolder() {
if (!_rushJsonFolder) {
let basePath = __dirname;
let tempPath = __dirname;
do {
const testRushJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME);
if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) {
_rushJsonFolder = basePath;
break;
}
else {
basePath = tempPath;
}
} while (basePath !== (tempPath = path__WEBPACK_IMPORTED_MODULE_3__.dirname(basePath))); // Exit the loop when we hit the disk root
if (!_rushJsonFolder) {
throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`);
}
}
return _rushJsonFolder;
}
/**
* Detects if the package in the specified directory is installed
*/
function _isPackageAlreadyInstalled(packageInstallFolder) {
try {
const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME);
if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(flagFilePath)) {
return false;
}
const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString();
return fileContents.trim() === process.version;
}
catch (e) {
return false;
}
}
/**
* Delete a file. Fail silently if it does not exist.
*/
function _deleteFile(file) {
try {
fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file);
}
catch (err) {
if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
throw err;
}
}
}
/**
* Removes the following files and directories under the specified folder path:
* - installed.flag
* -
* - node_modules
*/
function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) {
try {
const flagFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME);
_deleteFile(flagFile);
const packageLockFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json');
if (lockFilePath) {
fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile);
}
else {
// Not running `npm ci`, so need to cleanup
_deleteFile(packageLockFile);
const nodeModulesFolder = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME);
if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) {
const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler');
fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`));
}
}
}
catch (e) {
throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`);
}
}
function _createPackageJson(packageInstallFolder, name, version) {
try {
const packageJsonContents = {
name: 'ci-rush',
version: '0.0.0',
dependencies: {
[name]: version
},
description: "DON'T WARN",
repository: "DON'T WARN",
license: 'MIT'
};
const packageJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, PACKAGE_JSON_FILENAME);
fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2));
}
catch (e) {
throw new Error(`Unable to create package.json: ${e}`);
}
}
/**
* Run "npm install" in the package install folder.
*/
function _installPackage(logger, packageInstallFolder, name, version, command) {
try {
logger.info(`Installing ${name}...`);
const npmPath = getNpmPath();
const platformNpmPath = _getPlatformPath(npmPath);
const result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, [command], {
stdio: 'inherit',
cwd: packageInstallFolder,
env: process.env,
shell: _isWindows()
});
if (result.status !== 0) {
throw new Error(`"npm ${command}" encountered an error`);
}
logger.info(`Successfully installed ${name}@${version}`);
}
catch (e) {
throw new Error(`Unable to install package: ${e}`);
}
}
/**
* Get the ".bin" path for the package.
*/
function _getBinPath(packageInstallFolder, binName) {
const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin');
const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName;
return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName);
}
/**
* Returns a cross-platform path - windows must enclose any path containing spaces within double quotes.
*/
function _getPlatformPath(platformPath) {
return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath;
}
function _isWindows() {
return os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32';
}
/**
* Write a flag file to the package's install directory, signifying that the install was successful.
*/
function _writeFlagFile(packageInstallFolder) {
try {
const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME);
fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version);
}
catch (e) {
throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`);
}
}
function installAndRun(logger, packageName, packageVersion, packageBinName, packageBinArgs, lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]) {
const rushJsonFolder = findRushJsonFolder();
const rushCommonFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common');
const rushTempFolder = _getRushTempFolder(rushCommonFolder);
const packageInstallFolder = _ensureAndJoinPath(rushTempFolder, 'install-run', `${packageName}@${packageVersion}`);
if (!_isPackageAlreadyInstalled(packageInstallFolder)) {
// The package isn't already installed
_cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath);
const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush');
(0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({
sourceNpmrcFolder,
targetNpmrcFolder: packageInstallFolder,
logger,
supportEnvVarFallbackSyntax: false
});
_createPackageJson(packageInstallFolder, packageName, packageVersion);
const command = lockFilePath ? 'ci' : 'install';
_installPackage(logger, packageInstallFolder, packageName, packageVersion, command);
_writeFlagFile(packageInstallFolder);
}
const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`;
const statusMessageLine = new Array(statusMessage.length + 1).join('-');
logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n');
const binPath = _getBinPath(packageInstallFolder, packageBinName);
const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin');
// Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to
// assign via the process.env proxy to ensure that we append to the right PATH key.
const originalEnvPath = process.env.PATH || '';
let result;
try {
// `npm` bin stubs on Windows are `.cmd` files
// Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true`
const platformBinPath = _getPlatformPath(binPath);
process.env.PATH = [binFolderPath, originalEnvPath].join(path__WEBPACK_IMPORTED_MODULE_3__.delimiter);
result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformBinPath, packageBinArgs, {
stdio: 'inherit',
windowsVerbatimArguments: false,
shell: _isWindows(),
cwd: process.cwd(),
env: process.env
});
}
finally {
process.env.PATH = originalEnvPath;
}
if (result.status !== null) {
return result.status;
}
else {
throw result.error || new Error('An unknown error occurred.');
}
}
function runWithErrorAndStatusCode(logger, fn) {
process.exitCode = 1;
try {
const exitCode = fn();
process.exitCode = exitCode;
}
catch (e) {
logger.error('\n\n' + e.toString() + '\n\n');
}
}
function _run() {
const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, rawPackageSpecifier /* qrcode@^1.2.0 */, packageBinName /* qrcode */, ...packageBinArgs /* [-f, myproject/lib] */] = process.argv;
if (!nodePath) {
throw new Error('Unexpected exception: could not detect node path');
}
if (path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase() !== 'install-run.js') {
// If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control
// to the script that (presumably) imported this file
return;
}
if (process.argv.length < 4) {
console.log('Usage: install-run.js <package>@<version> <command> [args...]');
console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io');
process.exit(1);
}
const logger = { info: console.log, error: console.error };
runWithErrorAndStatusCode(logger, () => {
const rushJsonFolder = findRushJsonFolder();
const rushCommonFolder = _ensureAndJoinPath(rushJsonFolder, 'common');
const packageSpecifier = _parsePackageSpecifier(rawPackageSpecifier);
const name = packageSpecifier.name;
const version = _resolvePackageVersion(logger, rushCommonFolder, packageSpecifier);
if (packageSpecifier.version !== version) {
console.log(`Resolved to ${name}@${version}`);
}
return installAndRun(logger, name, version, packageBinName, packageBinArgs);
});
}
_run();
//# sourceMappingURL=install-run.js.map
})();
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=install-run.js.map
-14
View File
@@ -1,14 +0,0 @@
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import prettierRecommended from "eslint-plugin-prettier/recommended";
import configPrettier from "eslint-config-prettier";
/** @type {import('eslint').Linter.Config[]} */
export default [
pluginJs.configs.recommended,
prettierRecommended,
configPrettier,
...tseslint.configs.recommended,
{files: ["**/*.ts"], rules: {"@typescript-eslint/no-explicit-any": "off", '@typescript-eslint/no-empty-object-type': 'off'}},
];
-26
View File
@@ -1,26 +0,0 @@
{
"name": "@hcengineering/communication",
"workspaces": ["packages/*"],
"scripts": {
"publish": "sh scripts/publish.sh",
"publish:beta": "sh scripts/publish.sh beta",
"build": "turbo run build",
"lint": "turbo run lint",
"format": "turbo run format",
"reformat": "turbo run format && turbo run lint -- --fix",
"format:check": "prettier --check \"**/*.ts\"",
"clean": "turbo run clean"
},
"devDependencies": {
"@eslint/js": "^9.28.0",
"@types/bun": "^1.2.15",
"bun-types": "^1.2.15",
"eslint": "^9.28.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.4.1",
"prettier": "^3.5.3",
"typescript-eslint": "^8.33.1",
"turbo": "^2.5.4"
},
"packageManager": "bun@1.2.9"
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+37 -19
View File
@@ -1,39 +1,57 @@
{
"name": "@hcengineering/communication-client-query",
"version": "0.1.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:browser",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:browser": "bun build src/index.ts --outdir dist --target browser",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts ",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14"
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3"
},
"dependencies": {
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-query": "workspace:*",
"@hcengineering/communication-types": "^0.1.0",
"@hcengineering/communication-sdk-types": "^0.1.0",
"@hcengineering/communication-query": "^0.1.0",
"fast-equals": "^5.0.1"
},
"peerDependencies": {
"typescript": "^5.6.3"
},
"repository": {
"type": "git",
"url": "git+https://github.com/hcengineering/communication.git"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+5 -5
View File
@@ -24,23 +24,23 @@ export type { MessageQueryParams } from '@hcengineering/communication-query'
let lq: LiveQueries
let onDestroy: (fn: () => void) => void = () => {}
export function createMessagesQuery(): MessagesQuery {
export function createMessagesQuery (): MessagesQuery {
return new MessagesQuery(lq, onDestroy)
}
export function createNotificationsQuery(): NotificationsQuery {
export function createNotificationsQuery (): NotificationsQuery {
return new NotificationsQuery(lq, onDestroy)
}
export function createNotificationContextsQuery(): NotificationContextsQuery {
export function createNotificationContextsQuery (): NotificationContextsQuery {
return new NotificationContextsQuery(lq, onDestroy)
}
export function createLabelsQuery(): LabelsQuery {
export function createLabelsQuery (): LabelsQuery {
return new LabelsQuery(lq, onDestroy)
}
export function initLiveQueries(
export function initLiveQueries (
client: FindClient,
workspace: WorkspaceID,
filesUrl: string,
+18 -19
View File
@@ -13,7 +13,7 @@
// limitations under the License.
//
import { type LiveQueries } from '@hcengineering/communication-query'
import { type LiveQueries, MessageQueryParams } from '@hcengineering/communication-query'
import type { PagedQueryCallback, QueryCallback } from '@hcengineering/communication-sdk-types'
import {
type FindLabelsParams,
@@ -25,13 +25,12 @@ import {
type Notification
} from '@hcengineering/communication-types'
import { deepEqual } from 'fast-equals'
import type { MessageQueryParams } from '@hcengineering/communication-query'
class BaseQuery<P extends Record<string, any>, C extends (r: any) => void> {
private oldQuery: P | undefined
private oldCallback: C | undefined
constructor(
constructor (
protected readonly lq: LiveQueries,
onDestroy: (fn: () => void) => void
) {
@@ -42,7 +41,7 @@ class BaseQuery<P extends Record<string, any>, C extends (r: any) => void> {
unsubscribe: () => void = () => {}
query(params: P, callback: C): boolean {
query (params: P, callback: C): boolean {
if (!this.needUpdate(params, callback)) {
return false
}
@@ -50,7 +49,7 @@ class BaseQuery<P extends Record<string, any>, C extends (r: any) => void> {
return true
}
private doQuery(query: P, callback: C): void {
private doQuery (query: P, callback: C): void {
this.unsubscribe()
this.oldCallback = callback
this.oldQuery = query
@@ -65,13 +64,13 @@ class BaseQuery<P extends Record<string, any>, C extends (r: any) => void> {
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
createQuery(params: P, callback: C): { unsubscribe: () => void } {
createQuery (params: P, callback: C): { unsubscribe: () => void } {
return {
unsubscribe: () => {}
}
}
private needUpdate(params: P, callback: C): boolean {
private needUpdate (params: P, callback: C): boolean {
if (!deepEqual(params, this.oldQuery)) return true
if (!deepEqual(callback.toString(), this.oldCallback?.toString())) return true
return false
@@ -79,43 +78,43 @@ class BaseQuery<P extends Record<string, any>, C extends (r: any) => void> {
}
export class MessagesQuery extends BaseQuery<MessageQueryParams, PagedQueryCallback<Message>> {
override createQuery(params: MessageQueryParams, callback: PagedQueryCallback<Message>): { unsubscribe: () => void } {
override createQuery (params: MessageQueryParams, callback: PagedQueryCallback<Message>): { unsubscribe: () => void } {
return this.lq.queryMessages(params, callback)
}
}
export class NotificationsQuery extends BaseQuery<FindNotificationsParams, PagedQueryCallback<Notification>> {
override createQuery(
override createQuery (
params: FindNotificationsParams,
callback: PagedQueryCallback<Notification>
): {
unsubscribe: () => void
} {
unsubscribe: () => void
} {
return this.lq.queryNotifications(params, callback)
}
}
export class NotificationContextsQuery extends BaseQuery<
FindNotificationContextParams,
PagedQueryCallback<NotificationContext>
FindNotificationContextParams,
PagedQueryCallback<NotificationContext>
> {
override createQuery(
override createQuery (
params: FindNotificationContextParams,
callback: PagedQueryCallback<NotificationContext>
): {
unsubscribe: () => void
} {
unsubscribe: () => void
} {
return this.lq.queryNotificationContexts(params, callback)
}
}
export class LabelsQuery extends BaseQuery<FindLabelsParams, QueryCallback<Label>> {
override createQuery(
override createQuery (
params: FindLabelsParams,
callback: QueryCallback<Label>
): {
unsubscribe: () => void
} {
unsubscribe: () => void
} {
return this.lq.queryLabels(params, callback)
}
}
+8 -6
View File
@@ -1,10 +1,12 @@
{
"extends": "../../tsconfig.json",
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src"]
}
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+37 -19
View File
@@ -1,40 +1,58 @@
{
"name": "@hcengineering/communication-cockroach",
"version": "0.1.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:node",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:node": "bun build src/index.ts --target node --format cjs --outfile dist/index.js",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14"
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3"
},
"dependencies": {
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-types": "^0.1.0",
"@hcengineering/communication-sdk-types": "^0.1.0",
"@hcengineering/communication-shared": "^0.1.0",
"postgres": "^3.4.4",
"uuid": "^11.1.0"
},
"peerDependencies": {
"typescript": "^5.6.3"
},
"repository": {
"type": "git",
"url": "git+https://github.com/hcengineering/communication.git"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+47 -46
View File
@@ -77,7 +77,7 @@ export class CockroachAdapter implements DbAdapter {
private readonly notification: NotificationsDb
private readonly label: LabelsDb
constructor(
constructor (
private readonly sql: SqlClient,
private readonly workspace: WorkspaceID,
private readonly logger?: Logger,
@@ -88,7 +88,7 @@ export class CockroachAdapter implements DbAdapter {
this.label = new LabelsDb(this.sql, this.workspace, logger, options)
}
async createMessage(
async createMessage (
card: CardID,
type: MessageType,
content: RichText,
@@ -97,11 +97,11 @@ export class CockroachAdapter implements DbAdapter {
data?: MessageData,
externalId?: string,
id?: MessageID
): Promise<{ id: MessageID; created: Date }> {
): Promise<{ id: MessageID, created: Date }> {
return await this.message.createMessage(card, type, content, creator, created, data, externalId, id)
}
async createPatch(
async createPatch (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -113,19 +113,19 @@ export class CockroachAdapter implements DbAdapter {
await this.message.createPatch(card, message, messageCreated, type, data, creator, created)
}
async removePatches(card: CardID): Promise<void> {
async removePatches (card: CardID): Promise<void> {
await this.message.removePatches(card)
}
async createMessagesGroup(card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise<void> {
async createMessagesGroup (card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise<void> {
await this.message.createMessagesGroup(card, blobId, fromDate, toDate, count)
}
async removeMessagesGroup(card: CardID, blobId: BlobID): Promise<void> {
async removeMessagesGroup (card: CardID, blobId: BlobID): Promise<void> {
await this.message.removeMessagesGroup(card, blobId)
}
async createReaction(
async createReaction (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -136,7 +136,7 @@ export class CockroachAdapter implements DbAdapter {
await this.message.createReaction(card, message, messageCreated, reaction, creator, created)
}
async removeReaction(
async removeReaction (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -146,7 +146,7 @@ export class CockroachAdapter implements DbAdapter {
await this.message.removeReaction(card, message, messageCreated, reaction, creator, new Date())
}
async createFile(
async createFile (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -157,11 +157,11 @@ export class CockroachAdapter implements DbAdapter {
await this.message.createFile(card, message, messageCreated, data, creator, created)
}
async removeFiles(card: CardID, query: RemoveFileQuery): Promise<void> {
async removeFiles (card: CardID, query: RemoveFileQuery): Promise<void> {
await this.message.removeFiles(card, query)
}
async createLinkPreview(
async createLinkPreview (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -172,11 +172,11 @@ export class CockroachAdapter implements DbAdapter {
return await this.message.createLinkPreview(card, message, messageCreated, data, creator, created)
}
async removeLinkPreview(card: CardID, message: MessageID, id: LinkPreviewID): Promise<void> {
async removeLinkPreview (card: CardID, message: MessageID, id: LinkPreviewID): Promise<void> {
await this.message.removeLinkPreview(card, message, id)
}
async createThread(
async createThread (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -187,27 +187,27 @@ export class CockroachAdapter implements DbAdapter {
await this.message.createThread(card, message, messageCreated, thread, threadType, created)
}
async removeThreads(query: RemoveThreadQuery): Promise<void> {
async removeThreads (query: RemoveThreadQuery): Promise<void> {
await this.message.removeThreads(query)
}
async updateThread(thread: CardID, update: ThreadUpdates): Promise<void> {
async updateThread (thread: CardID, update: ThreadUpdates): Promise<void> {
await this.message.updateThread(thread, update)
}
async findMessages(params: FindMessagesParams): Promise<Message[]> {
async findMessages (params: FindMessagesParams): Promise<Message[]> {
return await this.message.find(params)
}
async findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
return await this.message.findMessagesGroups(params)
}
async findThread(thread: CardID): Promise<Thread | undefined> {
async findThread (thread: CardID): Promise<Thread | undefined> {
return await this.message.findThread(thread)
}
async addCollaborators(
async addCollaborators (
card: CardID,
cardType: CardType,
collaborators: AccountID[],
@@ -216,15 +216,15 @@ export class CockroachAdapter implements DbAdapter {
return await this.notification.addCollaborators(card, cardType, collaborators, date)
}
async removeCollaborators(card: CardID, query: RemoveCollaboratorsQuery): Promise<void> {
async removeCollaborators (card: CardID, query: RemoveCollaboratorsQuery): Promise<void> {
await this.notification.removeCollaborators(card, query)
}
async updateCollaborators(params: FindCollaboratorsParams, data: Partial<Collaborator>): Promise<void> {
async updateCollaborators (params: FindCollaboratorsParams, data: Partial<Collaborator>): Promise<void> {
await this.notification.updateCollaborators(params, data)
}
async createNotification(
async createNotification (
context: ContextID,
message: MessageID,
messageCreated: Date,
@@ -236,15 +236,15 @@ export class CockroachAdapter implements DbAdapter {
return await this.notification.createNotification(context, message, messageCreated, type, read, content, created)
}
async updateNotification(query: UpdateNotificationQuery, updates: NotificationUpdates): Promise<void> {
async updateNotification (query: UpdateNotificationQuery, updates: NotificationUpdates): Promise<void> {
await this.notification.updateNotification(query, updates)
}
async removeNotifications(query: RemoveNotificationsQuery): Promise<NotificationID[]> {
async removeNotifications (query: RemoveNotificationsQuery): Promise<NotificationID[]> {
return await this.notification.removeNotifications(query)
}
async createContext(
async createContext (
account: AccountID,
card: CardID,
lastUpdate: Date,
@@ -254,51 +254,52 @@ export class CockroachAdapter implements DbAdapter {
return await this.notification.createContext(account, card, lastUpdate, lastView, lastNotify)
}
async updateContext(context: ContextID, account: AccountID, updates: NotificationContextUpdates): Promise<void> {
async updateContext (context: ContextID, account: AccountID, updates: NotificationContextUpdates): Promise<void> {
await this.notification.updateContext(context, account, updates)
}
async removeContexts(query: RemoveNotificationContextQuery): Promise<void> {
async removeContexts (query: RemoveNotificationContextQuery): Promise<void> {
await this.notification.removeContexts(query)
}
async findNotificationContexts(params: FindNotificationContextParams): Promise<NotificationContext[]> {
async findNotificationContexts (params: FindNotificationContextParams): Promise<NotificationContext[]> {
return await this.notification.findContexts(params)
}
async findNotifications(params: FindNotificationsParams): Promise<Notification[]> {
async findNotifications (params: FindNotificationsParams): Promise<Notification[]> {
return await this.notification.findNotifications(params)
}
async findCollaborators(params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (params: FindCollaboratorsParams): Promise<Collaborator[]> {
return await this.notification.findCollaborators(params)
}
close(): void {
close (): void {
this.sql.close()
}
getCollaboratorsCursor(card: CardID, date: Date, size?: number): AsyncIterable<Collaborator[]> {
getCollaboratorsCursor (card: CardID, date: Date, size?: number): AsyncIterable<Collaborator[]> {
return this.notification.getCollaboratorsCursor(card, date, size)
}
createLabel(label: LabelID, card: CardID, cardType: CardType, account: AccountID, created: Date): Promise<void> {
createLabel (label: LabelID, card: CardID, cardType: CardType, account: AccountID, created: Date): Promise<void> {
return this.label.createLabel(label, card, cardType, account, created)
}
removeLabels(query: RemoveLabelQuery): Promise<void> {
removeLabels (query: RemoveLabelQuery): Promise<void> {
return this.label.removeLabels(query)
}
findLabels(params: FindLabelsParams): Promise<Label[]> {
findLabels (params: FindLabelsParams): Promise<Label[]> {
return this.label.findLabels(params)
}
updateLabels(card: CardID, updates: LabelUpdates): Promise<void> {
updateLabels (card: CardID, updates: LabelUpdates): Promise<void> {
return this.label.updateLabels(card, updates)
}
//TODO: remove it ??
async getAccountsByPersonIds(ids: string[]): Promise<AccountID[]> {
// TODO: remove it ??
async getAccountsByPersonIds (ids: string[]): Promise<AccountID[]> {
if (ids.length === 0) return []
const sql = `SELECT data ->> 'personUuid' AS "personUuid"
FROM public.contact
@@ -309,20 +310,20 @@ export class CockroachAdapter implements DbAdapter {
return result?.map((it) => it.personUuid as AccountID).filter((it) => it != null) ?? []
}
async getNameByAccount(id: AccountID): Promise<string | undefined> {
async getNameByAccount (id: AccountID): Promise<string | undefined> {
const sql = `SELECT data ->> 'name' AS name
FROM public.contact
WHERE "workspaceId" = $1::uuid
AND data ->> 'personUuid' = $2
LIMIT 1`
const result = await this.sql.execute(sql, [this.workspace, id])
const name = result[0]?.name
const name: string | undefined = result[0]?.name
return name ? formatName(name) : undefined
return name != null ? formatName(name) : undefined
}
}
export async function createDbAdapter(
export async function createDbAdapter (
connectionString: string,
workspace: WorkspaceID,
logger?: Logger,
@@ -338,14 +339,14 @@ export async function createDbAdapter(
}
class CockroachClient implements SqlClient {
constructor(
constructor (
private readonly db: PostgresClientReference,
private readonly sql: postgres.Sql
) {}
async execute<T = SqlRow>(query: string, params?: SqlParams): Promise<T[]> {
const convertedParams = convertArrayParams(params)
return this.sql.unsafe<T[]>(query, convertedParams)
return await this.sql.unsafe<T[]>(query, convertedParams)
}
cursor<T = SqlRow>(query: string, params?: SqlParams, size?: number): AsyncIterable<NonNullable<T[][number]>[]> {
@@ -353,7 +354,7 @@ class CockroachClient implements SqlClient {
return this.sql.unsafe<T[]>(query, convertedParams).cursor(size)
}
close(): void {
close (): void {
this.db.close()
}
}
+10 -10
View File
@@ -29,7 +29,7 @@ class PostgresClientReferenceImpl {
count: number
client: postgres.Sql | Promise<postgres.Sql>
constructor(
constructor (
client: postgres.Sql | Promise<postgres.Sql>,
readonly onclose: () => void
) {
@@ -37,14 +37,14 @@ class PostgresClientReferenceImpl {
this.client = client
}
async getClient(): Promise<postgres.Sql> {
async getClient (): Promise<postgres.Sql> {
if (this.client instanceof Promise) {
this.client = await this.client
}
return this.client
}
close(force: boolean = false): void {
close (force: boolean = false): void {
this.count--
if (this.count === 0 || force) {
if (force) {
@@ -59,7 +59,7 @@ class PostgresClientReferenceImpl {
}
}
addRef(): void {
addRef (): void {
this.count++
console.log('Add postgres connection', this.count)
}
@@ -67,12 +67,12 @@ class PostgresClientReferenceImpl {
export class ClientRef implements PostgresClientReference {
id = uuid()
constructor(readonly client: PostgresClientReferenceImpl) {
constructor (readonly client: PostgresClientReferenceImpl) {
clientRefs.set(this.id, this)
}
closed = false
async getClient(): Promise<postgres.Sql> {
async getClient (): Promise<postgres.Sql> {
if (!this.closed) {
return await this.client.getClient()
} else {
@@ -80,7 +80,7 @@ export class ClientRef implements PostgresClientReference {
}
}
close(): void {
close (): void {
// Do not allow double close of connection client-query
if (!this.closed) {
clientRefs.delete(this.id)
@@ -90,7 +90,7 @@ export class ClientRef implements PostgresClientReference {
}
}
export function connect(connectionString: string, database?: string): PostgresClientReference {
export function connect (connectionString: string, database?: string): PostgresClientReference {
const extraOptions = JSON.parse(process.env.POSTGRES_OPTIONS ?? '{}')
const key = `${connectionString}${extraOptions}`
let existing = connections.get(key)
@@ -103,8 +103,8 @@ export function connect(connectionString: string, database?: string): PostgresCl
fetch_types: true,
debug: false,
notice: false,
onnotice() {},
onparameter() {},
onnotice () {},
onparameter () {},
...extraOptions,
prepare: true,
connection: {
+1 -1
View File
@@ -19,7 +19,7 @@ import type { WorkspaceID } from '@hcengineering/communication-types'
import { type Logger, type Options, type SqlClient } from '../types'
export class BaseDb {
constructor(
constructor (
readonly client: SqlClient,
readonly workspace: WorkspaceID,
readonly logger?: Logger,
+5 -5
View File
@@ -29,7 +29,7 @@ import { toLabel } from './mapping'
import type { LabelUpdates, RemoveLabelQuery } from '@hcengineering/communication-sdk-types'
export class LabelsDb extends BaseDb {
async createLabel(
async createLabel (
label: LabelID,
card: CardID,
cardType: CardType,
@@ -54,7 +54,7 @@ export class LabelsDb extends BaseDb {
)
}
async removeLabels(query: RemoveLabelQuery): Promise<void> {
async removeLabels (query: RemoveLabelQuery): Promise<void> {
const db: Partial<LabelDb> = {
label_id: query.label,
card_id: query.card,
@@ -77,7 +77,7 @@ export class LabelsDb extends BaseDb {
await this.execute(sql, whereValues, 'remove labels')
}
async updateLabels(card: CardID, updates: LabelUpdates): Promise<void> {
async updateLabels (card: CardID, updates: LabelUpdates): Promise<void> {
const dbData: Partial<LabelDb> = {
card_type: updates.cardType
}
@@ -95,7 +95,7 @@ export class LabelsDb extends BaseDb {
await this.execute(sql, [this.workspace, card, ...setValues], 'update labels')
}
async findLabels(params: FindLabelsParams): Promise<Label[]> {
async findLabels (params: FindLabelsParams): Promise<Label[]> {
const select = `SELECT *
FROM ${TableName.Label} l`
@@ -111,7 +111,7 @@ export class LabelsDb extends BaseDb {
return result.map((it: any) => toLabel(it))
}
buildWhere(params: FindLabelsParams, startIndex: number = 0, prefix = 'l.'): { where: string; values: any[] } {
buildWhere (params: FindLabelsParams, startIndex: number = 0, prefix = 'l.'): { where: string, values: any[] } {
const where: string[] = []
const values: any[] = []
let index = startIndex + 1
+16 -16
View File
@@ -104,7 +104,7 @@ type RawContext = ContextDb & { id: ContextID } & {
notifications?: RawNotification[]
}
export function toMessage(raw: RawMessage): Message {
export function toMessage (raw: RawMessage): Message {
const patches = (raw.patches ?? []).map((it) => toPatch(it))
const rawMessage: Message = {
id: String(raw.id) as MessageID,
@@ -124,7 +124,7 @@ export function toMessage(raw: RawMessage): Message {
messageCreated: new Date(raw.created),
thread: raw.thread_id,
threadType: raw.thread_type,
repliesCount: raw.replies_count ? parseInt(raw.replies_count as any) : 0,
repliesCount: raw.replies_count != null ? parseInt(raw.replies_count as any) : 0,
lastReply: raw.last_reply ?? new Date()
}
: undefined,
@@ -140,7 +140,7 @@ export function toMessage(raw: RawMessage): Message {
return applyPatches(rawMessage, patches, [PatchType.update, PatchType.remove])
}
export function toReaction(raw: ReactionDb): Reaction {
export function toReaction (raw: ReactionDb): Reaction {
return {
reaction: raw.reaction,
creator: raw.creator,
@@ -148,7 +148,7 @@ export function toReaction(raw: ReactionDb): Reaction {
}
}
export function toFile(raw: Omit<FileDb, 'workspace_id'>): File {
export function toFile (raw: Omit<FileDb, 'workspace_id'>): File {
return {
blobId: raw.blob_id,
type: raw.type,
@@ -160,7 +160,7 @@ export function toFile(raw: Omit<FileDb, 'workspace_id'>): File {
}
}
export function toLinkPreview(raw: LinkPreviewDb): LinkPreview {
export function toLinkPreview (raw: LinkPreviewDb): LinkPreview {
return {
id: String(raw.id) as LinkPreviewID,
url: raw.url,
@@ -175,7 +175,7 @@ export function toLinkPreview(raw: LinkPreviewDb): LinkPreview {
}
}
export function toMessagesGroup(raw: MessagesGroupDb): MessagesGroup {
export function toMessagesGroup (raw: MessagesGroupDb): MessagesGroup {
return {
card: raw.card_id,
blobId: raw.blob_id,
@@ -186,7 +186,7 @@ export function toMessagesGroup(raw: MessagesGroupDb): MessagesGroup {
}
}
export function toPatch(raw: Omit<PatchDb, 'workspace_id'>): Patch {
export function toPatch (raw: Omit<PatchDb, 'workspace_id'>): Patch {
return {
type: raw.type,
messageCreated: new Date(raw.message_created),
@@ -197,7 +197,7 @@ export function toPatch(raw: Omit<PatchDb, 'workspace_id'>): Patch {
}
}
export function toThread(raw: ThreadDb): Thread {
export function toThread (raw: ThreadDb): Thread {
return {
card: raw.card_id,
message: String(raw.message_id) as MessageID,
@@ -209,7 +209,7 @@ export function toThread(raw: ThreadDb): Thread {
}
}
export function toNotificationContext(raw: RawContext): NotificationContext {
export function toNotificationContext (raw: RawContext): NotificationContext {
const lastView = new Date(raw.last_view)
return {
id: String(raw.id) as ContextID,
@@ -224,7 +224,7 @@ export function toNotificationContext(raw: RawContext): NotificationContext {
}
}
function toNotificationRaw(id: ContextID, card: CardID, raw: RawNotification): Notification {
function toNotificationRaw (id: ContextID, card: CardID, raw: RawNotification): Notification {
const created = new Date(raw.created)
let message: Message | undefined
@@ -261,17 +261,17 @@ function toNotificationRaw(id: ContextID, card: CardID, raw: RawNotification): N
})
)
let thread: Thread | undefined = undefined
let thread: Thread | undefined
if (raw.message_thread_id != null && raw.message_thread_type != null) {
thread = {
card,
message: String(raw.message_id) as MessageID,
messageCreated: raw.message_created ? new Date(raw.message_created) : created,
messageCreated: raw.message_created != null ? new Date(raw.message_created) : created,
thread: raw.message_thread_id,
threadType: raw.message_thread_type,
repliesCount: Number(raw.message_replies ?? 0),
lastReply: raw.message_last_reply ? new Date(raw.message_last_reply) : created
lastReply: raw.message_last_reply != null ? new Date(raw.message_last_reply) : created
}
}
message = {
@@ -338,11 +338,11 @@ function toNotificationRaw(id: ContextID, card: CardID, raw: RawNotification): N
}
}
export function toNotification(raw: RawNotification & { card_id: CardID }): Notification {
export function toNotification (raw: RawNotification & { card_id: CardID }): Notification {
return toNotificationRaw(raw.context_id, raw.card_id, raw)
}
export function toCollaborator(raw: CollaboratorDb): Collaborator {
export function toCollaborator (raw: CollaboratorDb): Collaborator {
return {
account: raw.account,
cardType: raw.card_type,
@@ -350,7 +350,7 @@ export function toCollaborator(raw: CollaboratorDb): Collaborator {
}
}
export function toLabel(raw: LabelDb): Label {
export function toLabel (raw: LabelDb): Label {
return {
label: raw.label_id,
card: raw.card_id,
+54 -50
View File
@@ -53,7 +53,7 @@ import type { RemoveFileQuery, RemoveThreadQuery, ThreadUpdates } from '@hcengin
export class MessagesDb extends BaseDb {
// Message
async createMessage(
async createMessage (
card: CardID,
type: MessageType,
content: RichText,
@@ -62,7 +62,7 @@ export class MessagesDb extends BaseDb {
data?: MessageData,
externalId?: string,
id?: MessageID
): Promise<{ id: MessageID; created: Date }> {
): Promise<{ id: MessageID, created: Date }> {
const db: Omit<MessageDb, 'id'> & { id?: MessageID } = {
type,
workspace_id: this.workspace,
@@ -104,7 +104,7 @@ export class MessagesDb extends BaseDb {
return { id: idR, created: createdR }
}
async createPatch(
async createPatch (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -136,7 +136,7 @@ export class MessagesDb extends BaseDb {
)
}
async removePatches(card: CardID): Promise<void> {
async removePatches (card: CardID): Promise<void> {
const sql = `DELETE
FROM ${TableName.Patch}
WHERE workspace_id = $1::uuid
@@ -145,7 +145,7 @@ export class MessagesDb extends BaseDb {
}
// File
async createFile(
async createFile (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -190,7 +190,7 @@ export class MessagesDb extends BaseDb {
)
}
async removeFiles(card: CardID, query: RemoveFileQuery): Promise<void> {
async removeFiles (card: CardID, query: RemoveFileQuery): Promise<void> {
const db: Partial<FileDb> = {
card_id: card,
message_id: query.message,
@@ -212,7 +212,7 @@ export class MessagesDb extends BaseDb {
await this.execute(sql, whereValues, 'remove files')
}
async createLinkPreview(
async createLinkPreview (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -261,13 +261,13 @@ export class MessagesDb extends BaseDb {
return result[0].id as LinkPreviewID
}
async removeLinkPreview(card: CardID, message: MessageID, id: LinkPreviewID): Promise<void> {
async removeLinkPreview (card: CardID, message: MessageID, id: LinkPreviewID): Promise<void> {
const sql = `DELETE FROM ${TableName.LinkPreview} WHERE workspace_id = $1::uuid AND card_id = $2::varchar AND message_id = $3::int8 AND id = $4::int8`
await this.execute(sql, [this.workspace, card, message, id], 'remove link preview')
}
// Reaction
async createReaction(
async createReaction (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -305,7 +305,7 @@ export class MessagesDb extends BaseDb {
}
}
async removeReaction(
async removeReaction (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -336,7 +336,7 @@ export class MessagesDb extends BaseDb {
}
// Thread
async createThread(
async createThread (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -373,7 +373,7 @@ export class MessagesDb extends BaseDb {
)
}
async removeThreads(query: RemoveThreadQuery): Promise<void> {
async removeThreads (query: RemoveThreadQuery): Promise<void> {
const db: Partial<ThreadDb> = {
card_id: query.card,
message_id: query.message,
@@ -396,7 +396,7 @@ export class MessagesDb extends BaseDb {
await this.execute(sql, whereValues, 'remove threads')
}
async updateThread(thread: CardID, update: ThreadUpdates): Promise<void> {
async updateThread (thread: CardID, update: ThreadUpdates): Promise<void> {
const set: string[] = []
const values: any[] = []
@@ -427,7 +427,7 @@ export class MessagesDb extends BaseDb {
}
// MessagesGroup
async createMessagesGroup(card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise<void> {
async createMessagesGroup (card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise<void> {
const db: MessagesGroupDb = {
workspace_id: this.workspace,
card_id: card,
@@ -446,7 +446,7 @@ export class MessagesDb extends BaseDb {
)
}
async removeMessagesGroup(card: CardID, blobId: BlobID): Promise<void> {
async removeMessagesGroup (card: CardID, blobId: BlobID): Promise<void> {
const sql = `DELETE
FROM ${TableName.MessagesGroup}
WHERE workspace_id = $1::uuid
@@ -455,7 +455,7 @@ export class MessagesDb extends BaseDb {
await this.execute(sql, [this.workspace, card, blobId], 'remove messages group')
}
async find(params: FindMessagesParams): Promise<Message[]> {
async find (params: FindMessagesParams): Promise<Message[]> {
const { where, values } = this.buildMessageWhere(params)
const orderBy = this.buildOrderBy(params)
const limit = this.buildLimit(params)
@@ -474,15 +474,15 @@ export class MessagesDb extends BaseDb {
return result.map((it: any) => toMessage(it))
}
private buildOrderBy(params: FindMessagesParams): string {
private buildOrderBy (params: FindMessagesParams): string {
return params.order != null ? `ORDER BY m.created ${params.order === SortingOrder.Ascending ? 'ASC' : 'DESC'}` : ''
}
private buildLimit(params: FindMessagesParams): string {
private buildLimit (params: FindMessagesParams): string {
return params.limit != null ? `LIMIT ${params.limit}` : ''
}
private buildCteLimitedMessages(where: string, orderBy: string, limit: string): string {
private buildCteLimitedMessages (where: string, orderBy: string, limit: string): string {
return `
limited_messages AS (
SELECT *
@@ -494,8 +494,8 @@ export class MessagesDb extends BaseDb {
`
}
private buildCteAggregatedFiles(params: FindMessagesParams): string {
if (!params.files) return ''
private buildCteAggregatedFiles (params: FindMessagesParams): string {
if (params.files !== true) return ''
return `,
agg_files AS (
SELECT
@@ -521,8 +521,8 @@ export class MessagesDb extends BaseDb {
`
}
private buildCteAggregatedLinkPreviews(params: FindMessagesParams): string {
if (!params.links) return ''
private buildCteAggregatedLinkPreviews (params: FindMessagesParams): string {
if (params.links !== true) return ''
return `,
agg_link_previews AS (
SELECT
@@ -551,8 +551,8 @@ export class MessagesDb extends BaseDb {
`
}
private buildCteAggregatedReactions(params: FindMessagesParams): string {
if (!params.reactions) return ''
private buildCteAggregatedReactions (params: FindMessagesParams): string {
if (params.reactions !== true) return ''
return `,
agg_reactions AS (
SELECT
@@ -574,7 +574,7 @@ export class MessagesDb extends BaseDb {
`
}
private buildCteAggregatedPatches(): string {
private buildCteAggregatedPatches (): string {
return `,
agg_patches AS (
SELECT
@@ -599,44 +599,48 @@ export class MessagesDb extends BaseDb {
`
}
private buildMainSelect(params: FindMessagesParams): string {
private buildMainSelect (params: FindMessagesParams): string {
const orderBy = this.buildOrderBy(params)
const selectReplies = params.replies
? `t.thread_id as thread_id, t.thread_type as thread_type, t.replies_count::int as replies_count, t.last_reply as last_reply,`
: ''
const selectReplies =
params.replies === true
? 't.thread_id as thread_id, t.thread_type as thread_type, t.replies_count::int as replies_count, t.last_reply as last_reply,'
: ''
const selectFiles = params.files ? `COALESCE(f.files, '[]'::jsonb) AS files,` : `'[]'::jsonb AS files,`
const selectLinks = params.links
? `COALESCE(l.link_previews, '[]'::jsonb) AS link_previews,`
: `'[]'::jsonb AS link_previews,`
const selectFiles = params.files === true ? "COALESCE(f.files, '[]'::jsonb) AS files," : "'[]'::jsonb AS files,"
const selectLinks =
params.links === true
? "COALESCE(l.link_previews, '[]'::jsonb) AS link_previews,"
: "'[]'::jsonb AS link_previews,"
const selectReactions = params.reactions
? `COALESCE(r.reactions, '[]'::jsonb) AS reactions,`
: `'[]'::jsonb AS reactions,`
const selectReactions =
params.reactions === true ? "COALESCE(r.reactions, '[]'::jsonb) AS reactions," : "'[]'::jsonb AS reactions,"
const joinFiles = params.files
? `
const joinFiles =
params.files === true
? `
LEFT JOIN agg_files f
ON f.workspace_id = m.workspace_id
AND f.card_id = m.card_id
AND f.message_id = m.id`
: ''
: ''
const joinLinks = params.links
? `
const joinLinks =
params.links === true
? `
LEFT JOIN agg_link_previews l
ON l.workspace_id = m.workspace_id
AND l.card_id = m.card_id
AND l.message_id = m.id`
: ''
: ''
const joinReactions = params.reactions
? `
const joinReactions =
params.reactions === true
? `
LEFT JOIN agg_reactions r
ON r.workspace_id = m.workspace_id
AND r.card_id = m.card_id
AND r.message_id = m.id`
: ''
: ''
return `
SELECT m.id::text,
@@ -668,7 +672,7 @@ export class MessagesDb extends BaseDb {
`
}
buildMessageWhere(params: FindMessagesParams): { where: string; values: any[] } {
buildMessageWhere (params: FindMessagesParams): { where: string, values: any[] } {
const where: string[] = ['m.workspace_id = $1::uuid']
const values: any[] = [this.workspace]
@@ -701,7 +705,7 @@ export class MessagesDb extends BaseDb {
}
// Find thread
async findThread(thread: CardID): Promise<Thread | undefined> {
async findThread (thread: CardID): Promise<Thread | undefined> {
const sql = `SELECT t.card_id,
t.message_id::text,
t.message_created,
@@ -719,7 +723,7 @@ export class MessagesDb extends BaseDb {
}
// Find messages groups
async findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
const select = `
SELECT mg.card_id,
mg.blob_id,
@@ -756,7 +760,7 @@ export class MessagesDb extends BaseDb {
return result.map((it: any) => toMessagesGroup(it))
}
buildMessagesGroupWhere(params: FindMessagesGroupsParams): {
buildMessagesGroupWhere (params: FindMessagesGroupsParams): {
where: string
values: any[]
} {
+22 -21
View File
@@ -45,7 +45,7 @@ import type {
} from '@hcengineering/communication-sdk-types'
export class NotificationsDb extends BaseDb {
async addCollaborators(
async addCollaborators (
card: CardID,
cardType: CardType,
collaborators: AccountID[],
@@ -68,7 +68,7 @@ export class NotificationsDb extends BaseDb {
return result.map((it: any) => it.account)
}
async removeCollaborators(card: CardID, query: RemoveCollaboratorsQuery): Promise<void> {
async removeCollaborators (card: CardID, query: RemoveCollaboratorsQuery): Promise<void> {
const { accounts } = query
if (accounts === undefined) {
const sql = `DELETE FROM ${TableName.Collaborators} WHERE workspace_id = $1::uuid AND card_id = $2::varchar`
@@ -92,7 +92,7 @@ export class NotificationsDb extends BaseDb {
}
}
getCollaboratorsCursor(
getCollaboratorsCursor (
card: CardID,
date: Date,
size?: number
@@ -108,7 +108,7 @@ export class NotificationsDb extends BaseDb {
return this.client.cursor<Collaborator>(sql, [this.workspace, card, date], size)
}
async createNotification(
async createNotification (
context: ContextID,
message: MessageID,
messageCreated: Date,
@@ -137,7 +137,7 @@ export class NotificationsDb extends BaseDb {
return result[0].id as NotificationID
}
async updateNotification(query: UpdateNotificationQuery, updates: NotificationUpdates): Promise<void> {
async updateNotification (query: UpdateNotificationQuery, updates: NotificationUpdates): Promise<void> {
const where: string[] = [
'nc.workspace_id = $1::uuid',
'nc.id = $2::int8',
@@ -175,7 +175,7 @@ export class NotificationsDb extends BaseDb {
await this.execute(sql, [...values, updates.read], 'update notification')
}
async removeNotifications(query: RemoveNotificationsQuery): Promise<NotificationID[]> {
async removeNotifications (query: RemoveNotificationsQuery): Promise<NotificationID[]> {
const { context, account, ids } = query
if (ids.length === 0) return []
const where: string[] = [
@@ -205,7 +205,7 @@ export class NotificationsDb extends BaseDb {
return result.map((row: any) => row.id)
}
async createContext(
async createContext (
account: AccountID,
card: CardID,
lastUpdate: Date,
@@ -231,7 +231,7 @@ export class NotificationsDb extends BaseDb {
return result[0].id as ContextID
}
async removeContexts(query: RemoveNotificationContextQuery): Promise<void> {
async removeContexts (query: RemoveNotificationContextQuery): Promise<void> {
const db: Partial<ContextDb> & { id?: ContextID } = {
id: query.id,
card_id: query.card,
@@ -253,7 +253,7 @@ export class NotificationsDb extends BaseDb {
await this.execute(sql, whereValues, 'remove notification context')
}
async updateContext(context: ContextID, account: AccountID, updates: NotificationContextUpdates): Promise<void> {
async updateContext (context: ContextID, account: AccountID, updates: NotificationContextUpdates): Promise<void> {
const dbData: Partial<ContextDb> = {}
if (updates.lastView != null) {
@@ -281,7 +281,7 @@ export class NotificationsDb extends BaseDb {
await this.execute(sql, [this.workspace, context, account, ...values], 'update notification context')
}
async findContexts(params: FindNotificationContextParams): Promise<NotificationContext[]> {
async findContexts (params: FindNotificationContextParams): Promise<NotificationContext[]> {
const withNotifications = params.notifications != null
const withMessages = params.notifications?.message === true
@@ -434,7 +434,7 @@ export class NotificationsDb extends BaseDb {
return result.map((it: any) => toNotificationContext(it))
}
async findNotifications(params: FindNotificationsParams): Promise<Notification[]> {
async findNotifications (params: FindNotificationsParams): Promise<Notification[]> {
const withMessage = params.message === true
let select =
@@ -513,14 +513,14 @@ export class NotificationsDb extends BaseDb {
return result.map((it: any) => toNotification(it))
}
async updateCollaborators(params: FindCollaboratorsParams, data: Partial<Collaborator>): Promise<void> {
async updateCollaborators (params: FindCollaboratorsParams, data: Partial<Collaborator>): Promise<void> {
const dbData: Partial<CollaboratorDb> = {
account: data.account,
card_id: data.card,
card_type: data.cardType
}
const entries = Object.entries(dbData).filter(([_, value]) => value != undefined)
const entries = Object.entries(dbData).filter(([_, value]) => value != null)
if (entries.length === 0) return
entries.unshift(['workspace_id', this.workspace])
@@ -535,7 +535,8 @@ export class NotificationsDb extends BaseDb {
await this.execute(sql, [...setValues, ...whereValues], 'update collaborators')
}
async findCollaborators(params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (params: FindCollaboratorsParams): Promise<Collaborator[]> {
const { where, values } = this.buildCollaboratorsWhere(params)
const select = `
SELECT *
@@ -552,11 +553,11 @@ export class NotificationsDb extends BaseDb {
return result.map((it: any) => toCollaborator(it))
}
private buildCollaboratorsWhere(
private buildCollaboratorsWhere (
params: FindCollaboratorsParams,
startIndex: number = 0,
prefix: string = 'c.'
): { where: string; values: any[] } {
): { where: string, values: any[] } {
const where: string[] = []
const values: any[] = []
let index = startIndex + 1
@@ -580,7 +581,7 @@ export class NotificationsDb extends BaseDb {
return { where: `WHERE ${where.join(' AND ')}`, values }
}
private buildContextWhere(params: FindNotificationContextParams): {
private buildContextWhere (params: FindNotificationContextParams): {
where: string
values: any[]
index: number
@@ -627,14 +628,14 @@ export class NotificationsDb extends BaseDb {
return { where: `WHERE ${where.join(' AND ')}`, values, index }
}
private buildNotificationWhere(
private buildNotificationWhere (
params: FindNotificationsParams,
initialIndex?: number,
skipWorkspace?: boolean
): {
where: string
values: any[]
} {
where: string
values: any[]
} {
const where: string[] = skipWorkspace === true ? [] : ['nc.workspace_id = $1::uuid']
const values: any[] = skipWorkspace === true ? [] : [this.workspace]
let index = (initialIndex ?? 0) + values.length + 1
+3 -2
View File
@@ -29,9 +29,10 @@ import {
type CardType,
type BlobMetadata,
type LinkPreviewImage,
type LinkPreviewID
type LinkPreviewID,
NotificationContent,
NotificationType
} from '@hcengineering/communication-types'
import type { NotificationContent, NotificationType } from '@hcengineering/communication-types'
export enum TableName {
File = 'communication.files',
+2 -2
View File
@@ -13,13 +13,13 @@
// limitations under the License.
//
export function getCondition(
export function getCondition (
table: string,
dbField: string,
startIndex: number,
param: any,
type: string
): { where: string; values: any[]; index: number } | undefined {
): { where: string, values: any[], index: number } | undefined {
const conditions: string[] = []
const values: any[] = []
let index = startIndex
+21 -19
View File
@@ -15,19 +15,21 @@
import type postgres from 'postgres'
/* eslint-disable @typescript-eslint/naming-convention */
const migrationsTableName = 'communication._migrations'
let isSchemaInitialized = false
let initPromise: Promise<void> | null = null
export function isInitialized(): boolean {
export function isInitialized (): boolean {
return isSchemaInitialized
}
export async function initSchema(sql: postgres.Sql): Promise<void> {
export async function initSchema (sql: postgres.Sql): Promise<void> {
if (isInitialized()) return
if (!initPromise) {
if (initPromise == null) {
initPromise = (async () => {
const maxAttempts = 3
const retryDelay = 3000
@@ -57,11 +59,11 @@ export async function initSchema(sql: postgres.Sql): Promise<void> {
await initPromise
}
function delay(ms: number): Promise<void> {
return new Promise((res) => setTimeout(res, ms))
function delay (ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms))
}
async function init(sql: postgres.Sql) {
async function init (sql: postgres.Sql): Promise<void> {
if (isSchemaInitialized) return
const start = performance.now()
console.log('🗃️ Initializing schema...')
@@ -99,7 +101,7 @@ async function init(sql: postgres.Sql) {
console.log(`🎉 All migrations complete in ${resTime.toFixed(2)} sec`)
}
function getMigrations(): [string, string][] {
function getMigrations (): [string, string][] {
return [
migrationV1_1(),
migrationV1_2(),
@@ -115,7 +117,7 @@ function getMigrations(): [string, string][] {
]
}
function migrationV1_1(): [string, string] {
function migrationV1_1 (): [string, string] {
const sql = `
DROP SCHEMA IF EXISTS communication CASCADE;
CREATE SCHEMA IF NOT EXISTS communication;
@@ -130,7 +132,7 @@ function migrationV1_1(): [string, string] {
return ['recreate_schema-v1_1', sql]
}
function migrationV1_2(): [string, string] {
function migrationV1_2 (): [string, string] {
const sql = `
CREATE TABLE IF NOT EXISTS communication.messages
(
@@ -280,7 +282,7 @@ function migrationV1_2(): [string, string] {
return ['reinit_tables-v1_2', sql]
}
function migrationV2_1(): [string, string] {
function migrationV2_1 (): [string, string] {
const sql = `
ALTER TABLE communication.notifications
ADD COLUMN IF NOT EXISTS type VARCHAR(255) NOT NULL DEFAULT 'message';
@@ -288,7 +290,7 @@ function migrationV2_1(): [string, string] {
return ['add_type_column_to_notifications-v2_1', sql]
}
function migrationV2_2(): [string, string] {
function migrationV2_2 (): [string, string] {
const sql = `
ALTER TABLE communication.notifications
ADD COLUMN IF NOT EXISTS read BOOLEAN NOT NULL DEFAULT false;
@@ -296,12 +298,12 @@ function migrationV2_2(): [string, string] {
return ['add_read_column_to_notifications-v2_2', sql]
}
function migrationV2_3(): [string, string] {
const sql = `UPDATE communication.notifications SET read = true; `
function migrationV2_3 (): [string, string] {
const sql = 'UPDATE communication.notifications SET read = true; '
return ['set_read_to_true-v2_3', sql]
}
function migrationV2_4(): [string, string] {
function migrationV2_4 (): [string, string] {
const sql = `
ALTER TABLE communication.notifications
ADD COLUMN IF NOT EXISTS message_created TIMESTAMPTZ;
@@ -309,7 +311,7 @@ function migrationV2_4(): [string, string] {
return ['add_message_created_column_to_notifications-v2_4', sql]
}
function migrationV2_5(): [string, string] {
function migrationV2_5 (): [string, string] {
const sql = `
UPDATE communication.notifications
SET message_created = created;
@@ -320,7 +322,7 @@ function migrationV2_5(): [string, string] {
return ['init_and_set_not_null_message_created_notifications-v2_4', sql]
}
function migrationV2_6(): [string, string] {
function migrationV2_6 (): [string, string] {
const sql = `
ALTER TABLE communication.notification_context
ADD COLUMN IF NOT EXISTS last_notify TIMESTAMPTZ;
@@ -328,7 +330,7 @@ function migrationV2_6(): [string, string] {
return ['add_last_notify_column_to_notification_context-v2_6', sql]
}
function migrationV2_7(): [string, string] {
function migrationV2_7 (): [string, string] {
const sql = `
UPDATE communication.notification_context
SET last_notify = last_update;`
@@ -336,7 +338,7 @@ function migrationV2_7(): [string, string] {
return ['set_last_notify_to_last_update-v2_7', sql]
}
function migrationV3_1(): [string, string] {
function migrationV3_1 (): [string, string] {
const sql = `
CREATE TABLE IF NOT EXISTS communication.link_preview
(
@@ -363,7 +365,7 @@ function migrationV3_1(): [string, string] {
return ['init_link_preview-v3_1', sql]
}
function migrationV4_1(): [string, string] {
function migrationV4_1 (): [string, string] {
const sql = `
CREATE INDEX IF NOT EXISTS notifications_context_id_read_created_desc_idx ON communication.notifications (context_id, read, created DESC);
`
+6 -6
View File
@@ -13,13 +13,13 @@
// limitations under the License.
//
export function injectVars(sql: string, values: any[]): string {
export function injectVars (sql: string, values: any[]): string {
return sql.replaceAll(/(\$\d+)/g, (_, idx) => {
return escape(values[parseInt(idx.substring(1)) - 1])
})
}
function escape(value: any): string {
function escape (value: any): string {
if (value === null || value === undefined) {
return 'NULL'
}
@@ -53,7 +53,7 @@ function escape(value: any): string {
}
}
export function convertArrayParams(params?: unknown[]): any[] | undefined {
export function convertArrayParams (params?: unknown[]): any[] | undefined {
if (params === undefined) return undefined
return params.map((param) => {
@@ -83,14 +83,14 @@ export function convertArrayParams(params?: unknown[]): any[] | undefined {
}
const SEP = ','
function getFirstName(name: string): string {
function getFirstName (name: string): string {
return name !== undefined ? name.substring(name.indexOf(SEP) + 1) : ''
}
function getLastName(name: string): string {
function getLastName (name: string): string {
return name !== undefined ? name.substring(0, name.indexOf(SEP)) : ''
}
export function formatName(name: string): string {
export function formatName (name: string): string {
return getFirstName(name) + ' ' + getLastName(name)
}
+8 -6
View File
@@ -1,10 +1,12 @@
{
"extends": "../../tsconfig.json",
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src"]
}
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+38 -21
View File
@@ -1,42 +1,59 @@
{
"name": "@hcengineering/communication-query",
"version": "0.1.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:browser",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:browser": "bun build src/index.ts --outdir dist --target browser",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts ",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/crypto-js": "^4.2.2"
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3"
},
"dependencies": {
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-yaml": "workspace:*",
"@hcengineering/communication-sdk-types": "^0.1.0",
"@hcengineering/communication-shared": "^0.1.0",
"@hcengineering/communication-types": "^0.1.0",
"@hcengineering/communication-yaml": "^0.1.0",
"fast-equals": "^5.0.1",
"uuid": "^11.1.0"
},
"peerDependencies": {
"typescript": "^5.6.3"
},
"repository": {
"type": "git",
"url": "git+https://github.com/hcengineering/communication.git"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+24 -23
View File
@@ -31,7 +31,7 @@ import {
import { QueryResult } from '../result'
import { type Query, type QueryId } from '../types'
function getId(label: Label): string {
function getId (label: Label): string {
return `${label.label}:${label.card}:${label.account}`
}
@@ -39,7 +39,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
private result: Promise<QueryResult<Label>> | QueryResult<Label>
private isCardRemoved = false
constructor(
constructor (
private readonly client: FindClient,
private readonly workspace: WorkspaceID,
private readonly filesUrl: string,
@@ -56,7 +56,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
}
}
async onEvent(event: ResponseEvent): Promise<void> {
async onEvent (event: ResponseEvent): Promise<void> {
if (this.isCardRemoved) return
switch (event.type) {
case LabelResponseEventType.LabelCreated:
@@ -75,19 +75,19 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
}
}
async onLabelCreated(event: LabelCreatedEvent): Promise<void> {
async onLabelCreated (event: LabelCreatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.limit && this.result.length >= this.params.limit) return
if (this.params.limit != null && this.result.length >= this.params.limit) return
const match = this.match(event.label)
if (!match) return
const existing = this.result.get(getId(event.label))
if (existing) return
if (existing != null) return
this.result.push(event.label)
void this.notify()
}
async onLabelRemoved(event: LabelRemovedEvent): Promise<void> {
async onLabelRemoved (event: LabelRemovedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
const existing = this.result
@@ -97,7 +97,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
const prevLength = this.result.length
this.result.delete(getId(existing))
if (this.params.limit && this.result.length < this.params.limit && prevLength >= this.params.limit) {
if (this.params.limit != null && this.result.length < this.params.limit && prevLength >= this.params.limit) {
const labels = await this.find(this.params)
this.result = new QueryResult(labels, getId)
}
@@ -105,7 +105,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
void this.notify()
}
async onCardTypeUpdated(event: CardTypeUpdatedEvent): Promise<void> {
async onCardTypeUpdated (event: CardTypeUpdatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
const result = this.result.getResult()
@@ -123,7 +123,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
}
for (const label of result) {
if (label.card == event.card) {
if (label.card === event.card) {
const updatedLabel: Label = { ...label, cardType: event.cardType }
const matched = this.match(updatedLabel)
if (matched) {
@@ -137,7 +137,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
if (updated) {
const newLength = this.result.length
if (this.params.limit && newLength < currentLength && newLength >= this.params.limit) {
if (this.params.limit != null && newLength < currentLength && newLength >= this.params.limit) {
const labels = await this.find(this.params)
this.result = new QueryResult(labels, getId)
}
@@ -146,7 +146,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
}
}
async onCardRemoved(event: CardRemovedEvent): Promise<void> {
async onCardRemoved (event: CardRemovedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.card === event.card) {
@@ -160,23 +160,24 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
const prevLength = this.result.length
let deleted = false
for (const label of result) {
if (label.card == event.card) {
if (label.card === event.card) {
this.result.delete(label.label)
deleted = true
}
}
if (deleted) {
if (this.params.limit && this.result.length < this.params.limit && prevLength >= this.params.limit) {
if (this.params.limit != null && this.result.length < this.params.limit && prevLength >= this.params.limit) {
const labels = await this.find(this.params)
this.result = new QueryResult(labels, getId)
}
void this.notify()
}
}
async onRequest(event: RequestEvent, promise: Promise<EventResult>): Promise<void> {}
private async initResult(): Promise<QueryResult<Label>> {
async onRequest (event: RequestEvent, promise: Promise<EventResult>): Promise<void> {}
private async initResult (): Promise<QueryResult<Label>> {
try {
const res = await this.find(this.params)
const result = new QueryResult(res, getId)
@@ -189,20 +190,20 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
}
}
async unsubscribe(): Promise<void> {
async unsubscribe (): Promise<void> {
await this.client.unsubscribeQuery(this.id)
}
removeCallback(): void {
removeCallback (): void {
this.callback = () => {}
}
setCallback(callback: QueryCallback<Label>): void {
setCallback (callback: QueryCallback<Label>): void {
this.callback = callback
void this.notify()
}
copyResult(): QueryResult<Label> | undefined {
copyResult (): QueryResult<Label> | undefined {
if (this.result instanceof Promise) {
return undefined
}
@@ -210,19 +211,19 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
return this.result.copy()
}
private async find(params: FindLabelsParams): Promise<Label[]> {
private async find (params: FindLabelsParams): Promise<Label[]> {
if (this.isCardRemoved) return []
return await this.client.findLabels(params, this.id)
}
private async notify(): Promise<void> {
private async notify (): Promise<void> {
if (this.callback == null) return
if (this.result instanceof Promise) this.result = await this.result
const result = this.result.getResult()
this.callback(result)
}
private match(label: Label): boolean {
private match (label: Label): boolean {
if (this.params.account != null && this.params.account !== label.account) {
return false
}
+17 -17
View File
@@ -51,7 +51,7 @@ export class LiveQueries {
private readonly unsubscribed = new Set<QueryId>()
private counter: number = 0
constructor(
constructor (
private readonly client: FindClient,
private readonly workspace: WorkspaceID,
private readonly filesUrl: string
@@ -64,19 +64,19 @@ export class LiveQueries {
}
}
async onEvent(event: ResponseEvent): Promise<void> {
async onEvent (event: ResponseEvent): Promise<void> {
for (const q of this.queries.values()) {
void q.onEvent(event)
}
}
async onRequest(event: RequestEvent, promise: Promise<EventResult>): Promise<void> {
async onRequest (event: RequestEvent, promise: Promise<EventResult>): Promise<void> {
for (const q of this.queries.values()) {
void q.onRequest(event, promise)
}
}
queryMessages(params: MessageQueryParams, callback: PagedQueryCallback<Message>): CreateQueryResult {
queryMessages (params: MessageQueryParams, callback: PagedQueryCallback<Message>): CreateQueryResult {
return this.createAndStoreQuery<Message, FindMessagesParams, MessagesQuery>(
params,
callback,
@@ -85,7 +85,7 @@ export class LiveQueries {
)
}
queryNotifications(params: FindNotificationsParams, callback: PagedQueryCallback<Notification>): CreateQueryResult {
queryNotifications (params: FindNotificationsParams, callback: PagedQueryCallback<Notification>): CreateQueryResult {
return this.createAndStoreQuery<Notification, FindNotificationsParams, NotificationQuery>(
params,
callback,
@@ -94,7 +94,7 @@ export class LiveQueries {
)
}
queryNotificationContexts(params: FindNotificationContextParams, callback: any): CreateQueryResult {
queryNotificationContexts (params: FindNotificationContextParams, callback: any): CreateQueryResult {
return this.createAndStoreQuery<NotificationContext, FindNotificationContextParams, NotificationContextsQuery>(
params,
callback,
@@ -103,7 +103,7 @@ export class LiveQueries {
)
}
queryLabels(params: FindLabelsParams, callback: any): CreateQueryResult {
queryLabels (params: FindLabelsParams, callback: any): CreateQueryResult {
return this.createAndStoreQuery<Label, FindLabelsParams, LabelsQuery>(params, callback, LabelsQuery, (params) =>
this.findLabelsQuery(params)
)
@@ -151,32 +151,32 @@ export class LiveQueries {
private findQuery<T extends AnyQuery>(params: FindParams, QueryClass: new (...args: any[]) => T): T | undefined {
for (const query of this.queries.values()) {
if (query instanceof QueryClass && this.queryCompare(params, query.params)) {
return query as T
return query
}
}
}
private findMessagesQuery(params: FindMessagesParams): MessagesQuery | undefined {
private findMessagesQuery (params: FindMessagesParams): MessagesQuery | undefined {
return this.findQuery(params, MessagesQuery)
}
private findNotificationQuery(params: FindNotificationsParams): NotificationQuery | undefined {
private findNotificationQuery (params: FindNotificationsParams): NotificationQuery | undefined {
return this.findQuery(params, NotificationQuery)
}
private findNotificationContextsQuery(params: FindNotificationContextParams): NotificationContextsQuery | undefined {
private findNotificationContextsQuery (params: FindNotificationContextParams): NotificationContextsQuery | undefined {
return this.findQuery(params, NotificationContextsQuery)
}
private findLabelsQuery(params: FindLabelsParams): LabelsQuery | undefined {
private findLabelsQuery (params: FindLabelsParams): LabelsQuery | undefined {
return this.findQuery(params, LabelsQuery)
}
private queryCompare(q1: FindParams, q2: FindParams): boolean {
private queryCompare (q1: FindParams, q2: FindParams): boolean {
return Object.keys(q1).length === Object.keys(q2).length && deepEqual(q1, q2)
}
private removeOldQueries(): void {
private removeOldQueries (): void {
const unsubscribed = Array.from(this.unsubscribed)
for (let i = 0; i < this.unsubscribed.size / 2; i++) {
const id = unsubscribed.shift()
@@ -185,7 +185,7 @@ export class LiveQueries {
}
}
private unsubscribe(id: QueryId): void {
private unsubscribe (id: QueryId): void {
const query = this.queries.get(id)
if (query == null) return
void query.unsubscribe()
@@ -193,7 +193,7 @@ export class LiveQueries {
this.unsubscribed.delete(id)
}
private unsubscribeQuery(query: AnyQuery): void {
private unsubscribeQuery (query: AnyQuery): void {
this.unsubscribed.add(query.id)
query.removeCallback()
if (this.unsubscribed.size > maxQueriesCache) {
@@ -201,7 +201,7 @@ export class LiveQueries {
}
}
close(): void {
close (): void {
this.queries.clear()
this.unsubscribed.clear()
}
+52 -52
View File
@@ -65,7 +65,7 @@ import {
type QueryId
} from '../types'
import { WindowImpl } from '../window'
import { addFile, addLinkPreview, addReaction, removeFile, removeLinkPreview, removeReaction } from '../utils.ts'
import { addFile, addLinkPreview, addReaction, removeFile, removeLinkPreview, removeReaction } from '../utils'
const GROUPS_LIMIT = 4
@@ -96,15 +96,15 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
buffer: [] as Message[]
}
private createdFiles: Map<MessageID, File[]> = new Map()
private createdReactions: Map<MessageID, Reaction[]> = new Map()
private createdLinkPreviews: Map<MessageID, LinkPreview[]> = new Map()
private createdPatches: Map<MessageID, Patch[]> = new Map()
private readonly createdFiles = new Map<MessageID, File[]>()
private readonly createdReactions = new Map<MessageID, Reaction[]>()
private readonly createdLinkPreviews = new Map<MessageID, LinkPreview[]>()
private readonly createdPatches = new Map<MessageID, Patch[]>()
private readonly tmpMessages = new Map<string, MessageID>()
private isCardRemoved = false
constructor(
constructor (
private readonly client: FindClient,
private readonly workspace: WorkspaceID,
private readonly filesUrl: string,
@@ -152,7 +152,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async onEvent(event: ResponseEvent): Promise<void> {
async onEvent (event: ResponseEvent): Promise<void> {
if (this.isCardRemoved) return
switch (event.type) {
case MessageResponseEventType.MessageCreated: {
@@ -196,7 +196,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async onCardRemoved(event: CardRemovedEvent): Promise<void> {
async onCardRemoved (event: CardRemovedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.card === event.card) {
this.isCardRemoved = true
@@ -220,7 +220,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async onRequest(event: RequestEvent, promise: Promise<EventResult>): Promise<void> {
async onRequest (event: RequestEvent, promise: Promise<EventResult>): Promise<void> {
if (this.isCardRemoved) return
switch (event.type) {
case MessageRequestEventType.CreateMessage: {
@@ -230,7 +230,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async onCreateMessageRequest(event: CreateMessageEvent, promise: Promise<CreateMessageResult>): Promise<void> {
async onCreateMessageRequest (event: CreateMessageEvent, promise: Promise<CreateMessageResult>): Promise<void> {
if (this.params.card !== event.card) return
const eventId = event._id
if (eventId == null) return
@@ -291,7 +291,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private insertMessage(result: QueryResult<Message>, message: Message): void {
private insertMessage (result: QueryResult<Message>, message: Message): void {
if (this.params.order === SortingOrder.Ascending) {
result.push(message)
} else {
@@ -299,11 +299,11 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async unsubscribe(): Promise<void> {
async unsubscribe (): Promise<void> {
await this.client.unsubscribeQuery(this.id)
}
async requestLoadNextPage(): Promise<void> {
async requestLoadNextPage (): Promise<void> {
if (this.isCardRemoved) return
if (this.result instanceof Promise) this.result = await this.result
@@ -318,7 +318,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
async requestLoadPrevPage(): Promise<void> {
async requestLoadPrevPage (): Promise<void> {
if (this.isCardRemoved) return
if (this.result instanceof Promise) this.result = await this.result
if (!this.result.isHead()) {
@@ -332,16 +332,16 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
removeCallback(): void {
removeCallback (): void {
this.callback = () => {}
}
setCallback(callback: PagedQueryCallback<Message>): void {
setCallback (callback: PagedQueryCallback<Message>): void {
this.callback = callback
void this.notify()
}
copyResult(): QueryResult<Message> | undefined {
copyResult (): QueryResult<Message> | undefined {
if (this.result instanceof Promise) {
return undefined
}
@@ -349,7 +349,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return this.result.copy()
}
private isInitLoadingForward(): boolean {
private isInitLoadingForward (): boolean {
const { order } = this.params
if (this.isOneMessageQuery(this.params)) {
@@ -359,7 +359,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return order === SortingOrder.Ascending
}
private async loadPage(direction: Direction, result: QueryResult<Message>): Promise<QueryResult<Message>> {
private async loadPage (direction: Direction, result: QueryResult<Message>): Promise<QueryResult<Message>> {
const { messages, fromDb } =
direction === Direction.Forward ? await this.loadNextMessages(result) : await this.loadPrevMessages(result)
@@ -393,7 +393,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
// Load next
private async loadNextMessages(result: QueryResult<Message>): Promise<{ messages: Message[]; fromDb: boolean }> {
private async loadNextMessages (result: QueryResult<Message>): Promise<{ messages: Message[], fromDb: boolean }> {
const messages: Message[] = this.next.buffer.splice(0, this.limit)
if (messages.length >= this.limit) return { messages, fromDb: false }
@@ -411,7 +411,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return { messages, fromDb: dbMessages.length > 0 }
}
private async findNextMessages(limit: number, result: QueryResult<Message>): Promise<Message[]> {
private async findNextMessages (limit: number, result: QueryResult<Message>): Promise<Message[]> {
if (this.next.hasGroups) {
return []
}
@@ -436,9 +436,9 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
// Load prev
private async loadPrevMessages(
private async loadPrevMessages (
result: QueryResult<Message>
): Promise<{ messages: Message[]; fromDb: boolean; hasNext?: boolean }> {
): Promise<{ messages: Message[], fromDb: boolean, hasNext?: boolean }> {
const messages: Message[] = []
const prevBuffer = this.prev.buffer
const last = prevBuffer[prevBuffer.length - 1]
@@ -482,7 +482,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return { messages, fromDb: false }
}
private async findPrevMessages(limit: number, result: QueryResult<Message>): Promise<Message[]> {
private async findPrevMessages (limit: number, result: QueryResult<Message>): Promise<Message[]> {
if (!this.prev.hasMessages || result.isHead()) return []
const first = this.params.order === SortingOrder.Ascending ? result.getFirst() : result.getLast()
@@ -502,7 +502,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
})
}
getLoadGroupsParams(direction: Direction): Pick<FindMessagesGroupsParams, 'fromDate' | 'toDate'> | undefined {
getLoadGroupsParams (direction: Direction): Pick<FindMessagesGroupsParams, 'fromDate' | 'toDate'> | undefined {
if (direction === Direction.Forward) {
if (this.lastGroup != null) {
return {
@@ -542,7 +542,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return undefined
}
private async loadGroups(direction: Direction, result: QueryResult<Message>): Promise<void> {
private async loadGroups (direction: Direction, result: QueryResult<Message>): Promise<void> {
let messagesCount = 0
const lastResult = result.getLast()
const toLoad: MessagesGroup[] = []
@@ -638,12 +638,12 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private matchFileMessages(
private matchFileMessages (
file: ParsedFile,
direction: Direction,
queryResult: QueryResult<Message>,
filterDate?: Date
): { next: Message[]; prev: Message[] } {
): { next: Message[], prev: Message[] } {
let result: Message[] = file.messages
const params = this.params
if (this.isOneMessageQuery(params)) {
@@ -687,7 +687,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return { next: nextResult, prev: prevResult }
}
private async loadMessagesFromFiles(group: MessagesGroup): Promise<ParsedFile> {
private async loadMessagesFromFiles (group: MessagesGroup): Promise<ParsedFile> {
const parsedFile = await loadGroupFile(this.workspace, this.filesUrl, group, { retries: 5 })
const patches = group.patches ?? []
@@ -701,13 +701,13 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
messages:
patches.length > 0
? parsedFile.messages.map((message) =>
applyPatches(message, patchesMap.get(message.id) ?? [], this.allowedPatches())
)
applyPatches(message, patchesMap.get(message.id) ?? [], this.allowedPatches())
)
: parsedFile.messages
}
}
private async findGroupByDate(params: Date): Promise<MessagesGroup | undefined> {
private async findGroupByDate (params: Date): Promise<MessagesGroup | undefined> {
const groups = await this.client.findMessagesGroups({
card: this.params.card,
fromDate: { lessOrEqual: params },
@@ -720,7 +720,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return groups[0]
}
private async findGroups(
private async findGroups (
direction: Direction,
date?: Pick<FindMessagesGroupsParams, 'fromDate' | 'toDate'>
): Promise<MessagesGroup[]> {
@@ -747,16 +747,16 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
})
}
private async find(params: FindMessagesParams): Promise<Message[]> {
private async find (params: FindMessagesParams): Promise<Message[]> {
delete (params as any).from
return await this.client.findMessages(params, this.id)
}
private isOneMessageQuery(params: MessageQueryParams): params is OneMessageQueryParams {
private isOneMessageQuery (params: MessageQueryParams): params is OneMessageQueryParams {
return 'id' in this.params && this.params.id != null
}
private async notify(): Promise<void> {
private async notify (): Promise<void> {
this.initialized = true
if (this.callback == null) return
if (this.result instanceof Promise) this.result = await this.result
@@ -764,7 +764,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
this.callback(new WindowImpl(result, this.result.isTail(), this.result.isHead(), this))
}
private match(message: Message): boolean {
private match (message: Message): boolean {
if (this.isOneMessageQuery(this.params) && this.params.id !== message.id) {
return false
}
@@ -774,7 +774,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return true
}
private async onThreadCreatedEvent(event: ThreadCreatedEvent): Promise<void> {
private async onThreadCreatedEvent (event: ThreadCreatedEvent): Promise<void> {
if (this.params.replies !== true) return
if (this.params.card !== event.thread.card) return
if (this.result instanceof Promise) this.result = await this.result
@@ -810,7 +810,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
})
}
private fillMessage(origin: Message): Message {
private fillMessage (origin: Message): Message {
let message = origin
if (this.params.files === true) {
message.files = this.createdFiles.get(message.id) ?? []
@@ -826,7 +826,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return message
}
private async onMessageCreatedEvent(event: MessageCreatedEvent): Promise<void> {
private async onMessageCreatedEvent (event: MessageCreatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.card !== event.message.card) return
let message = event.message
@@ -850,7 +850,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
const lastMessage = this.result.getLast()
const firstMessage = this.result.getFirst()
function shouldResort(order: SortingOrder): boolean {
function shouldResort (order: SortingOrder): boolean {
if (firstMessage == null || lastMessage == null) return false
if (order === SortingOrder.Ascending) {
return lastMessage.created > message.created
@@ -875,14 +875,14 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
this.cleanCache(message.id)
}
private cleanCache(message: MessageID): void {
private cleanCache (message: MessageID): void {
this.createdFiles.delete(message)
this.createdReactions.delete(message)
this.createdLinkPreviews.delete(message)
this.createdPatches.delete(message)
}
private async onPatchCreatedEvent(event: PatchCreatedEvent): Promise<void> {
private async onPatchCreatedEvent (event: PatchCreatedEvent): Promise<void> {
if (this.params.card !== event.card) return
if (!this.isAllowedPatch(event.patch.type)) return
const current = this.createdPatches.get(event.patch.message) ?? []
@@ -908,7 +908,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private async onReactionCreatedEvent(event: ReactionCreatedEvent): Promise<void> {
private async onReactionCreatedEvent (event: ReactionCreatedEvent): Promise<void> {
if (this.params.reactions !== true || this.params.card !== event.card) return
const current = this.createdReactions.get(event.message) ?? []
this.createdReactions.set(event.message, [...current, event.reaction])
@@ -935,7 +935,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private async onReactionRemovedEvent(event: ReactionRemovedEvent): Promise<void> {
private async onReactionRemovedEvent (event: ReactionRemovedEvent): Promise<void> {
if (this.params.reactions !== true || this.params.card !== event.card) return
const current = this.createdReactions.get(event.message) ?? []
const reactions = current.filter((it) => it.reaction !== event.reaction || it.creator !== event.creator)
@@ -958,7 +958,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
)
}
private updateFilesCache(message: MessageID, files: File[]): void {
private updateFilesCache (message: MessageID, files: File[]): void {
const filesCache = this.createdFiles.get(message) ?? []
this.createdFiles.set(message, filesCache)
for (const file of files) {
@@ -969,7 +969,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private async onFileCreatedEvent(event: FileCreatedEvent): Promise<void> {
private async onFileCreatedEvent (event: FileCreatedEvent): Promise<void> {
if (this.params.files !== true || event.card !== this.params.card) return
this.updateFilesCache(event.message, [event.file])
if (this.result instanceof Promise) this.result = await this.result
@@ -994,7 +994,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private async onLinkPreviewCreatedEvent(event: LinkPreviewCreatedEvent): Promise<void> {
private async onLinkPreviewCreatedEvent (event: LinkPreviewCreatedEvent): Promise<void> {
if (this.params.links !== true || this.params.card !== event.card) return
const current = this.createdLinkPreviews.get(event.message) ?? []
this.createdLinkPreviews.set(event.message, [...current, event.linkPreview])
@@ -1019,7 +1019,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
}
}
private async onLinkPreviewRemovedEvent(event: LinkPreviewRemovedEvent): Promise<void> {
private async onLinkPreviewRemovedEvent (event: LinkPreviewRemovedEvent): Promise<void> {
if (this.params.links !== true || this.params.card !== event.card) return
const current = this.createdLinkPreviews.get(event.message) ?? []
const linkPreviews = current.filter((it) => it.id !== event.id)
@@ -1042,7 +1042,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
this.prev.buffer = this.prev.buffer.map((it) => (it.id === event.message ? removeLinkPreview(it, event.id) : it))
}
private async onFileRemovedEvent(event: FileRemovedEvent): Promise<void> {
private async onFileRemovedEvent (event: FileRemovedEvent): Promise<void> {
if (this.params.files !== true) return
if (this.params.card !== event.card) return
const current = this.createdFiles.get(event.message) ?? []
@@ -1067,7 +1067,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
this.prev.buffer = this.prev.buffer.map((it) => (it.id === event.message ? removeFile(it, event.blobId) : it))
}
private allowedPatches(): PatchType[] {
private allowedPatches (): PatchType[] {
const result = [PatchType.update, PatchType.remove]
if (this.params.reactions === true) {
@@ -1082,7 +1082,7 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
return result
}
private isAllowedPatch(type: PatchType): boolean {
private isAllowedPatch (type: PatchType): boolean {
return this.allowedPatches().includes(type)
}
}
@@ -73,7 +73,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
private forward: Promise<NotificationContext[]> | NotificationContext[] = []
private backward: Promise<NotificationContext[]> | NotificationContext[] = []
constructor(
constructor (
private readonly client: FindClient,
private readonly workspace: WorkspaceID,
private readonly filesUrl: string,
@@ -123,7 +123,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
async onEvent(event: ResponseEvent): Promise<void> {
async onEvent (event: ResponseEvent): Promise<void> {
switch (event.type) {
case MessageResponseEventType.PatchCreated: {
await this.onCreatePatchEvent(event)
@@ -170,13 +170,13 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
async onRequest(event: RequestEvent): Promise<void> {}
async onRequest (event: RequestEvent): Promise<void> {}
async unsubscribe(): Promise<void> {
async unsubscribe (): Promise<void> {
await this.client.unsubscribeQuery(this.id)
}
async requestLoadNextPage(): Promise<void> {
async requestLoadNextPage (): Promise<void> {
if (this.result instanceof Promise) {
this.result = await this.result
}
@@ -216,7 +216,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
})
}
async requestLoadPrevPage(): Promise<void> {
async requestLoadPrevPage (): Promise<void> {
if (this.result instanceof Promise) {
this.result = await this.result
}
@@ -261,16 +261,16 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
})
}
removeCallback(): void {
removeCallback (): void {
this.callback = () => {}
}
setCallback(callback: PagedQueryCallback<NotificationContext>): void {
setCallback (callback: PagedQueryCallback<NotificationContext>): void {
this.callback = callback
void this.notify()
}
copyResult(): QueryResult<NotificationContext> | undefined {
copyResult (): QueryResult<NotificationContext> | undefined {
if (this.result instanceof Promise) {
return undefined
}
@@ -278,7 +278,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
return this.result.copy()
}
private async find(params: FindNotificationContextParams): Promise<NotificationContext[]> {
private async find (params: FindNotificationContextParams): Promise<NotificationContext[]> {
const contexts = await this.client.findNotificationContexts(params, this.id)
if (params.notifications?.message !== true) return contexts
@@ -314,7 +314,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
return contexts
}
private async onCreateNotificationContextEvent(event: NotificationContextCreatedEvent): Promise<void> {
private async onCreateNotificationContextEvent (event: NotificationContextCreatedEvent): Promise<void> {
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
@@ -333,7 +333,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
void this.notify()
}
private async onCreatePatchEvent(event: PatchCreatedEvent): Promise<void> {
private async onCreatePatchEvent (event: PatchCreatedEvent): Promise<void> {
const isUpdated = await this.updateMessage(event.card, event.patch.message, (message) =>
applyPatch(message, event.patch, allowedPatchTypes)
)
@@ -342,14 +342,14 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async onFileCreated(event: FileCreatedEvent): Promise<void> {
private async onFileCreated (event: FileCreatedEvent): Promise<void> {
const isUpdated = await this.updateMessage(event.card, event.message, (message) => addFile(message, event.file))
if (isUpdated) {
void this.notify()
}
}
private async onFileRemoved(event: FileRemovedEvent): Promise<void> {
private async onFileRemoved (event: FileRemovedEvent): Promise<void> {
const isUpdated = await this.updateMessage(event.card, event.message, (message) =>
removeFile(message, event.blobId)
)
@@ -358,7 +358,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async onThreadCreated(event: ThreadCreatedEvent): Promise<void> {
private async onThreadCreated (event: ThreadCreatedEvent): Promise<void> {
const isUpdated = await this.updateMessage(event.thread.card, event.thread.message, (message) =>
createThread(
message,
@@ -373,7 +373,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async onThreadUpdated(event: ThreadUpdatedEvent): Promise<void> {
private async onThreadUpdated (event: ThreadUpdatedEvent): Promise<void> {
const isUpdated = await this.updateMessage(event.card, event.message, (message) =>
updateThread(message, event.thread, event.updates.replies, event.updates.lastReply)
)
@@ -382,14 +382,14 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async onRemoveNotificationEvent(event: NotificationsRemovedEvent): Promise<void> {
private async onRemoveNotificationEvent (event: NotificationsRemovedEvent): Promise<void> {
if (this.params.notifications == null) return
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
const context = this.result.get(event.context)
if (context === undefined || context.notifications === undefined) return
if (context?.notifications === undefined) return
const filtered = context.notifications.filter((it) => !event.ids.includes(it.id))
if (filtered.length === context.notifications.length) return
@@ -413,14 +413,14 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
void this.notify()
}
private async onUpdateNotificationEvent(event: NotificationUpdatedEvent): Promise<void> {
private async onUpdateNotificationEvent (event: NotificationUpdatedEvent): Promise<void> {
if (this.params.notifications == null) return
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
const context = this.result.get(event.query.context)
if (context === undefined || context.notifications === undefined) return
if (context?.notifications === undefined) return
const toUpdate = context.notifications.filter(
(it) => matchNotification(it, event.query) && it.read !== event.updates.read
@@ -451,7 +451,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
void this.notify()
}
private async onCreateNotificationEvent(event: NotificationCreatedEvent): Promise<void> {
private async onCreateNotificationEvent (event: NotificationCreatedEvent): Promise<void> {
if (this.params.notifications == null) return
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
@@ -468,16 +468,16 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
const message =
this.params.notifications.message === true
? await findMessage(
this.client,
this.workspace,
this.filesUrl,
context.card,
event.notification.messageId,
event.notification.messageCreated,
false,
true,
true
)
this.client,
this.workspace,
this.filesUrl,
context.card,
event.notification.messageId,
event.notification.messageCreated,
false,
true,
true
)
: undefined
const notifications = [
@@ -506,7 +506,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async onRemoveNotificationContextEvent(event: NotificationContextRemovedEvent): Promise<void> {
private async onRemoveNotificationContextEvent (event: NotificationContextRemovedEvent): Promise<void> {
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
@@ -515,7 +515,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
const deleted = this.result.delete(event.context.id)
if (deleted != null) {
if (this.params.limit && length >= this.params.limit && this.result.length < this.params.limit) {
if (this.params.limit != null && length >= this.params.limit && this.result.length < this.params.limit) {
await this.reinit(length)
} else {
void this.notify()
@@ -523,7 +523,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private async reinit(limit: number): Promise<void> {
private async reinit (limit: number): Promise<void> {
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
@@ -547,7 +547,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
})
}
private async onUpdateNotificationContextEvent(event: NotificationContextUpdatedEvent): Promise<void> {
private async onUpdateNotificationContextEvent (event: NotificationContextUpdatedEvent): Promise<void> {
if (this.forward instanceof Promise) this.forward = await this.forward
if (this.backward instanceof Promise) this.backward = await this.backward
if (this.result instanceof Promise) this.result = await this.result
@@ -559,16 +559,16 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
const newNotifications =
event.lastView != null
? this.filterNotifications(
currentNotifications.map((it) => ({
...it,
read:
it.type == NotificationType.Message ? event.lastView != null && event.lastView >= it.created : it.read
}))
)
currentNotifications.map((it) => ({
...it,
read:
it.type === NotificationType.Message ? event.lastView != null && event.lastView >= it.created : it.read
}))
)
: currentNotifications
if (
this.params.notifications &&
this.params.notifications != null &&
newNotifications.length < currentNotifications.length &&
newNotifications.length < this.params.notifications.limit &&
this.params.notifications.order !== SortingOrder.Descending
@@ -601,12 +601,12 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
void this.notify()
}
async onCardRemoved(event: CardRemovedEvent): Promise<void> {
async onCardRemoved (event: CardRemovedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
let updated = false
const result = this.result.getResult()
for (const context of result) {
if (context.card == event.card) {
if (context.card === event.card) {
this.result.delete(context.id)
updated = true
}
@@ -626,7 +626,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
if (updated) {
if (this.params.limit && this.result.length < this.params.limit && result.length >= this.params.limit) {
if (this.params.limit != null && this.result.length < this.params.limit && result.length >= this.params.limit) {
const contexts = await this.find(this.params)
this.result = new QueryResult(contexts, (x) => x.id)
}
@@ -634,7 +634,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private filterNotifications(notifications: Notification[]): Notification[] {
private filterNotifications (notifications: Notification[]): Notification[] {
if (this.params.notifications == null) return notifications
const read = this.params.notifications.read
if (read == null) return notifications
@@ -642,7 +642,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
return notifications.filter((it) => it.read === read)
}
private async addContext(context: NotificationContext): Promise<void> {
private async addContext (context: NotificationContext): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.result.get(context.id) !== undefined) return
if (this.result.isTail()) {
@@ -658,7 +658,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
}
}
private match(context: NotificationContext): boolean {
private match (context: NotificationContext): boolean {
if (this.params.card !== undefined) {
const cards = Array.isArray(this.params.card) ? this.params.card : [this.params.card]
if (!cards.includes(context.card)) return false
@@ -706,7 +706,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
return true
}
private async notify(): Promise<void> {
private async notify (): Promise<void> {
if (this.callback === undefined) return
if (this.result instanceof Promise) {
this.result = await this.result
@@ -720,7 +720,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
this.callback(window)
}
private async updateMessage(
private async updateMessage (
card: CardID,
messageId: MessageID,
updater: (message: Message) => Message
+39 -38
View File
@@ -62,7 +62,7 @@ const allowedPatchTypes = [
export class NotificationQuery implements PagedQuery<Notification, FindNotificationsParams> {
private result: QueryResult<Notification> | Promise<QueryResult<Notification>>
constructor(
constructor (
private readonly client: FindClient,
private readonly workspace: WorkspaceID,
private readonly filesUrl: string,
@@ -86,7 +86,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async initResult(findParams: FindNotificationsParams, limit: number): Promise<QueryResult<Notification>> {
private async initResult (findParams: FindNotificationsParams, limit: number): Promise<QueryResult<Notification>> {
try {
const res = await this.find(findParams)
const isComplete = res.length <= limit
@@ -104,7 +104,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
async onEvent(event: ResponseEvent): Promise<void> {
async onEvent (event: ResponseEvent): Promise<void> {
switch (event.type) {
case NotificationResponseEventType.NotificationCreated: {
await this.onCreateNotificationEvent(event)
@@ -146,25 +146,25 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
async onRequest(event: RequestEvent): Promise<void> {}
async onRequest (event: RequestEvent): Promise<void> {}
async unsubscribe(): Promise<void> {
async unsubscribe (): Promise<void> {
await this.client.unsubscribeQuery(this.id)
}
async requestLoadNextPage(): Promise<void> {
async requestLoadNextPage (): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
await this.loadPage(SortingOrder.Ascending, this.result.getLast()?.created)
}
async requestLoadPrevPage(): Promise<void> {
async requestLoadPrevPage (): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
await this.loadPage(SortingOrder.Descending, this.result.getFirst()?.created)
}
private async loadPage(order: SortingOrder, created?: Date): Promise<void> {
if (!created) return
private async loadPage (order: SortingOrder, created?: Date): Promise<void> {
if (created == null) return
if (this.result instanceof Promise) this.result = await this.result
const limit = this.getLimit()
@@ -194,26 +194,26 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
removeCallback(): void {
removeCallback (): void {
this.callback = () => {}
}
setCallback(callback: PagedQueryCallback<Notification>): void {
setCallback (callback: PagedQueryCallback<Notification>): void {
this.callback = callback
void this.notify()
}
copyResult(): QueryResult<Notification> | undefined {
copyResult (): QueryResult<Notification> | undefined {
return this.result instanceof Promise ? undefined : this.result.copy()
}
private async find(params: FindNotificationsParams): Promise<Notification[]> {
private async find (params: FindNotificationsParams): Promise<Notification[]> {
const notifications = await this.client.findNotifications(params, this.id)
if (!params.message) return notifications
if (params.message !== true) return notifications
return await Promise.all(
notifications.map(async (notification) => {
if (notification.message || !notification.messageId) return notification
if (notification.message != null) return notification
const message = await loadMessageFromGroup(
notification.messageId,
this.workspace,
@@ -221,14 +221,14 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
notification.messageGroup,
notification.patches
)
return message ? { ...notification, message } : notification
return message != null ? { ...notification, message } : notification
})
)
}
private async onCreateNotificationEvent(event: NotificationCreatedEvent): Promise<void> {
private async onCreateNotificationEvent (event: NotificationCreatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.result.get(event.notification.id)) return
if (this.result.get(event.notification.id) != null) return
if (!this.result.isTail()) return
const match = matchNotification(event.notification, { ...this.params, created: undefined })
@@ -243,7 +243,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
await this.notify()
}
private async onUpdateNotificationContextEvent(event: NotificationContextUpdatedEvent): Promise<void> {
private async onUpdateNotificationContextEvent (event: NotificationContextUpdatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.context != null && this.params.context !== event.context) return
@@ -255,14 +255,14 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
const updated: Notification[] = toUpdate.map((it) => ({
...it,
read: it.type == NotificationType.Message ? lastView >= it.created : it.read
read: it.type === NotificationType.Message ? lastView >= it.created : it.read
}))
await this.updateNotificationRead(this.result, updated)
}
private async updateNotificationRead(result: QueryResult<Notification>, updated: Notification[]): Promise<void> {
const isAllowed = (n: Notification) => {
private async updateNotificationRead (result: QueryResult<Notification>, updated: Notification[]): Promise<void> {
const isAllowed = (n: Notification): boolean => {
if (this.params.read == null) return true
return n.read === this.params.read
}
@@ -284,11 +284,11 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onUpdateNotificationEvent(event: NotificationUpdatedEvent): Promise<void> {
private async onUpdateNotificationEvent (event: NotificationUpdatedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
const toUpdate = (
event.query.id
event.query.id != null
? [this.result.get(event.query.id)].filter((it): it is Notification => it != null)
: this.result.getResult().filter((it) => matchNotification(it, event.query))
).filter((it) => it.read !== event.updates.read)
@@ -297,7 +297,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
await this.updateNotificationRead(this.result, updated)
}
private async onRemoveNotificationsEvent(event: NotificationsRemovedEvent): Promise<void> {
private async onRemoveNotificationsEvent (event: NotificationsRemovedEvent): Promise<void> {
if (this.params.context !== undefined && this.params.context !== event.context) return
if (this.result instanceof Promise) this.result = await this.result
@@ -318,7 +318,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onRemoveNotificationContextEvent(event: NotificationContextRemovedEvent): Promise<void> {
private async onRemoveNotificationContextEvent (event: NotificationContextRemovedEvent): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
if (this.params.context != null && this.params.context !== event.context.id) return
@@ -346,7 +346,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onCreatePatchEvent(event: PatchCreatedEvent): Promise<void> {
private async onCreatePatchEvent (event: PatchCreatedEvent): Promise<void> {
if (this.params.message !== true) return
const isUpdated = await this.updateMessage(
(it) => this.matchNotificationByMessage(it, event.card, event.patch.message),
@@ -357,7 +357,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onFileCreated(event: FileCreatedEvent): Promise<void> {
private async onFileCreated (event: FileCreatedEvent): Promise<void> {
if (this.params.message !== true) return
const isUpdated = await this.updateMessage(
(it) => this.matchNotificationByMessage(it, event.card, event.message),
@@ -368,7 +368,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onFileRemoved(event: FileRemovedEvent): Promise<void> {
private async onFileRemoved (event: FileRemovedEvent): Promise<void> {
if (this.params.message !== true) return
const isUpdated = await this.updateMessage(
(it) => this.matchNotificationByMessage(it, event.card, event.message),
@@ -379,7 +379,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onThreadCreated(event: ThreadCreatedEvent): Promise<void> {
private async onThreadCreated (event: ThreadCreatedEvent): Promise<void> {
if (this.params.message !== true) return
const isUpdated = await this.updateMessage(
(it) => this.matchNotificationByMessage(it, event.thread.card, event.thread.message),
@@ -397,7 +397,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onThreadUpdated(event: ThreadUpdatedEvent): Promise<void> {
private async onThreadUpdated (event: ThreadUpdatedEvent): Promise<void> {
if (this.params.message !== true) return
const isUpdated = await this.updateMessage(
(it) => this.matchNotificationByMessage(it, event.card, event.message),
@@ -408,7 +408,7 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
}
}
private async onCardRemoved(event: CardRemovedEvent): Promise<void> {
private async onCardRemoved (event: CardRemovedEvent): Promise<void> {
if (this.params.message !== true) return
if (this.result instanceof Promise) this.result = await this.result
const isUpdated = await this.updateMessage(
@@ -419,19 +419,20 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
void this.notify()
}
}
private async notify(): Promise<void> {
if (!this.callback) return
private async notify (): Promise<void> {
if (this.callback == null) return
if (this.result instanceof Promise) this.result = await this.result
const window = new WindowImpl(this.result.getResult(), this.result.isTail(), this.result.isHead(), this)
this.callback(window)
}
private getLimit(): number {
private getLimit (): number {
return this.params.limit ?? defaultQueryParams.limit
}
private async reinit(limit: number): Promise<void> {
private async reinit (limit: number): Promise<void> {
if (this.result instanceof Promise) this.result = await this.result
this.result = this.find({ ...this.params, limit: limit + 1 }).then((res) => {
const isTail = res.length <= limit
@@ -451,11 +452,11 @@ export class NotificationQuery implements PagedQuery<Notification, FindNotificat
})
}
private matchNotificationByMessage(notification: Notification, card: CardID, messageId: MessageID): boolean {
private matchNotificationByMessage (notification: Notification, card: CardID, messageId: MessageID): boolean {
return notification.messageId === messageId && notification.message != null && notification.message.card === card
}
private async updateMessage(
private async updateMessage (
matchFn: (notification: Notification) => boolean,
updater: (message: Message) => Message
): Promise<boolean> {
+20 -20
View File
@@ -21,60 +21,60 @@ export class QueryResult<T> {
private tail: boolean = false
private head: boolean = false
get length(): number {
get length (): number {
return this.objectById.size
}
constructor(
constructor (
messages: T[],
private readonly getId: (it: T) => ID
) {
this.objectById = new Map(messages.map((it) => [getId(it), it]))
}
isTail(): boolean {
isTail (): boolean {
return this.tail
}
isHead(): boolean {
isHead (): boolean {
return this.head
}
setHead(head: boolean): void {
setHead (head: boolean): void {
this.head = head
}
setTail(tail: boolean): void {
setTail (tail: boolean): void {
this.tail = tail
}
getResult(): T[] {
getResult (): T[] {
return Array.from(this.objectById.values())
}
get(id: ID): Readonly<T> | undefined {
get (id: ID): Readonly<T> | undefined {
return this.objectById.get(id)
}
delete(id: ID): T | undefined {
delete (id: ID): T | undefined {
const object = this.objectById.get(id)
this.objectById.delete(id)
return object
}
deleteAll(): void {
deleteAll (): void {
this.objectById.clear()
}
push(object: T): void {
push (object: T): void {
this.objectById.set(this.getId(object), object)
}
unshift(object: T): void {
unshift (object: T): void {
this.objectById = new Map([[this.getId(object), object], ...this.objectById])
}
pop(): T | undefined {
pop (): T | undefined {
const array = Array.from(this.objectById.values())
const last = array[array.length - 1]
if (last === undefined) return
@@ -82,36 +82,36 @@ export class QueryResult<T> {
return last
}
update(object: T): void {
update (object: T): void {
this.objectById.set(this.getId(object), object)
}
getFirst(): T | undefined {
getFirst (): T | undefined {
return Array.from(this.objectById.values())[0]
}
getLast(): T | undefined {
getLast (): T | undefined {
return Array.from(this.objectById.values())[this.objectById.size - 1]
}
prepend(objects: T[]): void {
prepend (objects: T[]): void {
const current = Array.from(this.objectById.entries())
this.objectById = new Map([...objects.map<[ID, T]>((object) => [this.getId(object), object]), ...current])
}
append(objects: T[]): void {
append (objects: T[]): void {
for (const object of objects) {
this.objectById.set(this.getId(object), object)
}
}
sort(compare: (a: T, b: T) => number): void {
sort (compare: (a: T, b: T) => number): void {
const current = Array.from(this.objectById.values())
const sorted = current.sort(compare)
this.objectById = new Map(sorted.map<[ID, T]>((object) => [this.getId(object), object]))
}
copy(): QueryResult<T> {
copy (): QueryResult<T> {
const copy = new QueryResult(Array.from(this.objectById.values()), this.getId)
copy.setHead(this.head)
+1 -2
View File
@@ -13,7 +13,7 @@
// limitations under the License.
//
import { type ResponseEvent } from '@hcengineering/communication-sdk-types'
import { type ResponseEvent, EventResult, RequestEvent } from '@hcengineering/communication-sdk-types'
import {
SortingOrder,
type Window,
@@ -21,7 +21,6 @@ import {
type CardID,
type MessageID
} from '@hcengineering/communication-types'
import type { EventResult, RequestEvent } from '@hcengineering/communication-sdk-types'
import { QueryResult } from './result'
+17 -17
View File
@@ -35,7 +35,7 @@ import {
import { loadGroupFile } from '@hcengineering/communication-yaml'
import type { FindClient } from '@hcengineering/communication-sdk-types'
export async function findMessage(
export async function findMessage (
client: FindClient,
workspace: WorkspaceID,
filesUrl: string,
@@ -53,7 +53,7 @@ export async function findMessage(
return await findMessageInFiles(client, workspace, filesUrl, card, id, created)
}
export async function findMessageInFiles(
export async function findMessageInFiles (
client: FindClient,
workspace: WorkspaceID,
filesUrl: string,
@@ -96,7 +96,7 @@ export async function findMessageInFiles(
}
}
export async function loadMessageFromGroup(
export async function loadMessageFromGroup (
id: MessageID,
workspace: WorkspaceID,
filesUrl: string,
@@ -113,14 +113,14 @@ export async function loadMessageFromGroup(
return applyPatches(message, patches)
}
export function addFile(message: Message, file: File): Message {
export function addFile (message: Message, file: File): Message {
if (!message.files.some((it) => it.blobId === file.blobId)) {
message.files.push(file)
}
return message
}
export function removeFile(message: Message, blobId: BlobID): Message {
export function removeFile (message: Message, blobId: BlobID): Message {
const files = message.files.filter((it) => it.blobId !== blobId)
if (files.length === message.files.length) return message
@@ -130,7 +130,7 @@ export function removeFile(message: Message, blobId: BlobID): Message {
}
}
export function addLinkPreview(message: Message, linkPreview: LinkPreview): Message {
export function addLinkPreview (message: Message, linkPreview: LinkPreview): Message {
const current = message.links.find((it) => it.id === linkPreview.id)
if (current === undefined) {
message.links.push(linkPreview)
@@ -138,7 +138,7 @@ export function addLinkPreview(message: Message, linkPreview: LinkPreview): Mess
return message
}
export function removeLinkPreview(message: Message, id: LinkPreviewID): Message {
export function removeLinkPreview (message: Message, id: LinkPreviewID): Message {
const links = message.links.filter((it) => it.id !== id)
if (links.length === message.links.length) return message
return {
@@ -147,7 +147,7 @@ export function removeLinkPreview(message: Message, id: LinkPreviewID): Message
}
}
export function addReaction(message: Message, reaction: Reaction): Message {
export function addReaction (message: Message, reaction: Reaction): Message {
const current = message.reactions.find((it) => it.reaction === reaction.reaction && it.creator === reaction.creator)
if (current === undefined) {
message.reactions.push(reaction)
@@ -155,7 +155,7 @@ export function addReaction(message: Message, reaction: Reaction): Message {
return message
}
export function removeReaction(message: Message, emoji: string, creator: SocialID): Message {
export function removeReaction (message: Message, emoji: string, creator: SocialID): Message {
const reactions = message.reactions.filter((it) => it.reaction !== emoji || it.creator !== creator)
if (reactions.length === message.reactions.length) return message
@@ -165,7 +165,7 @@ export function removeReaction(message: Message, emoji: string, creator: SocialI
}
}
export function createThread(
export function createThread (
message: Message,
threadId: CardID,
threadType: CardType,
@@ -188,7 +188,7 @@ export function createThread(
return message
}
export function updateThread(
export function updateThread (
message: Message,
thread: CardID,
replies: 'increment' | 'decrement',
@@ -204,7 +204,7 @@ export function updateThread(
return message
}
export function matchNotification(notification: Notification, params: FindNotificationsParams): boolean {
export function matchNotification (notification: Notification, params: FindNotificationsParams): boolean {
if (params.type !== undefined && params.type !== notification.type) return false
if (params.read !== undefined && params.read !== notification.read) return false
if (params.id !== undefined && params.id !== notification.id) return false
@@ -212,15 +212,15 @@ export function matchNotification(notification: Notification, params: FindNotifi
const created = notification.created.getTime()
if (params.created) {
if (params.created != null) {
if (params.created instanceof Date) {
if (created !== params.created.getTime()) return false
} else {
const { greater, less, greaterOrEqual, lessOrEqual } = params.created
if (greater && created <= greater.getTime()) return false
if (less && created >= less.getTime()) return false
if (greaterOrEqual && created < greaterOrEqual.getTime()) return false
if (lessOrEqual && created > lessOrEqual.getTime()) return false
if (greater != null && created <= greater.getTime()) return false
if (less != null && created >= less.getTime()) return false
if (greaterOrEqual != null && created < greaterOrEqual.getTime()) return false
if (lessOrEqual != null && created > lessOrEqual.getTime()) return false
}
}
+6 -6
View File
@@ -18,32 +18,32 @@ import type { Window } from '@hcengineering/communication-types'
import type { PagedQuery } from './types'
export class WindowImpl<T> implements Window<T> {
constructor(
constructor (
private readonly result: T[],
private readonly isTail: boolean,
private readonly isHead: boolean,
private readonly query: PagedQuery<T>
) {}
getResult(): T[] {
getResult (): T[] {
return this.result
}
async loadNextPage(): Promise<void> {
async loadNextPage (): Promise<void> {
if (!this.hasNextPage()) return
await this.query.requestLoadNextPage()
}
async loadPrevPage(): Promise<void> {
async loadPrevPage (): Promise<void> {
if (!this.hasPrevPage()) return
await this.query.requestLoadPrevPage()
}
hasNextPage(): boolean {
hasNextPage (): boolean {
return !this.isTail
}
hasPrevPage(): boolean {
hasPrevPage (): boolean {
return !this.isHead
}
}
+8 -6
View File
@@ -1,10 +1,12 @@
{
"extends": "../../tsconfig.json",
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src"]
}
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+37 -20
View File
@@ -1,34 +1,44 @@
{
"name": "@hcengineering/communication-rest-client",
"version": "0.1.0",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:browser && bun run build:node",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:browser": "bun build src/index.ts --outdir dist --target browser",
"build:node": "bun build src/index.ts --target node --format cjs --outfile dist/index.cjs",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts ",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3",
"@types/snappyjs": "^0.7.1"
},
"peerDependencies": {
"typescript": "^5.6.3"
},
"dependencies": {
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-shared": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "^0.1.0",
"@hcengineering/communication-sdk-types": "^0.1.0",
"@hcengineering/communication-shared": "^0.1.0",
"@hcengineering/core": "^0.7.88",
"snappyjs": "^0.7.0"
},
@@ -38,5 +48,12 @@
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+19 -20
View File
@@ -14,7 +14,6 @@
//
import { concatLink } from '@hcengineering/core'
import { PlatformError, unknownError } from '@hcengineering/platform'
import {
MessageRequestEventType,
type EventResult,
@@ -48,14 +47,14 @@ import type { RestClient } from './types'
const retries = 3
export function createRestClient(endpoint: string, workspaceId: string, token: string): RestClient {
export function createRestClient (endpoint: string, workspaceId: string, token: string): RestClient {
return new RestClientImpl(endpoint, workspaceId, token)
}
class RestClientImpl implements RestClient {
endpoint: string
constructor(
constructor (
endpoint: string,
readonly workspace: string,
readonly token: string
@@ -63,7 +62,7 @@ class RestClientImpl implements RestClient {
this.endpoint = endpoint.replace('ws', 'http')
}
private jsonHeaders(): Record<string, string> {
private jsonHeaders (): Record<string, string> {
return {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + this.token,
@@ -71,7 +70,7 @@ class RestClientImpl implements RestClient {
}
}
private requestInit(): RequestInit {
private requestInit (): RequestInit {
return {
method: 'GET',
keepalive: true,
@@ -79,7 +78,7 @@ class RestClientImpl implements RestClient {
}
}
async event(event: RequestEvent): Promise<EventResult> {
async event (event: RequestEvent): Promise<EventResult> {
const response = await fetch(concatLink(this.endpoint, `/api/v1/event/${this.workspace}`), {
method: 'POST',
headers: {
@@ -90,12 +89,12 @@ class RestClientImpl implements RestClient {
body: JSON.stringify(event)
})
if (!response.ok) {
throw new PlatformError(unknownError(response.statusText))
throw new Error(response.statusText)
}
return (await response.json()) as EventResult
}
async createMessage(
async createMessage (
card: CardID,
cardType: CardType,
content: RichText,
@@ -121,7 +120,7 @@ class RestClientImpl implements RestClient {
return result as CreateMessageResult
}
async updateMessage(
async updateMessage (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -139,7 +138,7 @@ class RestClientImpl implements RestClient {
})
}
async removeMessage(card: CardID, message: MessageID, messageCreated: Date, creator: SocialID): Promise<void> {
async removeMessage (card: CardID, message: MessageID, messageCreated: Date, creator: SocialID): Promise<void> {
await this.event({
type: MessageRequestEventType.CreatePatch,
patchType: PatchType.remove,
@@ -151,7 +150,7 @@ class RestClientImpl implements RestClient {
})
}
async createFile(
async createFile (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -168,7 +167,7 @@ class RestClientImpl implements RestClient {
})
}
async removeFile(
async removeFile (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -185,7 +184,7 @@ class RestClientImpl implements RestClient {
})
}
async findMessages(params: FindMessagesParams): Promise<Message[]> {
async findMessages (params: FindMessagesParams): Promise<Message[]> {
const searchParams = new URLSearchParams()
if (Object.keys(params).length > 0) {
searchParams.append('params', JSON.stringify(params))
@@ -196,7 +195,7 @@ class RestClientImpl implements RestClient {
async () => {
const response = await fetch(requestUrl, this.requestInit())
if (!response.ok) {
throw new PlatformError(unknownError(response.statusText))
throw new Error(response.statusText)
}
return await extractJson<MessagesGroup[]>(response)
},
@@ -204,7 +203,7 @@ class RestClientImpl implements RestClient {
)
}
async findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
const searchParams = new URLSearchParams()
if (Object.keys(params).length > 0) {
searchParams.append('params', JSON.stringify(params))
@@ -217,7 +216,7 @@ class RestClientImpl implements RestClient {
async () => {
const response = await fetch(requestUrl, this.requestInit())
if (!response.ok) {
throw new PlatformError(unknownError(response.statusText))
throw new Error(response.statusText)
}
return await extractJson<MessagesGroup[]>(response)
},
@@ -225,7 +224,7 @@ class RestClientImpl implements RestClient {
)
}
async findNotificationContexts(params: FindNotificationContextParams): Promise<NotificationContext[]> {
async findNotificationContexts (params: FindNotificationContextParams): Promise<NotificationContext[]> {
const searchParams = new URLSearchParams()
if (Object.keys(params).length > 0) {
searchParams.append('params', JSON.stringify(params))
@@ -238,7 +237,7 @@ class RestClientImpl implements RestClient {
async () => {
const response = await fetch(requestUrl, this.requestInit())
if (!response.ok) {
throw new PlatformError(unknownError(response.statusText))
throw new Error(response.statusText)
}
return await extractJson<NotificationContext[]>(response)
},
@@ -246,7 +245,7 @@ class RestClientImpl implements RestClient {
)
}
async findNotifications(params: FindNotificationsParams): Promise<Notification[]> {
async findNotifications (params: FindNotificationsParams): Promise<Notification[]> {
const searchParams = new URLSearchParams()
if (Object.keys(params).length > 0) {
searchParams.append('params', JSON.stringify(params))
@@ -259,7 +258,7 @@ class RestClientImpl implements RestClient {
async () => {
const response = await fetch(requestUrl, this.requestInit())
if (!response.ok) {
throw new PlatformError(unknownError(response.statusText))
throw new Error(response.statusText)
}
return await extractJson<Notification[]>(response)
},
+3 -3
View File
@@ -15,19 +15,19 @@
import { uncompress } from 'snappyjs'
function isDateString(value: any) {
function isDateString (value: any): boolean {
if (typeof value !== 'string') return false
const dateStringRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/
return dateStringRegex.test(value)
}
function reviver(key: string, value: any) {
function reviver (key: string, value: any): Date {
if (isDateString(value)) return new Date(value)
return value
}
export async function extractJson<T>(response: Response): Promise<any> {
export async function extractJson<T> (response: Response): Promise<any> {
const encoding = response.headers.get('content-encoding')
if (encoding === 'snappy') {
const buffer = await response.arrayBuffer()
+8 -6
View File
@@ -1,10 +1,12 @@
{
"extends": "../../tsconfig.json",
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src"]
}
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+36 -19
View File
@@ -1,32 +1,42 @@
{
"name": "@hcengineering/communication-sdk-types",
"version": "0.1.0",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:browser && bun run build:node",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:browser": "bun build src/index.ts --outdir dist --target browser",
"build:node": "bun build src/index.ts --target node --format cjs --outfile dist/index.cjs",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14"
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3"
},
"dependencies": {
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/core": "^0.7.88"
},
"peerDependencies": {
"typescript": "^5.6.3"
"@hcengineering/core": "^0.7.88",
"@hcengineering/communication-types": "^0.1.0"
},
"repository": {
"type": "git",
@@ -34,5 +44,12 @@
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+8 -8
View File
@@ -29,19 +29,19 @@ import type {
import type { EventResult, RequestEvent, ResponseEvent } from './event'
export interface FindClient {
onEvent(event: ResponseEvent): void
onEvent: (event: ResponseEvent) => void
onRequest(event: RequestEvent, promise: Promise<EventResult>): void
findMessages: (params: FindMessagesParams, queryId?: number) => Promise<Message[]>
findMessages(params: FindMessagesParams, queryId?: number): Promise<Message[]>
findMessagesGroups: (params: FindMessagesGroupsParams) => Promise<MessagesGroup[]>
findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
findNotificationContexts: (params: FindNotificationContextParams, queryId?: number) => Promise<NotificationContext[]>
findNotificationContexts(params: FindNotificationContextParams, queryId?: number): Promise<NotificationContext[]>
findNotifications: (params: FindNotificationsParams, queryId?: number) => Promise<Notification[]>
findNotifications(params: FindNotificationsParams, queryId?: number): Promise<Notification[]>
findLabels: (params: FindLabelsParams, queryId?: number) => Promise<Label[]>
findLabels(params: FindLabelsParams, queryId?: number): Promise<Label[]>
onRequest: (event: RequestEvent, promise: Promise<EventResult>) => void
unsubscribeQuery(id: number): Promise<void>
unsubscribeQuery: (id: number) => Promise<void>
}
+51 -51
View File
@@ -50,7 +50,7 @@ import type {
} from '@hcengineering/communication-types'
export interface DbAdapter {
createMessage(
createMessage: (
card: CardID,
type: MessageType,
content: RichText,
@@ -59,9 +59,9 @@ export interface DbAdapter {
data?: MessageData,
externalId?: string,
id?: MessageID
): Promise<{ id: MessageID; created: Date }>
) => Promise<{ id: MessageID, created: Date }>
createPatch(
createPatch: (
card: CardID,
message: MessageID,
messageCreated: Date,
@@ -69,73 +69,73 @@ export interface DbAdapter {
data: PatchData,
creator: SocialID,
created: Date
): Promise<void>
) => Promise<void>
removePatches(card: CardID): Promise<void>
removePatches: (card: CardID) => Promise<void>
createMessagesGroup(card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise<void>
removeMessagesGroup(card: CardID, blobId: BlobID): Promise<void>
createMessagesGroup: (card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number) => Promise<void>
removeMessagesGroup: (card: CardID, blobId: BlobID) => Promise<void>
createReaction(
createReaction: (
card: CardID,
message: MessageID,
messageCreated: Date,
reaction: string,
creator: SocialID,
created: Date
): Promise<void>
removeReaction(
) => Promise<void>
removeReaction: (
card: CardID,
message: MessageID,
messageCreated: Date,
reaction: string,
creator: SocialID
): Promise<void>
) => Promise<void>
createFile(
createFile: (
card: CardID,
message: MessageID,
messageCreated: Date,
data: FileData,
creator: SocialID,
created: Date
): Promise<void>
removeFiles(card: CardID, query: RemoveFileQuery): Promise<void>
) => Promise<void>
removeFiles: (card: CardID, query: RemoveFileQuery) => Promise<void>
createLinkPreview(
createLinkPreview: (
card: CardID,
message: MessageID,
messageCreated: Date,
data: LinkPreviewData,
creator: SocialID,
created: Date
): Promise<LinkPreviewID>
) => Promise<LinkPreviewID>
removeLinkPreview(card: CardID, message: MessageID, id: LinkPreviewID): Promise<void>
removeLinkPreview: (card: CardID, message: MessageID, id: LinkPreviewID) => Promise<void>
createThread(
createThread: (
card: CardID,
message: MessageID,
messageCreated: Date,
thread: CardID,
threadType: CardType,
created: Date
): Promise<void>
removeThreads(query: RemoveThreadQuery): Promise<void>
updateThread(thread: CardID, update: ThreadUpdates): Promise<void>
) => Promise<void>
removeThreads: (query: RemoveThreadQuery) => Promise<void>
updateThread: (thread: CardID, update: ThreadUpdates) => Promise<void>
findMessages(params: FindMessagesParams): Promise<Message[]>
findMessagesGroups(params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
findThread(thread: CardID): Promise<Thread | undefined>
findMessages: (params: FindMessagesParams) => Promise<Message[]>
findMessagesGroups: (params: FindMessagesGroupsParams) => Promise<MessagesGroup[]>
findThread: (thread: CardID) => Promise<Thread | undefined>
addCollaborators(card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date): Promise<AccountID[]>
removeCollaborators(card: CardID, query: RemoveCollaboratorsQuery): Promise<void>
getCollaboratorsCursor(card: CardID, date: Date, size?: number): AsyncIterable<Collaborator[]>
addCollaborators: (card: CardID, cardType: CardType, collaborators: AccountID[], date?: Date) => Promise<AccountID[]>
removeCollaborators: (card: CardID, query: RemoveCollaboratorsQuery) => Promise<void>
getCollaboratorsCursor: (card: CardID, date: Date, size?: number) => AsyncIterable<Collaborator[]>
findCollaborators(params: FindCollaboratorsParams): Promise<Collaborator[]>
updateCollaborators(query: FindCollaboratorsParams, update: CollaboratorUpdates): Promise<void>
findCollaborators: (params: FindCollaboratorsParams) => Promise<Collaborator[]>
updateCollaborators: (query: FindCollaboratorsParams, update: CollaboratorUpdates) => Promise<void>
createNotification(
createNotification: (
context: ContextID,
message: MessageID,
messageCreated: Date,
@@ -143,44 +143,44 @@ export interface DbAdapter {
read: boolean,
content: NotificationContent | undefined,
created: Date
): Promise<NotificationID>
updateNotification(query: UpdateNotificationQuery, updates: NotificationUpdates): Promise<void>
removeNotifications(query: RemoveNotificationsQuery): Promise<NotificationID[]>
) => Promise<NotificationID>
updateNotification: (query: UpdateNotificationQuery, updates: NotificationUpdates) => Promise<void>
removeNotifications: (query: RemoveNotificationsQuery) => Promise<NotificationID[]>
createContext(
createContext: (
account: AccountID,
card: CardID,
lastUpdate: Date,
lastView: Date,
lastNotify?: Date
): Promise<ContextID>
updateContext(context: ContextID, account: AccountID, updates: NotificationContextUpdates): Promise<void>
removeContexts(query: RemoveNotificationContextQuery): Promise<void>
) => Promise<ContextID>
updateContext: (context: ContextID, account: AccountID, updates: NotificationContextUpdates) => Promise<void>
removeContexts: (query: RemoveNotificationContextQuery) => Promise<void>
findNotificationContexts(params: FindNotificationContextParams): Promise<NotificationContext[]>
findNotifications(params: FindNotificationsParams): Promise<Notification[]>
findNotificationContexts: (params: FindNotificationContextParams) => Promise<NotificationContext[]>
findNotifications: (params: FindNotificationsParams) => Promise<Notification[]>
createLabel(label: LabelID, card: CardID, cardType: CardType, account: AccountID, created: Date): Promise<void>
removeLabels(query: RemoveLabelQuery): Promise<void>
findLabels(params: FindLabelsParams): Promise<Label[]>
updateLabels(card: CardID, update: LabelUpdates): Promise<void>
createLabel: (label: LabelID, card: CardID, cardType: CardType, account: AccountID, created: Date) => Promise<void>
removeLabels: (query: RemoveLabelQuery) => Promise<void>
findLabels: (params: FindLabelsParams) => Promise<Label[]>
updateLabels: (card: CardID, update: LabelUpdates) => Promise<void>
getAccountsByPersonIds(ids: string[]): Promise<AccountID[]>
getNameByAccount(id: AccountID): Promise<string | undefined>
getAccountsByPersonIds: (ids: string[]) => Promise<AccountID[]>
getNameByAccount: (id: AccountID) => Promise<string | undefined>
close(): void
close: () => void
}
export type RemoveFileQuery = {
export interface RemoveFileQuery {
message: MessageID
blobId: BlobID
}
export type RemoveThreadQuery = Partial<Pick<Thread, 'card' | 'thread' | 'message'>>
export type RemoveCollaboratorsQuery = {
export interface RemoveCollaboratorsQuery {
accounts?: AccountID[]
}
export type RemoveNotificationContextQuery = Partial<Pick<NotificationContext, 'id' | 'account' | 'card'>>
export type RemoveNotificationsQuery = {
export interface RemoveNotificationsQuery {
context: ContextID
account: AccountID
ids: NotificationID[]
@@ -188,7 +188,7 @@ export type RemoveNotificationsQuery = {
export type RemoveLabelQuery = Partial<Pick<Label, 'card' | 'label' | 'account'>>
export type NotificationUpdates = Partial<Pick<Notification, 'read'>>
export type UpdateNotificationQuery = {
export interface UpdateNotificationQuery {
context: ContextID
account: AccountID
type?: NotificationType
@@ -198,7 +198,7 @@ export type UpdateNotificationQuery = {
export type NotificationContextUpdates = Partial<Pick<NotificationContext, 'lastView' | 'lastUpdate' | 'lastNotify'>>
export type ThreadUpdates = {
export interface ThreadUpdates {
threadType?: CardType
lastReply?: Date
replies?: 'increment' | 'decrement'
+2 -1
View File
@@ -20,7 +20,7 @@ import type {
NotificationRequestEvent,
NotificationRequestEventType
} from './requestEvents/notification'
import { type LabelResponseEvent, LabelResponseEventType } from './responseEvents/label'
import type { LabelResponseEvent, LabelResponseEventType } from './responseEvents/label'
import type { MessageResponseEvent, MessageResponseEventType } from './responseEvents/message'
import type { NotificationResponseEvent, NotificationResponseEventType } from './responseEvents/notification'
import type { CardRequestEvent, CardRequestEventType } from './requestEvents/card'
@@ -41,6 +41,7 @@ export type RequestEventType =
| LabelRequestEventType
| CardRequestEventType
export type RequestEvent = MessageRequestEvent | NotificationRequestEvent | LabelRequestEvent | CardRequestEvent
// eslint-disable-next-line @typescript-eslint/ban-types
export type EventResult = MessageEventResult | NotificationEventResult | {}
export type ResponseEventType =
+4 -4
View File
@@ -13,8 +13,8 @@
// limitations under the License.
//
export * from './client'
export * from './db'
export * from './query'
export type * from './client'
export type * from './db'
export type * from './query'
export * from './event'
export * from './serverApi'
export type * from './serverApi'
@@ -13,6 +13,6 @@
// limitations under the License.
//
export type BaseRequestEvent = {
export interface BaseRequestEvent {
_id?: string
}
@@ -121,6 +121,7 @@ export interface RemoveCollaboratorsEvent extends BaseRequestEvent {
created?: Date
}
// eslint-disable-next-line @typescript-eslint/ban-types
export type NotificationEventResult = CreateNotificationContextResult | {}
export interface CreateNotificationContextResult {
@@ -13,6 +13,6 @@
// limitations under the License.
//
export type BaseResponseEvent = {
export interface BaseResponseEvent {
_id?: string
}
+12 -12
View File
@@ -37,26 +37,26 @@ export interface SessionData {
}
export interface ServerApi {
findMessages(session: SessionData, params: FindMessagesParams, queryId?: number | string): Promise<Message[]>
findMessagesGroups(session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]>
findNotificationContexts(
findMessages: (session: SessionData, params: FindMessagesParams, queryId?: number | string) => Promise<Message[]>
findMessagesGroups: (session: SessionData, params: FindMessagesGroupsParams) => Promise<MessagesGroup[]>
findNotificationContexts: (
session: SessionData,
params: FindNotificationContextParams,
queryId?: number | string
): Promise<NotificationContext[]>
findNotifications(
) => Promise<NotificationContext[]>
findNotifications: (
session: SessionData,
params: FindNotificationsParams,
queryId?: number | string
): Promise<Notification[]>
) => Promise<Notification[]>
findLabels(session: SessionData, params: FindLabelsParams): Promise<Label[]>
findCollaborators(session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]>
findLabels: (session: SessionData, params: FindLabelsParams) => Promise<Label[]>
findCollaborators: (session: SessionData, params: FindCollaboratorsParams) => Promise<Collaborator[]>
event(session: SessionData, event: RequestEvent): Promise<EventResult>
event: (session: SessionData, event: RequestEvent) => Promise<EventResult>
unsubscribeQuery(session: SessionData, id: number): Promise<void>
unsubscribeQuery: (session: SessionData, id: number) => Promise<void>
closeSession(sessionId: string): Promise<void>
close(): Promise<void>
closeSession: (sessionId: string) => Promise<void>
close: () => Promise<void>
}
+8 -6
View File
@@ -1,10 +1,12 @@
{
"extends": "../../tsconfig.json",
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src"]
}
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
+40 -24
View File
@@ -1,49 +1,65 @@
{
"name": "@hcengineering/communication-server",
"version": "0.1.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "./types/index.d.ts",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"dist/index.js",
"dist/index.cjs",
"types/**/*.d.ts"
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"scripts": {
"build": "bun run build:types && bun run build:node",
"build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types",
"build:node": "bun build src/index.ts --target node --format cjs --outfile dist/index.js",
"lint": "eslint src/*.ts",
"format": "prettier --write src/**/*.ts",
"clean": "rm -rf dist && rm -rf types && rm -rf .turbo"
"build": "compile",
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\"",
"format": "prettier --write src/**/*.ts && eslint --fix \"src/**/*.ts\"",
"clean": "rm -rf lib && rm -rf types rm -rf node_modules"
},
"devDependencies": {
"@types/bun": "^1.1.14",
"@types/express": "^5.0.0",
"@types/cors": "^2.8.17",
"@types/ws": "^8.5.13"
"@hcengineering/platform-rig": "^0.6.490",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "~2.1.1",
"eslint": "^8.54.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3"
},
"dependencies": {
"@hcengineering/account-client": "^0.7.88",
"@hcengineering/communication-cockroach": "workspace:*",
"@hcengineering/communication-sdk-types": "workspace:*",
"@hcengineering/communication-types": "workspace:*",
"@hcengineering/communication-yaml": "workspace:*",
"@hcengineering/communication-cockroach": "^0.1.0",
"@hcengineering/communication-sdk-types": "^0.1.0",
"@hcengineering/communication-shared": "^0.1.0",
"@hcengineering/communication-types": "^0.1.0",
"@hcengineering/communication-yaml": "^0.1.0",
"@hcengineering/core": "^0.7.88",
"@hcengineering/server-token": "^0.7.88",
"@hcengineering/platform": "^0.7.88",
"@hcengineering/server-token": "^0.7.88",
"@hcengineering/text-core": "^0.7.88",
"@hcengineering/text-markdown": "^0.7.88",
"zod": "^3.24.2"
},
"peerDependencies": {
"typescript": "^5.6.3"
},
"repository": {
"type": "git",
"url": "git+https://github.com/hcengineering/communication.git"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
+6 -6
View File
@@ -17,33 +17,33 @@ export class ApiError extends Error {
public code: number
public message: string
private constructor(code: number, message: string) {
private constructor (code: number, message: string) {
super(message)
this.code = code
this.message = message
Object.setPrototypeOf(this, ApiError.prototype)
}
static badRequest(message: string): ApiError {
static badRequest (message: string): ApiError {
return new ApiError(400, `Bad Request: ${message}`)
}
static forbidden(message: string): ApiError {
static forbidden (message: string): ApiError {
return new ApiError(403, `Forbidden: ${message}`)
}
static notFound(message: string): ApiError {
static notFound (message: string): ApiError {
return new ApiError(404, `Not Found: ${message}`)
}
toJSON() {
toJSON (): object {
return {
code: this.code,
message: this.message
}
}
toString(): string {
toString (): string {
return JSON.stringify(this.toJSON())
}
}
+12 -12
View File
@@ -39,12 +39,12 @@ import type { BroadcastSessionsFunc, QueryId } from './types'
import { buildMiddlewares, Middlewares } from './middlewares'
export class Api implements ServerApi {
private constructor(
private constructor (
private readonly ctx: MeasureContext,
private readonly middlewares: Middlewares
) {}
static async create(
static async create (
ctx: MeasureContext,
workspace: WorkspaceID,
dbUrl: string,
@@ -63,15 +63,15 @@ export class Api implements ServerApi {
return new Api(ctx, middleware)
}
async findMessages(session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
async findMessages (session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
return await this.middlewares.findMessages(session, params, queryId)
}
async findMessagesGroups(session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
return await this.middlewares.findMessagesGroups(session, params)
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -79,7 +79,7 @@ export class Api implements ServerApi {
return await this.middlewares.findNotificationContexts(session, params, queryId)
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -87,27 +87,27 @@ export class Api implements ServerApi {
return await this.middlewares.findNotifications(session, params, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams): Promise<Label[]> {
return await this.middlewares.findLabels(session, params)
}
async findCollaborators(session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
return await this.middlewares.findCollaborators(session, params)
}
async unsubscribeQuery(session: SessionData, id: number): Promise<void> {
async unsubscribeQuery (session: SessionData, id: number): Promise<void> {
await this.middlewares.unsubscribeQuery(session, id)
}
async event(session: SessionData, event: RequestEvent): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent): Promise<EventResult> {
return await this.middlewares.event(session, event)
}
async closeSession(sessionId: string): Promise<void> {
async closeSession (sessionId: string): Promise<void> {
await this.middlewares.closeSession(sessionId)
}
async close(): Promise<void> {
async close (): Promise<void> {
await this.middlewares.close()
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
import type { Metadata } from './types'
export function getMetadata(): Metadata {
export function getMetadata (): Metadata {
return {
msg2fileUrl: process.env.MSG2FILE_URL ?? '',
accountsUrl: process.env.ACCOUNTS_URL ?? '',
+30 -30
View File
@@ -37,16 +37,16 @@ import type {
import type { Middleware, MiddlewareContext, QueryId } from '../types'
export class BaseMiddleware implements Middleware {
constructor(
constructor (
readonly context: MiddlewareContext,
protected readonly next?: Middleware
) {}
async findMessages(session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
async findMessages (session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
return await this.provideFindMessages(session, params, queryId)
}
async findMessagesGroups(
async findMessagesGroups (
session: SessionData,
params: FindMessagesGroupsParams,
queryId?: QueryId
@@ -54,7 +54,7 @@ export class BaseMiddleware implements Middleware {
return await this.provideFindMessagesGroups(session, params, queryId)
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -62,7 +62,7 @@ export class BaseMiddleware implements Middleware {
return await this.provideFindNotificationContexts(session, params, queryId)
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -70,106 +70,106 @@ export class BaseMiddleware implements Middleware {
return await this.provideFindNotifications(session, params, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
return await this.provideFindLabels(session, params, queryId)
}
async findCollaborators(session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
return await this.provideFindCollaborators(session, params)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
return await this.provideEvent(session, event, derived)
}
async response(session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
return await this.provideResponse(session, event, derived)
async response (session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
await this.provideResponse(session, event, derived)
}
unsubscribeQuery(session: SessionData, queryId: number): void {
unsubscribeQuery (session: SessionData, queryId: number): void {
if (this.next !== undefined) {
return this.next.unsubscribeQuery(session, queryId)
this.next.unsubscribeQuery(session, queryId)
}
}
close(): void {}
closeSession(sessionId: string): void {}
close (): void {}
closeSession (sessionId: string): void {}
protected async provideEvent(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
protected async provideEvent (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
if (this.next !== undefined) {
return this.next.event(session, event, derived)
return await this.next.event(session, event, derived)
}
return {}
}
protected async provideFindMessages(
protected async provideFindMessages (
session: SessionData,
params: FindMessagesParams,
queryId?: QueryId
): Promise<Message[]> {
if (this.next !== undefined) {
return this.next.findMessages(session, params, queryId)
return await this.next.findMessages(session, params, queryId)
}
return []
}
protected async provideFindMessagesGroups(
protected async provideFindMessagesGroups (
session: SessionData,
params: FindMessagesGroupsParams,
queryId?: QueryId
): Promise<MessagesGroup[]> {
if (this.next !== undefined) {
return this.next.findMessagesGroups(session, params, queryId)
return await this.next.findMessagesGroups(session, params, queryId)
}
return []
}
protected async provideFindNotificationContexts(
protected async provideFindNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
): Promise<NotificationContext[]> {
if (this.next !== undefined) {
return this.next.findNotificationContexts(session, params, queryId)
return await this.next.findNotificationContexts(session, params, queryId)
}
return []
}
protected async provideFindNotifications(
protected async provideFindNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
): Promise<Notification[]> {
if (this.next !== undefined) {
return this.next.findNotifications(session, params, queryId)
return await this.next.findNotifications(session, params, queryId)
}
return []
}
protected async provideFindLabels(
protected async provideFindLabels (
session: SessionData,
params: FindLabelsParams,
queryId?: QueryId
): Promise<Label[]> {
if (this.next !== undefined) {
return this.next.findLabels(session, params, queryId)
return await this.next.findLabels(session, params, queryId)
}
return []
}
protected async provideFindCollaborators(
protected async provideFindCollaborators (
session: SessionData,
params: FindCollaboratorsParams
): Promise<Collaborator[]> {
if (this.next !== undefined) {
return this.next.findCollaborators(session, params)
return await this.next.findCollaborators(session, params)
}
return []
}
protected async provideResponse(session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
protected async provideResponse (session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
if (this.next !== undefined) {
return this.next.response(session, event, derived)
await this.next.response(session, event, derived)
}
}
}
+18 -17
View File
@@ -51,14 +51,15 @@ interface SessionInfo {
export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
private readonly dataBySessionId = new Map<string, SessionInfo>()
constructor(
constructor (
private readonly broadcastFn: BroadcastSessionsFunc,
readonly context: MiddlewareContext,
next?: Middleware
) {
super(context, next)
}
async findMessages(session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
async findMessages (session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
this.createSession(session)
const result = await this.provideFindMessages(session, params, queryId)
@@ -68,7 +69,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
return result
}
async findMessagesGroups(
async findMessagesGroups (
session: SessionData,
params: FindMessagesGroupsParams,
queryId?: QueryId
@@ -77,7 +78,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
return await this.provideFindMessagesGroups(session, params, queryId)
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -91,7 +92,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
return result
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -100,17 +101,17 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
return await this.provideFindNotifications(session, params, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
this.createSession(session)
return await this.provideFindLabels(session, params, queryId)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
this.createSession(session)
return await this.provideEvent(session, event, derived)
}
unsubscribeQuery(session: SessionData, queryId: number): void {
unsubscribeQuery (session: SessionData, queryId: number): void {
if (session.sessionId == null) return
const data = this.dataBySessionId.get(session.sessionId)
if (data == null) return
@@ -119,7 +120,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
data.contextQueries.delete(queryId)
}
async response(session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
async response (session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
const sessionIds: string[] = []
for (const [sessionId, session] of this.dataBySessionId.entries()) {
if (this.match(event, session)) {
@@ -137,22 +138,22 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
await this.provideResponse(session, event, derived)
}
closeSession(sessionId: string): void {
closeSession (sessionId: string): void {
this.dataBySessionId.delete(sessionId)
}
close(): void {
close (): void {
this.dataBySessionId.clear()
}
private subscribeMessageQuery(session: SessionData, queryId: QueryId, params: Record<string, any>): void {
private subscribeMessageQuery (session: SessionData, queryId: QueryId, params: Record<string, any>): void {
const data = this.createSession(session)
if (data == null) return
data.messageQueries.set(queryId, params as FindMessagesParams)
}
private subscribeContextQuery(session: SessionData, queryId: QueryId, result: NotificationContext[]): void {
private subscribeContextQuery (session: SessionData, queryId: QueryId, result: NotificationContext[]): void {
const data = this.createSession(session)
if (data == null) return
@@ -162,7 +163,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
data.contextQueries.set(queryId, new Set([...current, ...cards]))
}
private createSession(session: SessionData): SessionInfo | undefined {
private createSession (session: SessionData): SessionInfo | undefined {
const id = session.sessionId
if (id == null) return
if (!this.dataBySessionId.has(id)) {
@@ -176,7 +177,7 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
return this.dataBySessionId.get(id)
}
private match(event: ResponseEvent, info: SessionInfo): boolean {
private match (event: ResponseEvent, info: SessionInfo): boolean {
switch (event.type) {
case MessageResponseEventType.MessageCreated:
return this.matchMessagesQuery(
@@ -238,8 +239,8 @@ export class BroadcastMiddleware extends BaseMiddleware implements Middleware {
}
}
private matchMessagesQuery(
params: { ids: MessageID[]; card: CardID },
private matchMessagesQuery (
params: { ids: MessageID[], card: CardID },
queries: FindMessagesParams[],
cards: Set<CardID>
): boolean {
+4 -4
View File
@@ -27,14 +27,14 @@ import type { Middleware, MiddlewareContext } from '../types'
import { BaseMiddleware } from './base'
export class DateMiddleware extends BaseMiddleware implements Middleware {
constructor(
constructor (
readonly context: MiddlewareContext,
next?: Middleware
) {
super(context, next)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
if (derived) return await this.provideEvent(session, event, derived)
switch (event.type) {
case MessageRequestEventType.CreateFile:
@@ -52,10 +52,10 @@ export class DateMiddleware extends BaseMiddleware implements Middleware {
break
}
return this.provideEvent(session, event, derived)
return await this.provideEvent(session, event, derived)
}
private isSystem(session: SessionData): boolean {
private isSystem (session: SessionData): boolean {
const account = session.account
return systemAccountUuid === account.uuid
}
+37 -37
View File
@@ -93,7 +93,7 @@ interface Result {
}
export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
constructor(
constructor (
private readonly db: DbAdapter,
readonly context: MiddlewareContext,
next?: Middleware
@@ -101,43 +101,43 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
super(context, next)
}
async findMessages(_: SessionData, params: FindMessagesParams): Promise<Message[]> {
async findMessages (_: SessionData, params: FindMessagesParams): Promise<Message[]> {
return await this.db.findMessages(params)
}
async findMessagesGroups(_: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (_: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
return await this.db.findMessagesGroups(params)
}
async findNotificationContexts(
async findNotificationContexts (
_: SessionData,
params: FindNotificationContextParams
): Promise<NotificationContext[]> {
return await this.db.findNotificationContexts(params)
}
async findNotifications(_: SessionData, params: FindNotificationsParams): Promise<Notification[]> {
async findNotifications (_: SessionData, params: FindNotificationsParams): Promise<Notification[]> {
return await this.db.findNotifications(params)
}
async findLabels(_: SessionData, params: FindLabelsParams): Promise<Label[]> {
async findLabels (_: SessionData, params: FindLabelsParams): Promise<Label[]> {
return await this.db.findLabels(params)
}
async findCollaborators(_: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (_: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
return await this.db.findCollaborators(params)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
const result = await this.processEvent(session, event)
if (result.responseEvent) {
if (result.responseEvent != null) {
void this.context.head?.response(session, result.responseEvent, derived)
}
return result.result ?? {}
}
private async processEvent(session: SessionData, event: RequestEvent): Promise<Result> {
private async processEvent (session: SessionData, event: RequestEvent): Promise<Result> {
switch (event.type) {
case MessageRequestEventType.CreateMessage:
return await this.createMessage(event)
@@ -190,7 +190,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async updateThread(event: UpdateThreadEvent): Promise<Result> {
private async updateThread (event: UpdateThreadEvent): Promise<Result> {
await this.db.updateThread(event.thread, event.updates)
return {
responseEvent: {
@@ -204,7 +204,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async addCollaborators(event: AddCollaboratorsEvent): Promise<Result> {
private async addCollaborators (event: AddCollaboratorsEvent): Promise<Result> {
const created = event.created ?? new Date()
const added = await this.db.addCollaborators(event.card, event.cardType, event.collaborators, created)
if (added.length === 0) return {}
@@ -221,7 +221,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeCollaborators(event: RemoveCollaboratorsEvent): Promise<Result> {
private async removeCollaborators (event: RemoveCollaboratorsEvent): Promise<Result> {
if (event.collaborators.length === 0) return {}
const created = event.created ?? new Date()
await this.db.removeCollaborators(event.card, { accounts: event.collaborators })
@@ -239,7 +239,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createMessage(event: CreateMessageEvent): Promise<Result> {
private async createMessage (event: CreateMessageEvent): Promise<Result> {
const created = event.created ?? new Date()
const result = await this.db.createMessage(
event.card,
@@ -277,7 +277,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createPatch(event: CreatePatchEvent): Promise<Result> {
private async createPatch (event: CreatePatchEvent): Promise<Result> {
const created = event.created ?? new Date()
await this.db.createPatch(
event.card,
@@ -289,14 +289,14 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
created
)
const patch = {
const patch: Patch = {
type: event.patchType,
messageCreated: event.messageCreated,
message: event.message,
data: event.data,
creator: event.creator,
created
} as Patch
} as any
const responseEvent: PatchCreatedEvent = {
_id: event._id,
type: MessageResponseEventType.PatchCreated,
@@ -308,7 +308,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createReaction(event: CreateReactionEvent): Promise<Result> {
private async createReaction (event: CreateReactionEvent): Promise<Result> {
const created = new Date()
await this.db.createReaction(
event.card,
@@ -337,7 +337,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeReaction(event: RemoveReactionEvent): Promise<Result> {
private async removeReaction (event: RemoveReactionEvent): Promise<Result> {
await this.db.removeReaction(event.card, event.message, event.messageCreated, event.reaction, event.creator)
const responseEvent: ReactionRemovedEvent = {
_id: event._id,
@@ -353,7 +353,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createFile(event: CreateFileEvent): Promise<Result> {
private async createFile (event: CreateFileEvent): Promise<Result> {
const created = event.created ?? new Date()
await this.db.createFile(event.card, event.message, event.messageCreated, event.data, event.creator, created)
const responseEvent: FileCreatedEvent = {
@@ -373,7 +373,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeFile(event: RemoveFileEvent): Promise<Result> {
private async removeFile (event: RemoveFileEvent): Promise<Result> {
await this.db.removeFiles(event.card, { message: event.message, blobId: event.blobId })
const responseEvent: FileRemovedEvent = {
_id: event._id,
@@ -389,7 +389,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createLinkPreview(event: CreateLinkPreviewEvent): Promise<Result> {
private async createLinkPreview (event: CreateLinkPreviewEvent): Promise<Result> {
const created = new Date()
const id = await this.db.createLinkPreview(
event.card,
@@ -419,7 +419,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeLinkPreview(event: RemoveLinkPreviewEvent): Promise<Result> {
private async removeLinkPreview (event: RemoveLinkPreviewEvent): Promise<Result> {
await this.db.removeLinkPreview(event.card, event.message, event.id)
const responseEvent: LinkPreviewRemovedEvent = {
_id: event._id,
@@ -435,7 +435,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createNotification(event: CreateNotificationEvent): Promise<Result> {
private async createNotification (event: CreateNotificationEvent): Promise<Result> {
const id = await this.db.createNotification(
event.context,
event.message,
@@ -465,7 +465,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async updateNotification(event: UpdateNotificationEvent): Promise<Result> {
private async updateNotification (event: UpdateNotificationEvent): Promise<Result> {
await this.db.updateNotification(event.query, event.updates)
const responseEvent: NotificationUpdatedEvent = {
_id: event._id,
@@ -478,7 +478,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeNotifications(event: RemoveNotificationsEvent): Promise<Result> {
private async removeNotifications (event: RemoveNotificationsEvent): Promise<Result> {
const ids = await this.db.removeNotifications({
context: event.context,
account: event.account,
@@ -499,7 +499,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createNotificationContext(event: CreateNotificationContextEvent): Promise<Result> {
private async createNotificationContext (event: CreateNotificationContextEvent): Promise<Result> {
const id = await this.db.createContext(
event.account,
event.card,
@@ -525,7 +525,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeNotificationContext(event: RemoveNotificationContextEvent): Promise<Result> {
private async removeNotificationContext (event: RemoveNotificationContextEvent): Promise<Result> {
const context = (await this.db.findNotificationContexts({ id: event.context, account: event.account }))[0]
if (context === undefined) return {}
@@ -543,7 +543,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
async updateNotificationContext(event: UpdateNotificationContextEvent): Promise<Result> {
async updateNotificationContext (event: UpdateNotificationContextEvent): Promise<Result> {
await this.db.updateContext(event.context, event.account, event.updates)
const responseEvent: NotificationContextUpdatedEvent = {
@@ -560,7 +560,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
async createMessagesGroup(event: CreateMessagesGroupEvent): Promise<Result> {
async createMessagesGroup (event: CreateMessagesGroupEvent): Promise<Result> {
const { fromDate, toDate, count, card, blobId } = event.group
await this.db.createMessagesGroup(card, blobId, fromDate, toDate, count)
@@ -580,13 +580,13 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
async removeMessagesGroup(event: RemoveMessagesGroupEvent): Promise<Result> {
async removeMessagesGroup (event: RemoveMessagesGroupEvent): Promise<Result> {
await this.db.removeMessagesGroup(event.card, event.blobId)
return {}
}
private async createThread(event: CreateThreadEvent): Promise<Result> {
private async createThread (event: CreateThreadEvent): Promise<Result> {
const date = new Date()
await this.db.createThread(event.card, event.message, event.messageCreated, event.thread, event.threadType, date)
const responseEvent: ThreadCreatedEvent = {
@@ -607,7 +607,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async createLabel(event: CreateLabelEvent): Promise<Result> {
private async createLabel (event: CreateLabelEvent): Promise<Result> {
const created = new Date()
await this.db.createLabel(event.label, event.card, event.cardType, event.account, created)
return {
@@ -625,7 +625,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeLabel(event: RemoveLabelEvent): Promise<Result> {
private async removeLabel (event: RemoveLabelEvent): Promise<Result> {
await this.db.removeLabels({
label: event.label,
card: event.card,
@@ -642,7 +642,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async updateCardType(event: UpdateCardTypeEvent): Promise<Result> {
private async updateCardType (event: UpdateCardTypeEvent): Promise<Result> {
return {
responseEvent: {
_id: event._id,
@@ -655,7 +655,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
private async removeCard(event: RemoveCardEvent): Promise<Result> {
private async removeCard (event: RemoveCardEvent): Promise<Result> {
return {
responseEvent: {
_id: event._id,
@@ -665,7 +665,7 @@ export class DatabaseMiddleware extends BaseMiddleware implements Middleware {
}
}
close(): void {
close (): void {
this.db.close()
}
}
+11 -11
View File
@@ -39,10 +39,10 @@ import type {
import { ApiError } from '../error'
import type { Middleware, MiddlewareContext, QueryId } from '../types'
import { BaseMiddleware } from './base'
import { findMessage } from '../triggers/utils.ts'
import { findMessage } from '../triggers/utils'
export class PermissionsMiddleware extends BaseMiddleware implements Middleware {
constructor(
constructor (
readonly db: DbAdapter,
readonly context: MiddlewareContext,
next?: Middleware
@@ -50,7 +50,7 @@ export class PermissionsMiddleware extends BaseMiddleware implements Middleware
super(context, next)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
if (derived) return await this.provideEvent(session, event, derived)
switch (event.type) {
case MessageRequestEventType.CreatePatch: {
@@ -92,10 +92,10 @@ export class PermissionsMiddleware extends BaseMiddleware implements Middleware
break
}
return this.provideEvent(session, event, derived)
return await this.provideEvent(session, event, derived)
}
async checkPatch(session: SessionData, event: CreatePatchEvent): Promise<void> {
async checkPatch (session: SessionData, event: CreatePatchEvent): Promise<void> {
const account = session.account
if (systemAccountUuid === account.uuid) return
const socialIds = account.socialIds
@@ -117,7 +117,7 @@ export class PermissionsMiddleware extends BaseMiddleware implements Middleware
}
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -126,7 +126,7 @@ export class PermissionsMiddleware extends BaseMiddleware implements Middleware
return await this.provideFindNotificationContexts(session, paramsWithAccount, queryId)
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -135,26 +135,26 @@ export class PermissionsMiddleware extends BaseMiddleware implements Middleware
return await this.provideFindNotifications(session, paramsWithAccount, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
const paramsWithAccount = this.expandParamsWithAccount(session, params)
return await this.provideFindLabels(session, paramsWithAccount, queryId)
}
private checkSocialId(session: SessionData, creator: SocialID): void {
private checkSocialId (session: SessionData, creator: SocialID): void {
const account = session.account
if (!account.socialIds.includes(creator) && systemAccountUuid !== account.uuid) {
throw ApiError.forbidden('social ID is not allowed')
}
}
private checkAccount(session: SessionData, creator: AccountID): void {
private checkAccount (session: SessionData, creator: AccountID): void {
const account = session.account
if (account.uuid !== creator && systemAccountUuid !== account.uuid) {
throw ApiError.forbidden('account is not allowed')
}
}
private onlySystemAccount(session: SessionData): void {
private onlySystemAccount (session: SessionData): void {
const account = session.account
if (systemAccountUuid !== account.uuid) {
throw ApiError.forbidden('only system account is allowed')
+5 -5
View File
@@ -24,7 +24,7 @@ import { notify } from '../notification/notification'
export class TriggersMiddleware extends BaseMiddleware implements Middleware {
private readonly ctx: MeasureContext
constructor(
constructor (
private readonly db: DbAdapter,
context: MiddlewareContext,
next?: Middleware
@@ -39,7 +39,7 @@ export class TriggersMiddleware extends BaseMiddleware implements Middleware {
) // 1hour
}
async response(session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
async response (session: SessionData, event: ResponseEvent, derived: boolean): Promise<void> {
const ctx: Omit<TriggerCtx, 'ctx'> = {
metadata: this.context.metadata,
db: this.db,
@@ -59,10 +59,10 @@ export class TriggersMiddleware extends BaseMiddleware implements Middleware {
ctx: this.ctx.newChild('create-notifications', {})
},
event
).then((res) => void this.propagate(session, res))
).then((res) => this.propagate(session, res))
}
private async applyTriggers(session: SessionData, event: ResponseEvent, ctx: Omit<TriggerCtx, 'ctx'>) {
private async applyTriggers (session: SessionData, event: ResponseEvent, ctx: Omit<TriggerCtx, 'ctx'>): Promise<void> {
const matchedTriggers = triggers.filter(([_, type]) => type === event.type)
if (matchedTriggers.length === 0) return
@@ -83,7 +83,7 @@ export class TriggersMiddleware extends BaseMiddleware implements Middleware {
await this.propagate(session, derived)
}
private async propagate(session: SessionData, derived: RequestEvent[]) {
private async propagate (session: SessionData, derived: RequestEvent[]): Promise<void> {
if (derived.length === 0) return
if (this.context.head === undefined) return
await Promise.all(derived.map((d) => this.context.head?.event(session, d, true)))
+24 -19
View File
@@ -39,16 +39,12 @@ import {
} from '@hcengineering/communication-types'
import { z } from 'zod'
import type { Middleware, MiddlewareContext, QueryId } from '../types'
import type { Middleware, QueryId } from '../types'
import { BaseMiddleware } from './base'
import { ApiError } from '../error'
export class ValidateMiddleware extends BaseMiddleware implements Middleware {
constructor(context: MiddlewareContext, next?: Middleware) {
super(context, next)
}
private validate(data: any, schema: z.ZodObject<any>): void {
private validate (data: any, schema: z.ZodObject<any>): void {
const validationResult = schema.safeParse(data)
if (!validationResult.success) {
const errors = validationResult.error.errors.map((err) => err.message)
@@ -57,12 +53,12 @@ export class ValidateMiddleware extends BaseMiddleware implements Middleware {
}
}
async findMessages(session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
async findMessages (session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
this.validate(params, FindMessagesParamsSchema)
return await this.provideFindMessages(session, params, queryId)
}
async findMessagesGroups(
async findMessagesGroups (
session: SessionData,
params: FindMessagesGroupsParams,
queryId?: QueryId
@@ -71,7 +67,7 @@ export class ValidateMiddleware extends BaseMiddleware implements Middleware {
return await this.provideFindMessagesGroups(session, params, queryId)
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -80,7 +76,7 @@ export class ValidateMiddleware extends BaseMiddleware implements Middleware {
return await this.provideFindNotificationContexts(session, params, queryId)
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -89,17 +85,17 @@ export class ValidateMiddleware extends BaseMiddleware implements Middleware {
return await this.provideFindNotifications(session, params, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams, queryId?: QueryId): Promise<Label[]> {
this.validate(params, FindLabelsParamsSchema)
return await this.provideFindLabels(session, params, queryId)
}
async findCollaborators(session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
this.validate(params, FindCollaboratorsParamsSchema)
return await this.provideFindCollaborators(session, params)
}
async event(session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent, derived: boolean): Promise<EventResult> {
if (derived) return await this.provideEvent(session, event, derived)
switch (event.type) {
case MessageRequestEventType.CreateMessage:
@@ -184,7 +180,7 @@ const PatchData = z.any()
const MessageID = z.string()
const NotificationID = z.string()
const MessageType = z.string()
const MessagesGroup = z.any()
const MessagesGroupSchema = z.any()
const PatchTypeSchema = z.enum([PatchType.update, PatchType.remove])
const RichText = z.string()
const SocialID = z.string()
@@ -257,7 +253,7 @@ const FindCollaboratorsParamsSchema = FindParamsSchema.extend({
card: CardID.optional(),
account: z.union([AccountID, z.array(AccountID)]).optional()
}).strict()
//Events
// Events
const BaseRequestEventSchema = z
.object({
@@ -265,7 +261,7 @@ const BaseRequestEventSchema = z
})
.strict()
//Label events
// Label events
const CreateLabelEventSchema = BaseRequestEventSchema.extend({
type: z.literal(LabelRequestEventType.CreateLabel),
label: LabelID,
@@ -401,7 +397,7 @@ const UpdateThreadEventSchema = BaseRequestEventSchema.extend({
const CreateMessagesGroupEventSchema = BaseRequestEventSchema.extend({
type: z.literal(MessageRequestEventType.CreateMessagesGroup),
group: MessagesGroup
group: MessagesGroupSchema
}).strict()
const RemoveMessagesGroupEventSchema = BaseRequestEventSchema.extend({
@@ -490,7 +486,7 @@ const RemoveCollaboratorsEventSchema = BaseRequestEventSchema.extend({
created: DateSchema.optional()
}).strict()
function deserializeEvent(event: RequestEvent): RequestEvent {
function deserializeEvent (event: RequestEvent): RequestEvent {
switch (event.type) {
case MessageRequestEventType.CreateMessage:
case CardRequestEventType.UpdateCardType:
@@ -508,12 +504,14 @@ function deserializeEvent(event: RequestEvent): RequestEvent {
case MessageRequestEventType.RemoveLinkPreview:
return {
...event,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
messageCreated: deserializeDate(event.messageCreated)!
}
case MessageRequestEventType.CreatePatch:
case MessageRequestEventType.CreateFile:
return {
...event,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
messageCreated: deserializeDate(event.messageCreated)!,
created: deserializeDate(event.created)
}
@@ -530,19 +528,24 @@ function deserializeEvent(event: RequestEvent): RequestEvent {
...event,
group: {
...event.group,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
fromDate: deserializeDate(event.group.fromDate)!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
toDate: deserializeDate(event.group.toDate)!
}
}
case NotificationRequestEventType.CreateNotification:
return {
...event,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
created: deserializeDate(event.created)!
}
case NotificationRequestEventType.CreateNotificationContext:
return {
...event,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
lastView: deserializeDate(event.lastView)!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
lastUpdate: deserializeDate(event.lastUpdate)!
}
case NotificationRequestEventType.UpdateNotificationContext:
@@ -550,7 +553,9 @@ function deserializeEvent(event: RequestEvent): RequestEvent {
...event,
updates: {
...event.updates,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
lastView: deserializeDate(event.updates.lastView)!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
lastUpdate: deserializeDate(event.updates.lastUpdate)!
}
}
@@ -559,7 +564,7 @@ function deserializeEvent(event: RequestEvent): RequestEvent {
return event
}
function deserializeDate(date?: Date | string | undefined | null): Date | undefined {
function deserializeDate (date?: Date | string | undefined | null): Date | undefined {
if (date == null) return undefined
if (date instanceof Date) return date
return new Date(date)
+15 -15
View File
@@ -46,7 +46,7 @@ import { TriggersMiddleware } from './middleware/triggers'
import { ValidateMiddleware } from './middleware/validate'
import { DateMiddleware } from './middleware/date'
export async function buildMiddlewares(
export async function buildMiddlewares (
ctx: MeasureContext,
workspace: WorkspaceID,
metadata: Metadata,
@@ -78,12 +78,12 @@ export class Middlewares {
private readonly middlewares: Middleware[] = []
private constructor(
private constructor (
private readonly ctx: MeasureContext,
private readonly context: MiddlewareContext
) {}
static async create(
static async create (
ctx: MeasureContext,
context: MiddlewareContext,
createFns: MiddlewareCreateFn[]
@@ -96,12 +96,12 @@ export class Middlewares {
return middlewares
}
private async buildChain(
private async buildChain (
ctx: MeasureContext,
createFns: MiddlewareCreateFn[],
context: MiddlewareContext
): Promise<Middleware | undefined> {
let current: Middleware | undefined = undefined
let current: Middleware | undefined
for (let index = createFns.length - 1; index >= 0; index--) {
const createFn = createFns[index]
try {
@@ -119,17 +119,17 @@ export class Middlewares {
return current
}
async findMessages(session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
async findMessages (session: SessionData, params: FindMessagesParams, queryId?: QueryId): Promise<Message[]> {
if (this.head === undefined) return []
return await this.head.findMessages(session, params, queryId)
}
async findMessagesGroups(session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
async findMessagesGroups (session: SessionData, params: FindMessagesGroupsParams): Promise<MessagesGroup[]> {
if (this.head === undefined) return []
return await this.head.findMessagesGroups(session, params)
}
async findNotificationContexts(
async findNotificationContexts (
session: SessionData,
params: FindNotificationContextParams,
queryId?: QueryId
@@ -138,7 +138,7 @@ export class Middlewares {
return await this.head.findNotificationContexts(session, params, queryId)
}
async findNotifications(
async findNotifications (
session: SessionData,
params: FindNotificationsParams,
queryId?: QueryId
@@ -147,32 +147,32 @@ export class Middlewares {
return await this.head.findNotifications(session, params, queryId)
}
async findLabels(session: SessionData, params: FindLabelsParams): Promise<Label[]> {
async findLabels (session: SessionData, params: FindLabelsParams): Promise<Label[]> {
if (this.head === undefined) return []
return await this.head.findLabels(session, params)
}
async findCollaborators(session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
async findCollaborators (session: SessionData, params: FindCollaboratorsParams): Promise<Collaborator[]> {
if (this.head === undefined) return []
return await this.head.findCollaborators(session, params)
}
async unsubscribeQuery(session: SessionData, id: number): Promise<void> {
async unsubscribeQuery (session: SessionData, id: number): Promise<void> {
if (this.head === undefined) return
this.head?.unsubscribeQuery(session, id)
}
async event(session: SessionData, event: RequestEvent): Promise<EventResult> {
async event (session: SessionData, event: RequestEvent): Promise<EventResult> {
if (this.head === undefined) return {}
return (await this.head?.event(session, event, false)) ?? {}
}
async closeSession(sessionId: string): Promise<void> {
async closeSession (sessionId: string): Promise<void> {
if (this.head === undefined) return
this.head.closeSession(sessionId)
}
async close(): Promise<void> {
async close (): Promise<void> {
for (const mw of this.middlewares) {
try {
mw.close()
@@ -39,11 +39,11 @@ import {
import type { TriggerCtx } from '../types'
import { findAccount } from '../utils'
import { findMessage } from '../triggers/utils.ts'
import { findMessage } from '../triggers/utils'
const BATCH_SIZE = 500
export async function notify(ctx: TriggerCtx, event: ResponseEvent): Promise<RequestEvent[]> {
export async function notify (ctx: TriggerCtx, event: ResponseEvent): Promise<RequestEvent[]> {
switch (event.type) {
case MessageResponseEventType.MessageCreated: {
return await notifyMessage(ctx, event.message, event.cardType)
@@ -66,7 +66,7 @@ export async function notify(ctx: TriggerCtx, event: ResponseEvent): Promise<Req
return []
}
async function removeReactionNotification(
async function removeReactionNotification (
ctx: TriggerCtx,
card: CardID,
message: MessageID,
@@ -94,9 +94,9 @@ async function removeReactionNotification(
if (toDelete === undefined) return result
const context = (await ctx.db.findNotificationContexts({ card: card, account: messageAccount, limit: 1 }))[0]
const context = (await ctx.db.findNotificationContexts({ card, account: messageAccount, limit: 1 }))[0]
if (context == null) return result
if (context.lastNotify && context.lastNotify.getTime() === toDelete.created.getTime()) {
if (context.lastNotify != null && context.lastNotify.getTime() === toDelete.created.getTime()) {
const lastNotification = (
await ctx.db.findNotifications({
account: messageAccount,
@@ -129,7 +129,7 @@ async function removeReactionNotification(
return result
}
async function notifyReaction(
async function notifyReaction (
ctx: TriggerCtx,
card: CardID,
message: MessageID,
@@ -147,7 +147,7 @@ async function notifyReaction(
const reactionAccount = await findAccount(ctx, reaction.creator)
if (reactionAccount === messageAccount) return result
const context = (await ctx.db.findNotificationContexts({ card: card, account: messageAccount }))[0]
const context = (await ctx.db.findNotificationContexts({ card, account: messageAccount }))[0]
let contextId: ContextID | undefined = context?.id
if (context == null) {
@@ -165,7 +165,7 @@ async function notifyReaction(
notificationType: NotificationType.Reaction,
account: messageAccount,
context: contextId,
message: message,
message,
messageCreated,
created: reaction.created,
content
@@ -182,7 +182,7 @@ async function notifyReaction(
return result
}
async function notifyMessage(ctx: TriggerCtx, message: Message, cardType: CardType): Promise<RequestEvent[]> {
async function notifyMessage (ctx: TriggerCtx, message: Message, cardType: CardType): Promise<RequestEvent[]> {
const cursor = ctx.db.getCollaboratorsCursor(message.card, message.created, BATCH_SIZE)
const creatorAccount = await findAccount(ctx, message.creator)
const result: RequestEvent[] = []
@@ -212,7 +212,7 @@ async function notifyMessage(ctx: TriggerCtx, message: Message, cardType: CardTy
return result
}
async function processCollaborator(
async function processCollaborator (
ctx: TriggerCtx,
cardType: CardType,
message: Message,
@@ -250,16 +250,16 @@ async function processCollaborator(
return result
}
async function createOrUpdateContext(
async function createOrUpdateContext (
ctx: TriggerCtx,
message: Message,
collaborator: AccountID,
isOwn: boolean,
context?: NotificationContext
): Promise<{
contextId: ContextID | undefined
events: RequestEvent[]
}> {
contextId: ContextID | undefined
events: RequestEvent[]
}> {
if (context == null) {
const contextId = await createContext(
ctx,
@@ -297,7 +297,7 @@ async function createOrUpdateContext(
}
}
async function createContext(
async function createContext (
ctx: TriggerCtx,
account: AccountID,
card: CardID,
@@ -326,7 +326,7 @@ async function createContext(
}
}
function isContextRead(context: NotificationContext): boolean {
function isContextRead (context: NotificationContext): boolean {
const { lastView, lastUpdate } = context
if (lastView == null) {
+7 -7
View File
@@ -24,9 +24,9 @@ import {
import { type ActivityTypeUpdate, ActivityUpdateType, MessageType } from '@hcengineering/communication-types'
import type { TriggerCtx, TriggerFn, Triggers } from '../types'
import { getNameBySocialID } from './utils.ts'
import { getNameBySocialID } from './utils'
async function createActivityOnCardTypeUpdate(ctx: TriggerCtx, event: CardTypeUpdatedEvent): Promise<RequestEvent[]> {
async function createActivityOnCardTypeUpdate (ctx: TriggerCtx, event: CardTypeUpdatedEvent): Promise<RequestEvent[]> {
const updateDate: ActivityTypeUpdate = {
type: ActivityUpdateType.Type,
newType: event.cardType
@@ -51,30 +51,30 @@ async function createActivityOnCardTypeUpdate(ctx: TriggerCtx, event: CardTypeUp
]
}
async function onCardTypeUpdates(ctx: TriggerCtx, event: CardTypeUpdatedEvent): Promise<RequestEvent[]> {
async function onCardTypeUpdates (ctx: TriggerCtx, event: CardTypeUpdatedEvent): Promise<RequestEvent[]> {
await ctx.db.updateCollaborators({ card: event.card }, { cardType: event.cardType })
await ctx.db.updateLabels(event.card, { cardType: event.cardType })
await ctx.db.updateThread(event.card, { threadType: event.cardType })
return []
}
async function removeCollaborators(ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
async function removeCollaborators (ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
await ctx.db.removeCollaborators(event.card, {})
return []
}
async function removeLabels(ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
async function removeLabels (ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
await ctx.db.removeLabels({ card: event.card })
return []
}
async function removeThreads(ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
async function removeThreads (ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
await ctx.db.removeThreads({ card: event.card })
await ctx.db.removeThreads({ thread: event.card })
return []
}
async function removeNotificationContexts(ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
async function removeNotificationContexts (ctx: TriggerCtx, event: CardRemovedEvent): Promise<RequestEvent[]> {
const result: RequestEvent[] = []
const contexts = await ctx.db.findNotificationContexts({ card: event.card })
for (const context of contexts) {
+8 -8
View File
@@ -42,12 +42,12 @@ import type { TriggerCtx, TriggerFn, Triggers } from '../types'
import { findAccount } from '../utils'
import { findMessageInFiles } from './utils'
async function onMessagesGroupCreated(ctx: TriggerCtx, event: MessagesGroupCreatedEvent): Promise<RequestEvent[]> {
async function onMessagesGroupCreated (ctx: TriggerCtx, event: MessagesGroupCreatedEvent): Promise<RequestEvent[]> {
ctx.registeredCards.delete(event.group.card)
return []
}
async function onMessagesRemoved(ctx: TriggerCtx, event: PatchCreatedEvent): Promise<RequestEvent[]> {
async function onMessagesRemoved (ctx: TriggerCtx, event: PatchCreatedEvent): Promise<RequestEvent[]> {
const { card, patch } = event
if (patch.type !== PatchType.remove) return []
const thread = await ctx.db.findThread(card)
@@ -79,7 +79,7 @@ async function onMessagesRemoved(ctx: TriggerCtx, event: PatchCreatedEvent): Pro
return result
}
async function onFileCreated(ctx: TriggerCtx, event: FileCreatedEvent): Promise<RequestEvent[]> {
async function onFileCreated (ctx: TriggerCtx, event: FileCreatedEvent): Promise<RequestEvent[]> {
const message = (await ctx.db.findMessages({ card: event.card, id: event.message, limit: 1 }))[0]
if (message !== undefined) return []
@@ -104,7 +104,7 @@ async function onFileCreated(ctx: TriggerCtx, event: FileCreatedEvent): Promise<
]
}
async function onFileRemoved(ctx: TriggerCtx, event: FileRemovedEvent): Promise<RequestEvent[]> {
async function onFileRemoved (ctx: TriggerCtx, event: FileRemovedEvent): Promise<RequestEvent[]> {
const message = (await ctx.db.findMessages({ card: event.card, id: event.message, limit: 1 }))[0]
if (message !== undefined) return []
const { blobId } = event
@@ -122,7 +122,7 @@ async function onFileRemoved(ctx: TriggerCtx, event: FileRemovedEvent): Promise<
]
}
async function registerCard(ctx: TriggerCtx, event: MessageCreatedEvent | PatchCreatedEvent): Promise<RequestEvent[]> {
async function registerCard (ctx: TriggerCtx, event: MessageCreatedEvent | PatchCreatedEvent): Promise<RequestEvent[]> {
const { workspace, metadata } = ctx
let card: CardID
switch (event.type) {
@@ -152,7 +152,7 @@ async function registerCard(ctx: TriggerCtx, event: MessageCreatedEvent | PatchC
return []
}
async function addCollaborators(ctx: TriggerCtx, event: MessageCreatedEvent): Promise<RequestEvent[]> {
async function addCollaborators (ctx: TriggerCtx, event: MessageCreatedEvent): Promise<RequestEvent[]> {
const { creator, type } = event.message
if (type === MessageType.Activity) return []
const account = await findAccount(ctx, creator)
@@ -188,7 +188,7 @@ async function addCollaborators(ctx: TriggerCtx, event: MessageCreatedEvent): Pr
]
}
async function addThreadReply(ctx: TriggerCtx, event: MessageCreatedEvent): Promise<RequestEvent[]> {
async function addThreadReply (ctx: TriggerCtx, event: MessageCreatedEvent): Promise<RequestEvent[]> {
if (event.message.type !== MessageType.Message || ctx.derived) return []
const { message } = event
const thread = await ctx.db.findThread(message.card)
@@ -217,7 +217,7 @@ async function addThreadReply(ctx: TriggerCtx, event: MessageCreatedEvent): Prom
]
}
async function onThreadCreated(ctx: TriggerCtx, event: ThreadCreatedEvent): Promise<RequestEvent[]> {
async function onThreadCreated (ctx: TriggerCtx, event: ThreadCreatedEvent): Promise<RequestEvent[]> {
let message: Message | undefined = (
await ctx.db.findMessages({
card: event.thread.card,
+8 -8
View File
@@ -38,10 +38,10 @@ import {
import { groupByArray } from '@hcengineering/core'
import type { TriggerCtx, TriggerFn, Triggers } from '../types'
import { findAccount } from '../utils.ts'
import { getAddCollaboratorsMessageContent, getRemoveCollaboratorsMessageContent } from './utils.ts'
import { findAccount } from '../utils'
import { getAddCollaboratorsMessageContent, getRemoveCollaboratorsMessageContent } from './utils'
async function onAddedCollaborators(ctx: TriggerCtx, event: AddedCollaboratorsEvent): Promise<RequestEvent[]> {
async function onAddedCollaborators (ctx: TriggerCtx, event: AddedCollaboratorsEvent): Promise<RequestEvent[]> {
const { card, cardType, collaborators } = event
if (collaborators.length === 0) return []
const result: RequestEvent[] = []
@@ -79,7 +79,7 @@ async function onAddedCollaborators(ctx: TriggerCtx, event: AddedCollaboratorsEv
return result
}
async function onRemovedCollaborators(ctx: TriggerCtx, event: RemovedCollaboratorsEvent): Promise<RequestEvent[]> {
async function onRemovedCollaborators (ctx: TriggerCtx, event: RemovedCollaboratorsEvent): Promise<RequestEvent[]> {
const { card, collaborators } = event
if (collaborators.length === 0) return []
const result: RequestEvent[] = []
@@ -128,7 +128,7 @@ async function onRemovedCollaborators(ctx: TriggerCtx, event: RemovedCollaborato
return result
}
async function onNotificationContextUpdated(
async function onNotificationContextUpdated (
ctx: TriggerCtx,
event: NotificationContextUpdatedEvent
): Promise<RequestEvent[]> {
@@ -166,7 +166,7 @@ async function onNotificationContextUpdated(
return result
}
async function onNotificationContextRemoved(
async function onNotificationContextRemoved (
ctx: TriggerCtx,
event: NotificationContextRemovedEvent
): Promise<RequestEvent[]> {
@@ -184,7 +184,7 @@ async function onNotificationContextRemoved(
return result
}
async function onMessagesRemoved(ctx: TriggerCtx, event: PatchCreatedEvent): Promise<RequestEvent[]> {
async function onMessagesRemoved (ctx: TriggerCtx, event: PatchCreatedEvent): Promise<RequestEvent[]> {
if (event.patch.type !== PatchType.remove) return []
const notifications = await ctx.db.findNotifications({
@@ -200,7 +200,7 @@ async function onMessagesRemoved(ctx: TriggerCtx, event: PatchCreatedEvent): Pro
for (const [context, ns] of byContextId.entries()) {
result.push({
type: NotificationRequestEventType.RemoveNotifications,
context: context,
context,
account: ns[0].account,
ids: notifications.map((it) => it.id)
})
+12 -12
View File
@@ -27,10 +27,10 @@ import { loadGroupFile } from '@hcengineering/communication-yaml'
import { applyPatches } from '@hcengineering/communication-shared'
import type { DbAdapter } from '@hcengineering/communication-sdk-types'
import type { TriggerCtx } from '../types.ts'
import { findAccount } from '../utils.ts'
import type { TriggerCtx } from '../types'
import { findAccount } from '../utils'
export async function findMessage(
export async function findMessage (
db: DbAdapter,
filesUrl: string,
workspace: WorkspaceID,
@@ -45,7 +45,7 @@ export async function findMessage(
return await findMessageInFiles(db, filesUrl, workspace, card, id, created)
}
export async function findMessageInFiles(
export async function findMessageInFiles (
db: DbAdapter,
filesUrl: string,
workspace: WorkspaceID,
@@ -88,19 +88,19 @@ export async function findMessageInFiles(
}
}
export async function getNameBySocialID(ctx: TriggerCtx, id: SocialID) {
export async function getNameBySocialID (ctx: TriggerCtx, id: SocialID): Promise<string> {
const account = await findAccount(ctx, id)
return account ? ((await ctx.db.getNameByAccount(account)) ?? 'System') : 'System'
return account != null ? ((await ctx.db.getNameByAccount(account)) ?? 'System') : 'System'
}
export async function getAddCollaboratorsMessageContent(
export async function getAddCollaboratorsMessageContent (
ctx: TriggerCtx,
sender: AccountID | undefined,
collaborators: AccountID[]
): Promise<RichText> {
const senderName = sender ? ((await ctx.db.getNameByAccount(sender)) ?? 'System') : 'System'
const senderName = sender != null ? ((await ctx.db.getNameByAccount(sender)) ?? 'System') : 'System'
if (sender && collaborators.length === 1 && collaborators.includes(sender)) {
if (sender != null && collaborators.length === 1 && collaborators.includes(sender)) {
return `${senderName} joined`
}
@@ -111,14 +111,14 @@ export async function getAddCollaboratorsMessageContent(
return `${senderName} added ${collaboratorsNames.join(', ')}`
}
export async function getRemoveCollaboratorsMessageContent(
export async function getRemoveCollaboratorsMessageContent (
ctx: TriggerCtx,
sender: AccountID | undefined,
collaborators: AccountID[]
): Promise<RichText> {
const senderName = sender ? ((await ctx.db.getNameByAccount(sender)) ?? 'System') : 'System'
const senderName = sender != null ? ((await ctx.db.getNameByAccount(sender)) ?? 'System') : 'System'
if (sender && collaborators.length === 1 && collaborators.includes(sender)) {
if (sender != null && collaborators.length === 1 && collaborators.includes(sender)) {
return `${senderName} left`
}

Some files were not shown because too many files have changed in this diff Show More