@jbrowse/plugin-authentication 4.3.0 → 5.0.0-beta.10

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 (50) hide show
  1. package/esm/DropboxOAuthModel/DropboxIcon.d.ts +1 -1
  2. package/esm/DropboxOAuthModel/configSchema.d.ts +154 -48
  3. package/esm/DropboxOAuthModel/configSchema.js +32 -2
  4. package/esm/DropboxOAuthModel/index.js +2 -2
  5. package/esm/DropboxOAuthModel/model.d.ts +301 -127
  6. package/esm/DropboxOAuthModel/model.js +46 -21
  7. package/esm/DropboxOAuthModel/util.d.ts +1 -1
  8. package/esm/DropboxOAuthModel/util.js +9 -12
  9. package/esm/ExternalTokenModel/ExternalTokenEntryForm.d.ts +1 -1
  10. package/esm/ExternalTokenModel/ExternalTokenEntryForm.js +11 -15
  11. package/esm/ExternalTokenModel/configSchema.d.ts +80 -19
  12. package/esm/ExternalTokenModel/configSchema.js +22 -1
  13. package/esm/ExternalTokenModel/index.js +2 -2
  14. package/esm/ExternalTokenModel/model.d.ts +49 -63
  15. package/esm/ExternalTokenModel/model.js +11 -54
  16. package/esm/GoogleDriveOAuthModel/GoogleDriveFilehandle.d.ts +2 -9
  17. package/esm/GoogleDriveOAuthModel/GoogleDriveFilehandle.js +27 -6
  18. package/esm/GoogleDriveOAuthModel/GoogleDriveIcon.d.ts +1 -1
  19. package/esm/GoogleDriveOAuthModel/configSchema.d.ts +152 -47
  20. package/esm/GoogleDriveOAuthModel/configSchema.js +32 -3
  21. package/esm/GoogleDriveOAuthModel/index.js +2 -2
  22. package/esm/GoogleDriveOAuthModel/model.d.ts +296 -128
  23. package/esm/GoogleDriveOAuthModel/model.js +45 -22
  24. package/esm/GoogleDriveOAuthModel/util.d.ts +1 -1
  25. package/esm/GoogleDriveOAuthModel/util.js +2 -11
  26. package/esm/HTTPBasicModel/HTTPBasicLoginForm.d.ts +1 -1
  27. package/esm/HTTPBasicModel/HTTPBasicLoginForm.js +17 -22
  28. package/esm/HTTPBasicModel/configSchema.d.ts +78 -21
  29. package/esm/HTTPBasicModel/configSchema.js +26 -1
  30. package/esm/HTTPBasicModel/index.js +2 -2
  31. package/esm/HTTPBasicModel/model.d.ts +57 -68
  32. package/esm/HTTPBasicModel/model.js +21 -51
  33. package/esm/OAuthModel/OAuthLoginPrompt.d.ts +4 -0
  34. package/esm/OAuthModel/OAuthLoginPrompt.js +12 -0
  35. package/esm/OAuthModel/configSchema.d.ts +81 -38
  36. package/esm/OAuthModel/configSchema.js +30 -1
  37. package/esm/OAuthModel/index.js +2 -2
  38. package/esm/OAuthModel/model.d.ts +231 -77
  39. package/esm/OAuthModel/model.js +361 -217
  40. package/esm/OAuthModel/util.d.ts +46 -7
  41. package/esm/OAuthModel/util.js +159 -16
  42. package/esm/index.d.ts +0 -1020
  43. package/esm/index.js +24 -57
  44. package/esm/lazyLoginForms.d.ts +18 -0
  45. package/esm/lazyLoginForms.js +25 -0
  46. package/esm/tokenEntryModelFactory.d.ts +135 -0
  47. package/esm/tokenEntryModelFactory.js +85 -0
  48. package/esm/util.d.ts +10 -0
  49. package/esm/util.js +24 -2
  50. package/package.json +10 -13
@@ -1 +1 @@
1
- export declare function getDescriptiveErrorMessage(response: Response, reason?: string): Promise<string>;
1
+ export declare const getDescriptiveErrorMessage: (response: Response, reason?: string) => Promise<string>;
@@ -1,18 +1,15 @@
1
- import { getResponseError } from "../util.js";
1
+ import { descriptiveErrorMessage } from '../util.js';
2
+ /**
3
+ * Error messages from
4
+ * https://www.dropbox.com/developers/documentation/http/documentation#sharing-get_shared_link_file
5
+ * */
2
6
  const dropboxErrorMessages = {
3
7
  shared_link_not_found: "The shared link wasn't found.",
4
8
  shared_link_access_denied: 'The caller is not allowed to access this shared link.',
5
9
  unsupported_link_type: 'This type of link is not supported; use files/export instead.',
6
10
  shared_link_is_directory: 'Directories cannot be retrieved by this endpoint.',
7
11
  };
8
- export async function getDescriptiveErrorMessage(response, reason) {
9
- let errorMessage = '';
10
- try {
11
- const err = JSON.parse(await response.text());
12
- const tag = err.error['.tag'];
13
- errorMessage = dropboxErrorMessages[tag] || tag;
14
- }
15
- catch (error) {
16
- }
17
- return getResponseError({ response, reason, statusText: errorMessage });
18
- }
12
+ export const getDescriptiveErrorMessage = descriptiveErrorMessage(err => {
13
+ const tag = err.error['.tag'];
14
+ return dropboxErrorMessages[tag] ?? tag;
15
+ });
@@ -1,4 +1,4 @@
1
1
  export declare const ExternalTokenEntryForm: ({ internetAccountId, handleClose, }: {
2
2
  internetAccountId: string;
3
3
  handleClose: (token?: string) => void;
4
- }) => import("react/jsx-runtime").JSX.Element;
4
+ }) => import("react").JSX.Element;
@@ -1,20 +1,16 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { Dialog } from '@jbrowse/core/ui';
4
- import { Button, DialogActions, DialogContent, TextField } from '@mui/material';
3
+ import { SubmitDialog } from '@jbrowse/core/ui';
4
+ import { TextField } from '@mui/material';
5
5
  export const ExternalTokenEntryForm = ({ internetAccountId, handleClose, }) => {
6
6
  const [token, setToken] = useState('');
7
- return (_jsxs(Dialog, { open: true, maxWidth: "xl", "data-testid": "externalToken-form", onClose: () => {
7
+ return (_jsx(SubmitDialog, { open: true, maxWidth: "xl", "data-testid": "externalToken-form", title: `Enter token for ${internetAccountId}`, submitText: "Add", submitDisabled: !token, onCancel: () => {
8
8
  handleClose();
9
- }, title: `Enter token for ${internetAccountId}`, children: [_jsx(DialogContent, { style: { display: 'flex', flexDirection: 'column' }, children: _jsx(TextField, { required: true, label: "Enter Token", variant: "outlined", onChange: event => {
10
- setToken(event.target.value);
11
- }, margin: "dense", slotProps: {
12
- htmlInput: { 'data-testid': 'entry-externalToken' },
13
- } }) }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", color: "primary", type: "submit", disabled: !token, onClick: () => {
14
- if (token) {
15
- handleClose(token);
16
- }
17
- }, children: "Add" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
18
- handleClose();
19
- }, children: "Cancel" })] })] }));
9
+ }, onSubmit: () => {
10
+ handleClose(token);
11
+ }, children: _jsx(TextField, { required: true, label: "Enter Token", variant: "outlined", onChange: event => {
12
+ setToken(event.target.value);
13
+ }, margin: "dense", slotProps: {
14
+ htmlInput: { 'data-testid': 'entry-externalToken' },
15
+ } }) }));
20
16
  };
@@ -1,37 +1,98 @@
1
1
  import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ /**
3
+ * #config ExternalTokenInternetAccount
4
+ *
5
+ * #example
6
+ * For a token the user pastes in, or that an embedding portal hands over.
7
+ * JBrowse does not obtain the token itself — it prompts for one, then sends it
8
+ * on every request to a matching domain.
9
+ * ```js
10
+ * {
11
+ * type: 'ExternalTokenInternetAccount',
12
+ * internetAccountId: 'portalToken',
13
+ * name: 'Data portal token',
14
+ * domains: ['api.myportal.org'],
15
+ * }
16
+ * ```
17
+ */
2
18
  declare const ExternalTokenConfigSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
19
+ authHeader: {
20
+ type: "string";
21
+ } & {
22
+ defaultValue: string;
23
+ };
24
+ description: {
25
+ type: "string";
26
+ } & {
27
+ defaultValue: string;
28
+ };
29
+ domains: {
30
+ type: "stringArray";
31
+ } & {
32
+ defaultValue: unknown;
33
+ };
34
+ internetAccountId: {
35
+ type: "string";
36
+ } & {
37
+ defaultValue: string;
38
+ };
39
+ name: {
40
+ type: "string";
41
+ } & {
42
+ defaultValue: string;
43
+ };
44
+ tokenType: {
45
+ type: "string";
46
+ } & {
47
+ defaultValue: string;
48
+ };
49
+ type: {
50
+ type: "string";
51
+ } & {
52
+ defaultValue: string;
53
+ };
3
54
  validateWithHEAD: {
4
- description: string;
5
- type: string;
55
+ type: "boolean";
56
+ } & {
6
57
  defaultValue: boolean;
7
58
  };
8
59
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
9
- name: {
10
- description: string;
11
- type: string;
60
+ readonly name: {
61
+ type: "string";
62
+ } & {
12
63
  defaultValue: string;
13
64
  };
14
- description: {
15
- description: string;
16
- type: string;
65
+ readonly description: {
66
+ type: "string";
67
+ } & {
17
68
  defaultValue: string;
18
69
  };
19
- authHeader: {
20
- description: string;
21
- type: string;
70
+ readonly authHeader: {
71
+ type: "string";
72
+ } & {
22
73
  defaultValue: string;
23
74
  };
24
- tokenType: {
25
- description: string;
26
- type: string;
75
+ readonly tokenType: {
76
+ type: "string";
77
+ } & {
27
78
  defaultValue: string;
28
79
  };
29
- domains: {
30
- description: string;
31
- type: string;
32
- defaultValue: never[];
80
+ readonly domains: {
81
+ type: "stringArray";
82
+ } & {
83
+ defaultValue: unknown;
84
+ };
85
+ type: {
86
+ type: "string";
87
+ } & {
88
+ defaultValue: string;
89
+ };
90
+ internetAccountId: {
91
+ type: "string";
92
+ } & {
93
+ defaultValue: string;
33
94
  };
34
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, "internetAccountId">>, undefined>>;
95
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, "internetAccountId", true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
35
96
  export type ExternalTokenInternetAccountConfigModel = typeof ExternalTokenConfigSchema;
36
97
  export type ExternalTokenInternetAccountConfig = Instance<ExternalTokenInternetAccountConfigModel>;
37
98
  export default ExternalTokenConfigSchema;
@@ -1,13 +1,34 @@
1
1
  import { ConfigurationSchema } from '@jbrowse/core/configuration';
2
2
  import { BaseInternetAccountConfig } from '@jbrowse/core/pluggableElementTypes/models';
3
- function x() { }
3
+ /**
4
+ * #config ExternalTokenInternetAccount
5
+ *
6
+ * #example
7
+ * For a token the user pastes in, or that an embedding portal hands over.
8
+ * JBrowse does not obtain the token itself — it prompts for one, then sends it
9
+ * on every request to a matching domain.
10
+ * ```js
11
+ * {
12
+ * type: 'ExternalTokenInternetAccount',
13
+ * internetAccountId: 'portalToken',
14
+ * name: 'Data portal token',
15
+ * domains: ['api.myportal.org'],
16
+ * }
17
+ * ```
18
+ */
4
19
  const ExternalTokenConfigSchema = ConfigurationSchema('ExternalTokenInternetAccount', {
20
+ /**
21
+ * #slot
22
+ */
5
23
  validateWithHEAD: {
6
24
  description: 'validate the token with a HEAD request before using it',
7
25
  type: 'boolean',
8
26
  defaultValue: true,
9
27
  },
10
28
  }, {
29
+ /**
30
+ * #baseConfiguration
31
+ */
11
32
  baseConfiguration: BaseInternetAccountConfig,
12
33
  explicitlyTyped: true,
13
34
  });
@@ -1,2 +1,2 @@
1
- export { default as configSchema } from "./configSchema.js";
2
- export { default as modelFactory } from "./model.js";
1
+ export { default as configSchema } from './configSchema.js';
2
+ export { default as modelFactory } from './model.js';
@@ -1,71 +1,56 @@
1
1
  import type { ExternalTokenInternetAccountConfigModel } from './configSchema.ts';
2
- import type { UriLocation } from '@jbrowse/core/util/types';
3
2
  import type { Instance } from '@jbrowse/mobx-state-tree';
4
- declare const stateModelFactory: (configSchema: ExternalTokenInternetAccountConfigModel) => import("@jbrowse/mobx-state-tree").IModelType<{
3
+ /**
4
+ * #stateModel ExternalTokenInternetAccount
5
+ * Internet account that authenticates requests with a user-supplied external
6
+ * token, prompting for the token via a dialog and optionally validating it with
7
+ * a HEAD request. See
8
+ * [TokenEntryInternetAccount](../tokenentryinternetaccount) for the shared
9
+ * behavior.
10
+ */
11
+ declare const stateModelFactory: (configSchema: ExternalTokenInternetAccountConfigModel) => import("@jbrowse/mobx-state-tree").IModelType<Omit<{
5
12
  id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
6
13
  type: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
7
- configuration: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
8
- name: {
9
- description: string;
10
- type: string;
14
+ configuration: import("@jbrowse/core/configuration/configurationSchema").IConfigurationReference<import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
15
+ readonly name: {
16
+ type: "string";
17
+ } & {
11
18
  defaultValue: string;
12
19
  };
13
- description: {
14
- description: string;
15
- type: string;
20
+ readonly description: {
21
+ type: "string";
22
+ } & {
16
23
  defaultValue: string;
17
24
  };
18
- authHeader: {
19
- description: string;
20
- type: string;
25
+ readonly authHeader: {
26
+ type: "string";
27
+ } & {
21
28
  defaultValue: string;
22
29
  };
23
- tokenType: {
24
- description: string;
25
- type: string;
30
+ readonly tokenType: {
31
+ type: "string";
32
+ } & {
26
33
  defaultValue: string;
27
34
  };
28
- domains: {
29
- description: string;
30
- type: string;
31
- defaultValue: never[];
35
+ readonly domains: {
36
+ type: "stringArray";
37
+ } & {
38
+ defaultValue: unknown;
32
39
  };
33
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, "internetAccountId">>;
34
- } & {
35
- type: import("@jbrowse/mobx-state-tree").ISimpleType<"ExternalTokenInternetAccount">;
36
- configuration: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
37
- validateWithHEAD: {
38
- description: string;
39
- type: string;
40
- defaultValue: boolean;
41
- };
42
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
43
- name: {
44
- description: string;
45
- type: string;
46
- defaultValue: string;
47
- };
48
- description: {
49
- description: string;
50
- type: string;
51
- defaultValue: string;
52
- };
53
- authHeader: {
54
- description: string;
55
- type: string;
40
+ type: {
41
+ type: "string";
42
+ } & {
56
43
  defaultValue: string;
57
44
  };
58
- tokenType: {
59
- description: string;
60
- type: string;
45
+ internetAccountId: {
46
+ type: "string";
47
+ } & {
61
48
  defaultValue: string;
62
49
  };
63
- domains: {
64
- description: string;
65
- type: string;
66
- defaultValue: never[];
67
- };
68
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, "internetAccountId">>, undefined>>;
50
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, "internetAccountId", true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>>;
51
+ }, "configuration" | "type"> & {
52
+ type: import("@jbrowse/mobx-state-tree").ILiteralType<"ExternalTokenInternetAccount">;
53
+ configuration: import("@jbrowse/core/configuration/configurationSchema").IConfigurationReference<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
69
54
  }, {
70
55
  readonly name: string;
71
56
  readonly description: string;
@@ -74,22 +59,21 @@ declare const stateModelFactory: (configSchema: ExternalTokenInternetAccountConf
74
59
  readonly tokenType: string;
75
60
  readonly domains: string[];
76
61
  readonly toggleContents: React.ReactNode;
77
- readonly SelectorComponent: import("@jbrowse/core/util").AnyReactComponentType | undefined;
78
62
  readonly selectorLabel: string | undefined;
63
+ readonly showInFileSelector: boolean;
79
64
  } & {
80
- handlesLocation(location: UriLocation): boolean;
65
+ handlesLocation(location: import("@jbrowse/core/util").UriLocation): boolean;
81
66
  readonly tokenKey: string;
82
67
  } & {
83
68
  getTokenFromUser(_resolve: (token: string) => void, _reject: (error: Error) => void): void;
84
69
  storeToken(token: string): void;
85
- removeToken(): void;
86
- retrieveToken(): string | null;
87
- validateToken(token: string, _loc: UriLocation): Promise<string>;
70
+ retrieveToken(): string | undefined;
71
+ validateToken(token: string, _loc: import("@jbrowse/core/util").UriLocation): Promise<string>;
88
72
  } & {
89
- getToken(location?: UriLocation): Promise<string>;
73
+ removeToken(): void;
74
+ getToken(location?: import("@jbrowse/core/util").UriLocation): Promise<string>;
90
75
  } & {
91
76
  addAuthHeaderToInit(init?: RequestInit, token?: string): {
92
- headers: Headers;
93
77
  body?: BodyInit | null;
94
78
  cache?: RequestCache;
95
79
  credentials?: RequestCredentials;
@@ -103,23 +87,25 @@ declare const stateModelFactory: (configSchema: ExternalTokenInternetAccountConf
103
87
  referrerPolicy?: ReferrerPolicy;
104
88
  signal?: AbortSignal | null;
105
89
  window?: null;
90
+ headers: Headers;
106
91
  };
107
- getPreAuthorizationInformation(location: UriLocation): Promise<{
92
+ fetchWithToken(loc: import("@jbrowse/core/util").UriLocation | undefined, run: (token: string) => Promise<Response>): Promise<Response>;
93
+ getPreAuthorizationInformation(location: import("@jbrowse/core/util").UriLocation): Promise<{
108
94
  internetAccountType: string;
109
95
  authInfo: {
110
96
  token: string;
111
- configuration: any;
97
+ configuration: import("@jbrowse/mobx-state-tree").ModelSnapshotType<Record<string, any>>;
112
98
  };
113
99
  }>;
114
100
  } & {
115
- getFetcher(loc?: UriLocation): (input: RequestInfo, init?: RequestInit) => Promise<Response>;
101
+ getFetcher(loc?: import("@jbrowse/core/util").UriLocation): (input: RequestInfo, init?: RequestInit) => Promise<Response>;
116
102
  } & {
117
- openLocation(location: UriLocation): import("@jbrowse/core/util/io").RemoteFileWithRangeCache;
103
+ openLocation(location: import("@jbrowse/core/util").UriLocation): import("@gmod/range-cache-filehandle").RemoteFileWithRangeCache;
118
104
  } & {
119
105
  readonly validateWithHEAD: boolean;
120
106
  } & {
121
107
  getTokenFromUser(resolve: (token: string) => void, reject: (error: Error) => void): void;
122
- validateToken(token: string, location: UriLocation): Promise<string>;
108
+ validateToken(token: string, location: import("@jbrowse/core/util").UriLocation): Promise<string>;
123
109
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
124
110
  export default stateModelFactory;
125
111
  export type ExternalTokenStateModel = ReturnType<typeof stateModelFactory>;
@@ -1,55 +1,12 @@
1
- import { ConfigurationReference, getConf } from '@jbrowse/core/configuration';
2
- import { InternetAccount } from '@jbrowse/core/pluggableElementTypes/models';
3
- import { getRoot, types } from '@jbrowse/mobx-state-tree';
4
- import { ExternalTokenEntryForm } from "./ExternalTokenEntryForm.js";
5
- const stateModelFactory = (configSchema) => {
6
- return InternetAccount.named('ExternalTokenInternetAccount')
7
- .props({
8
- type: types.literal('ExternalTokenInternetAccount'),
9
- configuration: ConfigurationReference(configSchema),
10
- })
11
- .views(self => ({
12
- get validateWithHEAD() {
13
- return getConf(self, 'validateWithHEAD');
14
- },
15
- }))
16
- .actions(self => ({
17
- getTokenFromUser(resolve, reject) {
18
- const { session } = getRoot(self);
19
- session.queueDialog((doneCallback) => [
20
- ExternalTokenEntryForm,
21
- {
22
- internetAccountId: self.internetAccountId,
23
- handleClose: (token) => {
24
- if (token) {
25
- resolve(token);
26
- }
27
- else {
28
- reject(new Error('user cancelled entry'));
29
- }
30
- doneCallback();
31
- },
32
- },
33
- ]);
34
- },
35
- async validateToken(token, location) {
36
- if (!self.validateWithHEAD) {
37
- return token;
38
- }
39
- const newInit = self.addAuthHeaderToInit({ method: 'HEAD' }, token);
40
- const response = await fetch(location.uri, newInit);
41
- if (!response.ok) {
42
- let errorMessage;
43
- try {
44
- errorMessage = await response.text();
45
- }
46
- catch (error) {
47
- errorMessage = '';
48
- }
49
- throw new Error(`Token could not be validated — ${response.status} ${errorMessage ? ` (${errorMessage})` : ''}`);
50
- }
51
- return token;
52
- },
53
- }));
54
- };
1
+ import { ExternalTokenEntryForm } from '../lazyLoginForms.js';
2
+ import { tokenEntryModelFactory } from '../tokenEntryModelFactory.js';
3
+ /**
4
+ * #stateModel ExternalTokenInternetAccount
5
+ * Internet account that authenticates requests with a user-supplied external
6
+ * token, prompting for the token via a dialog and optionally validating it with
7
+ * a HEAD request. See
8
+ * [TokenEntryInternetAccount](../tokenentryinternetaccount) for the shared
9
+ * behavior.
10
+ */
11
+ const stateModelFactory = (configSchema) => tokenEntryModelFactory('ExternalTokenInternetAccount', 'ExternalTokenInternetAccount', configSchema, ExternalTokenEntryForm);
55
12
  export default stateModelFactory;
@@ -1,15 +1,8 @@
1
1
  import { RemoteFileWithRangeCache } from '@jbrowse/core/util/io';
2
- import type { FilehandleOptions, Stats } from 'generic-filehandle2';
3
- export interface RequestInitWithMetadata extends RequestInit {
4
- metadataOnly?: boolean;
5
- }
6
- interface GoogleDriveFilehandleOptions extends FilehandleOptions {
7
- fetch(input: RequestInfo, opts?: RequestInitWithMetadata): Promise<Response>;
8
- }
2
+ import type { RequestInitWithMetadata } from './model.tsx';
3
+ import type { Stats } from 'generic-filehandle2';
9
4
  export declare class GoogleDriveFile extends RemoteFileWithRangeCache {
10
5
  private statsPromise;
11
- constructor(source: string, opts: GoogleDriveFilehandleOptions);
12
6
  fetch(input: RequestInfo, opts?: RequestInitWithMetadata): Promise<Response>;
13
7
  stat(): Promise<Stats>;
14
8
  }
15
- export {};
@@ -1,16 +1,37 @@
1
1
  import { RemoteFileWithRangeCache } from '@jbrowse/core/util/io';
2
2
  export class GoogleDriveFile extends RemoteFileWithRangeCache {
3
3
  statsPromise;
4
- constructor(source, opts) {
5
- super(source, opts);
6
- this.statsPromise = this.fetch(source, {
7
- metadataOnly: true,
8
- }).then(response => response.json());
9
- }
4
+ // Override to widen opts type so metadataOnly can be passed through to getFetcher
10
5
  async fetch(input, opts) {
11
6
  return super.fetch(input, opts);
12
7
  }
8
+ // Fetched on demand rather than from the constructor: openLocation builds a
9
+ // filehandle for every file a track opens and most are read by byte range
10
+ // only, so an eager metadata request cost a round trip (and a token
11
+ // validation) per handle for a size nobody asked for.
13
12
  async stat() {
13
+ this.statsPromise ??= this.fetch(this.url, { metadataOnly: true })
14
+ .then(response => response.json())
15
+ // Drive serializes its int64 fields as JSON strings, so `size` arrives as
16
+ // "12345" — passed on untouched it satisfies `Stats` in name only, and
17
+ // the first caller to do arithmetic on it concatenates instead
18
+ .then(({ size }) => {
19
+ const stats = { size: Number(size) };
20
+ // This is the only place the size of a Drive file is ever observed: the
21
+ // metadata request carries no Content-Range, so the chunk cache's own
22
+ // way of learning it never fires here, and without it every bgzf
23
+ // reader's deliberate over-read of the final block goes to the network
24
+ // to be refused. Drive omits `size` for a file that has none, and
25
+ // recordSize drops the NaN that produces rather than caching it.
26
+ this.recordSize(stats.size);
27
+ return stats;
28
+ })
29
+ // a cached rejection is permanent, so one dropped request would take
30
+ // every later stat() of this file with it
31
+ .catch((error) => {
32
+ this.statsPromise = undefined;
33
+ throw error;
34
+ });
14
35
  return this.statsPromise;
15
36
  }
16
37
  }
@@ -1,2 +1,2 @@
1
1
  import type { SvgIconProps } from '@mui/material';
2
- export default function GoogleDriveIcon(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
2
+ export default function GoogleDriveIcon(props: SvgIconProps): import("react").JSX.Element;