react-native-cloud-storage 0.1.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.
- package/LICENSE +20 -0
- package/README.md +33 -0
- package/app.plugin.js +1 -0
- package/ios/CloudStorage-Bridging-Header.h +2 -0
- package/ios/CloudStorage.m +19 -0
- package/ios/CloudStorage.swift +98 -0
- package/ios/CloudStorage.xcodeproj/project.pbxproj +283 -0
- package/lib/commonjs/RNCloudStorage.js +53 -0
- package/lib/commonjs/RNCloudStorage.js.map +1 -0
- package/lib/commonjs/createRNCloudStorage.js +27 -0
- package/lib/commonjs/createRNCloudStorage.js.map +1 -0
- package/lib/commonjs/expo-plugin/withRNCloudStorage.js +14 -0
- package/lib/commonjs/expo-plugin/withRNCloudStorage.js.map +1 -0
- package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js +39 -0
- package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js.map +1 -0
- package/lib/commonjs/google-drive/index.js +150 -0
- package/lib/commonjs/google-drive/index.js.map +1 -0
- package/lib/commonjs/google-drive/types.js +2 -0
- package/lib/commonjs/google-drive/types.js.map +1 -0
- package/lib/commonjs/hooks/useCloudFile.js +39 -0
- package/lib/commonjs/hooks/useCloudFile.js.map +1 -0
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types/main.js +13 -0
- package/lib/commonjs/types/main.js.map +1 -0
- package/lib/commonjs/types/native.js +2 -0
- package/lib/commonjs/types/native.js.map +1 -0
- package/lib/module/RNCloudStorage.js +45 -0
- package/lib/module/RNCloudStorage.js.map +1 -0
- package/lib/module/createRNCloudStorage.js +20 -0
- package/lib/module/createRNCloudStorage.js.map +1 -0
- package/lib/module/expo-plugin/withRNCloudStorage.js +7 -0
- package/lib/module/expo-plugin/withRNCloudStorage.js.map +1 -0
- package/lib/module/expo-plugin/withRNCloudStorageIos.js +32 -0
- package/lib/module/expo-plugin/withRNCloudStorageIos.js.map +1 -0
- package/lib/module/google-drive/index.js +143 -0
- package/lib/module/google-drive/index.js.map +1 -0
- package/lib/module/google-drive/types.js +2 -0
- package/lib/module/google-drive/types.js.map +1 -0
- package/lib/module/hooks/useCloudFile.js +31 -0
- package/lib/module/hooks/useCloudFile.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types/main.js +6 -0
- package/lib/module/types/main.js.map +1 -0
- package/lib/module/types/native.js +2 -0
- package/lib/module/types/native.js.map +1 -0
- package/lib/typescript/RNCloudStorage.d.ts +35 -0
- package/lib/typescript/RNCloudStorage.d.ts.map +1 -0
- package/lib/typescript/createRNCloudStorage.d.ts +3 -0
- package/lib/typescript/createRNCloudStorage.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withRNCloudStorage.d.ts +10 -0
- package/lib/typescript/expo-plugin/withRNCloudStorage.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts +4 -0
- package/lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts.map +1 -0
- package/lib/typescript/google-drive/index.d.ts +19 -0
- package/lib/typescript/google-drive/index.d.ts.map +1 -0
- package/lib/typescript/google-drive/types.d.ts +54 -0
- package/lib/typescript/google-drive/types.d.ts.map +1 -0
- package/lib/typescript/hooks/useCloudFile.d.ts +8 -0
- package/lib/typescript/hooks/useCloudFile.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +5 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types/main.d.ts +5 -0
- package/lib/typescript/types/main.d.ts.map +1 -0
- package/lib/typescript/types/native.d.ts +8 -0
- package/lib/typescript/types/native.d.ts.map +1 -0
- package/package.json +186 -0
- package/react-native-cloud-storage.podspec +35 -0
- package/src/RNCloudStorage.ts +50 -0
- package/src/createRNCloudStorage.ts +31 -0
- package/src/expo-plugin/withRNCloudStorage.ts +15 -0
- package/src/expo-plugin/withRNCloudStorageIos.ts +44 -0
- package/src/google-drive/index.ts +163 -0
- package/src/google-drive/types.ts +61 -0
- package/src/hooks/useCloudFile.ts +40 -0
- package/src/index.ts +5 -0
- package/src/types/main.ts +4 -0
- package/src/types/native.ts +8 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { GDrive, MimeTypes } from 'react-native-google-drive-api-wrapper-js';
|
|
2
|
+
import type NativeRNCloudStorage from '../types/native';
|
|
3
|
+
import type { NativeRNCloudStorageScope } from '../types/native';
|
|
4
|
+
import type { GoogleDriveFile, GoogleDriveListOperationResponse } from './types';
|
|
5
|
+
|
|
6
|
+
class GoogleDriveApiClient implements NativeRNCloudStorage {
|
|
7
|
+
private static drive: GDrive = new GDrive();
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
GoogleDriveApiClient.drive.fetchTimeout = 3000;
|
|
11
|
+
return new Proxy(this, {
|
|
12
|
+
// before calling any function, check if the access token is set
|
|
13
|
+
get(target: GoogleDriveApiClient, prop: keyof GoogleDriveApiClient) {
|
|
14
|
+
if (typeof target[prop] === 'function') {
|
|
15
|
+
if (!GoogleDriveApiClient.drive.accessToken) {
|
|
16
|
+
throw new Error(`Google Drive access token is not set, cannot call function ${prop.toString()}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return target[prop];
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// when setting accessToken, set it on the GDrive instance
|
|
26
|
+
public static set accessToken(accessToken: string) {
|
|
27
|
+
GoogleDriveApiClient.drive.accessToken = accessToken;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static get accessToken(): string {
|
|
31
|
+
return GoogleDriveApiClient.drive.accessToken;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private getRootDirectory(scope: NativeRNCloudStorageScope): 'drive' | 'appDataFolder' {
|
|
35
|
+
switch (scope) {
|
|
36
|
+
case 'documents':
|
|
37
|
+
return 'drive';
|
|
38
|
+
case 'hidden':
|
|
39
|
+
return 'appDataFolder';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private resolvePathToDirectories(path: string): { directories: string[]; filename: string } {
|
|
44
|
+
if (path.startsWith('/')) path = path.slice(1);
|
|
45
|
+
if (path.endsWith('/')) path = path.slice(0, -1);
|
|
46
|
+
const directories = path.split('/');
|
|
47
|
+
const actualFilename = directories.pop() ?? '';
|
|
48
|
+
return { directories, filename: actualFilename };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private findParentDirectoryId(files: GoogleDriveFile[], directoryTree: string[]): string | null {
|
|
52
|
+
const possibleTopDirectories = files
|
|
53
|
+
.filter((f) => f.mimeType === MimeTypes.FOLDER)
|
|
54
|
+
.filter((f) => f.name === directoryTree[0]);
|
|
55
|
+
|
|
56
|
+
let topDirectoryId: string | undefined;
|
|
57
|
+
if (possibleTopDirectories.length === 0) return null;
|
|
58
|
+
else if (possibleTopDirectories.length === 1) {
|
|
59
|
+
topDirectoryId = possibleTopDirectories[0]!.id;
|
|
60
|
+
} else {
|
|
61
|
+
/* when multiple directories carry the same name, we need to check every one of them if their parent id exists in
|
|
62
|
+
the files array - if it does not, it means that the directory is a child of the root directory and the one we're
|
|
63
|
+
looking for */
|
|
64
|
+
for (const possibleTopDirectory of possibleTopDirectories) {
|
|
65
|
+
if (!files.find((f) => f.id === possibleTopDirectory!.parents![0] && f.mimeType === MimeTypes.FOLDER)) {
|
|
66
|
+
topDirectoryId = possibleTopDirectory!.id;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!topDirectoryId) {
|
|
73
|
+
throw new Error(`Could not find top directory with name ${directoryTree[0]}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// now, we traverse the directories array and get the id of the last directory from the files array
|
|
77
|
+
let currentDirectoryId = topDirectoryId;
|
|
78
|
+
for (let i = 1; i < directoryTree.length; i++) {
|
|
79
|
+
const currentDirectory = files.find((f) => f.id === currentDirectoryId);
|
|
80
|
+
if (!currentDirectory) throw new Error(`Could not find directory with id ${currentDirectoryId}`);
|
|
81
|
+
const nextDirectory = files.find((f) => f.name === directoryTree[i] && f.parents![0] === currentDirectoryId);
|
|
82
|
+
if (!nextDirectory) throw new Error(`Could not find directory with name ${directoryTree[i]}`);
|
|
83
|
+
currentDirectoryId = nextDirectory.id;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return currentDirectoryId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async listFiles(scope: NativeRNCloudStorageScope): Promise<GoogleDriveFile[]> {
|
|
90
|
+
const files: GoogleDriveListOperationResponse = await GoogleDriveApiClient.drive.files.list({
|
|
91
|
+
spaces: [this.getRootDirectory(scope)],
|
|
92
|
+
fields: 'files(id,kind,mimeType,name,parents,spaces)',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return files.files;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private async getFileId(path: string, scope: NativeRNCloudStorageScope): Promise<string> {
|
|
99
|
+
const files = await this.listFiles(scope);
|
|
100
|
+
const { directories, filename } = this.resolvePathToDirectories(path);
|
|
101
|
+
const parentDirectoryId = this.findParentDirectoryId(files, directories);
|
|
102
|
+
let file: GoogleDriveFile | undefined;
|
|
103
|
+
if (parentDirectoryId === null) {
|
|
104
|
+
/* when the file is supposes to be in the root directory, we need to get the file where the name is the filename
|
|
105
|
+
and the first parent has an id which does not exist in the files array */
|
|
106
|
+
file = files.find((f) => f.name === filename && !files.find((f2) => f2.id === f.parents![0]));
|
|
107
|
+
} else {
|
|
108
|
+
file = files.find((f) => f.name === filename && f.parents![0] === parentDirectoryId);
|
|
109
|
+
}
|
|
110
|
+
if (!file) throw new Error(`File not found`);
|
|
111
|
+
return file.id;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async fileExists(path: string, scope: NativeRNCloudStorageScope): Promise<boolean> {
|
|
115
|
+
try {
|
|
116
|
+
await this.getFileId(path, scope);
|
|
117
|
+
return true;
|
|
118
|
+
} catch (e: any) {
|
|
119
|
+
if (e.message === 'File not found') return false;
|
|
120
|
+
else throw e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async createFile(path: string, data: string, scope: NativeRNCloudStorageScope, overwrite: boolean): Promise<void> {
|
|
125
|
+
let fileId: string | undefined;
|
|
126
|
+
if (overwrite) {
|
|
127
|
+
try {
|
|
128
|
+
fileId = await this.getFileId(path, scope);
|
|
129
|
+
} catch (e: any) {
|
|
130
|
+
/* do nothing, simply create the file */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const uploader = GoogleDriveApiClient.drive.files.newMultipartUploader().setData(data, MimeTypes.TEXT);
|
|
134
|
+
if (fileId) uploader.setIdOfFileToUpdate(fileId);
|
|
135
|
+
else {
|
|
136
|
+
const files = await this.listFiles(scope);
|
|
137
|
+
const { directories, filename } = this.resolvePathToDirectories(path);
|
|
138
|
+
const parentDirectoryId = this.findParentDirectoryId(files, directories);
|
|
139
|
+
uploader.setRequestBody({
|
|
140
|
+
name: filename,
|
|
141
|
+
parents: parentDirectoryId
|
|
142
|
+
? [parentDirectoryId]
|
|
143
|
+
: scope === 'hidden'
|
|
144
|
+
? [this.getRootDirectory(scope)]
|
|
145
|
+
: undefined,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
await uploader.execute();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async readFile(path: string, scope: NativeRNCloudStorageScope): Promise<string> {
|
|
152
|
+
const fileId = await this.getFileId(path, scope);
|
|
153
|
+
const content = await GoogleDriveApiClient.drive.files.getText(fileId);
|
|
154
|
+
return content;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async deleteFile(path: string, scope: NativeRNCloudStorageScope): Promise<void> {
|
|
158
|
+
const fileId = await this.getFileId(path, scope);
|
|
159
|
+
await GoogleDriveApiClient.drive.files.delete(fileId);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export default GoogleDriveApiClient;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface GoogleDriveFile {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: 'drive#file';
|
|
4
|
+
mimeType: string;
|
|
5
|
+
name: string;
|
|
6
|
+
parents: string[];
|
|
7
|
+
spaces: ('appDataFolder' | 'drive')[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface GoogleDriveListOperationQueryParameters {
|
|
11
|
+
corpora?: 'user' | 'drive' | 'domain' | 'allDrives';
|
|
12
|
+
driveId?: string;
|
|
13
|
+
fields?: string;
|
|
14
|
+
includeItemsFromAllDrives?: boolean;
|
|
15
|
+
includePermissionsForView?: 'published';
|
|
16
|
+
// comma-separated list of 'createdTime' | 'folder' | 'modifiedByMeTime' | 'modifiedTime' | 'name' | 'name_natural' | 'quotaBytesUsed' | 'recency' | 'sharedWithMeTime' | 'starred' | 'viewedByMeTime'
|
|
17
|
+
orderBy?: string;
|
|
18
|
+
pageSize?: number;
|
|
19
|
+
pageToken?: string;
|
|
20
|
+
q?: string;
|
|
21
|
+
// comma-separated list of 'appDataFolder' | 'drive' | 'photos'
|
|
22
|
+
spaces?: string;
|
|
23
|
+
supportsAllDrives?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface GoogleDriveListOperationResponse {
|
|
27
|
+
files: GoogleDriveFile[];
|
|
28
|
+
incompleteSearch: boolean;
|
|
29
|
+
kind: 'drive#fileList';
|
|
30
|
+
nextPageToken: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface GoogleDriveDeleteOperationQueryParameters {
|
|
34
|
+
supportsAllDrives?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface GoogleDriveGetOperationQueryParameters {
|
|
38
|
+
acknowledgeAbuse?: boolean;
|
|
39
|
+
fields?: string;
|
|
40
|
+
includeLabels?: string;
|
|
41
|
+
includePermissionsForView?: 'published';
|
|
42
|
+
supportsAllDrives?: boolean;
|
|
43
|
+
alt?: 'media';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GoogleDriveCreateOperationRequestBody {
|
|
47
|
+
name?: string;
|
|
48
|
+
mimeType?: string;
|
|
49
|
+
parents?: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface GoogleDriveCreateOperationQueryParameters {
|
|
53
|
+
uploadType: 'media' | 'multipart' | 'resumable';
|
|
54
|
+
ignoreDefaultVisibility?: boolean;
|
|
55
|
+
includeLabels?: string;
|
|
56
|
+
includePermissionsForView?: 'published';
|
|
57
|
+
keepRevisionForever?: boolean;
|
|
58
|
+
ocrLanguage?: string;
|
|
59
|
+
supportsAllDrives?: boolean;
|
|
60
|
+
useContentAsIndexableText?: boolean;
|
|
61
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { StorageScope } from '../types/main';
|
|
2
|
+
import RNCloudStorage from '../RNCloudStorage';
|
|
3
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export const useCloudFile = (path: string, scope: StorageScope) => {
|
|
6
|
+
const [content, setContent] = useState<string | null>(null);
|
|
7
|
+
|
|
8
|
+
const read = useCallback(async () => {
|
|
9
|
+
const exists = await RNCloudStorage.exists(path, scope);
|
|
10
|
+
if (!exists) {
|
|
11
|
+
setContent(null);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
RNCloudStorage.readFile(path, scope).then(setContent);
|
|
15
|
+
}, [path, scope]);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
read();
|
|
19
|
+
}, [read]);
|
|
20
|
+
|
|
21
|
+
const update = useCallback(
|
|
22
|
+
async (newContent: string) => {
|
|
23
|
+
await RNCloudStorage.writeFile(path, newContent, scope);
|
|
24
|
+
read();
|
|
25
|
+
},
|
|
26
|
+
[path, scope, read]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const remove = useCallback(async () => {
|
|
30
|
+
await RNCloudStorage.unlink(path, scope);
|
|
31
|
+
setContent(null);
|
|
32
|
+
}, [path, scope]);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
content,
|
|
36
|
+
read,
|
|
37
|
+
update,
|
|
38
|
+
remove,
|
|
39
|
+
};
|
|
40
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type NativeRNCloudStorageScope = 'documents' | 'hidden';
|
|
2
|
+
|
|
3
|
+
export default interface NativeRNCloudStorage {
|
|
4
|
+
fileExists: (path: string, scope: NativeRNCloudStorageScope) => Promise<boolean>;
|
|
5
|
+
createFile: (path: string, data: string, scope: NativeRNCloudStorageScope, overwrite: boolean) => Promise<void>;
|
|
6
|
+
readFile: (path: string, scope: NativeRNCloudStorageScope) => Promise<string>;
|
|
7
|
+
deleteFile: (path: string, scope: NativeRNCloudStorageScope) => Promise<void>;
|
|
8
|
+
}
|