Skip to content

Extract storage client #8860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
944 changes: 461 additions & 483 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions packages/api-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"@types/node": "~20.11.16",
"@types/jest": "^29.5.5",
"@types/ws": "^8.5.11",
"@types/node-fetch": "~2.6.2",
"@types/snappyjs": "^0.7.1"
},
"dependencies": {
Expand All @@ -59,8 +58,6 @@
"@hcengineering/platform": "^0.6.11",
"@hcengineering/text": "^0.6.5",
"@hcengineering/text-markdown": "^0.6.0",
"form-data": "^4.0.0",
"node-fetch": "^2.6.6",
"snappyjs": "^0.7.0"
},
"repository": "https://github.com/hcengineering/platform",
Expand Down
2 changes: 0 additions & 2 deletions packages/api-client/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { concatLink } from '@hcengineering/core'
export interface ServerConfig {
ACCOUNTS_URL: string
COLLABORATOR_URL: string
FILES_URL: string
UPLOAD_URL: string
}

export async function loadServerConfig (url: string): Promise<ServerConfig> {
Expand Down
1 change: 0 additions & 1 deletion packages/api-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ export * from './types'
export * from './rest'
export * from './config'
export * from './utils'
export * from './storage'
7 changes: 7 additions & 0 deletions packages/storage-client/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
4 changes: 4 additions & 0 deletions packages/storage-client/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/
11 changes: 11 additions & 0 deletions packages/storage-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Huly Storage API Client

A TypeScript client library for interacting with the Huly Storage API.

## Installation

In order to be able to install required packages, you will need to obtain GitHub access token. You can create a token by following the instructions [here](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#authenticating-with-a-personal-access-token).

```bash
npm install @hcengineering/stotage-client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: stotage -> storage

```
4 changes: 4 additions & 0 deletions packages/storage-client/config/rig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
7 changes: 7 additions & 0 deletions packages/storage-client/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: ["./src"],
coverageReporters: ["text-summary", "html"]
}
61 changes: 61 additions & 0 deletions packages/storage-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@hcengineering/storage-client",
"version": "0.6.0",
"main": "lib/index.js",
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
},
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"author": "Anticrm Platform Contributors",
"template": "@hcengineering/api-package",
"license": "EPL-2.0",
"scripts": {
"build": "compile",
"build:watch": "compile",
"test": "jest --passWithNoTests --silent",
"format": "format src",
"_phase:build": "compile transpile src",
"_phase:test": "jest --passWithNoTests --silent",
"_phase:format": "format src",
"_phase:validate": "compile validate"
},
"devDependencies": {
"@hcengineering/platform-rig": "^0.6.0",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-n": "^15.4.0",
"eslint": "^8.54.0",
"simplytyped": "^3.3.0",
"@typescript-eslint/parser": "^6.11.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"prettier": "^3.1.0",
"typescript": "^5.3.3",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.8.0",
"@types/node": "~20.11.16",
"@types/jest": "^29.5.5",
"@types/node-fetch": "~2.6.2"
},
"dependencies": {
"@hcengineering/account-client": "^0.6.0",
"@hcengineering/core": "^0.6.32",
"form-data": "^4.0.0",
"node-fetch": "^2.6.6"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
Expand All @@ -11,18 +10,17 @@
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import core, { concatLink, WorkspaceUuid, Blob, Ref } from '@hcengineering/core'
import FormData from 'form-data'
import { Readable } from 'stream'
import { StorageClient } from './types'
import { loadServerConfig, ServerConfig } from '../config'
import { NetworkError, NotFoundError, StorageError } from './error'
import { AuthOptions } from '../types'
import { getWorkspaceToken } from '../utils'
import nodeFetch from 'node-fetch'

import { StorageClient, AuthOptions } from './types'
import { loadServerConfig, ServerConfig } from './config'
import { NetworkError, NotFoundError, StorageError } from './error'
import { getWorkspaceToken } from './utils'

interface ObjectMetadata {
name: string
etag: string
Expand Down
29 changes: 29 additions & 0 deletions packages/storage-client/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright © 2025 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 { concatLink } from '@hcengineering/core'

export interface ServerConfig {
ACCOUNTS_URL: string
FILES_URL: string
UPLOAD_URL: string
}

export async function loadServerConfig (url: string): Promise<ServerConfig> {
const configUrl = concatLink(url, '/config.json')
const res = await fetch(configUrl, { keepalive: true })
if (res.ok) {
return (await res.json()) as ServerConfig
}
throw new Error('Failed to fetch config')
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@
export { createStorageClient, connectStorage } from './client'
export * from './error'
export * from './types'
export * from './config'
export * from './utils'
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
Expand All @@ -11,7 +10,6 @@
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import { Blob } from '@hcengineering/core'
import { Readable } from 'stream'
Expand All @@ -23,3 +21,37 @@ export interface StorageClient {
partial: (objectName: string, offset: number, length?: number) => Promise<Readable>
remove: (objectName: string) => Promise<void>
}

/**
* Configuration options for password-based authentication
* @public
*/
export interface PasswordAuthOptions {
/** User's email address */
email: string

/** User's password */
password: string

/** Workspace URL name */
workspace: string
}

/**
* Configuration options for token-based authentication
* @public
*/
export interface TokenAuthOptions {
/** Authentication token */
token: string

/** Workspace URL name */
workspace: string
}

/**
* Union type representing all authentication options
* Can be either password-based or token-based authentication
* @public
*/
export type AuthOptions = PasswordAuthOptions | TokenAuthOptions
53 changes: 53 additions & 0 deletions packages/storage-client/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright © 2025 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 WorkspaceLoginInfo, getClient as getAccountClient } from '@hcengineering/account-client'
import { WorkspaceUuid } from '@hcengineering/core'
import { AuthOptions } from './types'
import { loadServerConfig, ServerConfig } from './config'

export interface WorkspaceToken {
endpoint: string
token: string
workspaceId: WorkspaceUuid
info: WorkspaceLoginInfo
}

export async function getWorkspaceToken (
url: string,
options: AuthOptions,
config?: ServerConfig
): Promise<WorkspaceToken> {
config ??= await loadServerConfig(url)

let token: string | undefined

if ('token' in options) {
token = options.token
} else {
const { email, password } = options
const loginInfo = await getAccountClient(config.ACCOUNTS_URL).login(email, password)
token = loginInfo.token
}

if (token === undefined) {
throw new Error('Login failed')
}

const ws = await getAccountClient(config.ACCOUNTS_URL, token).selectWorkspace(options.workspace)
if (ws === undefined) {
throw new Error('Workspace not found')
}

return { endpoint: ws.endpoint, token: ws.token, workspaceId: ws.workspace, info: ws }
}
11 changes: 11 additions & 0 deletions packages/storage-client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",

"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"tsBuildInfoFile": ".build/build.tsbuildinfo",
"types": ["node", "jest"]
}
}
5 changes: 5 additions & 0 deletions rush.json
Original file line number Diff line number Diff line change
Expand Up @@ -2497,6 +2497,11 @@
"packageName": "@hcengineering/model-communication",
"projectFolder": "models/communication",
"shouldPublish": false
},
{
"packageName": "@hcengineering/storage-client",
"projectFolder": "packages/storage-client",
"shouldPublish": false
}
]
}
1 change: 1 addition & 0 deletions ws-tests/api-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"snappyjs": "^0.7.0",
"@hcengineering/api-client": "^0.6.0",
"@hcengineering/account-client": "^0.6.0",
"@hcengineering/storage-client": "^0.6.0",
"@hcengineering/tracker": "^0.6.24",
"@hcengineering/task": "^0.6.20",
"@hcengineering/contact": "^0.6.24",
Expand Down
10 changes: 5 additions & 5 deletions ws-tests/api-tests/src/__tests__/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

import {
connectStorage,
getWorkspaceToken,
loadServerConfig,
NotFoundError,
type ServerConfig,
type StorageClient,
type WorkspaceToken
} from '@hcengineering/api-client'
type ServerConfig,
type WorkspaceToken,
loadServerConfig,
getWorkspaceToken
} from '@hcengineering/storage-client'
import { systemAccountUuid, generateUuid, type Ref, type Blob } from '@hcengineering/core'
import { generateToken } from '@hcengineering/server-token'

Expand Down
Loading