react-native-cloud-storage 0.7.0 → 1.0.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 (57) hide show
  1. package/README.md +0 -2
  2. package/ios/CloudStorage.swift +95 -76
  3. package/lib/commonjs/RNCloudStorage.js +19 -14
  4. package/lib/commonjs/RNCloudStorage.js.map +1 -1
  5. package/lib/commonjs/expo-plugin/types/index.js +2 -0
  6. package/lib/commonjs/expo-plugin/types/index.js.map +1 -0
  7. package/lib/commonjs/expo-plugin/withRNCloudStorage.js +1 -1
  8. package/lib/commonjs/expo-plugin/withRNCloudStorage.js.map +1 -1
  9. package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js +3 -3
  10. package/lib/commonjs/expo-plugin/withRNCloudStorageIos.js.map +1 -1
  11. package/lib/commonjs/google-drive/index.js +5 -0
  12. package/lib/commonjs/google-drive/index.js.map +1 -1
  13. package/lib/commonjs/hooks/useCloudFile.js +14 -3
  14. package/lib/commonjs/hooks/useCloudFile.js.map +1 -1
  15. package/lib/commonjs/types/native.js +1 -1
  16. package/lib/commonjs/utils/helpers.js +23 -0
  17. package/lib/commonjs/utils/helpers.js.map +1 -0
  18. package/lib/module/RNCloudStorage.js +19 -14
  19. package/lib/module/RNCloudStorage.js.map +1 -1
  20. package/lib/module/expo-plugin/types/index.js +2 -0
  21. package/lib/module/expo-plugin/types/index.js.map +1 -0
  22. package/lib/module/expo-plugin/withRNCloudStorage.js +1 -2
  23. package/lib/module/expo-plugin/withRNCloudStorage.js.map +1 -1
  24. package/lib/module/expo-plugin/withRNCloudStorageIos.js +3 -3
  25. package/lib/module/expo-plugin/withRNCloudStorageIos.js.map +1 -1
  26. package/lib/module/google-drive/index.js +5 -0
  27. package/lib/module/google-drive/index.js.map +1 -1
  28. package/lib/module/hooks/useCloudFile.js +15 -3
  29. package/lib/module/hooks/useCloudFile.js.map +1 -1
  30. package/lib/module/types/native.js +1 -1
  31. package/lib/module/utils/helpers.js +16 -0
  32. package/lib/module/utils/helpers.js.map +1 -0
  33. package/lib/typescript/RNCloudStorage.d.ts +17 -15
  34. package/lib/typescript/RNCloudStorage.d.ts.map +1 -1
  35. package/lib/typescript/expo-plugin/types/index.d.ts +7 -0
  36. package/lib/typescript/expo-plugin/types/index.d.ts.map +1 -0
  37. package/lib/typescript/expo-plugin/withRNCloudStorage.d.ts +1 -6
  38. package/lib/typescript/expo-plugin/withRNCloudStorage.d.ts.map +1 -1
  39. package/lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts +3 -2
  40. package/lib/typescript/expo-plugin/withRNCloudStorageIos.d.ts.map +1 -1
  41. package/lib/typescript/google-drive/index.d.ts.map +1 -1
  42. package/lib/typescript/hooks/useCloudFile.d.ts +13 -2
  43. package/lib/typescript/hooks/useCloudFile.d.ts.map +1 -1
  44. package/lib/typescript/types/native.d.ts +1 -1
  45. package/lib/typescript/types/native.d.ts.map +1 -1
  46. package/lib/typescript/utils/helpers.d.ts +10 -0
  47. package/lib/typescript/utils/helpers.d.ts.map +1 -0
  48. package/package.json +24 -20
  49. package/react-native-cloud-storage.podspec +7 -1
  50. package/src/RNCloudStorage.ts +26 -22
  51. package/src/expo-plugin/types/index.ts +6 -0
  52. package/src/expo-plugin/withRNCloudStorage.ts +2 -7
  53. package/src/expo-plugin/withRNCloudStorageIos.ts +8 -10
  54. package/src/google-drive/index.ts +11 -0
  55. package/src/hooks/useCloudFile.ts +14 -3
  56. package/src/types/native.ts +1 -1
  57. package/src/utils/helpers.ts +17 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-cloud-storage",
3
- "version": "0.7.0",
3
+ "version": "1.0.1",
4
4
  "description": "Save to & read from iCloud and Google Drive using React Native",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -29,34 +29,35 @@
29
29
  ],
30
30
  "scripts": {
31
31
  "test": "jest",
32
+ "example": "yarn workspace react-native-cloud-storage-example",
33
+ "docs": "yarn workspace react-native-cloud-storage-docs",
32
34
  "typecheck": "tsc --noEmit",
33
35
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
34
- "prepack": "bob build",
35
- "release": "release-it",
36
- "example": "yarn --cwd example",
37
- "docs": "yarn --cwd docs",
38
- "bootstrap": "yarn example && yarn docs && yarn install && yarn example pods",
39
- "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build"
36
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
37
+ "prepare": "bob build",
38
+ "release": "release-it"
40
39
  },
41
40
  "keywords": [
42
41
  "react-native",
43
42
  "ios",
44
43
  "android"
45
44
  ],
46
- "repository": "https://github.com/kuatsu/react-native-cloud-storage",
47
- "author": "Kuatsu Digital Agency <hello@kuatsu.de> (https://github.com/kuatsu)",
45
+ "repository": "https://github.com/Kuatsu/react-native-cloud-storage",
46
+ "author": "Kuatsu App Agency <hello@kuatsu.de> (https://github.com/Kuatsu)",
48
47
  "license": "MIT",
49
48
  "bugs": {
50
- "url": "https://github.com/kuatsu/react-native-cloud-storage/issues"
49
+ "url": "https://github.com/Kuatsu/react-native-cloud-storage/issues"
51
50
  },
52
- "homepage": "https://github.com/kuatsu/react-native-cloud-storage#readme",
51
+ "homepage": "https://github.com/Kuatsu/react-native-cloud-storage#readme",
53
52
  "publishConfig": {
54
53
  "registry": "https://registry.npmjs.org/"
55
54
  },
56
55
  "devDependencies": {
57
56
  "@commitlint/config-conventional": "^17.0.2",
58
- "@evilmartians/lefthook": "^1.2.2",
59
- "@react-native-community/eslint-config": "^3.0.2",
57
+ "@evilmartians/lefthook": "^1.5.0",
58
+ "@expo/config-plugins": "^7.2.5",
59
+ "@react-native-community/eslint-config": "^3.2.0",
60
+ "@react-native/eslint-config": "^0.72.2",
60
61
  "@release-it/conventional-changelog": "^5.0.0",
61
62
  "@types/jest": "^28.1.2",
62
63
  "@types/react": "~17.0.21",
@@ -66,21 +67,20 @@
66
67
  "eslint": "^8.4.1",
67
68
  "eslint-config-prettier": "^8.5.0",
68
69
  "eslint-plugin-prettier": "^4.0.0",
69
- "expo": "^47.0.0",
70
70
  "jest": "^28.1.1",
71
71
  "pod-install": "^0.1.0",
72
72
  "prettier": "^2.0.5",
73
73
  "react": "18.2.0",
74
- "react-native": "0.71.6",
75
- "react-native-builder-bob": "^0.20.4",
74
+ "react-native": "0.72.5",
75
+ "react-native-builder-bob": "^0.20.0",
76
76
  "release-it": "^15.0.0",
77
- "typescript": "^4.5.2"
77
+ "typescript": "^5.0.2"
78
78
  },
79
79
  "resolutions": {
80
80
  "@types/react": "17.0.21"
81
81
  },
82
82
  "peerDependencies": {
83
- "expo": ">=47.0.0",
83
+ "expo": ">=48.0.0",
84
84
  "react": "*",
85
85
  "react-native": "*"
86
86
  },
@@ -89,10 +89,14 @@
89
89
  "optional": true
90
90
  }
91
91
  },
92
+ "workspaces": [
93
+ "example",
94
+ "docs"
95
+ ],
92
96
  "engines": {
93
- "node": ">= 16.0.0"
97
+ "node": ">= 18.0.0"
94
98
  },
95
- "packageManager": "^yarn@1.22.15",
99
+ "packageManager": "yarn@3.6.1",
96
100
  "jest": {
97
101
  "preset": "react-native",
98
102
  "modulePathIgnorePatterns": [
@@ -12,10 +12,15 @@ Pod::Spec.new do |s|
12
12
  s.authors = package["author"]
13
13
 
14
14
  s.platforms = { :ios => "11.0" }
15
- s.source = { :git => "https://github.com/kuatsu/react-native-cloud-storage.git", :tag => "#{s.version}" }
15
+ s.source = { :git => "https://github.com/Kuatsu/react-native-cloud-storage.git", :tag => "#{s.version}" }
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
18
 
19
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
21
+ if respond_to?(:install_modules_dependencies, true)
22
+ install_modules_dependencies(s)
23
+ else
19
24
  s.dependency "React-Core"
20
25
 
21
26
  # Don't install the dependencies when we run `pod install` in the old architecture.
@@ -31,5 +36,6 @@ Pod::Spec.new do |s|
31
36
  s.dependency "RCTRequired"
32
37
  s.dependency "RCTTypeSafety"
33
38
  s.dependency "ReactCommon/turbomodule/core"
39
+ end
34
40
  end
35
41
  end
@@ -1,11 +1,15 @@
1
1
  import createRNCloudStorage from './createRNCloudStorage';
2
2
  import GoogleDriveApiClient from './google-drive';
3
- import type { CloudStorageFileStat, CloudStorageScope } from './types/main';
3
+ import { type CloudStorageFileStat, CloudStorageScope } from './types/main';
4
4
  import { Platform } from 'react-native';
5
+ import { verifyLeadingSlash } from './utils/helpers';
5
6
 
6
7
  const nativeInstance = createRNCloudStorage();
8
+ let defaultScope = CloudStorageScope.AppData;
7
9
 
8
10
  const RNCloudStorage = {
11
+ getDefaultScope: () => defaultScope,
12
+ setDefaultScope: (scope: CloudStorageScope) => (defaultScope = scope),
9
13
  getGoogleDriveAccessToken: () => GoogleDriveApiClient.accessToken,
10
14
  setGoogleDriveAccessToken: (accessToken: string) => (GoogleDriveApiClient.accessToken = accessToken),
11
15
  setThrowOnFilesWithSameName: (enable: boolean) => (GoogleDriveApiClient.throwOnFilesWithSameName = enable),
@@ -29,72 +33,72 @@ const RNCloudStorage = {
29
33
  /**
30
34
  * Tests whether or not the file at the given path exists.
31
35
  * @param path The path to test.
32
- * @param scope The directory scope the path is in.
36
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
33
37
  * @returns A promise that resolves to true if the path exists, false otherwise.
34
38
  */
35
- exists: (path: string, scope: CloudStorageScope): Promise<boolean> => {
36
- return nativeInstance.fileExists(path, scope);
39
+ exists: (path: string, scope?: CloudStorageScope): Promise<boolean> => {
40
+ return nativeInstance.fileExists(verifyLeadingSlash(path), scope ?? defaultScope);
37
41
  },
38
42
 
39
43
  /**
40
44
  * Writes to the file at the given path, creating it if it doesn't exist or overwriting it if it does.
41
45
  * @param path The file to write to.
42
46
  * @param data The data to write.
43
- * @param scope The directory scope the path is in.
47
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
44
48
  * @returns A promise that resolves when the file has been written.
45
49
  */
46
- writeFile: (path: string, data: string, scope: CloudStorageScope): Promise<void> => {
47
- return nativeInstance.createFile(path, data, scope, true);
50
+ writeFile: (path: string, data: string, scope?: CloudStorageScope): Promise<void> => {
51
+ return nativeInstance.createFile(verifyLeadingSlash(path), data, scope ?? defaultScope, true);
48
52
  },
49
53
 
50
54
  /**
51
55
  * Creates a new directory at the given path.
52
56
  * @param path The directory to create.
53
- * @param scope The directory scope the path is in.
57
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
54
58
  * @returns A promise that resolves when the directory has been created.
55
59
  */
56
- mkdir: (path: string, scope: CloudStorageScope): Promise<void> => {
57
- return nativeInstance.createDirectory(path, scope);
60
+ mkdir: (path: string, scope?: CloudStorageScope): Promise<void> => {
61
+ return nativeInstance.createDirectory(verifyLeadingSlash(path), scope ?? defaultScope);
58
62
  },
59
63
 
60
64
  /**
61
65
  * Lists the contents of the directory at the given path.
62
66
  * @param path The directory to list.
63
- * @param scope The directory scope the path is in.
67
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
64
68
  * @returns A promise that resolves to an array of file names, excluding '.' and '..'.
65
69
  */
66
- readdir: (path: string, scope: CloudStorageScope): Promise<string[]> => {
67
- return nativeInstance.listFiles(path, scope);
70
+ readdir: (path: string, scope?: CloudStorageScope): Promise<string[]> => {
71
+ return nativeInstance.listFiles(verifyLeadingSlash(path), scope ?? defaultScope);
68
72
  },
69
73
 
70
74
  /**
71
75
  * Reads the contents of the file at the given path.
72
76
  * @param path The file to read.
73
- * @param scope The directory scope the path is in.
77
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
74
78
  * @returns A promise that resolves to the contents of the file.
75
79
  */
76
- readFile: (path: string, scope: CloudStorageScope): Promise<string> => {
77
- return nativeInstance.readFile(path, scope);
80
+ readFile: (path: string, scope?: CloudStorageScope): Promise<string> => {
81
+ return nativeInstance.readFile(verifyLeadingSlash(path), scope ?? defaultScope);
78
82
  },
79
83
 
80
84
  /**
81
85
  * Deletes the file at the given path.
82
86
  * @param path The file to delete.
83
- * @param scope The directory scope the path is in.
87
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
84
88
  * @returns A promise that resolves when the file has been deleted.
85
89
  */
86
- unlink: (path: string, scope: CloudStorageScope): Promise<void> => {
87
- return nativeInstance.deleteFile(path, scope);
90
+ unlink: (path: string, scope?: CloudStorageScope): Promise<void> => {
91
+ return nativeInstance.deleteFile(verifyLeadingSlash(path), scope ?? defaultScope);
88
92
  },
89
93
 
90
94
  /**
91
95
  * Gets the size, creation time, and modification time of the file at the given path.
92
96
  * @param path The file to stat.
93
- * @param scope The directory scope the path is in.
97
+ * @param scope The directory scope the path is in. Defaults to the set default scope.
94
98
  * @returns A promise that resolves to the CloudStorageFileStat object.
95
99
  */
96
- stat: async (path: string, scope: CloudStorageScope): Promise<CloudStorageFileStat> => {
97
- const native = await nativeInstance.statFile(path, scope);
100
+ stat: async (path: string, scope?: CloudStorageScope): Promise<CloudStorageFileStat> => {
101
+ const native = await nativeInstance.statFile(verifyLeadingSlash(path), scope ?? defaultScope);
98
102
 
99
103
  return {
100
104
  ...native,
@@ -0,0 +1,6 @@
1
+ export interface RNCloudStorageConfigPluginOptions {
2
+ /**
3
+ * The iCloud container environment to use. Defaults to 'Production'.
4
+ */
5
+ iCloudContainerEnvironment?: 'Production' | 'Development';
6
+ }
@@ -1,15 +1,10 @@
1
+ import type { RNCloudStorageConfigPluginOptions } from './types';
1
2
  import withRNCloudStorageIos from './withRNCloudStorageIos';
2
3
  import type { ConfigPlugin } from '@expo/config-plugins';
3
4
 
4
5
  // Android config plugin not needed as there's no native code to configure.
5
6
 
6
- interface RNCloudStorageConfigPluginOptions {
7
- /**
8
- * The iCloud container environment to use. Defaults to 'Production'.
9
- */
10
- iCloudContainerEnvironment?: 'Production' | 'Development';
11
- }
12
7
  const withRNCloudStorage: ConfigPlugin<RNCloudStorageConfigPluginOptions> = (config, options) =>
13
- withRNCloudStorageIos(config, options?.iCloudContainerEnvironment ?? 'Production');
8
+ withRNCloudStorageIos(config, options);
14
9
 
15
10
  export default withRNCloudStorage;
@@ -1,7 +1,7 @@
1
- import { withEntitlementsPlist, withInfoPlist, withPlugins } from '@expo/config-plugins';
2
- import type { ExpoConfig } from 'expo/config';
1
+ import { withEntitlementsPlist, withInfoPlist, withPlugins, type ConfigPlugin } from '@expo/config-plugins';
2
+ import type { RNCloudStorageConfigPluginOptions } from './types';
3
3
 
4
- const withRNCloudStorageInfoPlist = (config: ExpoConfig) =>
4
+ const withRNCloudStorageInfoPlist: ConfigPlugin = (config) =>
5
5
  withInfoPlist(config, async (newConfig) => {
6
6
  if (!config.ios?.bundleIdentifier) {
7
7
  throw new Error('Missing iOS bundle identifier');
@@ -18,10 +18,7 @@ const withRNCloudStorageInfoPlist = (config: ExpoConfig) =>
18
18
  return newConfig;
19
19
  });
20
20
 
21
- const withRNCloudStorageEntitlementsPlist = (
22
- config: ExpoConfig,
23
- iCloudContainerEnvironment: 'Production' | 'Development'
24
- ) =>
21
+ const withRNCloudStorageEntitlementsPlist: ConfigPlugin<RNCloudStorageConfigPluginOptions> = (config, options) =>
25
22
  withEntitlementsPlist(config, async (newConfig) => {
26
23
  if (!config.ios?.bundleIdentifier) {
27
24
  throw new Error('Missing iOS bundle identifier');
@@ -29,7 +26,8 @@ const withRNCloudStorageEntitlementsPlist = (
29
26
  const entitlementsPlist = newConfig.modResults;
30
27
  entitlementsPlist['com.apple.developer.icloud-container-identifiers'] = [`iCloud.${config.ios.bundleIdentifier}`];
31
28
  entitlementsPlist['com.apple.developer.icloud-services'] = ['CloudDocuments'];
32
- entitlementsPlist['com.apple.developer.icloud-container-environment'] = iCloudContainerEnvironment;
29
+ entitlementsPlist['com.apple.developer.icloud-container-environment'] =
30
+ options?.iCloudContainerEnvironment ?? 'Production';
33
31
  entitlementsPlist['com.apple.developer.ubiquity-container-identifiers'] = [`iCloud.${config.ios.bundleIdentifier}`];
34
32
  entitlementsPlist[
35
33
  'com.apple.developer.ubiquity-kvstore-identifier'
@@ -38,7 +36,7 @@ const withRNCloudStorageEntitlementsPlist = (
38
36
  return newConfig;
39
37
  });
40
38
 
41
- const withRNCloudStorageIos = (config: ExpoConfig, iCloudContainerEnvironment: 'Production' | 'Development') =>
42
- withPlugins(config, [withRNCloudStorageInfoPlist, [withRNCloudStorageEntitlementsPlist, iCloudContainerEnvironment]]);
39
+ const withRNCloudStorageIos: ConfigPlugin<RNCloudStorageConfigPluginOptions> = (config, options) =>
40
+ withPlugins(config, [withRNCloudStorageInfoPlist, [withRNCloudStorageEntitlementsPlist, options]]);
43
41
 
44
42
  export default withRNCloudStorageIos;
@@ -178,6 +178,17 @@ export default class GoogleDriveApiClient implements NativeRNCloudStorage {
178
178
  ): Promise<string> {
179
179
  try {
180
180
  const files = await this.listInternalFiles(scope);
181
+
182
+ if (path === '' || path === '/') {
183
+ const rootDirectoryId = await this.getRootDirectoryId(scope);
184
+ if (!rootDirectoryId)
185
+ throw new CloudStorageError(
186
+ `Root directory in scope ${scope} not found`,
187
+ CloudStorageErrorCode.DIRECTORY_NOT_FOUND
188
+ );
189
+ return rootDirectoryId;
190
+ }
191
+
181
192
  const { directories, filename } = this.resolvePathToDirectories(path);
182
193
  const parentDirectoryId = this.findParentDirectoryId(files, directories);
183
194
  let file: GoogleDriveFile | undefined;
@@ -2,7 +2,13 @@ import type { CloudStorageScope } from '../types/main';
2
2
  import RNCloudStorage from '../RNCloudStorage';
3
3
  import { useCallback, useEffect, useState } from 'react';
4
4
 
5
- export const useCloudFile = (path: string, scope: CloudStorageScope) => {
5
+ /**
6
+ * A utility hook for reading and writing to a single file in the cloud.
7
+ * @param path The path to the file.
8
+ * @param scope The directory scope the path is in. If not provided, defaults to the default scope set in the library.
9
+ * @returns An object containing the file's contents and functions for reading, writing, and removing the file.
10
+ */
11
+ export const useCloudFile = (path: string, scope?: CloudStorageScope) => {
6
12
  const [content, setContent] = useState<string | null>(null);
7
13
 
8
14
  const read = useCallback(async () => {
@@ -18,7 +24,7 @@ export const useCloudFile = (path: string, scope: CloudStorageScope) => {
18
24
  read();
19
25
  }, [read]);
20
26
 
21
- const update = useCallback(
27
+ const write = useCallback(
22
28
  async (newContent: string) => {
23
29
  await RNCloudStorage.writeFile(path, newContent, scope);
24
30
  read();
@@ -34,7 +40,12 @@ export const useCloudFile = (path: string, scope: CloudStorageScope) => {
34
40
  return {
35
41
  content,
36
42
  read,
37
- update,
43
+ write,
38
44
  remove,
45
+ /**
46
+ * @deprecated Use `write` instead.
47
+ * @alias write
48
+ */
49
+ update: write,
39
50
  };
40
51
  };
@@ -11,7 +11,7 @@ export interface NativeRNCloudCloudStorageFileStat {
11
11
  export enum CloudStorageErrorCode {
12
12
  FILE_NOT_FOUND = 'ERR_FILE_NOT_FOUND',
13
13
  PATH_IS_DIRECTORY = 'ERR_PATH_IS_DIRECTORY',
14
- DIRECTORY_NOT_FOUND = 'ERR_NO_DIRECTORY_FOUND',
14
+ DIRECTORY_NOT_FOUND = 'ERR_DIRECTORY_NOT_FOUND',
15
15
  FILE_ALREADY_EXISTS = 'ERR_FILE_EXISTS',
16
16
  MULTIPLE_FILES_SAME_NAME = 'ERR_MULTIPLE_FILES_SAME_NAME',
17
17
  AUTHENTICATION_FAILED = 'ERR_AUTHENTICATION_FAILED',
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Checks if the path starts with a leading slash and adds one if it doesn't to maintain backwards compatibility.
3
+ * Will log a warning to the console if it had to add a leading slash. Will throw an error in the future.
4
+ *
5
+ * @param path The path to check.
6
+ * @returns The path with a leading slash, if it didn't have one already.
7
+ * @private
8
+ */
9
+ export const verifyLeadingSlash = (path: string) => {
10
+ if (!path.startsWith('/')) {
11
+ console.warn(
12
+ `[react-native-cloud-storage] Path "${path}" did not start with a leading slash. This is deprecated and will be an error in the future.`
13
+ );
14
+ return `/${path}`;
15
+ }
16
+ return path;
17
+ };