This commit is contained in:
Kristina 2025-05-06 18:38:55 +04:00 committed by GitHub
commit 3c236fc198
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 700 additions and 503 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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": {
@ -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",

View File

@ -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> {

View File

@ -20,4 +20,3 @@ export * from './types'
export * from './rest'
export * from './config'
export * from './utils'
export * from './storage'

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'
}
}

View File

@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/

View File

@ -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
```

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}

View File

@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: ["./src"],
coverageReporters: ["text-summary", "html"]
}

View File

@ -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"
}
}

View File

@ -1,4 +1,3 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
@ -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

View File

@ -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')
}

View File

@ -16,3 +16,5 @@
export { createStorageClient, connectStorage } from './client'
export * from './error'
export * from './types'
export * from './config'
export * from './utils'

View File

@ -1,4 +1,3 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
@ -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'
@ -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

View File

@ -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 }
}

View File

@ -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"]
}
}

View File

@ -2497,6 +2497,11 @@
"packageName": "@hcengineering/model-communication",
"projectFolder": "models/communication",
"shouldPublish": false
},
{
"packageName": "@hcengineering/storage-client",
"projectFolder": "packages/storage-client",
"shouldPublish": false
}
]
}

View File

@ -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",

View File

@ -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'