diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index c0a3e82da1..bc29378660 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.3 specifiers: '@microsoft/api-extractor': ^7.18.4 '@rush-temp/client': file:./projects/client.tgz + '@rush-temp/client-resources': file:./projects/client-resources.tgz '@rush-temp/core': file:./projects/core.tgz '@rush-temp/dev-server': file:./projects/dev-server.tgz '@rush-temp/dev-storage': file:./projects/dev-storage.tgz @@ -61,6 +62,7 @@ specifiers: dependencies: '@microsoft/api-extractor': 7.18.4 '@rush-temp/client': file:projects/client.tgz_6c259fadfeb3a4b20890aefe87070b8b + '@rush-temp/client-resources': file:projects/client-resources.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/core': file:projects/core.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/dev-server': file:projects/dev-server.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/dev-storage': file:projects/dev-storage.tgz_6c259fadfeb3a4b20890aefe87070b8b @@ -7686,6 +7688,24 @@ packages: commander: 2.20.3 dev: false + file:projects/client-resources.tgz_6c259fadfeb3a4b20890aefe87070b8b: + resolution: {integrity: sha512-PjpCnRuDrh/T+p0+t2m0AHQJ2RswCa3JNpnEtFuJSskxnd3FYKcu7MYjnujM9wcrPZqygAeSfmei1ZA9uS5bqA==, tarball: file:projects/client-resources.tgz} + id: file:projects/client-resources.tgz + name: '@rush-temp/client-resources' + version: 0.0.0 + dependencies: + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 4.28.5_a8e83fcad666e1ba86be4b2e27a20aea + eslint: 7.32.0 + eslint-plugin-import: 2.23.4_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 4.3.1 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - supports-color + - typescript + dev: false + file:projects/client.tgz_6c259fadfeb3a4b20890aefe87070b8b: resolution: {integrity: sha512-8YJou7AitxzzH2roWCno/zgd27SiQXlqrdDVyhAAvZrBZY7KGbxw4OxGkI+6eVK+Lk/zajS2FkGZ+oyZ+Bxe6g==, tarball: file:projects/client.tgz} id: file:projects/client.tgz @@ -7851,7 +7871,7 @@ packages: dev: false file:projects/presentation.tgz_c38cf1a7a413db8918b0b4754c21e4c5: - resolution: {integrity: sha512-v1qRQGQrWDFfME4IEpK6bM0E3IQljeG2+Ft/YVPM/Fbf/y3e+28AvI3nyvLn+1N6gY+5faEAHLE4M9vBbR+A1A==, tarball: file:projects/presentation.tgz} + resolution: {integrity: sha512-0da7jIZ76QPDe/6DKiocyNFA3rzQvBBNMIpouw0nWZS9qgnOgDARiBB9mg+2vuw4u1FmRgFQUIdpMxrwRi2b/g==, tarball: file:projects/presentation.tgz} id: file:projects/presentation.tgz name: '@rush-temp/presentation' version: 0.0.0 @@ -8059,7 +8079,7 @@ packages: dev: false file:projects/workbench-resources.tgz_c38cf1a7a413db8918b0b4754c21e4c5: - resolution: {integrity: sha512-UZMkx/Mq9SBiSR6JFaCmJ548KfR1cSser177G9y196X9ot7EYLYHSZ0Teo9hZTwUgDU1TDkk2KW2sxuFN71naA==, tarball: file:projects/workbench-resources.tgz} + resolution: {integrity: sha512-i2M+58McWVoRf331FyY9crFu/50O8YuU1x6WbnJ+hBqq+nuW3XJdqJcabrr6+ZYMMnPqfuXrKkZJoGipc9zwMA==, tarball: file:projects/workbench-resources.tgz} id: file:projects/workbench-resources.tgz name: '@rush-temp/workbench-resources' version: 0.0.0 diff --git a/packages/platform/src/rpc.ts b/packages/platform/src/rpc.ts index c6b35666d5..45d1266cfb 100644 --- a/packages/platform/src/rpc.ts +++ b/packages/platform/src/rpc.ts @@ -24,9 +24,9 @@ export type ReqId = string | number /** * @public */ -export interface Request

{ +export interface Request

{ id?: ReqId - method: M + method: string params: P } diff --git a/plugins/client-resources/.eslintrc.js b/plugins/client-resources/.eslintrc.js new file mode 100644 index 0000000000..89f8151bd4 --- /dev/null +++ b/plugins/client-resources/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + project: './tsconfig.json' + } +} \ No newline at end of file diff --git a/plugins/client-resources/.npmignore b/plugins/client-resources/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/plugins/client-resources/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/plugins/client-resources/config/rig.json b/plugins/client-resources/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/plugins/client-resources/config/rig.json @@ -0,0 +1,18 @@ +// The "rig.json" file directs tools to look for their config files in an external package. +// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@anticrm/platform-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/plugins/client-resources/package.json b/plugins/client-resources/package.json new file mode 100644 index 0000000000..719b31b9fc --- /dev/null +++ b/plugins/client-resources/package.json @@ -0,0 +1,25 @@ +{ + "name": "@anticrm/client-resources", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "lint:fix": "eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig":"~0.6.0", + "@types/heft-jest":"^1.0.2", + "@typescript-eslint/eslint-plugin":"4", + "eslint-plugin-import":"2", + "eslint-plugin-promise":"4", + "eslint-plugin-node":"11", + "eslint":"^7.32.0" + }, + "dependencies": { + "@anticrm/platform":"~0.6.3", + "@anticrm/core":"~0.6.0", + "@anticrm/client":"~0.6.0" + } +} diff --git a/plugins/client-resources/src/connection.ts b/plugins/client-resources/src/connection.ts new file mode 100644 index 0000000000..9c5b0fb415 --- /dev/null +++ b/plugins/client-resources/src/connection.ts @@ -0,0 +1,80 @@ +// +// Copyright © 2020, 2021 Anticrm Platform Contributors. +// Copyright © 2021 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import type { Class, Doc, DocumentQuery, FindOptions, FindResult, Ref, Storage, Tx, TxHander } from '@anticrm/core' +import type { ReqId } from '@anticrm/platform' +import { serialize, readResponse } from '@anticrm/platform' + +class DeferredPromise { + readonly promise: Promise + resolve!: (value?: any) => void + reject!: (reason?: any) => void + constructor () { + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve + this.reject = reject + }) + } +} + +class Connection implements Storage { + private readonly webSocket: WebSocket + private readonly requests = new Map() + private lastId = 0 + + constructor (url: string, private readonly handler: TxHander) { + this.webSocket = new WebSocket(url) + this.webSocket.onmessage = (event: MessageEvent) => { + const resp = readResponse(event.data) + if (resp.id !== undefined) { + const promise = this.requests.get(resp.id) + if (promise === undefined) { throw new Error(`unknown response id: ${resp.id}`) } + this.requests.delete(resp.id) + if (resp.error !== undefined) { + promise.reject(resp.error) + } else { + promise.resolve(resp.result) + } + } else { + this.handler(resp.result as Tx) + } + } + } + + private sendRequest (method: string, ...params: any[]): Promise { + const id = this.lastId++ + this.webSocket.send(serialize({ + method, + params, + id + })) + const promise = new DeferredPromise() + this.requests.set(id, promise) + return promise.promise + } + + findAll(_class: Ref>, query: DocumentQuery, options?: FindOptions): Promise> { + return this.sendRequest('findAll', _class, query, options) + } + + tx (tx: Tx): Promise { + return this.sendRequest('tx', tx) + } +} + +export async function connect (url: string, handler: TxHander): Promise { + return new Connection(url, handler) +} diff --git a/plugins/client-resources/src/index.ts b/plugins/client-resources/src/index.ts new file mode 100644 index 0000000000..b918ace91a --- /dev/null +++ b/plugins/client-resources/src/index.ts @@ -0,0 +1,47 @@ +// +// Copyright © 2020 Anticrm Platform Contributors. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { createClient, Client, TxHander } from '@anticrm/core' +import { getMetadata } from '@anticrm/platform' +import clientPlugin from '@anticrm/client' + +import { connect } from './connection' + +/*! + * Anticrm Platform™ Client Dev Plugin + * © 2020 Anticrm Platform Contributors. All Rights Reserved. + * Licensed under the Eclipse Public License, Version 2.0 + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export default async () => { + let client: Client | undefined + + return { + function: { + GetClient: async (): Promise => { + if (client === undefined) { + const url = getMetadata(clientPlugin.metadata.ClientUrl) + if (url === undefined) { + throw new Error('no app server url provided.') + } + return await createClient((handler: TxHander) => { + return connect(url, handler) + }) + } + return client + } + } + } +} diff --git a/plugins/client-resources/tsconfig.json b/plugins/client-resources/tsconfig.json new file mode 100644 index 0000000000..32045300ce --- /dev/null +++ b/plugins/client-resources/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "lib": ["esnext", "dom"] + } +} \ No newline at end of file diff --git a/rush.json b/rush.json index 44f6628445..a9539a1aab 100644 --- a/rush.json +++ b/rush.json @@ -536,6 +536,11 @@ "projectFolder": "plugins/client", "shouldPublish": true }, + { + "packageName": "@anticrm/client-resources", + "projectFolder": "plugins/client-resources", + "shouldPublish": true + }, { "packageName": "@anticrm/query", "projectFolder": "packages/query",