feat: add api package
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,6 +22,7 @@ packages/files/dist
|
|||||||
packages/models/dist
|
packages/models/dist
|
||||||
packages/services/dist
|
packages/services/dist
|
||||||
packages/utils/dist
|
packages/utils/dist
|
||||||
|
packages/api/dist
|
||||||
|
|
||||||
**/.pnp.*
|
**/.pnp.*
|
||||||
**/.yarn/*
|
**/.yarn/*
|
||||||
|
|||||||
Binary file not shown.
BIN
.yarn/cache/@standardnotes-security-npm-1.1.0-9d90b8c189-2098584cd3.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-security-npm-1.1.0-9d90b8c189-2098584cd3.zip
vendored
Normal file
Binary file not shown.
2
packages/api/.eslintignore
Normal file
2
packages/api/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
6
packages/api/.eslintrc
Normal file
6
packages/api/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../.eslintrc",
|
||||||
|
"parserOptions": {
|
||||||
|
"project": "./linter.tsconfig.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
118
packages/api/CHANGELOG.md
Normal file
118
packages/api/CHANGELOG.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [1.3.0](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.2.1...@standardnotes/api@1.3.0) (2022-07-06)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* remove filepicker, features, services and models packages in favor of standardnotes/app repository ([27f474e](https://github.com/standardnotes/snjs/commit/27f474e859701c5713c8b6ed27cd1a4d5e4392bb))
|
||||||
|
|
||||||
|
## [1.2.1](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.2.0...@standardnotes/api@1.2.1) (2022-07-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
# [1.2.0](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.20...@standardnotes/api@1.2.0) (2022-07-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* remove encryption package in favor of standardnotes/app repository ([f6d1c9e](https://github.com/standardnotes/snjs/commit/f6d1c9ee538bb59ee7ac28c0d49ca682d4eb4d38))
|
||||||
|
|
||||||
|
## [1.1.20](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.19...@standardnotes/api@1.1.20) (2022-07-04)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add missing reflect-metadata package to all packages ([ce3a5bb](https://github.com/standardnotes/snjs/commit/ce3a5bbf3f1d2276ac4abc3eec3c6a44c8c3ba9b))
|
||||||
|
|
||||||
|
## [1.1.19](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.18...@standardnotes/api@1.1.19) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.18](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.17...@standardnotes/api@1.1.18) (2022-06-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* setting custom host ([#773](https://github.com/standardnotes/snjs/issues/773)) ([2fe27b0](https://github.com/standardnotes/snjs/commit/2fe27b0324486fad915a91096142579e649995b8))
|
||||||
|
|
||||||
|
## [1.1.17](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.16...@standardnotes/api@1.1.17) (2022-06-27)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.16](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.15...@standardnotes/api@1.1.16) (2022-06-27)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.15](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.14...@standardnotes/api@1.1.15) (2022-06-23)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* set host on user server ([#771](https://github.com/standardnotes/snjs/issues/771)) ([62d2c60](https://github.com/standardnotes/snjs/commit/62d2c60834b20b386b8c60f0ee172aec3e57ec05))
|
||||||
|
|
||||||
|
## [1.1.14](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.13...@standardnotes/api@1.1.14) (2022-06-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.13](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.12...@standardnotes/api@1.1.13) (2022-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* missing dependency ([b748571](https://github.com/standardnotes/snjs/commit/b748571c3288ecec3a2c0aed333ceaaf718832cd))
|
||||||
|
|
||||||
|
## [1.1.12](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.11...@standardnotes/api@1.1.12) (2022-06-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.11](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.10...@standardnotes/api@1.1.11) (2022-06-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.10](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.9...@standardnotes/api@1.1.10) (2022-06-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.9](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.8...@standardnotes/api@1.1.9) (2022-06-15)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.8](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.7...@standardnotes/api@1.1.8) (2022-06-10)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.7](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.6...@standardnotes/api@1.1.7) (2022-06-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.6](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.5...@standardnotes/api@1.1.6) (2022-06-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.5](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.4...@standardnotes/api@1.1.5) (2022-06-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.4](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.3...@standardnotes/api@1.1.4) (2022-06-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.3](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.2...@standardnotes/api@1.1.3) (2022-06-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api
|
||||||
|
|
||||||
|
## [1.1.2](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.1...@standardnotes/api@1.1.2) (2022-06-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add option to define additional params to the user registration request if needed ([78f169f](https://github.com/standardnotes/snjs/commit/78f169f993cb0d1950e553fe251f6bc903dd6da8))
|
||||||
|
|
||||||
|
## [1.1.1](https://github.com/standardnotes/snjs/compare/@standardnotes/api@1.1.0...@standardnotes/api@1.1.1) (2022-06-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make response headers optional for ease of defining on the server side ([#755](https://github.com/standardnotes/snjs/issues/755)) ([b5c2092](https://github.com/standardnotes/snjs/commit/b5c2092fc33dbd389fa67c122b3907956ca2eafa))
|
||||||
|
|
||||||
|
# 1.1.0 (2022-06-03)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* api service refactor -extract registration ([#733](https://github.com/standardnotes/snjs/issues/733)) ([1d7fac8](https://github.com/standardnotes/snjs/commit/1d7fac8c9dbb0fdb78a88743965a33c6d6a7d7d3))
|
||||||
19
packages/api/jest.config.js
Normal file
19
packages/api/jest.config.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const base = require('../../node_modules/@standardnotes/config/src/jest.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...base,
|
||||||
|
globals: {
|
||||||
|
'ts-jest': {
|
||||||
|
tsconfig: 'tsconfig.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
branches: 17,
|
||||||
|
functions: 43,
|
||||||
|
lines: 46,
|
||||||
|
statements: 46
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
4
packages/api/linter.tsconfig.json
Normal file
4
packages/api/linter.tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"exclude": ["dist"]
|
||||||
|
}
|
||||||
44
packages/api/package.json
Normal file
44
packages/api/package.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "@standardnotes/api",
|
||||||
|
"version": "1.3.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0 <17.0.0"
|
||||||
|
},
|
||||||
|
"description": "Interfaces for dealing with SN server-side API",
|
||||||
|
"main": "dist/src/index.js",
|
||||||
|
"author": "Standard Notes",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist/src"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"license": "AGPL-3.0-or-later",
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rm -fr dist",
|
||||||
|
"prestart": "yarn clean",
|
||||||
|
"start": "tsc -p tsconfig.json --watch",
|
||||||
|
"prebuild": "yarn clean",
|
||||||
|
"build": "tsc -p tsconfig.json",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"test:unit": "jest spec --coverage"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^27.4.1",
|
||||||
|
"@types/lodash": "^4.14.182",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||||
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"jest": "^27.5.1",
|
||||||
|
"ts-jest": "^27.1.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@standardnotes/common": "^1.23.1",
|
||||||
|
"@standardnotes/encryption": "workspace:*",
|
||||||
|
"@standardnotes/models": "workspace:*",
|
||||||
|
"@standardnotes/responses": "^1.6.39",
|
||||||
|
"@standardnotes/security": "^1.1.0",
|
||||||
|
"@standardnotes/services": "workspace:*",
|
||||||
|
"reflect-metadata": "^0.1.13"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
packages/api/src/Domain/Api/ApiVersion.ts
Normal file
3
packages/api/src/Domain/Api/ApiVersion.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export enum ApiVersion {
|
||||||
|
v0 = '20200115',
|
||||||
|
}
|
||||||
1
packages/api/src/Domain/Api/index.ts
Normal file
1
packages/api/src/Domain/Api/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ApiVersion'
|
||||||
77
packages/api/src/Domain/Client/User/UserApiService.spec.ts
Normal file
77
packages/api/src/Domain/Client/User/UserApiService.spec.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { ProtocolVersion } from '@standardnotes/common'
|
||||||
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
import { UserServerInterface } from '../../Server'
|
||||||
|
import { UserApiService } from './UserApiService'
|
||||||
|
|
||||||
|
describe('UserApiService', () => {
|
||||||
|
let userServer: UserServerInterface
|
||||||
|
let keyParams: RootKeyParamsInterface
|
||||||
|
|
||||||
|
const createService = () => new UserApiService(userServer)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
userServer = {} as jest.Mocked<UserServerInterface>
|
||||||
|
userServer.register = jest.fn().mockReturnValue({
|
||||||
|
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
||||||
|
} as jest.Mocked<UserRegistrationResponse>)
|
||||||
|
|
||||||
|
keyParams = {} as jest.Mocked<RootKeyParamsInterface>
|
||||||
|
keyParams.getPortableValue = jest.fn().mockReturnValue({
|
||||||
|
identifier: 'test@test.te',
|
||||||
|
version: ProtocolVersion.V004,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should register a user', async () => {
|
||||||
|
const response = await createService().register('test@test.te', 'testpasswd', keyParams, false)
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'test@test.te',
|
||||||
|
uuid: '1-2-3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(userServer.register).toHaveBeenCalledWith({
|
||||||
|
api: '20200115',
|
||||||
|
email: 'test@test.te',
|
||||||
|
ephemeral: false,
|
||||||
|
identifier: 'test@test.te',
|
||||||
|
password: 'testpasswd',
|
||||||
|
version: '004',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not register a user if it is already registering', async () => {
|
||||||
|
const service = createService()
|
||||||
|
Object.defineProperty(service, 'registering', {
|
||||||
|
get: () => true,
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await service.register('test@test.te', 'testpasswd', keyParams, false)
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not register a user if the server fails', async () => {
|
||||||
|
userServer.register = jest.fn().mockImplementation(() => {
|
||||||
|
throw new Error('Oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await createService().register('test@test.te', 'testpasswd', keyParams, false)
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
45
packages/api/src/Domain/Client/User/UserApiService.ts
Normal file
45
packages/api/src/Domain/Client/User/UserApiService.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
import { ErrorMessage } from '../../Error/ErrorMessage'
|
||||||
|
import { ApiCallError } from '../../Error/ApiCallError'
|
||||||
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
import { UserServerInterface } from '../../Server/User/UserServerInterface'
|
||||||
|
import { ApiVersion } from '../../Api/ApiVersion'
|
||||||
|
import { ApiEndpointParam } from '../../Request/ApiEndpointParam'
|
||||||
|
import { UserApiServiceInterface } from './UserApiServiceInterface'
|
||||||
|
|
||||||
|
export class UserApiService implements UserApiServiceInterface {
|
||||||
|
private registering: boolean
|
||||||
|
|
||||||
|
constructor(private userServer: UserServerInterface) {
|
||||||
|
this.registering = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(
|
||||||
|
email: string,
|
||||||
|
serverPassword: string,
|
||||||
|
keyParams: RootKeyParamsInterface,
|
||||||
|
ephemeral: boolean,
|
||||||
|
): Promise<UserRegistrationResponse> {
|
||||||
|
if (this.registering) {
|
||||||
|
throw new ApiCallError(ErrorMessage.RegistrationInProgress)
|
||||||
|
}
|
||||||
|
this.registering = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.userServer.register({
|
||||||
|
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||||
|
password: serverPassword,
|
||||||
|
email,
|
||||||
|
ephemeral,
|
||||||
|
...keyParams.getPortableValue(),
|
||||||
|
})
|
||||||
|
|
||||||
|
this.registering = false
|
||||||
|
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
|
||||||
|
export interface UserApiServiceInterface {
|
||||||
|
register(
|
||||||
|
email: string,
|
||||||
|
serverPassword: string,
|
||||||
|
keyParams: RootKeyParamsInterface,
|
||||||
|
ephemeral: boolean,
|
||||||
|
): Promise<UserRegistrationResponse>
|
||||||
|
}
|
||||||
2
packages/api/src/Domain/Client/index.ts
Normal file
2
packages/api/src/Domain/Client/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './User/UserApiService'
|
||||||
|
export * from './User/UserApiServiceInterface'
|
||||||
6
packages/api/src/Domain/Error/ApiCallError.ts
Normal file
6
packages/api/src/Domain/Error/ApiCallError.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export class ApiCallError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message)
|
||||||
|
Object.setPrototypeOf(this, ApiCallError.prototype)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
packages/api/src/Domain/Error/ErrorMessage.ts
Normal file
7
packages/api/src/Domain/Error/ErrorMessage.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export enum ErrorMessage {
|
||||||
|
RegistrationInProgress = 'An existing registration request is already in progress.',
|
||||||
|
GenericRegistrationFail = 'A server error occurred while trying to register. Please try again.',
|
||||||
|
RateLimited = 'Too many successive server requests. Please wait a few minutes and try again.',
|
||||||
|
InsufficientPasswordMessage = 'Your password must be at least %LENGTH% characters in length. For your security, please choose a longer password or, ideally, a passphrase, and try again.',
|
||||||
|
PasscodeRequired = 'Your passcode is required in order to register for an account.',
|
||||||
|
}
|
||||||
2
packages/api/src/Domain/Error/index.ts
Normal file
2
packages/api/src/Domain/Error/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './ApiCallError'
|
||||||
|
export * from './ErrorMessage'
|
||||||
11
packages/api/src/Domain/Http/ErrorTag.ts
Normal file
11
packages/api/src/Domain/Http/ErrorTag.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export enum ErrorTag {
|
||||||
|
MfaInvalid = 'mfa-invalid',
|
||||||
|
MfaRequired = 'mfa-required',
|
||||||
|
RefreshTokenInvalid = 'invalid-refresh-token',
|
||||||
|
RefreshTokenExpired = 'expired-refresh-token',
|
||||||
|
AccessTokenExpired = 'expired-access-token',
|
||||||
|
ParametersInvalid = 'invalid-parameters',
|
||||||
|
RevokedSession = 'revoked-session',
|
||||||
|
AuthInvalid = 'invalid-auth',
|
||||||
|
ReadOnlyAccess = 'read-only-access',
|
||||||
|
}
|
||||||
8
packages/api/src/Domain/Http/HttpErrorResponseBody.ts
Normal file
8
packages/api/src/Domain/Http/HttpErrorResponseBody.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { ErrorTag } from './ErrorTag'
|
||||||
|
|
||||||
|
export type HttpErrorResponseBody = {
|
||||||
|
error: {
|
||||||
|
message: string
|
||||||
|
tag?: ErrorTag
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/api/src/Domain/Http/HttpHeaders.ts
Normal file
1
packages/api/src/Domain/Http/HttpHeaders.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type HttpHeaders = Map<string, string | null>
|
||||||
13
packages/api/src/Domain/Http/HttpRequest.ts
Normal file
13
packages/api/src/Domain/Http/HttpRequest.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { HttpRequestParams } from './HttpRequestParams'
|
||||||
|
import { HttpVerb } from './HttpVerb'
|
||||||
|
|
||||||
|
export type HttpRequest = {
|
||||||
|
url: string
|
||||||
|
params?: HttpRequestParams
|
||||||
|
rawBytes?: Uint8Array
|
||||||
|
verb: HttpVerb
|
||||||
|
authentication?: string
|
||||||
|
customHeaders?: Record<string, string>[]
|
||||||
|
responseType?: XMLHttpRequestResponseType
|
||||||
|
external?: boolean
|
||||||
|
}
|
||||||
1
packages/api/src/Domain/Http/HttpRequestParams.ts
Normal file
1
packages/api/src/Domain/Http/HttpRequestParams.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type HttpRequestParams = Record<string, unknown>
|
||||||
12
packages/api/src/Domain/Http/HttpResponse.ts
Normal file
12
packages/api/src/Domain/Http/HttpResponse.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { HttpStatusCode } from './HttpStatusCode'
|
||||||
|
import { HttpResponseBody } from './HttpResponseBody'
|
||||||
|
import { HttpErrorResponseBody } from './HttpErrorResponseBody'
|
||||||
|
import { HttpResponseMeta } from './HttpResponseMeta'
|
||||||
|
import { HttpHeaders } from './HttpHeaders'
|
||||||
|
|
||||||
|
export interface HttpResponse {
|
||||||
|
status: HttpStatusCode
|
||||||
|
data?: HttpResponseBody | HttpErrorResponseBody
|
||||||
|
meta?: HttpResponseMeta
|
||||||
|
headers?: HttpHeaders
|
||||||
|
}
|
||||||
1
packages/api/src/Domain/Http/HttpResponseBody.ts
Normal file
1
packages/api/src/Domain/Http/HttpResponseBody.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type HttpResponseBody = Record<string, unknown>
|
||||||
12
packages/api/src/Domain/Http/HttpResponseMeta.ts
Normal file
12
packages/api/src/Domain/Http/HttpResponseMeta.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Role } from '@standardnotes/security'
|
||||||
|
import { Uuid } from '@standardnotes/common'
|
||||||
|
|
||||||
|
export type HttpResponseMeta = {
|
||||||
|
auth: {
|
||||||
|
userUuid?: Uuid
|
||||||
|
roles?: Role[]
|
||||||
|
}
|
||||||
|
server: {
|
||||||
|
filesServerUrl?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
27
packages/api/src/Domain/Http/HttpService.spec.ts
Normal file
27
packages/api/src/Domain/Http/HttpService.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Environment } from '@standardnotes/services'
|
||||||
|
import { HttpResponseMeta } from './HttpResponseMeta'
|
||||||
|
import { HttpService } from './HttpService'
|
||||||
|
|
||||||
|
describe('HttpService', () => {
|
||||||
|
const environment = Environment.Web
|
||||||
|
const appVersion = '1.2.3'
|
||||||
|
const snjsVersion = '2.3.4'
|
||||||
|
const host = 'http://bar'
|
||||||
|
let updateMetaCallback: (meta: HttpResponseMeta) => void
|
||||||
|
|
||||||
|
const createService = () => new HttpService(environment, appVersion, snjsVersion, host, updateMetaCallback)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
updateMetaCallback = jest.fn()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should set host', () => {
|
||||||
|
const service = createService()
|
||||||
|
|
||||||
|
expect(service['host']).toEqual('http://bar')
|
||||||
|
|
||||||
|
service.setHost('http://foo')
|
||||||
|
|
||||||
|
expect(service['host']).toEqual('http://foo')
|
||||||
|
})
|
||||||
|
})
|
||||||
190
packages/api/src/Domain/Http/HttpService.ts
Normal file
190
packages/api/src/Domain/Http/HttpService.ts
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
import { isString, joinPaths } from '@standardnotes/utils'
|
||||||
|
import { Environment } from '@standardnotes/services'
|
||||||
|
import { HttpRequestParams } from './HttpRequestParams'
|
||||||
|
import { HttpVerb } from './HttpVerb'
|
||||||
|
import { HttpRequest } from './HttpRequest'
|
||||||
|
import { HttpResponse } from './HttpResponse'
|
||||||
|
import { HttpServiceInterface } from './HttpServiceInterface'
|
||||||
|
import { HttpStatusCode } from './HttpStatusCode'
|
||||||
|
import { XMLHttpRequestState } from './XMLHttpRequestState'
|
||||||
|
import { ErrorMessage } from '../Error/ErrorMessage'
|
||||||
|
import { HttpResponseMeta } from './HttpResponseMeta'
|
||||||
|
import { HttpErrorResponseBody } from './HttpErrorResponseBody'
|
||||||
|
|
||||||
|
export class HttpService implements HttpServiceInterface {
|
||||||
|
constructor(
|
||||||
|
private environment: Environment,
|
||||||
|
private appVersion: string,
|
||||||
|
private snjsVersion: string,
|
||||||
|
private host: string,
|
||||||
|
private updateMetaCallback: (meta: HttpResponseMeta) => void,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
setHost(host: string): void {
|
||||||
|
this.host = host
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||||
|
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Get, authentication })
|
||||||
|
}
|
||||||
|
|
||||||
|
async post(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||||
|
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Post, authentication })
|
||||||
|
}
|
||||||
|
|
||||||
|
async put(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||||
|
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Put, authentication })
|
||||||
|
}
|
||||||
|
|
||||||
|
async patch(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||||
|
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Patch, authentication })
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||||
|
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Delete, authentication })
|
||||||
|
}
|
||||||
|
|
||||||
|
private async runHttp(httpRequest: HttpRequest): Promise<HttpResponse> {
|
||||||
|
const request = this.createXmlRequest(httpRequest)
|
||||||
|
|
||||||
|
const response = await this.runRequest(request, this.createRequestBody(httpRequest))
|
||||||
|
|
||||||
|
if (response.meta) {
|
||||||
|
this.updateMetaCallback(response.meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
private createRequestBody(httpRequest: HttpRequest): string | Uint8Array | undefined {
|
||||||
|
if (
|
||||||
|
httpRequest.params !== undefined &&
|
||||||
|
[HttpVerb.Post, HttpVerb.Put, HttpVerb.Patch, HttpVerb.Delete].includes(httpRequest.verb)
|
||||||
|
) {
|
||||||
|
return JSON.stringify(httpRequest.params)
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpRequest.rawBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
private createXmlRequest(httpRequest: HttpRequest) {
|
||||||
|
const request = new XMLHttpRequest()
|
||||||
|
if (httpRequest.params && httpRequest.verb === HttpVerb.Get && Object.keys(httpRequest.params).length > 0) {
|
||||||
|
httpRequest.url = this.urlForUrlAndParams(httpRequest.url, httpRequest.params)
|
||||||
|
}
|
||||||
|
request.open(httpRequest.verb, httpRequest.url, true)
|
||||||
|
request.responseType = httpRequest.responseType ?? ''
|
||||||
|
|
||||||
|
if (!httpRequest.external) {
|
||||||
|
request.setRequestHeader('X-SNJS-Version', this.snjsVersion)
|
||||||
|
|
||||||
|
const appVersionHeaderValue = `${Environment[this.environment]}-${this.appVersion}`
|
||||||
|
request.setRequestHeader('X-Application-Version', appVersionHeaderValue)
|
||||||
|
|
||||||
|
if (httpRequest.authentication) {
|
||||||
|
request.setRequestHeader('Authorization', 'Bearer ' + httpRequest.authentication)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let contenTypeIsSet = false
|
||||||
|
if (httpRequest.customHeaders && httpRequest.customHeaders.length > 0) {
|
||||||
|
httpRequest.customHeaders.forEach(({ key, value }) => {
|
||||||
|
request.setRequestHeader(key, value)
|
||||||
|
if (key === 'Content-Type') {
|
||||||
|
contenTypeIsSet = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!contenTypeIsSet && !httpRequest.external) {
|
||||||
|
request.setRequestHeader('Content-Type', 'application/json')
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
private async runRequest(request: XMLHttpRequest, body?: string | Uint8Array): Promise<HttpResponse> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request.onreadystatechange = () => {
|
||||||
|
this.stateChangeHandlerForRequest(request, resolve, reject)
|
||||||
|
}
|
||||||
|
request.send(body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private stateChangeHandlerForRequest(
|
||||||
|
request: XMLHttpRequest,
|
||||||
|
resolve: (response: HttpResponse) => void,
|
||||||
|
reject: (response: HttpResponse) => void,
|
||||||
|
) {
|
||||||
|
if (request.readyState !== XMLHttpRequestState.Completed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const httpStatus = request.status
|
||||||
|
const response: HttpResponse = {
|
||||||
|
status: httpStatus,
|
||||||
|
headers: new Map<string, string | null>(),
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseHeaderLines = request
|
||||||
|
.getAllResponseHeaders()
|
||||||
|
?.trim()
|
||||||
|
.split(/[\r\n]+/)
|
||||||
|
responseHeaderLines?.forEach((responseHeaderLine) => {
|
||||||
|
const parts = responseHeaderLine.split(': ')
|
||||||
|
const name = parts.shift() as string
|
||||||
|
const value = parts.join(': ')
|
||||||
|
|
||||||
|
;(<Map<string, string | null>>response.headers).set(name, value)
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (httpStatus !== HttpStatusCode.NoContent) {
|
||||||
|
let body
|
||||||
|
|
||||||
|
const contentTypeHeader = response.headers?.get('content-type') || response.headers?.get('Content-Type')
|
||||||
|
|
||||||
|
if (contentTypeHeader?.includes('application/json')) {
|
||||||
|
body = JSON.parse(request.responseText)
|
||||||
|
} else {
|
||||||
|
body = request.response
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* v0 APIs do not have a `data` top-level object. In such cases, mimic
|
||||||
|
* the newer response body style by putting all the top-level
|
||||||
|
* properties inside a `data` object.
|
||||||
|
*/
|
||||||
|
if (!body.data) {
|
||||||
|
response.data = body
|
||||||
|
}
|
||||||
|
if (!isString(body)) {
|
||||||
|
Object.assign(response, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
if (httpStatus >= HttpStatusCode.Success && httpStatus < HttpStatusCode.MultipleChoices) {
|
||||||
|
resolve(response)
|
||||||
|
} else {
|
||||||
|
if (httpStatus === HttpStatusCode.Forbidden && response.data && response.data.error !== undefined) {
|
||||||
|
;(response.data as HttpErrorResponseBody).error.message = ErrorMessage.RateLimited
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private urlForUrlAndParams(url: string, params: HttpRequestParams) {
|
||||||
|
const keyValueString = Object.keys(params)
|
||||||
|
.map((key) => {
|
||||||
|
return key + '=' + encodeURIComponent(params[key] as string)
|
||||||
|
})
|
||||||
|
.join('&')
|
||||||
|
|
||||||
|
if (url.includes('?')) {
|
||||||
|
return url + '&' + keyValueString
|
||||||
|
} else {
|
||||||
|
return url + '?' + keyValueString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
packages/api/src/Domain/Http/HttpServiceInterface.ts
Normal file
11
packages/api/src/Domain/Http/HttpServiceInterface.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { HttpRequestParams } from './HttpRequestParams'
|
||||||
|
import { HttpResponse } from './HttpResponse'
|
||||||
|
|
||||||
|
export interface HttpServiceInterface {
|
||||||
|
setHost(host: string): void
|
||||||
|
get(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||||
|
post(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||||
|
put(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||||
|
patch(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||||
|
delete(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||||
|
}
|
||||||
9
packages/api/src/Domain/Http/HttpStatusCode.ts
Normal file
9
packages/api/src/Domain/Http/HttpStatusCode.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export enum HttpStatusCode {
|
||||||
|
Success = 200,
|
||||||
|
NoContent = 204,
|
||||||
|
MultipleChoices = 300,
|
||||||
|
BadRequest = 400,
|
||||||
|
Unauthorized = 401,
|
||||||
|
Forbidden = 403,
|
||||||
|
ExpiredAccessToken = 498,
|
||||||
|
}
|
||||||
7
packages/api/src/Domain/Http/HttpVerb.ts
Normal file
7
packages/api/src/Domain/Http/HttpVerb.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export enum HttpVerb {
|
||||||
|
Get = 'GET',
|
||||||
|
Post = 'POST',
|
||||||
|
Put = 'PUT',
|
||||||
|
Patch = 'PATCH',
|
||||||
|
Delete = 'DELETE',
|
||||||
|
}
|
||||||
3
packages/api/src/Domain/Http/XMLHttpRequestState.ts
Normal file
3
packages/api/src/Domain/Http/XMLHttpRequestState.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export enum XMLHttpRequestState {
|
||||||
|
Completed = 4,
|
||||||
|
}
|
||||||
13
packages/api/src/Domain/Http/index.ts
Normal file
13
packages/api/src/Domain/Http/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export * from './ErrorTag'
|
||||||
|
export * from './HttpErrorResponseBody'
|
||||||
|
export * from './HttpHeaders'
|
||||||
|
export * from './HttpRequest'
|
||||||
|
export * from './HttpRequestParams'
|
||||||
|
export * from './HttpResponse'
|
||||||
|
export * from './HttpResponseBody'
|
||||||
|
export * from './HttpResponseMeta'
|
||||||
|
export * from './HttpService'
|
||||||
|
export * from './HttpServiceInterface'
|
||||||
|
export * from './HttpStatusCode'
|
||||||
|
export * from './HttpVerb'
|
||||||
|
export * from './XMLHttpRequestState'
|
||||||
7
packages/api/src/Domain/Request/ApiEndpointParam.ts
Normal file
7
packages/api/src/Domain/Request/ApiEndpointParam.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export enum ApiEndpointParam {
|
||||||
|
LastSyncToken = 'sync_token',
|
||||||
|
PaginationToken = 'cursor_token',
|
||||||
|
SyncDlLimit = 'limit',
|
||||||
|
SyncPayloads = 'items',
|
||||||
|
ApiVersion = 'api',
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||||
|
import { ApiEndpointParam } from '../ApiEndpointParam'
|
||||||
|
import { ApiVersion } from '../../Api/ApiVersion'
|
||||||
|
|
||||||
|
export type UserRegistrationRequestParams = AnyKeyParamsContent & {
|
||||||
|
[ApiEndpointParam.ApiVersion]: ApiVersion.v0
|
||||||
|
password: string
|
||||||
|
email: string
|
||||||
|
ephemeral: boolean
|
||||||
|
[additionalParam: string]: unknown
|
||||||
|
}
|
||||||
2
packages/api/src/Domain/Request/index.ts
Normal file
2
packages/api/src/Domain/Request/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './ApiEndpointParam'
|
||||||
|
export * from './User/UserRegistrationRequestParams'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||||
|
import { HttpResponse } from '../../Http/HttpResponse'
|
||||||
|
import { UserRegistrationResponseBody } from './UserRegistrationResponseBody'
|
||||||
|
|
||||||
|
export interface UserRegistrationResponse extends HttpResponse {
|
||||||
|
data: UserRegistrationResponseBody | HttpErrorResponseBody
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Uuid } from '@standardnotes/common'
|
||||||
|
import { KeyParamsData, SessionBody } from '@standardnotes/responses'
|
||||||
|
|
||||||
|
export type UserRegistrationResponseBody = {
|
||||||
|
session: SessionBody
|
||||||
|
key_params: KeyParamsData
|
||||||
|
user: {
|
||||||
|
uuid: Uuid
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/api/src/Domain/Response/index.ts
Normal file
2
packages/api/src/Domain/Response/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './User/UserRegistrationResponse'
|
||||||
|
export * from './User/UserRegistrationResponseBody'
|
||||||
9
packages/api/src/Domain/Server/User/Paths.ts
Normal file
9
packages/api/src/Domain/Server/User/Paths.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const UserPaths = {
|
||||||
|
register: '/v1/users',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Paths = {
|
||||||
|
v1: {
|
||||||
|
...UserPaths,
|
||||||
|
},
|
||||||
|
}
|
||||||
39
packages/api/src/Domain/Server/User/UserServer.spec.ts
Normal file
39
packages/api/src/Domain/Server/User/UserServer.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { ProtocolVersion } from '@standardnotes/common'
|
||||||
|
import { ApiVersion } from '../../Api'
|
||||||
|
import { HttpServiceInterface } from '../../Http'
|
||||||
|
import { UserRegistrationResponse } from '../../Response'
|
||||||
|
import { UserServer } from './UserServer'
|
||||||
|
|
||||||
|
describe('UserServer', () => {
|
||||||
|
let httpService: HttpServiceInterface
|
||||||
|
|
||||||
|
const createServer = () => new UserServer(httpService)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
httpService = {} as jest.Mocked<HttpServiceInterface>
|
||||||
|
httpService.post = jest.fn().mockReturnValue({
|
||||||
|
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
||||||
|
} as jest.Mocked<UserRegistrationResponse>)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should register a user', async () => {
|
||||||
|
const response = await createServer().register({
|
||||||
|
password: 'test',
|
||||||
|
api: ApiVersion.v0,
|
||||||
|
email: 'test@test.te',
|
||||||
|
ephemeral: false,
|
||||||
|
version: ProtocolVersion.V004,
|
||||||
|
pw_nonce: 'test',
|
||||||
|
identifier: 'test@test.te',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'test@test.te',
|
||||||
|
uuid: '1-2-3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
15
packages/api/src/Domain/Server/User/UserServer.ts
Normal file
15
packages/api/src/Domain/Server/User/UserServer.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||||
|
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
||||||
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
import { Paths } from './Paths'
|
||||||
|
import { UserServerInterface } from './UserServerInterface'
|
||||||
|
|
||||||
|
export class UserServer implements UserServerInterface {
|
||||||
|
constructor(private httpService: HttpServiceInterface) {}
|
||||||
|
|
||||||
|
async register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse> {
|
||||||
|
const response = await this.httpService.post(Paths.v1.register, params)
|
||||||
|
|
||||||
|
return response as UserRegistrationResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
||||||
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
|
||||||
|
export interface UserServerInterface {
|
||||||
|
register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse>
|
||||||
|
}
|
||||||
3
packages/api/src/Domain/Server/index.ts
Normal file
3
packages/api/src/Domain/Server/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './User/Paths'
|
||||||
|
export * from './User/UserServer'
|
||||||
|
export * from './User/UserServerInterface'
|
||||||
7
packages/api/src/Domain/index.ts
Normal file
7
packages/api/src/Domain/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export * from './Api'
|
||||||
|
export * from './Client'
|
||||||
|
export * from './Error'
|
||||||
|
export * from './Http'
|
||||||
|
export * from './Request'
|
||||||
|
export * from './Response'
|
||||||
|
export * from './Server'
|
||||||
1
packages/api/src/index.ts
Normal file
1
packages/api/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './Domain'
|
||||||
13
packages/api/tsconfig.json
Normal file
13
packages/api/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../node_modules/@standardnotes/config/src/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"references": [],
|
||||||
|
"exclude": ["**/*.spec.ts", "dist", "node_modules"]
|
||||||
|
}
|
||||||
37
yarn.lock
37
yarn.lock
@@ -6167,19 +6167,25 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@standardnotes/api@npm:^1.1.19":
|
"@standardnotes/api@^1.1.19, @standardnotes/api@workspace:packages/api":
|
||||||
version: 1.1.19
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/api@npm:1.1.19"
|
resolution: "@standardnotes/api@workspace:packages/api"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/auth": ^3.19.4
|
|
||||||
"@standardnotes/common": ^1.23.1
|
"@standardnotes/common": ^1.23.1
|
||||||
"@standardnotes/encryption": ^1.8.23
|
"@standardnotes/encryption": "workspace:*"
|
||||||
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": ^1.6.39
|
"@standardnotes/responses": ^1.6.39
|
||||||
"@standardnotes/services": ^1.13.23
|
"@standardnotes/security": ^1.1.0
|
||||||
"@standardnotes/utils": ^1.6.12
|
"@standardnotes/services": "workspace:*"
|
||||||
checksum: cca168245a80d333ca6433799a7cbe4a233956cace92b9e9ec45b3f67e4e907ef4f08a9573008bdf2b11a09100dc0381cff820ee5bea384407c2107c494913ba
|
"@types/jest": ^27.4.1
|
||||||
languageName: node
|
"@types/lodash": ^4.14.182
|
||||||
linkType: hard
|
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||||
|
eslint-plugin-prettier: ^4.2.1
|
||||||
|
jest: ^27.5.1
|
||||||
|
reflect-metadata: ^0.1.13
|
||||||
|
ts-jest: ^27.1.3
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@standardnotes/app-monorepo@workspace:.":
|
"@standardnotes/app-monorepo@workspace:.":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
@@ -7081,6 +7087,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@standardnotes/security@npm:^1.1.0":
|
||||||
|
version: 1.1.0
|
||||||
|
resolution: "@standardnotes/security@npm:1.1.0"
|
||||||
|
dependencies:
|
||||||
|
"@standardnotes/common": ^1.23.1
|
||||||
|
jsonwebtoken: ^8.5.1
|
||||||
|
reflect-metadata: ^0.1.13
|
||||||
|
checksum: 2098584cd3fae7b89c13aba6b110a7717dbcce7121162a29478b0c2e754e37d349d1e869f6d0040b709377ec83d0ab0eeef668e234dedba1652fb760ffdf57cc
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@standardnotes/services@^1.13.23, @standardnotes/services@workspace:*, @standardnotes/services@workspace:packages/services":
|
"@standardnotes/services@^1.13.23, @standardnotes/services@workspace:*, @standardnotes/services@workspace:packages/services":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/services@workspace:packages/services"
|
resolution: "@standardnotes/services@workspace:packages/services"
|
||||||
|
|||||||
Reference in New Issue
Block a user