Compare commits

..
Author SHA1 Message Date
StandardNotes CI 4641f3235d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].7
2023-07-13 11:34:30 +00:00
Aman Harwara 95a9aafc91 chore: fix icon color 2023-07-13 16:35:54 +05:30
Mo 2c68ea1d76 refactor: component manager usecases (#2354) 2023-07-13 05:46:52 -05:00
Aman Harwara ecc5b5e503 chore: make modal header text unselectable 2023-07-13 15:46:29 +05:30
Aman Harwara e4f1af1e94 chore: fix toolbar image option color 2023-07-13 15:45:09 +05:30
Aman Harwara ff56f04b2e chore: allow click-to-dismiss on toasts with actions 2023-07-13 15:21:28 +05:30
StandardNotes CI 60ee79f333 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2023-07-12 21:21:07 +00:00
Aman Harwara 512b8d9fbc chore: correctly close modals and show toast after creating note from shared text 2023-07-13 02:16:54 +05:30
StandardNotes CI 8294d0663f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].5
2023-07-12 18:58:36 +00:00
Aman Harwara 3f796b48eb chore: lint 2023-07-12 23:59:58 +05:30
Aman Harwara 139e8789a4 chore: lint 2023-07-12 23:43:38 +05:30
Aman Harwara 7039525c4f chore: add border to menus in dark theme 2023-07-12 23:32:16 +05:30
Mo 078ef3772c refactor: native feature management (#2350) 2023-07-12 12:56:08 -05:00
StandardNotes CI 49f7581cd8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2023-07-12 16:09:58 +00:00
Aman Harwara 6f18a73d94 chore: close currently open modals/popovers when sharing text into sn 2023-07-12 21:03:06 +05:30
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
820 changed files with 14234 additions and 8298 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.
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.
+40
View File
@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.26.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-13)
**Note:** Version bump only for package @standardnotes/api
## [1.26.27](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.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
+2 -1
View File
@@ -6,4 +6,5 @@ module.exports = {
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.json' }],
},
};
coverageThreshold: {},
}
+3 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.18",
"version": "1.26.28",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -27,7 +27,6 @@
},
"devDependencies": {
"@types/jest": "^29.2.3",
"@types/lodash": "^4.14.189",
"@typescript-eslint/eslint-plugin": "*",
"eslint": "^8.27.0",
"eslint-plugin-prettier": "*",
@@ -36,9 +35,8 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.48.3",
"@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",
@@ -4,4 +4,6 @@ export enum SubscriptionApiOperations {
ListingInvites,
AcceptingInvite,
ConfirmAppleIAP,
GetSubscription,
GetAvailableSubscriptions,
}
@@ -8,11 +8,17 @@ import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscriptio
import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody'
import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody'
import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody'
import { HttpResponse, ApiEndpointParam } from '@standardnotes/responses'
import {
HttpResponse,
ApiEndpointParam,
GetSubscriptionResponse,
GetAvailableSubscriptionsResponse,
} from '@standardnotes/responses'
import { SubscriptionApiServiceInterface } from './SubscriptionApiServiceInterface'
import { SubscriptionApiOperations } from './SubscriptionApiOperations'
import { AppleIAPConfirmRequestParams } from '../../Request'
import { GetUserSubscriptionRequestParams } from '../../Request/Subscription/GetUserSubscriptionRequestParams'
export class SubscriptionApiService implements SubscriptionApiServiceInterface {
private operationsInProgress: Map<SubscriptionApiOperations, boolean>
@@ -118,4 +124,36 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
this.operationsInProgress.set(SubscriptionApiOperations.ConfirmAppleIAP, false)
}
}
async getUserSubscription(params: GetUserSubscriptionRequestParams): Promise<HttpResponse<GetSubscriptionResponse>> {
if (this.operationsInProgress.get(SubscriptionApiOperations.GetSubscription)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(SubscriptionApiOperations.GetSubscription, true)
try {
const response = await this.subscriptionServer.getUserSubscription(params)
return response
} finally {
this.operationsInProgress.set(SubscriptionApiOperations.GetSubscription, false)
}
}
async getAvailableSubscriptions(): Promise<HttpResponse<GetAvailableSubscriptionsResponse>> {
if (this.operationsInProgress.get(SubscriptionApiOperations.GetAvailableSubscriptions)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(SubscriptionApiOperations.GetAvailableSubscriptions, true)
try {
const response = await this.subscriptionServer.getAvailableSubscriptions()
return response
} finally {
this.operationsInProgress.set(SubscriptionApiOperations.GetAvailableSubscriptions, false)
}
}
}
@@ -4,7 +4,8 @@ import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscriptio
import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody'
import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody'
import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody'
import { HttpResponse } from '@standardnotes/responses'
import { GetAvailableSubscriptionsResponse, GetSubscriptionResponse, HttpResponse } from '@standardnotes/responses'
import { GetUserSubscriptionRequestParams } from '../../Request/Subscription/GetUserSubscriptionRequestParams'
export interface SubscriptionApiServiceInterface {
invite(inviteeEmail: string): Promise<HttpResponse<SubscriptionInviteResponseBody>>
@@ -12,4 +13,6 @@ export interface SubscriptionApiServiceInterface {
cancelInvite(inviteUuid: string): Promise<HttpResponse<SubscriptionInviteCancelResponseBody>>
acceptInvite(inviteUuid: string): Promise<HttpResponse<SubscriptionInviteAcceptResponseBody>>
confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise<HttpResponse<AppleIAPConfirmResponseBody>>
getUserSubscription(params: GetUserSubscriptionRequestParams): Promise<HttpResponse<GetSubscriptionResponse>>
getAvailableSubscriptions(): Promise<HttpResponse<GetAvailableSubscriptionsResponse>>
}
@@ -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
}
}
+7 -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(
@@ -131,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)
@@ -209,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
}
}
}

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