@jbrowse/plugin-authentication 2.4.2 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/DropboxOAuthModel/configSchema.d.ts +105 -1
  2. package/dist/DropboxOAuthModel/configSchema.js +0 -8
  3. package/dist/DropboxOAuthModel/configSchema.js.map +1 -1
  4. package/dist/DropboxOAuthModel/model.d.ts +304 -8
  5. package/dist/DropboxOAuthModel/model.js +26 -35
  6. package/dist/DropboxOAuthModel/model.js.map +1 -1
  7. package/dist/DropboxOAuthModel/util.d.ts +1 -0
  8. package/dist/DropboxOAuthModel/util.js +28 -0
  9. package/dist/DropboxOAuthModel/util.js.map +1 -0
  10. package/dist/ExternalTokenModel/ExternalTokenEntryForm.d.ts +2 -2
  11. package/dist/ExternalTokenModel/ExternalTokenEntryForm.js +10 -11
  12. package/dist/ExternalTokenModel/ExternalTokenEntryForm.js.map +1 -1
  13. package/dist/ExternalTokenModel/configSchema.d.ts +36 -1
  14. package/dist/ExternalTokenModel/model.d.ts +93 -3
  15. package/dist/GoogleDriveOAuthModel/GoogleDriveFilehandle.d.ts +15 -0
  16. package/dist/GoogleDriveOAuthModel/GoogleDriveFilehandle.js +20 -0
  17. package/dist/GoogleDriveOAuthModel/GoogleDriveFilehandle.js.map +1 -0
  18. package/dist/GoogleDriveOAuthModel/configSchema.d.ts +105 -1
  19. package/dist/GoogleDriveOAuthModel/model.d.ts +219 -20
  20. package/dist/GoogleDriveOAuthModel/model.js +38 -51
  21. package/dist/GoogleDriveOAuthModel/model.js.map +1 -1
  22. package/dist/GoogleDriveOAuthModel/util.d.ts +1 -0
  23. package/dist/GoogleDriveOAuthModel/util.js +17 -0
  24. package/dist/GoogleDriveOAuthModel/util.js.map +1 -0
  25. package/dist/HTTPBasicModel/HTTPBasicLoginForm.d.ts +2 -2
  26. package/dist/HTTPBasicModel/HTTPBasicLoginForm.js +17 -21
  27. package/dist/HTTPBasicModel/HTTPBasicLoginForm.js.map +1 -1
  28. package/dist/HTTPBasicModel/configSchema.d.ts +44 -1
  29. package/dist/HTTPBasicModel/model.d.ts +135 -3
  30. package/dist/HTTPBasicModel/model.js +24 -9
  31. package/dist/HTTPBasicModel/model.js.map +1 -1
  32. package/dist/OAuthModel/configSchema.d.ts +94 -1
  33. package/dist/OAuthModel/configSchema.js +1 -9
  34. package/dist/OAuthModel/configSchema.js.map +1 -1
  35. package/dist/OAuthModel/model.d.ts +263 -8
  36. package/dist/OAuthModel/model.js +165 -113
  37. package/dist/OAuthModel/model.js.map +1 -1
  38. package/dist/OAuthModel/util.d.ts +7 -0
  39. package/dist/OAuthModel/util.js +60 -0
  40. package/dist/OAuthModel/util.js.map +1 -0
  41. package/dist/index.d.ts +954 -105
  42. package/dist/util.d.ts +6 -0
  43. package/dist/util.js +23 -0
  44. package/dist/util.js.map +1 -0
  45. package/esm/DropboxOAuthModel/configSchema.d.ts +105 -1
  46. package/esm/DropboxOAuthModel/configSchema.js +0 -8
  47. package/esm/DropboxOAuthModel/configSchema.js.map +1 -1
  48. package/esm/DropboxOAuthModel/model.d.ts +304 -8
  49. package/esm/DropboxOAuthModel/model.js +26 -35
  50. package/esm/DropboxOAuthModel/model.js.map +1 -1
  51. package/esm/DropboxOAuthModel/util.d.ts +1 -0
  52. package/esm/DropboxOAuthModel/util.js +24 -0
  53. package/esm/DropboxOAuthModel/util.js.map +1 -0
  54. package/esm/ExternalTokenModel/ExternalTokenEntryForm.d.ts +2 -2
  55. package/esm/ExternalTokenModel/ExternalTokenEntryForm.js +10 -11
  56. package/esm/ExternalTokenModel/ExternalTokenEntryForm.js.map +1 -1
  57. package/esm/ExternalTokenModel/configSchema.d.ts +36 -1
  58. package/esm/ExternalTokenModel/model.d.ts +93 -3
  59. package/esm/GoogleDriveOAuthModel/GoogleDriveFilehandle.d.ts +15 -0
  60. package/esm/GoogleDriveOAuthModel/GoogleDriveFilehandle.js +16 -0
  61. package/esm/GoogleDriveOAuthModel/GoogleDriveFilehandle.js.map +1 -0
  62. package/esm/GoogleDriveOAuthModel/configSchema.d.ts +105 -1
  63. package/esm/GoogleDriveOAuthModel/model.d.ts +219 -20
  64. package/esm/GoogleDriveOAuthModel/model.js +37 -49
  65. package/esm/GoogleDriveOAuthModel/model.js.map +1 -1
  66. package/esm/GoogleDriveOAuthModel/util.d.ts +1 -0
  67. package/esm/GoogleDriveOAuthModel/util.js +13 -0
  68. package/esm/GoogleDriveOAuthModel/util.js.map +1 -0
  69. package/esm/HTTPBasicModel/HTTPBasicLoginForm.d.ts +2 -2
  70. package/esm/HTTPBasicModel/HTTPBasicLoginForm.js +18 -22
  71. package/esm/HTTPBasicModel/HTTPBasicLoginForm.js.map +1 -1
  72. package/esm/HTTPBasicModel/configSchema.d.ts +44 -1
  73. package/esm/HTTPBasicModel/model.d.ts +135 -3
  74. package/esm/HTTPBasicModel/model.js +24 -9
  75. package/esm/HTTPBasicModel/model.js.map +1 -1
  76. package/esm/OAuthModel/configSchema.d.ts +94 -1
  77. package/esm/OAuthModel/configSchema.js +1 -9
  78. package/esm/OAuthModel/configSchema.js.map +1 -1
  79. package/esm/OAuthModel/model.d.ts +263 -8
  80. package/esm/OAuthModel/model.js +164 -86
  81. package/esm/OAuthModel/model.js.map +1 -1
  82. package/esm/OAuthModel/util.d.ts +7 -0
  83. package/esm/OAuthModel/util.js +30 -0
  84. package/esm/OAuthModel/util.js.map +1 -0
  85. package/esm/index.d.ts +954 -105
  86. package/esm/util.d.ts +6 -0
  87. package/esm/util.js +18 -0
  88. package/esm/util.js.map +1 -0
  89. package/package.json +3 -4
  90. package/src/DropboxOAuthModel/configSchema.ts +0 -8
  91. package/src/DropboxOAuthModel/model.tsx +35 -54
  92. package/src/DropboxOAuthModel/util.ts +36 -0
  93. package/src/ExternalTokenModel/ExternalTokenEntryForm.tsx +39 -41
  94. package/src/GoogleDriveOAuthModel/GoogleDriveFilehandle.ts +38 -0
  95. package/src/GoogleDriveOAuthModel/model.tsx +54 -104
  96. package/src/GoogleDriveOAuthModel/util.ts +29 -0
  97. package/src/HTTPBasicModel/HTTPBasicLoginForm.tsx +53 -56
  98. package/src/HTTPBasicModel/model.tsx +26 -11
  99. package/src/OAuthModel/configSchema.ts +2 -9
  100. package/src/OAuthModel/model.tsx +190 -108
  101. package/src/OAuthModel/util.ts +33 -0
  102. package/src/util.ts +25 -0
package/esm/util.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export declare function getResponseError({ response, reason, statusText, }: {
2
+ response: Response;
3
+ reason?: string;
4
+ statusText?: string;
5
+ }): Promise<string>;
6
+ export declare function getError(response: Response): Promise<string>;
package/esm/util.js ADDED
@@ -0,0 +1,18 @@
1
+ export async function getResponseError({ response, reason, statusText, }) {
2
+ return [
3
+ `HTTP ${response.status}`,
4
+ reason,
5
+ statusText !== null && statusText !== void 0 ? statusText : (await getError(response)),
6
+ ]
7
+ .filter(f => !!f)
8
+ .join(' - ');
9
+ }
10
+ export async function getError(response) {
11
+ try {
12
+ return response.text();
13
+ }
14
+ catch (e) {
15
+ return response.statusText;
16
+ }
17
+ }
18
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,QAAQ,EACR,MAAM,EACN,UAAU,GAKX;IACC,OAAO;QACL,QAAQ,QAAQ,CAAC,MAAM,EAAE;QACzB,MAAM;QACN,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;KACzC;SACE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAChB,IAAI,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAkB;IAC/C,IAAI;QACF,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAA;KACvB;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,QAAQ,CAAC,UAAU,CAAA;KAC3B;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-authentication",
3
- "version": "2.4.2",
3
+ "version": "2.6.1",
4
4
  "description": "JBrowse 2 Authentication",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -38,8 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "crypto-js": "^3.0.0",
41
- "generic-filehandle": "^3.0.0",
42
- "jwt-decode": "^3.1.2"
41
+ "generic-filehandle": "^3.0.0"
43
42
  },
44
43
  "peerDependencies": {
45
44
  "@jbrowse/core": "^2.0.0",
@@ -57,5 +56,5 @@
57
56
  "distModule": "esm/index.js",
58
57
  "srcModule": "src/index.ts",
59
58
  "module": "esm/index.js",
60
- "gitHead": "36e382a70e7d220343b873e7e6aba5c83e5342c8"
59
+ "gitHead": "1cbe7ba097fb2d2763c776e5e429e4670cdd583c"
61
60
  }
@@ -51,14 +51,6 @@ const DropboxOAuthConfigSchema = ConfigurationSchema(
51
51
  'getdropbox.com',
52
52
  ],
53
53
  },
54
- /**
55
- * #slot
56
- */
57
- hasRefreshToken: {
58
- description: 'true if the endpoint can supply a refresh token',
59
- type: 'boolean',
60
- defaultValue: true,
61
- },
62
54
  },
63
55
  {
64
56
  /**
@@ -3,26 +3,12 @@ import { ConfigurationReference } from '@jbrowse/core/configuration'
3
3
  import { UriLocation } from '@jbrowse/core/util/types'
4
4
  import { SvgIconProps, SvgIcon } from '@mui/material'
5
5
  import { Instance, types } from 'mobx-state-tree'
6
+
7
+ // locals
6
8
  import { DropboxOAuthInternetAccountConfigModel } from './configSchema'
7
9
  import baseModel from '../OAuthModel/model'
8
10
  import { configSchema as OAuthConfigSchema } from '../OAuthModel'
9
-
10
- interface DropboxError {
11
- error_summary: string
12
- error: {
13
- '.tag': string
14
- }
15
- }
16
-
17
- /** Error messages from https://www.dropbox.com/developers/documentation/http/documentation#sharing-get_shared_link_file */
18
- const dropboxErrorMessages: Record<string, string | undefined> = {
19
- shared_link_not_found: "The shared link wasn't found.",
20
- shared_link_access_denied:
21
- 'The caller is not allowed to access this shared link.',
22
- unsupported_link_type:
23
- 'This type of link is not supported; use files/export instead.',
24
- shared_link_is_directory: 'Directories cannot be retrieved by this endpoint.',
25
- }
11
+ import { getDescriptiveErrorMessage } from './util'
26
12
 
27
13
  export function DropboxIcon(props: SvgIconProps) {
28
14
  return (
@@ -32,55 +18,45 @@ export function DropboxIcon(props: SvgIconProps) {
32
18
  )
33
19
  }
34
20
 
35
- async function getDescriptiveErrorMessage(response: Response) {
36
- let errorMessage
37
- try {
38
- errorMessage = await response.text()
39
- } catch (error) {
40
- errorMessage = ''
41
- }
42
- if (errorMessage) {
43
- let errorMessageParsed: DropboxError | undefined
44
- try {
45
- errorMessageParsed = JSON.parse(errorMessage)
46
- } catch (error) {
47
- errorMessageParsed = undefined
48
- }
49
- if (errorMessageParsed) {
50
- const messageTag = errorMessageParsed.error['.tag']
51
- errorMessage = dropboxErrorMessages[messageTag] || messageTag
52
- }
53
- }
54
- return `Network response failure — ${response.status} (${
55
- response.statusText
56
- })${errorMessage ? ` (${errorMessage})` : ''}`
57
- }
58
-
21
+ /**
22
+ * #stateModel DropboxOAuthInternetAccount
23
+ */
59
24
  const stateModelFactory = (
60
25
  configSchema: DropboxOAuthInternetAccountConfigModel,
61
26
  ) => {
62
27
  return baseModel(OAuthConfigSchema)
63
28
  .named('DropboxOAuthInternetAccount')
64
29
  .props({
30
+ /**
31
+ * #property
32
+ */
65
33
  type: types.literal('DropboxOAuthInternetAccount'),
34
+ /**
35
+ * #property
36
+ */
66
37
  configuration: ConfigurationReference(configSchema),
67
38
  })
68
39
  .views(() => ({
40
+ /**
41
+ * #getter
42
+ * The FileSelector icon for Dropbox
43
+ */
69
44
  get toggleContents() {
70
45
  return <DropboxIcon />
71
46
  },
47
+ /**
48
+ * #getter
49
+ */
72
50
  get selectorLabel() {
73
51
  return 'Enter Dropbox share link'
74
52
  },
75
53
  }))
76
54
  .actions(self => ({
77
- getFetcher(
78
- location?: UriLocation,
79
- ): (input: RequestInfo, init?: RequestInit) => Promise<Response> {
80
- return async (
81
- input: RequestInfo,
82
- init?: RequestInit,
83
- ): Promise<Response> => {
55
+ /**
56
+ * #method
57
+ */
58
+ getFetcher(location?: UriLocation) {
59
+ return async (input: RequestInfo, init?: RequestInit) => {
84
60
  const authToken = await self.getToken(location)
85
61
  const newInit = self.addAuthHeaderToInit(
86
62
  { ...init, method: 'POST' },
@@ -95,12 +71,14 @@ const stateModelFactory = (
95
71
  newInit,
96
72
  )
97
73
  if (!response.ok) {
98
- const message = await getDescriptiveErrorMessage(response)
99
- throw new Error(message)
74
+ throw new Error(await getDescriptiveErrorMessage(response))
100
75
  }
101
76
  return response
102
77
  }
103
78
  },
79
+ /**
80
+ * #action
81
+ */
104
82
  async validateToken(
105
83
  token: string,
106
84
  location: UriLocation,
@@ -119,8 +97,7 @@ const stateModelFactory = (
119
97
  },
120
98
  )
121
99
  if (!response.ok) {
122
- const refreshToken =
123
- self.hasRefreshToken && self.retrieveRefreshToken()
100
+ const refreshToken = self.retrieveRefreshToken()
124
101
  if (refreshToken) {
125
102
  self.removeRefreshToken()
126
103
  const newToken = await self.exchangeRefreshForAccessToken(
@@ -128,8 +105,12 @@ const stateModelFactory = (
128
105
  )
129
106
  return this.validateToken(newToken, location)
130
107
  }
131
- const message = await getDescriptiveErrorMessage(response)
132
- throw new Error(`Token could not be validated. ${message}`)
108
+ throw new Error(
109
+ await getDescriptiveErrorMessage(
110
+ response,
111
+ 'Token could not be validated',
112
+ ),
113
+ )
133
114
  }
134
115
  return token
135
116
  },
@@ -0,0 +1,36 @@
1
+ import { getResponseError } from '../util'
2
+
3
+ interface DropboxError {
4
+ error_summary: string
5
+ error: {
6
+ '.tag': string
7
+ }
8
+ }
9
+
10
+ /**
11
+ * Error messages from
12
+ * https://www.dropbox.com/developers/documentation/http/documentation#sharing-get_shared_link_file
13
+ * */
14
+ const dropboxErrorMessages: Record<string, string | undefined> = {
15
+ shared_link_not_found: "The shared link wasn't found.",
16
+ shared_link_access_denied:
17
+ 'The caller is not allowed to access this shared link.',
18
+ unsupported_link_type:
19
+ 'This type of link is not supported; use files/export instead.',
20
+ shared_link_is_directory: 'Directories cannot be retrieved by this endpoint.',
21
+ }
22
+
23
+ export async function getDescriptiveErrorMessage(
24
+ response: Response,
25
+ reason?: string,
26
+ ) {
27
+ let errorMessage = ''
28
+ try {
29
+ const err = JSON.parse(await response.text()) as DropboxError
30
+ const tag = err.error['.tag']
31
+ errorMessage = dropboxErrorMessages[tag] || tag
32
+ } catch (error) {
33
+ /* do nothing */
34
+ }
35
+ return getResponseError({ response, reason, statusText: errorMessage })
36
+ }
@@ -12,46 +12,44 @@ export const ExternalTokenEntryForm = ({
12
12
  const [token, setToken] = useState('')
13
13
 
14
14
  return (
15
- <>
16
- <Dialog
17
- open
18
- maxWidth="xl"
19
- data-testid="externalToken-form"
20
- title={`Enter token for ${internetAccountId}`}
21
- >
22
- <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
23
- <TextField
24
- required
25
- label="Enter Token"
26
- variant="outlined"
27
- inputProps={{ 'data-testid': 'entry-externalToken' }}
28
- onChange={event => setToken(event.target.value)}
29
- margin="dense"
30
- />
31
- </DialogContent>
32
- <DialogActions>
33
- <Button
34
- variant="contained"
35
- color="primary"
36
- type="submit"
37
- disabled={!token}
38
- onClick={() => {
39
- if (token) {
40
- handleClose(token)
41
- }
42
- }}
43
- >
44
- Add
45
- </Button>
46
- <Button
47
- variant="contained"
48
- color="primary"
49
- onClick={() => handleClose()}
50
- >
51
- Cancel
52
- </Button>
53
- </DialogActions>
54
- </Dialog>
55
- </>
15
+ <Dialog
16
+ open
17
+ maxWidth="xl"
18
+ data-testid="externalToken-form"
19
+ title={`Enter token for ${internetAccountId}`}
20
+ >
21
+ <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
22
+ <TextField
23
+ required
24
+ label="Enter Token"
25
+ variant="outlined"
26
+ inputProps={{ 'data-testid': 'entry-externalToken' }}
27
+ onChange={event => setToken(event.target.value)}
28
+ margin="dense"
29
+ />
30
+ </DialogContent>
31
+ <DialogActions>
32
+ <Button
33
+ variant="contained"
34
+ color="primary"
35
+ type="submit"
36
+ disabled={!token}
37
+ onClick={() => {
38
+ if (token) {
39
+ handleClose(token)
40
+ }
41
+ }}
42
+ >
43
+ Add
44
+ </Button>
45
+ <Button
46
+ variant="contained"
47
+ color="secondary"
48
+ onClick={() => handleClose()}
49
+ >
50
+ Cancel
51
+ </Button>
52
+ </DialogActions>
53
+ </Dialog>
56
54
  )
57
55
  }
@@ -0,0 +1,38 @@
1
+ import { RemoteFileWithRangeCache } from '@jbrowse/core/util/io'
2
+ import {
3
+ FilehandleOptions,
4
+ Stats,
5
+ PolyfilledResponse,
6
+ } from 'generic-filehandle'
7
+
8
+ export interface RequestInitWithMetadata extends RequestInit {
9
+ metadataOnly?: boolean
10
+ }
11
+
12
+ interface GoogleDriveFilehandleOptions extends FilehandleOptions {
13
+ fetch(
14
+ input: RequestInfo,
15
+ opts?: RequestInitWithMetadata,
16
+ ): Promise<PolyfilledResponse>
17
+ }
18
+
19
+ export class GoogleDriveFile extends RemoteFileWithRangeCache {
20
+ private statsPromise: Promise<{ size: number }>
21
+ constructor(source: string, opts: GoogleDriveFilehandleOptions) {
22
+ super(source, opts)
23
+ this.statsPromise = this.fetch(source, {
24
+ metadataOnly: true,
25
+ }).then((response: Response) => response.json())
26
+ }
27
+
28
+ async fetch(
29
+ input: RequestInfo,
30
+ opts?: RequestInitWithMetadata,
31
+ ): Promise<PolyfilledResponse> {
32
+ return super.fetch(input, opts)
33
+ }
34
+
35
+ async stat(): Promise<Stats> {
36
+ return this.statsPromise
37
+ }
38
+ }
@@ -1,66 +1,20 @@
1
1
  import React from 'react'
2
2
  import { ConfigurationReference } from '@jbrowse/core/configuration'
3
3
  import { Instance, types } from 'mobx-state-tree'
4
- import { RemoteFileWithRangeCache } from '@jbrowse/core/util/io'
5
4
  import { UriLocation } from '@jbrowse/core/util/types'
6
5
  import { SvgIconProps, SvgIcon } from '@mui/material'
7
- import {
8
- FilehandleOptions,
9
- Stats,
10
- PolyfilledResponse,
11
- } from 'generic-filehandle'
12
6
 
13
7
  // locals
14
8
  import { GoogleDriveOAuthInternetAccountConfigModel } from './configSchema'
15
9
  import baseModel from '../OAuthModel/model'
16
10
  import { configSchema as OAuthConfigSchema } from '../OAuthModel'
11
+ import { getDescriptiveErrorMessage } from './util'
12
+ import { GoogleDriveFile } from './GoogleDriveFilehandle'
17
13
 
18
14
  export interface RequestInitWithMetadata extends RequestInit {
19
15
  metadataOnly?: boolean
20
16
  }
21
17
 
22
- interface GoogleDriveFilehandleOptions extends FilehandleOptions {
23
- fetch(
24
- input: RequestInfo,
25
- opts?: RequestInitWithMetadata,
26
- ): Promise<PolyfilledResponse>
27
- }
28
-
29
- interface GoogleDriveError {
30
- error: {
31
- errors: {
32
- domain: string
33
- reason: string
34
- message: string
35
- locationType?: string
36
- location?: string
37
- }[]
38
- code: number
39
- message: string
40
- }
41
- }
42
-
43
- export class GoogleDriveFile extends RemoteFileWithRangeCache {
44
- private statsPromise: Promise<{ size: number }>
45
- constructor(source: string, opts: GoogleDriveFilehandleOptions) {
46
- super(source, opts)
47
- this.statsPromise = this.fetch(source, {
48
- metadataOnly: true,
49
- }).then((response: Response) => response.json())
50
- }
51
-
52
- async fetch(
53
- input: RequestInfo,
54
- opts?: RequestInitWithMetadata,
55
- ): Promise<PolyfilledResponse> {
56
- return super.fetch(input, opts)
57
- }
58
-
59
- async stat(): Promise<Stats> {
60
- return this.statsPromise
61
- }
62
- }
63
-
64
18
  function GoogleDriveIcon(props: SvgIconProps) {
65
19
  return (
66
20
  <SvgIcon {...props}>
@@ -69,58 +23,51 @@ function GoogleDriveIcon(props: SvgIconProps) {
69
23
  )
70
24
  }
71
25
 
72
- async function getDescriptiveErrorMessage(response: Response) {
73
- let errorMessage
74
- try {
75
- errorMessage = await response.text()
76
- } catch (error) {
77
- errorMessage = ''
78
- }
79
- if (errorMessage) {
80
- let errorMessageParsed: GoogleDriveError | undefined
81
- try {
82
- errorMessageParsed = JSON.parse(errorMessage)
83
- } catch (error) {
84
- errorMessageParsed = undefined
85
- }
86
- if (errorMessageParsed) {
87
- errorMessage = errorMessageParsed.error.message
88
- }
89
- }
90
- return `Network response failure — ${response.status} (${
91
- response.statusText
92
- })${errorMessage ? ` (${errorMessage})` : ''}`
26
+ function getUri(str: string) {
27
+ const urlId = str.match(/[-\w]{25,}/)
28
+ return `https://www.googleapis.com/drive/v3/files/${urlId}`
93
29
  }
94
30
 
95
- const stateModelFactory = (
31
+ /**
32
+ * #stateModel GoogleDriveOAuthInternetAccount
33
+ */
34
+ export default function stateModelFactory(
96
35
  configSchema: GoogleDriveOAuthInternetAccountConfigModel,
97
- ) => {
36
+ ) {
98
37
  return baseModel(OAuthConfigSchema)
99
38
  .named('GoogleDriveOAuthInternetAccount')
100
39
  .props({
40
+ /**
41
+ * #property
42
+ */
101
43
  type: types.literal('GoogleDriveOAuthInternetAccount'),
44
+ /**
45
+ * #property
46
+ */
102
47
  configuration: ConfigurationReference(configSchema),
103
48
  })
104
49
  .views(() => ({
50
+ /**
51
+ * #getter
52
+ * The FileSelector icon for Google drive
53
+ */
105
54
  get toggleContents() {
106
55
  return <GoogleDriveIcon />
107
56
  },
57
+ /**
58
+ * #getter
59
+ */
108
60
  get selectorLabel() {
109
61
  return 'Enter Google Drive share link'
110
62
  },
111
63
  }))
112
64
  .actions(self => ({
113
- getFetcher(
114
- location?: UriLocation,
115
- ): (input: RequestInfo, init?: RequestInit) => Promise<Response> {
116
- return async (
117
- input: RequestInfo,
118
- init?: RequestInitWithMetadata,
119
- ): Promise<Response> => {
120
- const urlId = String(input).match(/[-\w]{25,}/)
121
- const driveUrl = new URL(
122
- `https://www.googleapis.com/drive/v3/files/${urlId}`,
123
- )
65
+ /**
66
+ * #method
67
+ */
68
+ getFetcher(location?: UriLocation) {
69
+ return async (input: RequestInfo, init?: RequestInitWithMetadata) => {
70
+ const driveUrl = new URL(getUri(String(input)))
124
71
  const searchParams = new URLSearchParams()
125
72
  if (init?.metadataOnly) {
126
73
  searchParams.append('fields', 'size')
@@ -129,46 +76,49 @@ const stateModelFactory = (
129
76
  }
130
77
  driveUrl.search = searchParams.toString()
131
78
  const authToken = await self.getToken(location)
132
- const newInit = self.addAuthHeaderToInit(
133
- { ...init, method: 'GET', credentials: 'same-origin' },
134
- authToken,
79
+ const response = await fetch(
80
+ driveUrl,
81
+ self.addAuthHeaderToInit(
82
+ { ...init, method: 'GET', credentials: 'same-origin' },
83
+ authToken,
84
+ ),
135
85
  )
136
- const response = await fetch(driveUrl.toString(), newInit)
137
86
  if (!response.ok) {
138
- const message = await getDescriptiveErrorMessage(response)
139
- throw new Error(message)
87
+ throw new Error(await getDescriptiveErrorMessage(response))
140
88
  }
141
89
  return response
142
90
  }
143
91
  },
92
+ /**
93
+ * #method
94
+ */
144
95
  openLocation(location: UriLocation) {
145
96
  return new GoogleDriveFile(location.uri, {
146
97
  fetch: this.getFetcher(location),
147
98
  })
148
99
  },
149
- async validateToken(
150
- token: string,
151
- location: UriLocation,
152
- ): Promise<string> {
153
- const urlId = location.uri.match(/[-\w]{25,}/)
154
- const response = await fetch(
155
- `https://www.googleapis.com/drive/v3/files/${urlId}`,
156
- {
157
- headers: {
158
- Authorization: `Bearer ${token}`,
159
- 'Content-Type': 'application/x-www-form-urlencoded',
160
- },
100
+ /**
101
+ * #action
102
+ */
103
+ async validateToken(token: string, location: UriLocation) {
104
+ const response = await fetch(getUri(location.uri), {
105
+ headers: {
106
+ Authorization: `Bearer ${token}`,
107
+ 'Content-Type': 'application/x-www-form-urlencoded',
161
108
  },
162
- )
109
+ })
163
110
  if (!response.ok) {
164
- const message = await getDescriptiveErrorMessage(response)
165
- throw new Error(`Token could not be validated. ${message}`)
111
+ throw new Error(
112
+ await getDescriptiveErrorMessage(
113
+ response,
114
+ 'Token could not be validated',
115
+ ),
116
+ )
166
117
  }
167
118
  return token
168
119
  },
169
120
  }))
170
121
  }
171
122
 
172
- export default stateModelFactory
173
123
  export type GoogleDriveOAuthStateModel = ReturnType<typeof stateModelFactory>
174
124
  export type GoogleDriveOAuthModel = Instance<GoogleDriveOAuthStateModel>
@@ -0,0 +1,29 @@
1
+ import { getResponseError } from '../util'
2
+
3
+ interface GoogleDriveError {
4
+ error: {
5
+ errors: {
6
+ domain: string
7
+ reason: string
8
+ message: string
9
+ locationType?: string
10
+ location?: string
11
+ }[]
12
+ code: number
13
+ message: string
14
+ }
15
+ }
16
+
17
+ export async function getDescriptiveErrorMessage(
18
+ response: Response,
19
+ reason?: string,
20
+ ) {
21
+ let errorMessage = ''
22
+ try {
23
+ const err = JSON.parse(await response.text()) as GoogleDriveError
24
+ errorMessage = err.error.message
25
+ } catch (error) {
26
+ /* do nothing */
27
+ }
28
+ return getResponseError({ response, reason, statusText: errorMessage })
29
+ }