Compare commits

...
Author SHA1 Message Date
StandardNotes CI a9378ab5d7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].3
2023-07-12 14:57:07 +00:00
Aman Harwara 69ba1a0809 chore: fix error 2023-07-12 19:52:03 +05:30
Aman Harwara af3eafb009 chore: fix clipper CI failing 2023-07-12 19:42:57 +05:30
StandardNotes CI e4b858f2e8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].2
2023-07-12 12:22:07 +00:00
Karol Sójko 325737bfbd chore: fix ContentType usage (#2353)
* chore: fix ContentType usage

* chore: fix specs
2023-07-12 13:53:29 +02:00
StandardNotes CI d057cdff84 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2023-07-12 10:06:57 +00:00
Aman Harwara 0528c06ce8 chore: release 2023-07-12 15:05:45 +05:30
StandardNotes CI bd906f2a12 chore(release): publish
- @standardnotes/[email protected].1
 - @standardnotes/[email protected]
2023-07-12 09:06:16 +00:00
Aman Harwara 669b395709 chore: fix crash on ios 2023-07-12 13:08:08 +05:30
StandardNotes CI da4967434a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2023-07-11 19:40:10 +00:00
Aman Harwara 96897163fb chore: update lexical 2023-07-12 00:42:26 +05:30
Aman Harwara 3dc179c7b0 feat: On Android, you can now share text & files from other apps directly into Standard Notes (#2352) 2023-07-12 00:16:32 +05:30
StandardNotes CI 1f5354c816 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
2023-07-11 15:46:44 +00:00
Karol Sójko f097f6e354 chore(api): fix request params and make api package publishable (#2351)
* chore(api): fix request params and make api package publishable

* chore(api): fix deps

* chore(encryption): fix privacy
2023-07-11 17:19:37 +02:00
StandardNotes CI 97456f7c0b chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
2023-07-11 09:02:46 +00:00
Karol Sójko 937f9d98d7 chore(api): fix missing exports 2023-07-11 10:34:35 +02:00
StandardNotes CI 07410cefb7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-10 15:32:29 +00:00
Aman Harwara de6994f743 fix: Fixed issue where files would not download correctly on mobile if they had special characters in the name 2023-07-10 20:27:52 +05:30
StandardNotes CI 5c87f3a3b4 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
2023-07-10 13:32:35 +00:00
Mo b257af17aa internal: temporarily disable home server imports 2023-07-10 08:00:04 -05:00
StandardNotes CI 3a75afc817 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
2023-07-10 09:29:39 +00:00
Aman Harwara e4488dcb8c chore: take popover offset into account when fitting inside rect 2023-07-10 14:29:49 +05:30
StandardNotes CI bb997312e8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].7
2023-07-07 15:19:11 +00:00
Aman Harwara b229a96e58 chore: bump node version 2023-07-07 20:16:21 +05:30
Aman Harwara 7f0bb4e127 refactor: use Fetch API for HttpService (#2349) 2023-07-07 19:26:31 +05:30
StandardNotes CI bf9449b67d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2023-07-07 06:37:18 +00:00
Aman Harwara 67359801bb chore: fix PageUp and PageDown not scrolling in preferences view 2023-07-06 22:13:34 +05:30
StandardNotes CI 53e978c30e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2023-07-06 15:33:57 +00:00
Aman Harwara ebc9fcb995 chore: fix blank screen issue when moving iOS floating keyboard 2023-07-06 20:30:49 +05:30
StandardNotes CI 7923e9f198 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].4
2023-07-06 14:32:38 +00:00
Aman Harwara 9081607dc7 chore: fix challenge modal automatically closing 2023-07-06 19:27:14 +05:30
Mo c8e52b667c internal: change password preprocessing step (#2347) 2023-07-06 08:51:06 -05:00
StandardNotes CI 5c6ccaf4e1 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].3
2023-07-05 16:57:29 +00:00
Mo 0ab6b5c6fe chore(fix): fixes sync response not correctly identifying all errors (#2346) 2023-07-05 11:28:45 -05:00
StandardNotes CI 2a050fd966 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].2
2023-07-05 16:26:01 +00:00
Mo 40f0d3d5bf chore: merge 2023-07-05 10:54:16 -05:00
Mo c9c93d143a internal: move home server into internal flag 2023-07-05 10:53:10 -05:00
StandardNotes CI a52828cd45 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2023-07-05 15:50:04 +00:00
Aman Harwara 2611c88cee chore: fix modal positioning when using themed desktop titlebar 2023-07-05 20:43:55 +05:30
StandardNotes CI d4db3e055c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].0
2023-07-04 15:29:47 +00:00
Karol Sójko 05528782a4 feat: New one-click Home Server, now in Labs. Launch your own self-hosted server instance with just 1 click from the Preferences window. (#2345)
* fix(desktop): add home server coming-soon message on windows platform

* fix(desktop): typos and remove feature block

* fix(desktop): instantiate home server only upon starting
2023-07-04 16:55:37 +02:00
StandardNotes CI 9664d31c4e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].3
2023-07-04 13:02:42 +00:00
Mo b06999d25b refactor: root key manager (#2344) 2023-07-04 07:31:50 -05:00
StandardNotes CI b4a90025c4 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2023-07-04 09:33:32 +00:00
Aman Harwara 31b42553be chore: improve super formatting toolbar positioning 2023-07-04 14:33:24 +05:30
StandardNotes CI 41311801c0 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
2023-07-03 19:20:31 +00:00
Mo ccc9d73b3b chore: make home server internal feature 2023-07-03 13:53:03 -05:00
StandardNotes CI 1f144e062e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2023-07-03 14:58:46 +00:00
Mo 40f8985ede chore: implement removeApplication 2023-07-03 09:21:09 -05:00
Mo 27fc4be886 chore: fix mobile device interface 2023-07-03 09:08:27 -05:00
Mo 96f42643a9 feat: New one-click Home Server, now in Labs. Launch your own self-hosted server instance with just 1 click from the Preferences window. (#2341) 2023-07-03 08:30:48 -05:00
Mo d79e7b14b1 chore: legacy fixes (#2343) 2023-07-03 08:03:25 -05:00
Mo 6d5cbcb396 chore: ci 2023-07-03 07:03:06 -05:00
StandardNotes CI 20bbd70595 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2023-07-02 16:14:29 +00:00
Aman Harwara 5839f7d075 chore: fix empty super note error on exporting to markdown 2023-07-02 21:17:13 +05:30
StandardNotes CI 6a6cbe57a1 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
2023-07-02 15:46:14 +00:00
Aman Harwara a8bc20e99e fix: Fixed issue where subfolders would show one extra item count 2023-07-02 20:46:33 +05:30
StandardNotes CI d42acab032 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2023-07-02 10:59:59 +00:00
Aman Harwara efa0669dbc chore: show non-editable link bar to allow opening auto-links 2023-07-02 15:29:02 +05:30
StandardNotes CI a6d7844ad4 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2023-07-02 09:43:13 +00:00
Aman Harwara 929642195d feat: Link and formatting toolbars for super are now unified on web/desktop to allow formatting existing links and updated link editor on mobile (#2342) 2023-07-02 14:45:49 +05:30
StandardNotes CI f354a50c26 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-06-30 18:25:33 +00:00
Aman Harwara ab1937226f chore: make "potentially out of sync" warning more visible on mobile 2023-06-30 23:22:15 +05:30
StandardNotes CI 64729a816c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-06-30 16:30:45 +00:00
Aman Harwara c9a95c818b chore: fix session modal error after revoking session 2023-06-30 20:57:57 +05:30
StandardNotes CI a0bc6153d6 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
2023-06-30 14:51:02 +00:00
Aman Harwara 89849c9f90 fix: Fixed issue where clicking in file dialog context menu closed the dialog 2023-06-30 19:51:08 +05:30
Mo b032eb9c9b internal: incomplete vault systems behind feature flag (#2340) 2023-06-30 09:01:56 -05:00
952 changed files with 28490 additions and 8239 deletions
+1
View File
@@ -17,6 +17,7 @@ on:
- 'packages/sncrypto-web/**'
- 'packages/snjs/**'
- 'packages/utils/**'
workflow_dispatch:
jobs:
test:
+1 -1
View File
@@ -1 +1 @@
16.15.1
18.6.0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -26,7 +26,6 @@
"build:snjs": "yarn workspaces foreach -p --topological-dev --verbose -R --from @standardnotes/snjs run build",
"build:services": "yarn workspaces foreach -pt --topological-dev --verbose -R --from @standardnotes/services run build",
"build:api": "yarn workspaces foreach -pt --topological-dev --verbose -R --from @standardnotes/api run build",
"start:server:web": "lerna run start --scope=@standardnotes/web",
"e2e": "lerna run start:test-server --scope=@standardnotes/snjs",
"reset": "find . -type dir -name node_modules | xargs rm -rf && rm -rf yarn.lock && yarn install",
"release:prod": "lerna version --conventional-commits --yes -m \"chore(release): publish\"",
+36
View File
@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.26.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-12)
**Note:** Version bump only for package @standardnotes/api
## [1.26.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-11)
**Note:** Version bump only for package @standardnotes/api
## [1.26.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-11)
**Note:** Version bump only for package @standardnotes/api
## [1.26.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-07)
**Note:** Version bump only for package @standardnotes/api
## [1.26.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-06)
**Note:** Version bump only for package @standardnotes/api
## [1.26.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-05)
**Note:** Version bump only for package @standardnotes/api
## [1.26.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-04)
**Note:** Version bump only for package @standardnotes/api
## [1.26.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-03)
**Note:** Version bump only for package @standardnotes/api
## [1.26.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-06-30)
**Note:** Version bump only for package @standardnotes/api
## [1.26.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-06-29)
**Note:** Version bump only for package @standardnotes/api
+2 -1
View File
@@ -6,4 +6,5 @@ module.exports = {
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.json' }],
},
};
coverageThreshold: {},
}
+3 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.17",
"version": "1.26.26",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -36,9 +36,8 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.46.6",
"@standardnotes/domain-core": "^1.12.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.7.6",
@@ -1,14 +1,14 @@
import { ErrorMessage } from '../../Error/ErrorMessage'
import { ApiCallError } from '../../Error/ApiCallError'
import { ApiVersion } from '../../Api/ApiVersion'
import { ApiEndpointParam } from '../../Request/ApiEndpointParam'
import { SubscriptionServerInterface } from '../../Server/Subscription/SubscriptionServerInterface'
import { AppleIAPConfirmResponseBody } from './../../Response/Subscription/AppleIAPConfirmResponseBody'
import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscription/SubscriptionInviteAcceptResponseBody'
import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody'
import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody'
import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody'
import { HttpResponse } from '@standardnotes/responses'
import { HttpResponse, ApiEndpointParam } from '@standardnotes/responses'
import { SubscriptionApiServiceInterface } from './SubscriptionApiServiceInterface'
import { SubscriptionApiOperations } from './SubscriptionApiOperations'
@@ -2,4 +2,5 @@ export enum UserApiOperations {
Registering,
SubmittingRequest,
DeletingAccount,
UpdatingUser,
}
@@ -5,8 +5,7 @@ import { ErrorMessage } from '../../Error/ErrorMessage'
import { ApiCallError } from '../../Error/ApiCallError'
import { UserServerInterface } from '../../Server/User/UserServerInterface'
import { ApiVersion } from '../../Api/ApiVersion'
import { ApiEndpointParam } from '../../Request/ApiEndpointParam'
import { HttpResponse } from '@standardnotes/responses'
import { HttpResponse, ApiEndpointParam } from '@standardnotes/responses'
import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody'
import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody'
@@ -15,6 +14,7 @@ import { UserRequestServerInterface } from '../../Server/UserRequest/UserRequest
import { UserApiOperations } from './UserApiOperations'
import { UserApiServiceInterface } from './UserApiServiceInterface'
import { UserUpdateResponse } from '../../Response/User/UserUpdateResponse'
export class UserApiService implements UserApiServiceInterface {
private operationsInProgress: Map<UserApiOperations, boolean>
@@ -35,7 +35,7 @@ export class UserApiService implements UserApiServiceInterface {
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
@@ -84,6 +84,23 @@ export class UserApiService implements UserApiServiceInterface {
}
}
async updateUser(updateDTO: { userUuid: string }): Promise<HttpResponse<UserUpdateResponse>> {
this.lockOperation(UserApiOperations.UpdatingUser)
try {
const response = await this.userServer.update({
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
user_uuid: updateDTO.userUuid,
})
this.unlockOperation(UserApiOperations.UpdatingUser)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
private lockOperation(operation: UserApiOperations): void {
if (this.operationsInProgress.get(operation)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
@@ -5,6 +5,7 @@ import { HttpResponse } from '@standardnotes/responses'
import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody'
import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody'
import { UserRequestResponseBody } from '../../Response/UserRequest/UserRequestResponseBody'
import { UserUpdateResponse } from '../../Response/User/UserUpdateResponse'
export interface UserApiServiceInterface {
register(registerDTO: {
@@ -13,9 +14,12 @@ export interface UserApiServiceInterface {
keyParams: RootKeyParamsInterface
ephemeral: boolean
}): Promise<HttpResponse<UserRegistrationResponseBody>>
updateUser(updateDTO: { userUuid: string }): Promise<HttpResponse<UserUpdateResponse>>
submitUserRequest(dto: {
userUuid: string
requestType: UserRequestType
}): Promise<HttpResponse<UserRequestResponseBody>>
deleteAccount(userUuid: string): Promise<HttpResponse<UserDeletionResponseBody>>
}
@@ -0,0 +1,144 @@
import { Environment } from '@standardnotes/models'
import { HttpVerb } from '@standardnotes/responses'
import { FetchRequestHandler } from './FetchRequestHandler'
import { HttpErrorResponseBody, HttpRequest } from '@standardnotes/responses'
import { ErrorMessage } from '../Error'
describe('FetchRequestHandler', () => {
const snjsVersion = 'snjsVersion'
const appVersion = 'appVersion'
const environment = Environment.Web
const requestHandler = new FetchRequestHandler(snjsVersion, appVersion, environment)
it('should create a request', () => {
const httpRequest: HttpRequest = {
url: 'http://localhost:3000/test',
verb: HttpVerb.Get,
external: false,
authentication: 'authentication',
customHeaders: [],
params: {
key: 'value',
},
}
const request = requestHandler['createRequest'](httpRequest)
expect(request).toBeInstanceOf(Request)
expect(request.url).toBe(httpRequest.url)
expect(request.method).toBe(httpRequest.verb)
expect(request.headers.get('X-SNJS-Version')).toBe(snjsVersion)
expect(request.headers.get('X-Application-Version')).toBe(`${Environment[environment]}-${appVersion}`)
expect(request.headers.get('Content-Type')).toBe('application/json')
})
it('should get url for url and params', () => {
const urlWithoutExistingParams = requestHandler['urlForUrlAndParams']('url', { key: 'value' })
expect(urlWithoutExistingParams).toBe('url?key=value')
const urlWithExistingParams = requestHandler['urlForUrlAndParams']('url?key=value', { key2: 'value2' })
expect(urlWithExistingParams).toBe('url?key=value&key2=value2')
})
it('should create request body if not GET', () => {
const body = requestHandler['createRequestBody']({
url: 'url',
verb: HttpVerb.Post,
external: false,
authentication: 'authentication',
customHeaders: [],
params: {
key: 'value',
},
})
expect(body).toBe('{"key":"value"}')
})
it('should not create request body if GET', () => {
const body = requestHandler['createRequestBody']({
url: 'url',
verb: HttpVerb.Get,
external: false,
authentication: 'authentication',
customHeaders: [],
params: {
key: 'value',
},
})
expect(body).toBeUndefined()
})
it('should handle json response', async () => {
const fetchResponse = new Response('{"key":"value"}', {
status: 200,
headers: {
'Content-Type': 'application/json',
},
})
const response = await requestHandler['handleFetchResponse'](fetchResponse)
expect(response).toEqual({
status: 200,
headers: new Map<string, string | null>([['content-type', 'application/json']]),
data: {
key: 'value',
},
key: 'value',
})
})
it('should handle non-json response', async () => {
const fetchResponse = new Response('body', {
status: 200,
headers: {
'Content-Type': 'text/plain',
},
})
const response = await requestHandler['handleFetchResponse'](fetchResponse)
expect(response.status).toBe(200)
expect(response.headers).toEqual(new Map<string, string | null>([['content-type', 'text/plain']]))
expect(response.data).toBeInstanceOf(ArrayBuffer)
})
it('should have ratelimit error when forbidden', async () => {
const fetchResponse = new Response('body', {
status: 403,
headers: {
'Content-Type': 'text/plain',
},
})
const response = await requestHandler['handleFetchResponse'](fetchResponse)
expect(response.status).toBe(403)
expect(response.headers).toEqual(new Map<string, string | null>([['content-type', 'text/plain']]))
expect((response.data as HttpErrorResponseBody).error).toEqual({
message: ErrorMessage.RateLimited,
})
})
describe('should return ErrorResponse when status is not >=200 and <500', () => {
it('should add unknown error message when response has no data', async () => {
const fetchResponse = new Response('', {
status: 599,
headers: {
'Content-Type': 'text/plain',
},
})
const response = await requestHandler['handleFetchResponse'](fetchResponse)
expect(response.status).toBe(599)
expect(response.headers).toEqual(new Map<string, string | null>([['content-type', 'text/plain']]))
expect((response.data as HttpErrorResponseBody).error).toEqual({
message: 'Unknown error',
})
})
})
})
@@ -0,0 +1,178 @@
import {
HttpErrorResponse,
HttpRequest,
HttpRequestParams,
HttpResponse,
HttpStatusCode,
HttpVerb,
isErrorResponse,
} from '@standardnotes/responses'
import { RequestHandlerInterface } from './RequestHandlerInterface'
import { Environment } from '@standardnotes/models'
import { isString } from 'lodash'
import { ErrorMessage } from '../Error'
export class FetchRequestHandler implements RequestHandlerInterface {
constructor(
protected readonly snjsVersion: string,
protected readonly appVersion: string,
protected readonly environment: Environment,
) {}
async handleRequest<T>(httpRequest: HttpRequest): Promise<HttpResponse<T>> {
const request = this.createRequest(httpRequest)
const response = await this.runRequest<T>(request, this.createRequestBody(httpRequest))
return response
}
private createRequest(httpRequest: HttpRequest): Request {
if (httpRequest.params && httpRequest.verb === HttpVerb.Get && Object.keys(httpRequest.params).length > 0) {
httpRequest.url = this.urlForUrlAndParams(httpRequest.url, httpRequest.params)
}
const headers: Record<string, string> = {}
if (!httpRequest.external) {
headers['X-SNJS-Version'] = this.snjsVersion
const appVersionHeaderValue = `${Environment[this.environment]}-${this.appVersion}`
headers['X-Application-Version'] = appVersionHeaderValue
if (httpRequest.authentication) {
headers['Authorization'] = 'Bearer ' + httpRequest.authentication
}
}
let contentTypeIsSet = false
if (httpRequest.customHeaders && httpRequest.customHeaders.length > 0) {
httpRequest.customHeaders.forEach(({ key, value }) => {
headers[key] = value
if (key === 'Content-Type') {
contentTypeIsSet = true
}
})
}
if (!contentTypeIsSet && !httpRequest.external) {
headers['Content-Type'] = 'application/json'
}
return new Request(httpRequest.url, {
method: httpRequest.verb,
headers,
})
}
private async runRequest<T>(request: Request, body?: string | Uint8Array | undefined): Promise<HttpResponse<T>> {
const fetchResponse = await fetch(request, {
body,
})
const response = await this.handleFetchResponse<T>(fetchResponse)
return response
}
private async handleFetchResponse<T>(fetchResponse: Response): Promise<HttpResponse<T>> {
const httpStatus = fetchResponse.status
const response: HttpResponse<T> = {
status: httpStatus,
headers: new Map<string, string | null>(),
data: {} as T,
}
fetchResponse.headers.forEach((value, key) => {
;(<Map<string, string | null>>response.headers).set(key, 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(await fetchResponse.text())
} else {
body = await fetchResponse.arrayBuffer()
}
/**
* 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.InternalServerError) {
if (httpStatus === HttpStatusCode.Forbidden && isErrorResponse(response)) {
if (!response.data.error) {
response.data.error = {
message: ErrorMessage.RateLimited,
}
} else {
response.data.error.message = ErrorMessage.RateLimited
}
}
return response
} else {
const errorResponse = response as HttpErrorResponse
if (!errorResponse.data) {
errorResponse.data = {
error: {
message: 'Unknown error',
},
}
}
if (isString(errorResponse.data)) {
errorResponse.data = {
error: {
message: errorResponse.data,
},
}
}
if (!errorResponse.data.error) {
errorResponse.data.error = {
message: 'Unknown error',
}
}
return errorResponse
}
}
private urlForUrlAndParams(url: string, params: HttpRequestParams) {
const keyValueString = Object.keys(params as Record<string, unknown>)
.map((key) => {
return key + '=' + encodeURIComponent((params as Record<string, unknown>)[key] as string)
})
.join('&')
if (url.includes('?')) {
return url + '&' + keyValueString
} else {
return url + '?' + keyValueString
}
}
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
}
}
+28 -162
View File
@@ -1,4 +1,4 @@
import { isString, joinPaths, sleep } from '@standardnotes/utils'
import { joinPaths, sleep } from '@standardnotes/utils'
import { Environment } from '@standardnotes/models'
import { Session, SessionToken } from '@standardnotes/domain-core'
import {
@@ -8,15 +8,14 @@ import {
HttpRequest,
HttpResponse,
HttpResponseMeta,
HttpErrorResponse,
isErrorResponse,
} from '@standardnotes/responses'
import { HttpServiceInterface } from './HttpServiceInterface'
import { XMLHttpRequestState } from './XMLHttpRequestState'
import { ErrorMessage } from '../Error/ErrorMessage'
import { Paths } from '../Server/Auth/Paths'
import { SessionRefreshResponseBody } from '../Response/Auth/SessionRefreshResponseBody'
import { FetchRequestHandler } from './FetchRequestHandler'
import { RequestHandlerInterface } from './RequestHandlerInterface'
export class HttpService implements HttpServiceInterface {
private session: Session | null
@@ -27,8 +26,11 @@ export class HttpService implements HttpServiceInterface {
private updateMetaCallback!: (meta: HttpResponseMeta) => void
private refreshSessionCallback!: (session: Session) => void
private requestHandler: RequestHandlerInterface
constructor(private environment: Environment, private appVersion: string, private snjsVersion: string) {
this.session = null
this.requestHandler = new FetchRequestHandler(this.snjsVersion, this.appVersion, this.environment)
}
setCallbacks(
@@ -53,7 +55,15 @@ export class HttpService implements HttpServiceInterface {
this.host = host
}
getHost(): string {
return this.host
}
async get<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
if (!this.host) {
throw new Error('Attempting to make network request before host is set')
}
return this.runHttp({
url: joinPaths(this.host, path),
params,
@@ -62,7 +72,20 @@ export class HttpService implements HttpServiceInterface {
})
}
async getExternal<T>(url: string, params?: HttpRequestParams): Promise<HttpResponse<T>> {
return this.runHttp({
url,
params,
verb: HttpVerb.Get,
external: true,
})
}
async post<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
if (!this.host) {
throw new Error('Attempting to make network request before host is set')
}
return this.runHttp({
url: joinPaths(this.host, path),
params,
@@ -110,9 +133,7 @@ export class HttpService implements HttpServiceInterface {
httpRequest.authentication = this.session?.accessToken.value
}
const request = this.createXmlRequest(httpRequest)
const response = await this.runRequest<T>(request, this.createRequestBody(httpRequest))
const response = await this.requestHandler.handleRequest<T>(httpRequest)
if (response.meta && !httpRequest.external) {
this.updateMetaCallback?.(response.meta)
@@ -188,159 +209,4 @@ export class HttpService implements HttpServiceInterface {
return true
}
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<T>(request: XMLHttpRequest, body?: string | Uint8Array): Promise<HttpResponse<T>> {
return new Promise((resolve) => {
request.onreadystatechange = () => {
this.stateChangeHandlerForRequest(request, resolve)
}
request.send(body)
})
}
private stateChangeHandlerForRequest<T>(request: XMLHttpRequest, resolve: (response: HttpResponse<T>) => void) {
if (request.readyState !== XMLHttpRequestState.Completed) {
return
}
const httpStatus = request.status
const response: HttpResponse<T> = {
status: httpStatus,
headers: new Map<string, string | null>(),
data: {} as T,
}
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.InternalServerError) {
if (
httpStatus === HttpStatusCode.Forbidden &&
response.data &&
(response as HttpErrorResponse).data.error !== undefined
) {
;(response as HttpErrorResponse).data.error.message = ErrorMessage.RateLimited
}
resolve(response)
} else {
const errorResponse = response as HttpErrorResponse
if (!errorResponse.data) {
errorResponse.data = {
error: {
message: 'Unknown error',
},
}
}
if (isString(errorResponse.data)) {
errorResponse.data = {
error: {
message: errorResponse.data,
},
}
}
if (!errorResponse.data.error) {
errorResponse.data.error = {
message: 'Unknown error',
}
}
resolve(errorResponse)
}
}
private urlForUrlAndParams(url: string, params: HttpRequestParams) {
const keyValueString = Object.keys(params as Record<string, unknown>)
.map((key) => {
return key + '=' + encodeURIComponent((params as Record<string, unknown>)[key] as string)
})
.join('&')
if (url.includes('?')) {
return url + '&' + keyValueString
} else {
return url + '?' + keyValueString
}
}
}
@@ -3,8 +3,10 @@ import { HttpRequest, HttpRequestParams, HttpResponse, HttpResponseMeta } from '
export interface HttpServiceInterface {
setHost(host: string): void
getHost(): string
setSession(session: Session): void
get<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
getExternal<T>(url: string, params?: HttpRequestParams): Promise<HttpResponse<T>>
post<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
put<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
patch<T>(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
@@ -0,0 +1,5 @@
import { HttpRequest, HttpResponse } from '@standardnotes/responses'
export interface RequestHandlerInterface {
handleRequest<T>(httpRequest: HttpRequest): Promise<HttpResponse<T>>
}
@@ -1,7 +0,0 @@
export enum ApiEndpointParam {
LastSyncToken = 'sync_token',
PaginationToken = 'cursor_token',
SyncDlLimit = 'limit',
SyncPayloads = 'items',
ApiVersion = 'api',
}
@@ -0,0 +1,5 @@
export type CreateAsymmetricMessageParams = {
recipientUuid: string
encryptedMessage: string
replaceabilityIdentifier?: string
}
@@ -0,0 +1,3 @@
export type DeleteAsymmetricMessageRequestParams = {
messageUuid: string
}
@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type GetOutboundAsymmetricMessagesRequestParams = {}
@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type GetUserAsymmetricMessagesRequestParams = {}
@@ -0,0 +1,4 @@
export type UpdateAsymmetricMessageParams = {
messageUuid: string
encryptedMessage: string
}
@@ -0,0 +1,12 @@
import { ValetTokenOperation } from '@standardnotes/responses'
import { SharedVaultMoveType } from './SharedVaultMoveType'
export type CreateSharedVaultValetTokenParams = {
sharedVaultUuid: string
fileUuid?: string
remoteIdentifier: string
operation: ValetTokenOperation
unencryptedFileSize?: number
moveOperationType?: SharedVaultMoveType
sharedVaultToSharedVaultMoveTargetUuid?: string
}
@@ -0,0 +1 @@
export type SharedVaultMoveType = 'shared-vault-to-user' | 'user-to-shared-vault' | 'shared-vault-to-shared-vault'
@@ -0,0 +1,4 @@
export type AcceptInviteRequestParams = {
sharedVaultUuid: string
inviteUuid: string
}
@@ -0,0 +1,8 @@
import { SharedVaultPermission } from '@standardnotes/responses'
export type CreateSharedVaultInviteParams = {
sharedVaultUuid: string
recipientUuid: string
encryptedMessage: string
permissions: SharedVaultPermission
}
@@ -0,0 +1,4 @@
export type DeclineInviteRequestParams = {
sharedVaultUuid: string
inviteUuid: string
}
@@ -0,0 +1,3 @@
export type DeleteAllSharedVaultInvitesRequestParams = {
sharedVaultUuid: string
}
@@ -0,0 +1,4 @@
export type DeleteInviteRequestParams = {
sharedVaultUuid: string
inviteUuid: string
}
@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type GetOutboundUserInvitesRequestParams = {}
@@ -0,0 +1,3 @@
export type GetSharedVaultInvitesRequestParams = {
sharedVaultUuid: string
}
@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type GetUserInvitesRequestParams = {}

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