@anymux/connect 0.1.0
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.
- package/dist/GitBrowser-BLgTNQyd.js +905 -0
- package/dist/GitBrowser-BLgTNQyd.js.map +1 -0
- package/dist/GitBrowser-CIyWiuX-.js +3 -0
- package/dist/ObjectStorageBrowser-B2YkUxMl.js +3 -0
- package/dist/ObjectStorageBrowser-B_25Emfu.js +267 -0
- package/dist/ObjectStorageBrowser-B_25Emfu.js.map +1 -0
- package/dist/RepoPicker-BprFGOn7.js +3 -0
- package/dist/RepoPicker-CoHMiJ-3.js +168 -0
- package/dist/RepoPicker-CoHMiJ-3.js.map +1 -0
- package/dist/index.d.ts +697 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2539 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +3 -0
- package/dist/scope-labels-B4VAwoL6.js +582 -0
- package/dist/scope-labels-B4VAwoL6.js.map +1 -0
- package/dist/scope-labels-DvdJLcSL.d.ts +50 -0
- package/dist/scope-labels-DvdJLcSL.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/adapters/adapter-registry.ts +177 -0
- package/src/auth/auth-client.ts +101 -0
- package/src/auth/token-manager.ts +27 -0
- package/src/components/ActionHistoryPanel.tsx +137 -0
- package/src/components/CapabilityCell.tsx +97 -0
- package/src/components/CapabilityError.tsx +50 -0
- package/src/components/CapabilityPanel.tsx +530 -0
- package/src/components/CapabilityPill.tsx +56 -0
- package/src/components/ConnectButton.tsx +149 -0
- package/src/components/ConnectedMenu.tsx +142 -0
- package/src/components/ConnectionStatus.tsx +28 -0
- package/src/components/CredentialForm.tsx +246 -0
- package/src/components/FullScreenBrowser.tsx +84 -0
- package/src/components/GitBrowser.tsx +705 -0
- package/src/components/GitHubRepoPicker.tsx +125 -0
- package/src/components/ObjectStorageBrowser.tsx +176 -0
- package/src/components/RepoPicker.tsx +93 -0
- package/src/components/ServiceCard.tsx +77 -0
- package/src/components/ServiceCardGrid.tsx +141 -0
- package/src/components/ServiceDashboard.tsx +84 -0
- package/src/components/ServiceIcon.tsx +37 -0
- package/src/components/ServiceRow.tsx +50 -0
- package/src/components/useAdapter.ts +33 -0
- package/src/demos/ServiceDashboardDemo.tsx +108 -0
- package/src/index.ts +68 -0
- package/src/models/ActionNotificationModel.ts +72 -0
- package/src/models/ConnectionManagerModel.ts +410 -0
- package/src/models/CredentialFormModel.ts +111 -0
- package/src/models/DashboardModel.ts +157 -0
- package/src/models/GitHostBrowserModel.ts +89 -0
- package/src/models/GitRepoBrowserModel.ts +285 -0
- package/src/models/ObjectStorageBrowserModel.ts +131 -0
- package/src/models/RepoPickerModel.ts +132 -0
- package/src/registry/service-registry.ts +46 -0
- package/src/registry/services/apple.ts +22 -0
- package/src/registry/services/bitbucket.ts +24 -0
- package/src/registry/services/box.ts +22 -0
- package/src/registry/services/browser-fs.ts +19 -0
- package/src/registry/services/dropbox.ts +22 -0
- package/src/registry/services/flickr.ts +22 -0
- package/src/registry/services/gitea.ts +24 -0
- package/src/registry/services/github.ts +24 -0
- package/src/registry/services/gitlab.ts +24 -0
- package/src/registry/services/google.ts +24 -0
- package/src/registry/services/icloud.ts +23 -0
- package/src/registry/services/indexeddb.ts +19 -0
- package/src/registry/services/instagram.ts +22 -0
- package/src/registry/services/microsoft.ts +24 -0
- package/src/registry/services/s3.ts +21 -0
- package/src/registry/services/webdav.ts +21 -0
- package/src/registry.ts +4 -0
- package/src/types/connection-state.ts +33 -0
- package/src/types/connection.ts +11 -0
- package/src/types/optional-deps.d.ts +149 -0
- package/src/types/service.ts +18 -0
- package/src/types/user-profile.ts +21 -0
- package/src/utils/action-toast.ts +53 -0
- package/src/utils/scope-labels.ts +91 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const bitbucketService: ServiceDefinition = {
|
|
4
|
+
id: 'bitbucket',
|
|
5
|
+
name: 'Bitbucket',
|
|
6
|
+
icon: 'GitBranch',
|
|
7
|
+
color: '#0052CC',
|
|
8
|
+
authProvider: 'bitbucket',
|
|
9
|
+
grantsUrl: 'https://bitbucket.org/account/settings/app-authorizations/',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: true },
|
|
14
|
+
{ id: 'git-host', supported: true },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['repository'],
|
|
21
|
+
'git-repo': ['repository'],
|
|
22
|
+
'git-host': ['repository', 'pullrequest'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const boxService: ServiceDefinition = {
|
|
4
|
+
id: 'box',
|
|
5
|
+
name: 'Box',
|
|
6
|
+
icon: 'Box',
|
|
7
|
+
color: '#0061D5',
|
|
8
|
+
authProvider: 'box',
|
|
9
|
+
grantsUrl: 'https://app.box.com/account/security',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['root_readwrite'],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const browserFsService: ServiceDefinition = {
|
|
4
|
+
id: 'browser-fs',
|
|
5
|
+
name: 'Local Files',
|
|
6
|
+
icon: 'FolderOpen',
|
|
7
|
+
color: '#4CAF50',
|
|
8
|
+
authProvider: 'browser-fs',
|
|
9
|
+
capabilities: [
|
|
10
|
+
{ id: 'file-system', supported: true },
|
|
11
|
+
{ id: 'object-storage', supported: false },
|
|
12
|
+
{ id: 'git-repo', supported: false },
|
|
13
|
+
{ id: 'git-host', supported: false },
|
|
14
|
+
{ id: 'media', supported: false },
|
|
15
|
+
{ id: 'contacts', supported: false },
|
|
16
|
+
{ id: 'calendar', supported: false },
|
|
17
|
+
],
|
|
18
|
+
scopes: {},
|
|
19
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const dropboxService: ServiceDefinition = {
|
|
4
|
+
id: 'dropbox',
|
|
5
|
+
name: 'Dropbox',
|
|
6
|
+
icon: 'Box',
|
|
7
|
+
color: '#0061FF',
|
|
8
|
+
authProvider: 'dropbox',
|
|
9
|
+
grantsUrl: 'https://www.dropbox.com/account/connected_apps',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['files.metadata.read', 'files.content.read', 'files.content.write'],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const flickrService: ServiceDefinition = {
|
|
4
|
+
id: 'flickr',
|
|
5
|
+
name: 'Flickr',
|
|
6
|
+
icon: 'Camera',
|
|
7
|
+
color: '#FF0084',
|
|
8
|
+
authProvider: 'flickr',
|
|
9
|
+
grantsUrl: 'https://www.flickr.com/auth/applications/',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: false },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: true },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'media': ['read'],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const giteaService: ServiceDefinition = {
|
|
4
|
+
id: 'gitea',
|
|
5
|
+
name: 'Gitea',
|
|
6
|
+
icon: 'GitBranch',
|
|
7
|
+
color: '#609926',
|
|
8
|
+
authProvider: 'gitea',
|
|
9
|
+
grantsUrl: 'https://gitea.io/en-us/user_settings/applications',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: true },
|
|
14
|
+
{ id: 'git-host', supported: true },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['read:repository'],
|
|
21
|
+
'git-repo': ['read:repository'],
|
|
22
|
+
'git-host': ['read:repository', 'read:user'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const githubService: ServiceDefinition = {
|
|
4
|
+
id: 'github',
|
|
5
|
+
name: 'GitHub',
|
|
6
|
+
icon: 'Github',
|
|
7
|
+
color: '#24292F',
|
|
8
|
+
authProvider: 'github',
|
|
9
|
+
grantsUrl: 'https://github.com/settings/applications',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: true },
|
|
14
|
+
{ id: 'git-host', supported: true },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['repo'],
|
|
21
|
+
'git-repo': ['repo'],
|
|
22
|
+
'git-host': ['repo'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const gitlabService: ServiceDefinition = {
|
|
4
|
+
id: 'gitlab',
|
|
5
|
+
name: 'GitLab',
|
|
6
|
+
icon: 'GitBranch',
|
|
7
|
+
color: '#FC6D26',
|
|
8
|
+
authProvider: 'gitlab',
|
|
9
|
+
grantsUrl: 'https://gitlab.com/-/user_settings/applications',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: true },
|
|
14
|
+
{ id: 'git-host', supported: true },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['read_api'],
|
|
21
|
+
'git-repo': ['read_api'],
|
|
22
|
+
'git-host': ['read_api'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const googleService: ServiceDefinition = {
|
|
4
|
+
id: 'google',
|
|
5
|
+
name: 'Google',
|
|
6
|
+
icon: 'Cloud',
|
|
7
|
+
color: '#4285F4',
|
|
8
|
+
authProvider: 'google',
|
|
9
|
+
grantsUrl: 'https://myaccount.google.com/permissions',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: true },
|
|
17
|
+
{ id: 'calendar', supported: true },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['https://www.googleapis.com/auth/drive'],
|
|
21
|
+
'calendar': ['https://www.googleapis.com/auth/calendar.readonly'],
|
|
22
|
+
'contacts': ['https://www.googleapis.com/auth/contacts.readonly'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const icloudService: ServiceDefinition = {
|
|
4
|
+
id: 'icloud',
|
|
5
|
+
name: 'iCloud',
|
|
6
|
+
icon: 'Cloud',
|
|
7
|
+
color: '#007AFF',
|
|
8
|
+
authProvider: 'icloud',
|
|
9
|
+
grantsUrl: 'https://appleid.apple.com/account/manage',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: false },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: true },
|
|
17
|
+
{ id: 'calendar', supported: true },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
contacts: [],
|
|
21
|
+
calendar: [],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const indexeddbService: ServiceDefinition = {
|
|
4
|
+
id: 'indexeddb',
|
|
5
|
+
name: 'IndexedDB',
|
|
6
|
+
icon: 'Database',
|
|
7
|
+
color: '#FF9800',
|
|
8
|
+
authProvider: 'indexeddb',
|
|
9
|
+
capabilities: [
|
|
10
|
+
{ id: 'file-system', supported: true },
|
|
11
|
+
{ id: 'object-storage', supported: false },
|
|
12
|
+
{ id: 'git-repo', supported: false },
|
|
13
|
+
{ id: 'git-host', supported: false },
|
|
14
|
+
{ id: 'media', supported: false },
|
|
15
|
+
{ id: 'contacts', supported: false },
|
|
16
|
+
{ id: 'calendar', supported: false },
|
|
17
|
+
],
|
|
18
|
+
scopes: {},
|
|
19
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const instagramService: ServiceDefinition = {
|
|
4
|
+
id: 'instagram',
|
|
5
|
+
name: 'Instagram',
|
|
6
|
+
icon: 'Camera',
|
|
7
|
+
color: '#E4405F',
|
|
8
|
+
authProvider: 'instagram',
|
|
9
|
+
grantsUrl: 'https://www.instagram.com/accounts/apps/',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: false },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: true },
|
|
16
|
+
{ id: 'contacts', supported: false },
|
|
17
|
+
{ id: 'calendar', supported: false },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'media': ['user_profile', 'user_media'],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const microsoftService: ServiceDefinition = {
|
|
4
|
+
id: 'microsoft',
|
|
5
|
+
name: 'Microsoft',
|
|
6
|
+
icon: 'AppWindow',
|
|
7
|
+
color: '#00A4EF',
|
|
8
|
+
authProvider: 'microsoft',
|
|
9
|
+
grantsUrl: 'https://account.live.com/consent/Manage',
|
|
10
|
+
capabilities: [
|
|
11
|
+
{ id: 'file-system', supported: true },
|
|
12
|
+
{ id: 'object-storage', supported: false },
|
|
13
|
+
{ id: 'git-repo', supported: false },
|
|
14
|
+
{ id: 'git-host', supported: false },
|
|
15
|
+
{ id: 'media', supported: false },
|
|
16
|
+
{ id: 'contacts', supported: true },
|
|
17
|
+
{ id: 'calendar', supported: true },
|
|
18
|
+
],
|
|
19
|
+
scopes: {
|
|
20
|
+
'file-system': ['Files.ReadWrite.All'],
|
|
21
|
+
'contacts': ['Contacts.Read'],
|
|
22
|
+
'calendar': ['Calendars.Read'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const s3Service: ServiceDefinition = {
|
|
4
|
+
id: 's3',
|
|
5
|
+
name: 'Amazon S3',
|
|
6
|
+
icon: 'Database',
|
|
7
|
+
color: '#FF9900',
|
|
8
|
+
authProvider: 's3',
|
|
9
|
+
capabilities: [
|
|
10
|
+
{ id: 'file-system', supported: false },
|
|
11
|
+
{ id: 'object-storage', supported: true },
|
|
12
|
+
{ id: 'git-repo', supported: false },
|
|
13
|
+
{ id: 'git-host', supported: false },
|
|
14
|
+
{ id: 'media', supported: false },
|
|
15
|
+
{ id: 'contacts', supported: false },
|
|
16
|
+
{ id: 'calendar', supported: false },
|
|
17
|
+
],
|
|
18
|
+
scopes: {
|
|
19
|
+
'object-storage': ['s3:GetObject', 's3:PutObject', 's3:ListBucket'],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ServiceDefinition } from '../../types/service';
|
|
2
|
+
|
|
3
|
+
export const webdavService: ServiceDefinition = {
|
|
4
|
+
id: 'webdav',
|
|
5
|
+
name: 'WebDAV',
|
|
6
|
+
icon: 'Server',
|
|
7
|
+
color: '#6B7280',
|
|
8
|
+
authProvider: 'webdav',
|
|
9
|
+
capabilities: [
|
|
10
|
+
{ id: 'file-system', supported: true },
|
|
11
|
+
{ id: 'object-storage', supported: false },
|
|
12
|
+
{ id: 'git-repo', supported: false },
|
|
13
|
+
{ id: 'git-host', supported: false },
|
|
14
|
+
{ id: 'media', supported: false },
|
|
15
|
+
{ id: 'contacts', supported: false },
|
|
16
|
+
{ id: 'calendar', supported: false },
|
|
17
|
+
],
|
|
18
|
+
scopes: {
|
|
19
|
+
'file-system': [],
|
|
20
|
+
},
|
|
21
|
+
};
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Registry-only entry point — no React, safe for server components
|
|
2
|
+
export type { CapabilityId, ServiceCapability, ServiceDefinition } from './types/service';
|
|
3
|
+
export { serviceRegistry } from './registry/service-registry';
|
|
4
|
+
export { getScopeLabels, getScopeLabel } from './utils/scope-labels';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { match } from 'ts-pattern';
|
|
2
|
+
import type { ConnectionManagerModel } from '../models/ConnectionManagerModel';
|
|
3
|
+
import type { IUserProfile } from './user-profile';
|
|
4
|
+
|
|
5
|
+
export type ServiceConnectionState =
|
|
6
|
+
| { status: 'loading' }
|
|
7
|
+
| { status: 'not_configured' }
|
|
8
|
+
| { status: 'disconnected' }
|
|
9
|
+
| { status: 'connecting' }
|
|
10
|
+
| { status: 'connected'; token: string; user: { name: string; image?: string } | null; profile: IUserProfile | undefined }
|
|
11
|
+
| { status: 'error'; error?: string }
|
|
12
|
+
| { status: 'expired' };
|
|
13
|
+
|
|
14
|
+
export function getServiceConnectionState(
|
|
15
|
+
connectionManager: ConnectionManagerModel,
|
|
16
|
+
serviceId: string
|
|
17
|
+
): ServiceConnectionState {
|
|
18
|
+
const status = connectionManager.getStatus(serviceId);
|
|
19
|
+
return match(status)
|
|
20
|
+
.with('loading', () => ({ status: 'loading' as const }))
|
|
21
|
+
.with('not_configured', () => ({ status: 'not_configured' as const }))
|
|
22
|
+
.with('disconnected', () => ({ status: 'disconnected' as const }))
|
|
23
|
+
.with('connecting', () => ({ status: 'connecting' as const }))
|
|
24
|
+
.with('connected', () => ({
|
|
25
|
+
status: 'connected' as const,
|
|
26
|
+
token: connectionManager.getToken(serviceId) ?? '',
|
|
27
|
+
user: connectionManager.getUserInfo(serviceId),
|
|
28
|
+
profile: connectionManager.getUserProfile(serviceId),
|
|
29
|
+
}))
|
|
30
|
+
.with('error', () => ({ status: 'error' as const }))
|
|
31
|
+
.with('expired', () => ({ status: 'expired' as const }))
|
|
32
|
+
.exhaustive();
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'expired' | 'error' | 'not_configured' | 'loading';
|
|
2
|
+
|
|
3
|
+
export interface ConnectedService {
|
|
4
|
+
serviceId: string;
|
|
5
|
+
status: ConnectionStatus;
|
|
6
|
+
accessToken?: string | undefined;
|
|
7
|
+
refreshToken?: string | undefined;
|
|
8
|
+
expiresAt?: number | undefined;
|
|
9
|
+
scopes: string[];
|
|
10
|
+
connectedAt?: Date;
|
|
11
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
declare module '@anymux/object-ui' {
|
|
2
|
+
import type { FC } from 'react';
|
|
3
|
+
import type { IMediaProvider } from '@anymux/object-ui/types/media';
|
|
4
|
+
import type { IContactProvider } from '@anymux/object-ui/types/contact';
|
|
5
|
+
import type { ICalendarProvider } from '@anymux/object-ui/types/calendar';
|
|
6
|
+
|
|
7
|
+
export const MediaBrowserDemo: FC;
|
|
8
|
+
export const ContactBrowserDemo: FC;
|
|
9
|
+
export const CalendarBrowserDemo: FC;
|
|
10
|
+
|
|
11
|
+
export class MediaBrowserModel {
|
|
12
|
+
constructor(provider: IMediaProvider);
|
|
13
|
+
}
|
|
14
|
+
export class ContactListModel {
|
|
15
|
+
constructor(provider: IContactProvider);
|
|
16
|
+
}
|
|
17
|
+
export class CalendarModel {
|
|
18
|
+
constructor(provider: ICalendarProvider);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const MediaBrowser: FC<{ model: MediaBrowserModel; provider: IMediaProvider; className?: string }>;
|
|
22
|
+
export const ContactBrowser: FC<{ model: ContactListModel; className?: string }>;
|
|
23
|
+
export const CalendarBrowser: FC<{ model: CalendarModel; className?: string }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare module '@anymux/google-drive' {
|
|
27
|
+
import type { IFileSystem } from '@anymux/file-system';
|
|
28
|
+
import type { IMediaProvider } from '@anymux/object-ui/types/media';
|
|
29
|
+
import type { IContactProvider } from '@anymux/object-ui/types/contact';
|
|
30
|
+
import type { ICalendarProvider } from '@anymux/object-ui/types/calendar';
|
|
31
|
+
|
|
32
|
+
export class GoogleDriveFileSystem implements IFileSystem {
|
|
33
|
+
constructor(config: { accessToken: string; rootFolderId?: string });
|
|
34
|
+
readdir(path: string): Promise<string[]>;
|
|
35
|
+
readFile(path: string): Promise<string>;
|
|
36
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
37
|
+
mkdir(path: string): Promise<void>;
|
|
38
|
+
stat(path: string): Promise<unknown>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class GooglePhotosMediaProvider implements IMediaProvider {
|
|
42
|
+
constructor(accessToken: string);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class GoogleContactsProvider implements IContactProvider {
|
|
46
|
+
constructor(accessToken: string);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class GoogleCalendarProvider implements ICalendarProvider {
|
|
50
|
+
constructor(accessToken: string);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare module '@anymux/dropbox' {
|
|
55
|
+
import type { IFileSystem } from '@anymux/file-system';
|
|
56
|
+
|
|
57
|
+
export class DropboxFileSystem implements IFileSystem {
|
|
58
|
+
constructor(config: { accessToken: string });
|
|
59
|
+
readdir(path: string): Promise<string[]>;
|
|
60
|
+
readFile(path: string): Promise<string>;
|
|
61
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
62
|
+
mkdir(path: string): Promise<void>;
|
|
63
|
+
stat(path: string): Promise<unknown>;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
declare module '@anymux/github' {
|
|
68
|
+
import type { IFileSystem, IGitRepo, IGitHost } from '@anymux/file-system';
|
|
69
|
+
|
|
70
|
+
export class GitHubFileSystem implements IFileSystem {
|
|
71
|
+
constructor(config: { token: string; owner: string; repo: string; branch?: string });
|
|
72
|
+
readdir(path: string): Promise<string[]>;
|
|
73
|
+
readFile(path: string): Promise<string>;
|
|
74
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
75
|
+
mkdir(path: string): Promise<void>;
|
|
76
|
+
stat(path: string): Promise<unknown>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class GitHubGitRepo implements IGitRepo {
|
|
80
|
+
constructor(config: { token: string; owner: string; repo: string });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class GitHubGitHost implements IGitHost {
|
|
84
|
+
constructor(config: { token: string; owner: string; repo: string });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare module '@anymux/s3' {
|
|
89
|
+
import type { IObjectStorage } from '@anymux/file-system';
|
|
90
|
+
|
|
91
|
+
export class S3ObjectStorage implements IObjectStorage {
|
|
92
|
+
constructor(config: {
|
|
93
|
+
region: string;
|
|
94
|
+
endpoint?: string;
|
|
95
|
+
credentials?: { accessKeyId: string; secretAccessKey: string };
|
|
96
|
+
forcePathStyle?: boolean;
|
|
97
|
+
bucket?: string;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare module '@anymux/webdav' {
|
|
103
|
+
import type { IFileSystem } from '@anymux/file-system';
|
|
104
|
+
|
|
105
|
+
export class WebDAVFileSystem implements IFileSystem {
|
|
106
|
+
constructor(config: { url: string; username?: string; password?: string });
|
|
107
|
+
readdir(path: string): Promise<string[]>;
|
|
108
|
+
readFile(path: string): Promise<string>;
|
|
109
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
110
|
+
mkdir(path: string): Promise<void>;
|
|
111
|
+
stat(path: string): Promise<unknown>;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
declare module '@anymux/icloud' {
|
|
116
|
+
import type { ICalendarProvider } from '@anymux/object-ui/types/calendar';
|
|
117
|
+
import type { IContactProvider } from '@anymux/object-ui/types/contact';
|
|
118
|
+
|
|
119
|
+
export interface ICloudCredentials {
|
|
120
|
+
email: string;
|
|
121
|
+
appPassword: string;
|
|
122
|
+
proxyUrl?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class ICloudCalendarProvider implements ICalendarProvider {
|
|
126
|
+
constructor(credentials: ICloudCredentials);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class ICloudContactsProvider implements IContactProvider {
|
|
130
|
+
constructor(credentials: ICloudCredentials);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare module '@anymux/flickr' {
|
|
135
|
+
import type { IMediaProvider } from '@anymux/object-ui/types/media';
|
|
136
|
+
|
|
137
|
+
export interface FlickrClientConfig {
|
|
138
|
+
apiKey: string;
|
|
139
|
+
accessToken?: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class FlickrMediaProvider implements IMediaProvider {
|
|
143
|
+
constructor(config: FlickrClientConfig);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export class FlickrClient {
|
|
147
|
+
constructor(config: FlickrClientConfig);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type CapabilityId = 'file-system' | 'object-storage' | 'git-repo' | 'git-host' | 'media' | 'contacts' | 'calendar';
|
|
2
|
+
|
|
3
|
+
export interface ServiceCapability {
|
|
4
|
+
id: CapabilityId;
|
|
5
|
+
supported: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ServiceDefinition {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
icon: string;
|
|
12
|
+
color: string;
|
|
13
|
+
authProvider: string;
|
|
14
|
+
capabilities: ServiceCapability[];
|
|
15
|
+
scopes: Partial<Record<CapabilityId, string[]>>;
|
|
16
|
+
/** URL to the provider's app permissions/grants page where users can manage access */
|
|
17
|
+
grantsUrl?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized user profile from any OAuth provider or credential-based service.
|
|
3
|
+
* Each connected service produces its own IUserProfile, so a user who connects
|
|
4
|
+
* both GitHub and Google will have two profiles with different avatars, names, etc.
|
|
5
|
+
*/
|
|
6
|
+
export interface IUserProfile {
|
|
7
|
+
/** Provider-specific user id (e.g. GitHub numeric id, Google sub) */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Display name from the provider */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Email associated with this provider account */
|
|
12
|
+
email?: string;
|
|
13
|
+
/** Avatar / profile picture URL */
|
|
14
|
+
avatarUrl?: string;
|
|
15
|
+
/** Link to the user's profile on the provider (e.g. github.com/user) */
|
|
16
|
+
profileUrl?: string;
|
|
17
|
+
/** AnyMux service id (e.g. 'github', 'google-drive') */
|
|
18
|
+
provider: string;
|
|
19
|
+
/** Raw provider-specific data for future use */
|
|
20
|
+
raw?: Record<string, unknown>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { toast } from 'sonner';
|
|
2
|
+
import type { ActionNotificationModel, ActionType } from '../models/ActionNotificationModel';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Show a toast notification for a user action, with optional undo.
|
|
6
|
+
* Records the action in the ActionNotificationModel for history.
|
|
7
|
+
*/
|
|
8
|
+
export function showActionToast(
|
|
9
|
+
model: ActionNotificationModel,
|
|
10
|
+
type: ActionType,
|
|
11
|
+
description: string,
|
|
12
|
+
options?: {
|
|
13
|
+
undo?: () => Promise<void>;
|
|
14
|
+
/** Duration in ms before auto-dismiss. Default 5000. */
|
|
15
|
+
duration?: number;
|
|
16
|
+
},
|
|
17
|
+
): string {
|
|
18
|
+
const actionId = model.record(type, description, options?.undo);
|
|
19
|
+
|
|
20
|
+
if (options?.undo) {
|
|
21
|
+
toast(description, {
|
|
22
|
+
duration: options.duration ?? 5000,
|
|
23
|
+
action: {
|
|
24
|
+
label: 'Undo',
|
|
25
|
+
onClick: async () => {
|
|
26
|
+
try {
|
|
27
|
+
await options.undo!();
|
|
28
|
+
model.markUndone(actionId);
|
|
29
|
+
toast.success('Action undone');
|
|
30
|
+
} catch (err) {
|
|
31
|
+
toast.error(`Undo failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
toast.success(description, {
|
|
38
|
+
duration: options?.duration ?? 3000,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return actionId;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Show an error toast */
|
|
46
|
+
export function showErrorToast(message: string, context?: string) {
|
|
47
|
+
toast.error(context ? `${context}: ${message}` : message);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Show an info toast */
|
|
51
|
+
export function showInfoToast(message: string) {
|
|
52
|
+
toast.info(message);
|
|
53
|
+
}
|