@cetapod/react-native-smb 1.0.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.
Files changed (137) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +72 -0
  3. package/ReactNativeSmb.podspec +59 -0
  4. package/cpp/ios/OnLoad.mm +24 -0
  5. package/cpp/shared/HybridSMB.cpp +324 -0
  6. package/cpp/shared/HybridSMB.hpp +102 -0
  7. package/cpp/shared/ReactNativeSmb.hpp +428 -0
  8. package/cpp/shared/connection/ContextRequest.hpp +27 -0
  9. package/cpp/shared/connection/ContextRequestQueue.cpp +85 -0
  10. package/cpp/shared/connection/ContextRequestQueue.hpp +28 -0
  11. package/cpp/shared/connection/MetadataContextLease.hpp +33 -0
  12. package/cpp/shared/connection/PoolContextHandle.cpp +35 -0
  13. package/cpp/shared/connection/PoolContextHandle.hpp +44 -0
  14. package/cpp/shared/connection/PoolSlot.cpp +73 -0
  15. package/cpp/shared/connection/PoolSlot.hpp +46 -0
  16. package/cpp/shared/connection/PoolTypes.hpp +41 -0
  17. package/cpp/shared/connection/SmbConnection.cpp +385 -0
  18. package/cpp/shared/connection/SmbConnection.hpp +93 -0
  19. package/cpp/shared/connection/SmbConnectionPool.cpp +316 -0
  20. package/cpp/shared/connection/SmbConnectionPool.hpp +84 -0
  21. package/cpp/shared/core/CancellationToken.hpp +22 -0
  22. package/cpp/shared/core/OperatorContext.hpp +24 -0
  23. package/cpp/shared/core/SmbEnums.hpp +126 -0
  24. package/cpp/shared/core/SmbTask.cpp +131 -0
  25. package/cpp/shared/core/SmbTask.hpp +52 -0
  26. package/cpp/shared/core/SmbTaskCore.cpp +222 -0
  27. package/cpp/shared/core/SmbTaskCore.hpp +107 -0
  28. package/cpp/shared/core/SmbTypes.hpp +35 -0
  29. package/cpp/shared/core/TaskObserverHub.cpp +166 -0
  30. package/cpp/shared/core/TaskObserverHub.hpp +66 -0
  31. package/cpp/shared/core/TaskSnapshotCodec.cpp +32 -0
  32. package/cpp/shared/core/TaskSnapshotCodec.hpp +41 -0
  33. package/cpp/shared/io/SmbCopyTree.hpp +114 -0
  34. package/cpp/shared/io/SmbDirScan.hpp +80 -0
  35. package/cpp/shared/io/SmbFileIO.cpp +1355 -0
  36. package/cpp/shared/io/SmbFileIO.hpp +45 -0
  37. package/cpp/shared/io/SmbPathUtil.hpp +75 -0
  38. package/cpp/shared/io/SmbSecurity.cpp +308 -0
  39. package/cpp/shared/io/SmbSecurity.hpp +32 -0
  40. package/cpp/shared/io/SmbTreeOps.hpp +112 -0
  41. package/cpp/shared/operators/Operator.hpp +35 -0
  42. package/cpp/shared/operators/OperatorBase.cpp +57 -0
  43. package/cpp/shared/operators/OperatorBase.hpp +57 -0
  44. package/cpp/shared/operators/connection/ConnectOperator.cpp +19 -0
  45. package/cpp/shared/operators/connection/ConnectOperator.hpp +22 -0
  46. package/cpp/shared/operators/connection/ConnectShareOperator.cpp +19 -0
  47. package/cpp/shared/operators/connection/ConnectShareOperator.hpp +21 -0
  48. package/cpp/shared/operators/connection/DisconnectOperator.cpp +12 -0
  49. package/cpp/shared/operators/connection/DisconnectOperator.hpp +15 -0
  50. package/cpp/shared/operators/connection/InitializeOperator.cpp +12 -0
  51. package/cpp/shared/operators/connection/InitializeOperator.hpp +22 -0
  52. package/cpp/shared/operators/connection/ListSharesOperator.cpp +13 -0
  53. package/cpp/shared/operators/connection/ListSharesOperator.hpp +18 -0
  54. package/cpp/shared/operators/listing/GetPathInfoOperator.cpp +43 -0
  55. package/cpp/shared/operators/listing/GetPathInfoOperator.hpp +21 -0
  56. package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.cpp +202 -0
  57. package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.hpp +22 -0
  58. package/cpp/shared/operators/listing/ListDirectoryOperator.cpp +20 -0
  59. package/cpp/shared/operators/listing/ListDirectoryOperator.hpp +24 -0
  60. package/cpp/shared/operators/mutate/CopyItemOperator.cpp +19 -0
  61. package/cpp/shared/operators/mutate/CopyItemOperator.hpp +25 -0
  62. package/cpp/shared/operators/mutate/CreateDirectoryOperator.cpp +28 -0
  63. package/cpp/shared/operators/mutate/CreateDirectoryOperator.hpp +20 -0
  64. package/cpp/shared/operators/mutate/DeleteItemOperator.cpp +96 -0
  65. package/cpp/shared/operators/mutate/DeleteItemOperator.hpp +23 -0
  66. package/cpp/shared/operators/mutate/DuplicateItemOperator.cpp +48 -0
  67. package/cpp/shared/operators/mutate/DuplicateItemOperator.hpp +23 -0
  68. package/cpp/shared/operators/mutate/MoveItemOperator.cpp +32 -0
  69. package/cpp/shared/operators/mutate/MoveItemOperator.hpp +21 -0
  70. package/cpp/shared/operators/mutate/RenameItemOperator.cpp +37 -0
  71. package/cpp/shared/operators/mutate/RenameItemOperator.hpp +21 -0
  72. package/cpp/shared/operators/transfer/DownloadFileOperator.cpp +31 -0
  73. package/cpp/shared/operators/transfer/DownloadFileOperator.hpp +21 -0
  74. package/cpp/shared/operators/transfer/UploadFileOperator.cpp +27 -0
  75. package/cpp/shared/operators/transfer/UploadFileOperator.hpp +21 -0
  76. package/cpp/shared/util/SmbErrorMapper.hpp +229 -0
  77. package/cpp/shared/util/SmbLog.hpp +20 -0
  78. package/docs/API.md +105 -0
  79. package/docs/ARCHITECTURE.md +70 -0
  80. package/docs/TASK_MODEL.md +149 -0
  81. package/ios/include/smb2/libsmb2-dcerpc-lsa.h +172 -0
  82. package/ios/include/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  83. package/ios/include/smb2/libsmb2-dcerpc.h +155 -0
  84. package/ios/include/smb2/libsmb2-raw.h +497 -0
  85. package/ios/include/smb2/libsmb2.h +1384 -0
  86. package/ios/include/smb2/smb2-errors.h +549 -0
  87. package/ios/include/smb2/smb2.h +1251 -0
  88. package/ios/libs/device/libsmb2-device.a +0 -0
  89. package/ios/libs/libsmb2.xcframework/Info.plist +48 -0
  90. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
  91. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  92. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc.h +155 -0
  93. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-raw.h +497 -0
  94. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2.h +1384 -0
  95. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2-errors.h +549 -0
  96. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2.h +1251 -0
  97. package/ios/libs/libsmb2.xcframework/ios-arm64/libsmb2.a +0 -0
  98. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
  99. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  100. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc.h +155 -0
  101. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-raw.h +497 -0
  102. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2.h +1384 -0
  103. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2-errors.h +549 -0
  104. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2.h +1251 -0
  105. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/libsmb2.a +0 -0
  106. package/ios/libs/simulator/libsmb2-simulator.a +0 -0
  107. package/lib/ReactNativeSmb.d.ts +200 -0
  108. package/lib/ReactNativeSmb.js +1 -0
  109. package/lib/bridge/decode.d.ts +4 -0
  110. package/lib/bridge/decode.js +92 -0
  111. package/lib/core/SMB.d.ts +3 -0
  112. package/lib/core/SMB.js +4 -0
  113. package/lib/core/SmbClient.d.ts +35 -0
  114. package/lib/core/SmbClient.js +99 -0
  115. package/lib/core/SmbTask.d.ts +41 -0
  116. package/lib/core/SmbTask.js +74 -0
  117. package/lib/core/TransferStore.d.ts +22 -0
  118. package/lib/core/TransferStore.js +88 -0
  119. package/lib/core/ids.d.ts +1 -0
  120. package/lib/core/ids.js +3 -0
  121. package/lib/core/taskResult.d.ts +3 -0
  122. package/lib/core/taskResult.js +52 -0
  123. package/lib/hooks/useSubscribe.d.ts +20 -0
  124. package/lib/hooks/useSubscribe.js +36 -0
  125. package/lib/hooks/useTransfers.d.ts +7 -0
  126. package/lib/hooks/useTransfers.js +29 -0
  127. package/lib/index.d.ts +7 -0
  128. package/lib/index.js +7 -0
  129. package/lib/labels.d.ts +6 -0
  130. package/lib/labels.js +71 -0
  131. package/lib/types.d.ts +141 -0
  132. package/lib/types.js +59 -0
  133. package/lib/utils.d.ts +79 -0
  134. package/lib/utils.js +153 -0
  135. package/package.json +63 -0
  136. package/scripts/build-libsmb2.sh +143 -0
  137. package/scripts/create-xcframework.sh +84 -0
@@ -0,0 +1,200 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+ import type { SmbCredentials, NativeSmbTask } from './types';
3
+ /**
4
+ * A Nitro module that provides SMB client functionality using libsmb2
5
+ *
6
+ * This interface provides low-level access to SMB operations with proper
7
+ * TypeScript typing for React Native applications.
8
+ */
9
+ export interface ReactNativeSmb extends HybridObject<{
10
+ ios: 'c++';
11
+ android: 'c++';
12
+ }> {
13
+ /**
14
+ * Checks connection status
15
+ * @returns True if currently connected to an SMB server
16
+ */
17
+ isConnected(): boolean;
18
+ /**
19
+ * Checks if the SMB client is initialized
20
+ * @returns True if initialized, false otherwise
21
+ */
22
+ isInitialized(): boolean;
23
+ /**
24
+ * Initializes connection to an SMB server (without connecting to a specific share)
25
+ * @param url Server URL (e.g., "smb://server-ip")
26
+ * @param credentials Authentication credentials
27
+ * @returns SmbTask that resolves when initialized
28
+ */
29
+ initialize(taskId: string, url: string, credentials: SmbCredentials): NativeSmbTask;
30
+ /**
31
+ * Establishes a connection to an SMB server
32
+ * @param url The SMB server URL (e.g., "smb://server-ip/share")
33
+ * @param credentials Authentication credentials
34
+ * @returns SmbTask with connection information
35
+ * @throws {Error} When connection fails
36
+ *
37
+ * @example
38
+ * await smb.connect('smb://192.168.1.100', {
39
+ * username: 'admin',
40
+ * password: 'secret'
41
+ * });
42
+ */
43
+ connect(taskId: string, url: string, credentials: SmbCredentials): NativeSmbTask;
44
+ /**
45
+ * Connects to a specific share
46
+ * @param share Name of the share to connect to
47
+ * @returns SmbTask that resolves when connected
48
+ * @throws {Error} If not initialized or share doesn't exist
49
+ */
50
+ connectShare(taskId: string, share: string): NativeSmbTask;
51
+ /**
52
+ * Disconnects from the current SMB server
53
+ * @returns SmbTask that resolves when disconnected
54
+ */
55
+ disconnect(taskId: string): NativeSmbTask;
56
+ /**
57
+ * Lists available shares on the server
58
+ * @returns SmbTask resolving to array of share information
59
+ * @throws {Error} If not initialized
60
+ *
61
+ * @example
62
+ * const shares = await smb.listShares();
63
+ * shares.forEach(share => console.log(share.name));
64
+ */
65
+ listShares(taskId: string): NativeSmbTask;
66
+ /**
67
+ * Lists contents of a directory
68
+ * @param path Directory path (use "/" for root)
69
+ * @param recursive Whether to list recursively (default: false)
70
+ * @param maxDepth Maximum recursion depth (-1 = unlimited, 0 = current only)
71
+ * @param taskId Unique ID for the task
72
+ * @param onStatusChange Callback for status updates
73
+ * @param onProgress Callback for progress updates
74
+ * @returns SmbTask resolving to array of file/directory info
75
+ */
76
+ listDirectory(taskId: string, path: string, recursive: boolean, maxDepth: number): NativeSmbTask;
77
+ /**
78
+ * Gets detailed information about a path (file or directory).
79
+ * Generic version that handles both file/directory types.
80
+ * @param path Path to the item
81
+ * @param taskId Unique ID for the task
82
+ * @param onStatusChange Callback for status updates
83
+ * @param onProgress Callback for progress updates
84
+ * @returns SmbTask resolving to file information
85
+ */
86
+ getPathInfo(taskId: string, path: string): NativeSmbTask;
87
+ /**
88
+ * Retrieves security descriptor for a file/directory
89
+ * @param path Path to the item
90
+ * @param taskId Unique ID for the task
91
+ * @returns SmbTask resolving to security descriptor
92
+ *
93
+ * @example
94
+ * const security = await smb.getSecurityDescriptor('/important.txt');
95
+ * console.log('Owner:', security.ownerSid);
96
+ */
97
+ getSecurityDescriptor(taskId: string, path: string): NativeSmbTask;
98
+ downloadFile(taskId: string, remotePath: string, localPath: string): NativeSmbTask;
99
+ /**
100
+ * Uploads a file from local storage to the SMB server
101
+ * @param localPath Local path to the file
102
+ * @param remotePath Destination path on the server
103
+ * @param progressHandler Optional callback to track upload progress
104
+ * @returns SmbTask that resolves when upload completes
105
+ */
106
+ uploadFile(taskId: string, localPath: string, remotePath: string): NativeSmbTask;
107
+ /**
108
+ * Creates a new directory
109
+ * @param path Path of the directory to create
110
+ * @returns SmbTask that resolves when directory is created
111
+ */
112
+ createDirectory(taskId: string, path: string): NativeSmbTask;
113
+ /**
114
+ * Deletes a file or directory (automatically handles recursive deletion)
115
+ * @param path Path to the item to delete
116
+ * @returns SmbTask that resolves when deletion completes
117
+ */
118
+ deleteItem(taskId: string, path: string): NativeSmbTask;
119
+ /**
120
+ * Moves or renames a file/directory
121
+ * @param fromPath Current path
122
+ * @param toPath New path
123
+ * @returns SmbTask that resolves when move completes
124
+ */
125
+ moveItem(taskId: string, fromPath: string, toPath: string): NativeSmbTask;
126
+ /**
127
+ * Renames a file/directory (in the same directory)
128
+ * @param currentPath Current path
129
+ * @param newName New name (without path)
130
+ * @returns SmbTask that resolves when rename completes
131
+ */
132
+ renameItem(taskId: string, currentPath: string, newName: string): NativeSmbTask;
133
+ /**
134
+ * Copies a file or directory on the SMB server
135
+ * @param fromPath Source path
136
+ * @param toPath Destination path
137
+ * @param recursive Whether to copy recursively
138
+ * @param taskId Unique ID for the task
139
+ * @param onStatusChange Callback for status updates
140
+ * @param onProgress Callback for progress updates
141
+ */
142
+ copyItem(taskId: string, fromPath: string, toPath: string, recursive: boolean): NativeSmbTask;
143
+ /**
144
+ * Duplicates an item giving it a unique name
145
+ * @param path Path to the item
146
+ * @returns SmbTask resolving to the new path
147
+ */
148
+ duplicateItem(taskId: string, path: string): NativeSmbTask;
149
+ /**
150
+ * Subscribe to task events (created, status, progress, settled, removed)
151
+ * @param listener Callback that receives task events
152
+ * @returns Subscription ID for unsubscribing
153
+ */
154
+ subscribeTaskEvents(listener: (event: Record<string, string>) => void): string;
155
+ /**
156
+ * Unsubscribe from task events
157
+ * @param subscriptionId The subscription ID returned from subscribeTaskEvents
158
+ */
159
+ unsubscribeTaskEvents(subscriptionId: string): void;
160
+ /**
161
+ * Get a specific task snapshot by ID
162
+ * @param taskId The task ID to retrieve
163
+ * @returns Task snapshot as string-keyed map, or {exists: '0'} if not found
164
+ */
165
+ getTask(taskId: string): Record<string, string>;
166
+ /**
167
+ * Get all currently active (pending/running) tasks
168
+ * @returns Array of task snapshots
169
+ */
170
+ getActiveTasks(): Array<Record<string, string>>;
171
+ /**
172
+ * Get task history (settled tasks)
173
+ * @param limit Maximum number of tasks to return
174
+ * @param offset Number of tasks to skip
175
+ * @returns Array of task snapshots
176
+ */
177
+ getTaskHistory(limit: number, offset: number): Array<Record<string, string>>;
178
+ /**
179
+ * Cancels a specific task by ID
180
+ */
181
+ cancelTask(taskId: string): void;
182
+ /**
183
+ * Clear task history
184
+ * @param beforeTs Clear tasks that ended before this timestamp (0 = clear all)
185
+ */
186
+ clearTaskHistory(beforeTs: bigint): void;
187
+ subscribePoolInfo(listener: (snapshot: Array<{
188
+ [key: string]: string;
189
+ }>) => void): string;
190
+ unsubscribePoolInfo(subscriptionId: string): void;
191
+ getPoolInfo(): Array<{
192
+ [key: string]: string;
193
+ }>;
194
+ /**
195
+ * Force-disconnects every connection-pool slot and forgets cached config.
196
+ * Use for recovery when slots become stuck (`isConnected:false` but
197
+ * `inUse:true`). Subsequent operations must re-connect from scratch.
198
+ */
199
+ resetPool(): void;
200
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { TaskStatus, type PoolInfo, type SmbTaskState } from '../types';
2
+ export declare function shapeTaskSnapshot(raw: Record<string, string>): SmbTaskState | null;
3
+ export declare function shapePoolInfo(raw: Array<Record<string, string>>): PoolInfo;
4
+ export declare function terminalStatus(raw: Record<string, string>): TaskStatus | null;
@@ -0,0 +1,92 @@
1
+ import { SmbOperatorKind, SlotState, TaskStatus, } from '../types';
2
+ function parseIntField(raw, key) {
3
+ const v = raw[key];
4
+ if (v === undefined || v === '') {
5
+ throw new Error(`Missing bridge field: ${key}`);
6
+ }
7
+ const n = parseInt(v, 10);
8
+ if (!Number.isFinite(n)) {
9
+ throw new Error(`Invalid bridge field ${key}: ${v}`);
10
+ }
11
+ return n;
12
+ }
13
+ function parseIntOptional(raw, key, fallback = 0) {
14
+ const v = raw[key];
15
+ if (v === undefined || v === '')
16
+ return fallback;
17
+ const n = parseInt(v, 10);
18
+ return Number.isFinite(n) ? n : fallback;
19
+ }
20
+ function parseFloatField(raw, key, fallback = 0) {
21
+ const v = raw[key];
22
+ if (v === undefined || v === '')
23
+ return fallback;
24
+ const n = parseFloat(v);
25
+ return Number.isFinite(n) ? n : fallback;
26
+ }
27
+ function parseBoolField(raw, key) {
28
+ const v = raw[key];
29
+ return v === '1' || v === 'true';
30
+ }
31
+ function enumFromInt(value, enumObj) {
32
+ const valid = Object.values(enumObj).filter((v) => typeof v === 'number');
33
+ if (valid.includes(value)) {
34
+ return value;
35
+ }
36
+ throw new Error(`Invalid enum value: ${value}`);
37
+ }
38
+ export function shapeTaskSnapshot(raw) {
39
+ if (raw.exists === '0')
40
+ return null;
41
+ const kind = enumFromInt(parseIntField(raw, 'kind'), SmbOperatorKind);
42
+ const status = enumFromInt(parseIntField(raw, 'status'), TaskStatus);
43
+ return {
44
+ taskId: raw.taskId ?? '',
45
+ kind,
46
+ status,
47
+ determinate: parseBoolField(raw, 'determinate'),
48
+ progress: parseFloatField(raw, 'progress'),
49
+ bytesDone: parseIntOptional(raw, 'bytesDone'),
50
+ totalBytes: parseIntOptional(raw, 'totalBytes'),
51
+ bytesPerSecond: parseFloatField(raw, 'bytesPerSecond'),
52
+ etaSeconds: parseFloatField(raw, 'etaSeconds'),
53
+ sourcePath: raw.sourcePath ?? '',
54
+ destinationPath: raw.destinationPath ?? '',
55
+ errorCode: parseIntOptional(raw, 'errorCode'),
56
+ errorMessage: raw.errorMessage ?? '',
57
+ startedAt: parseIntOptional(raw, 'startedAt'),
58
+ updatedAt: parseIntOptional(raw, 'updatedAt'),
59
+ endedAt: parseIntOptional(raw, 'endedAt'),
60
+ };
61
+ }
62
+ function shapePoolSlot(raw) {
63
+ return {
64
+ index: parseIntField(raw, 'index'),
65
+ interactiveOnly: parseBoolField(raw, 'interactiveOnly'),
66
+ state: enumFromInt(parseIntField(raw, 'state'), SlotState),
67
+ isConnected: parseBoolField(raw, 'isConnected'),
68
+ shareName: raw.shareName ?? '',
69
+ taskId: raw.taskId ?? '',
70
+ kind: enumFromInt(parseIntField(raw, 'kind'), SmbOperatorKind),
71
+ };
72
+ }
73
+ export function shapePoolInfo(raw) {
74
+ if (!raw || raw.length === 0)
75
+ return { poolSize: 0, slots: [] };
76
+ const poolSize = parseIntField(raw[0], 'poolSize');
77
+ return {
78
+ poolSize,
79
+ slots: raw.map(shapePoolSlot),
80
+ };
81
+ }
82
+ export function terminalStatus(raw) {
83
+ if (raw.exists === '0')
84
+ return null;
85
+ const status = enumFromInt(parseIntField(raw, 'status'), TaskStatus);
86
+ if (status === TaskStatus.Success ||
87
+ status === TaskStatus.Error ||
88
+ status === TaskStatus.Cancelled) {
89
+ return status;
90
+ }
91
+ return null;
92
+ }
@@ -0,0 +1,3 @@
1
+ import { SmbClient } from './SmbClient';
2
+ export declare function SMB(): SmbClient;
3
+ export type Smb = SmbClient;
@@ -0,0 +1,4 @@
1
+ import { SmbClient } from './SmbClient';
2
+ export function SMB() {
3
+ return new SmbClient();
4
+ }
@@ -0,0 +1,35 @@
1
+ import type { ReactNativeSmb } from '../ReactNativeSmb';
2
+ import type { PoolInfo, SmbConnectionInfo, SmbCredentials, SmbFileInfo, SmbSecurityDescriptor, SmbShareList } from '../types';
3
+ import { SmbTask } from './SmbTask';
4
+ import { TransferStore } from './TransferStore';
5
+ export declare class SmbClient {
6
+ private readonly native;
7
+ private transfers_?;
8
+ constructor(native?: ReactNativeSmb);
9
+ private op;
10
+ transferStore(): TransferStore;
11
+ dispose(): void;
12
+ isConnected(): boolean;
13
+ isInitialized(): boolean;
14
+ initialize(url: string, creds: SmbCredentials): SmbTask<void>;
15
+ connect(url: string, creds: SmbCredentials): SmbTask<SmbConnectionInfo>;
16
+ connectShare(share: string): SmbTask<SmbConnectionInfo>;
17
+ disconnect(): SmbTask<void>;
18
+ listShares(): SmbTask<SmbShareList[]>;
19
+ listDirectory(path: string, recursive?: boolean, maxDepth?: number): SmbTask<SmbFileInfo[]>;
20
+ getPathInfo(path: string): SmbTask<SmbFileInfo>;
21
+ getSecurityDescriptor(path: string): SmbTask<SmbSecurityDescriptor>;
22
+ downloadFile(remotePath: string, localPath: string): SmbTask<void>;
23
+ uploadFile(localPath: string, remotePath: string): SmbTask<void>;
24
+ createDirectory(path: string): SmbTask<void>;
25
+ deleteItem(path: string): SmbTask<void>;
26
+ moveItem(from: string, to: string): SmbTask<void>;
27
+ renameItem(path: string, newName: string): SmbTask<void>;
28
+ copyItem(from: string, to: string, recursive?: boolean): SmbTask<void>;
29
+ duplicateItem(path: string): SmbTask<string>;
30
+ cancelTask(taskId: string): void;
31
+ getPoolInfo(): PoolInfo;
32
+ subscribePoolInfo(cb: (info: PoolInfo) => void): string;
33
+ unsubscribePoolInfo(id: string | null): void;
34
+ resetPool(): void;
35
+ }
@@ -0,0 +1,99 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ import { shapePoolInfo } from '../bridge/decode';
3
+ import { generateTaskId } from './ids';
4
+ import { SmbTask } from './SmbTask';
5
+ import { TransferStore } from './TransferStore';
6
+ export class SmbClient {
7
+ constructor(native) {
8
+ this.native =
9
+ native ?? NitroModules.createHybridObject('ReactNativeSmb');
10
+ }
11
+ op(call) {
12
+ const id = generateTaskId();
13
+ return new SmbTask(id, call(id));
14
+ }
15
+ transferStore() {
16
+ if (!this.transfers_) {
17
+ this.transfers_ = new TransferStore(this.native);
18
+ }
19
+ return this.transfers_;
20
+ }
21
+ dispose() {
22
+ this.transfers_?.stop();
23
+ this.transfers_ = undefined;
24
+ }
25
+ isConnected() {
26
+ return this.native.isConnected();
27
+ }
28
+ isInitialized() {
29
+ return this.native.isInitialized();
30
+ }
31
+ initialize(url, creds) {
32
+ return this.op((id) => this.native.initialize(id, url, creds));
33
+ }
34
+ connect(url, creds) {
35
+ return this.op((id) => this.native.connect(id, url, creds));
36
+ }
37
+ connectShare(share) {
38
+ return this.op((id) => this.native.connectShare(id, share));
39
+ }
40
+ disconnect() {
41
+ return this.op((id) => this.native.disconnect(id));
42
+ }
43
+ listShares() {
44
+ return this.op((id) => this.native.listShares(id));
45
+ }
46
+ listDirectory(path, recursive = false, maxDepth = -1) {
47
+ return this.op((id) => this.native.listDirectory(id, path, recursive, maxDepth));
48
+ }
49
+ getPathInfo(path) {
50
+ return this.op((id) => this.native.getPathInfo(id, path));
51
+ }
52
+ getSecurityDescriptor(path) {
53
+ return this.op((id) => this.native.getSecurityDescriptor(id, path));
54
+ }
55
+ downloadFile(remotePath, localPath) {
56
+ return this.op((id) => this.native.downloadFile(id, remotePath, localPath));
57
+ }
58
+ uploadFile(localPath, remotePath) {
59
+ return this.op((id) => this.native.uploadFile(id, localPath, remotePath));
60
+ }
61
+ createDirectory(path) {
62
+ return this.op((id) => this.native.createDirectory(id, path));
63
+ }
64
+ deleteItem(path) {
65
+ return this.op((id) => this.native.deleteItem(id, path));
66
+ }
67
+ moveItem(from, to) {
68
+ return this.op((id) => this.native.moveItem(id, from, to));
69
+ }
70
+ renameItem(path, newName) {
71
+ return this.op((id) => this.native.renameItem(id, path, newName));
72
+ }
73
+ copyItem(from, to, recursive = false) {
74
+ return this.op((id) => this.native.copyItem(id, from, to, recursive));
75
+ }
76
+ duplicateItem(path) {
77
+ return this.op((id) => this.native.duplicateItem(id, path));
78
+ }
79
+ cancelTask(taskId) {
80
+ this.native.cancelTask(taskId);
81
+ }
82
+ getPoolInfo() {
83
+ return shapePoolInfo(this.native.getPoolInfo());
84
+ }
85
+ subscribePoolInfo(cb) {
86
+ const id = this.native.subscribePoolInfo((raw) => {
87
+ cb(shapePoolInfo(raw));
88
+ });
89
+ cb(this.getPoolInfo());
90
+ return id;
91
+ }
92
+ unsubscribePoolInfo(id) {
93
+ if (id)
94
+ this.native.unsubscribePoolInfo(id);
95
+ }
96
+ resetPool() {
97
+ this.native.resetPool();
98
+ }
99
+ }
@@ -0,0 +1,41 @@
1
+ import { TaskStatus, type NativeSmbTask, type SmbTaskState } from '../types';
2
+ /**
3
+ * Handle for one native async operation.
4
+ *
5
+ * Creating a task does not subscribe. Three optional actions:
6
+ * - {@link subscribe} — live progress / status
7
+ * - {@link result} — await completion and get the typed value
8
+ * - {@link cancel} — abort
9
+ */
10
+ export declare class SmbTask<T = void> {
11
+ private readonly native;
12
+ readonly id: string;
13
+ private snapshot_;
14
+ constructor(id: string, native: NativeSmbTask);
15
+ /** 0–1 after {@link subscribe} has been called. */
16
+ get progress(): number;
17
+ /** Latest status after {@link subscribe}, or a one-shot read via {@link get}. */
18
+ get status(): TaskStatus;
19
+ cancel(): void;
20
+ /** One-shot snapshot without subscribing. */
21
+ get(): SmbTaskState | null;
22
+ /**
23
+ * Subscribe to live updates. Optional — call only when you need progress UI.
24
+ * Returns unsubscribe. Updates {@link progress} and {@link status} getters.
25
+ */
26
+ subscribe(listener?: (snapshot: SmbTaskState) => void): () => void;
27
+ /**
28
+ * Await the typed result. Subscribes only when called — not at task creation.
29
+ *
30
+ * @example
31
+ * const task = smb.listDirectory('/', false, -1);
32
+ * const files = await task.result();
33
+ */
34
+ result(): Promise<T>;
35
+ /** Like `Promise.allSettled` over {@link result}. */
36
+ static settleAll<T>(tasks: SmbTask<T>[]): Promise<PromiseSettledResult<T>[]>;
37
+ /** @internal */
38
+ getRaw(): Record<string, string>;
39
+ /** @internal */
40
+ getResultValue(): T;
41
+ }
@@ -0,0 +1,74 @@
1
+ import { shapeTaskSnapshot } from '../bridge/decode';
2
+ import { TaskStatus } from '../types';
3
+ import { taskResult } from './taskResult';
4
+ /**
5
+ * Handle for one native async operation.
6
+ *
7
+ * Creating a task does not subscribe. Three optional actions:
8
+ * - {@link subscribe} — live progress / status
9
+ * - {@link result} — await completion and get the typed value
10
+ * - {@link cancel} — abort
11
+ */
12
+ export class SmbTask {
13
+ constructor(id, native) {
14
+ this.native = native;
15
+ this.snapshot_ = null;
16
+ this.id = id;
17
+ }
18
+ /** 0–1 after {@link subscribe} has been called. */
19
+ get progress() {
20
+ return this.snapshot_?.progress ?? this.get()?.progress ?? 0;
21
+ }
22
+ /** Latest status after {@link subscribe}, or a one-shot read via {@link get}. */
23
+ get status() {
24
+ return this.snapshot_?.status ?? this.get()?.status ?? TaskStatus.Pending;
25
+ }
26
+ cancel() {
27
+ this.native.cancel();
28
+ }
29
+ /** One-shot snapshot without subscribing. */
30
+ get() {
31
+ return shapeTaskSnapshot(this.native.get());
32
+ }
33
+ /**
34
+ * Subscribe to live updates. Optional — call only when you need progress UI.
35
+ * Returns unsubscribe. Updates {@link progress} and {@link status} getters.
36
+ */
37
+ subscribe(listener) {
38
+ const subId = this.native.subscribe((raw) => {
39
+ const snap = shapeTaskSnapshot(raw);
40
+ if (!snap)
41
+ return;
42
+ this.snapshot_ = snap;
43
+ listener?.(snap);
44
+ });
45
+ const initial = this.get();
46
+ if (initial) {
47
+ this.snapshot_ = initial;
48
+ listener?.(initial);
49
+ }
50
+ return () => this.native.unsubscribe(subId);
51
+ }
52
+ /**
53
+ * Await the typed result. Subscribes only when called — not at task creation.
54
+ *
55
+ * @example
56
+ * const task = smb.listDirectory('/', false, -1);
57
+ * const files = await task.result();
58
+ */
59
+ result() {
60
+ return taskResult(this);
61
+ }
62
+ /** Like `Promise.allSettled` over {@link result}. */
63
+ static settleAll(tasks) {
64
+ return Promise.allSettled(tasks.map((task) => task.result()));
65
+ }
66
+ /** @internal */
67
+ getRaw() {
68
+ return this.native.get();
69
+ }
70
+ /** @internal */
71
+ getResultValue() {
72
+ return this.native.getResultValue();
73
+ }
74
+ }
@@ -0,0 +1,22 @@
1
+ import type { ReactNativeSmb } from '../ReactNativeSmb';
2
+ import { type SmbTaskState } from '../types';
3
+ type Listener = () => void;
4
+ export declare class TransferStore {
5
+ private readonly native;
6
+ private tasks;
7
+ private hidden;
8
+ private listeners;
9
+ private subId;
10
+ private started;
11
+ private snapshot;
12
+ constructor(native: ReactNativeSmb);
13
+ start(): void;
14
+ stop(): void;
15
+ subscribe(listener: Listener): () => void;
16
+ getSnapshot(): SmbTaskState[];
17
+ private rebuildSnapshot;
18
+ clearCompleted(): void;
19
+ hide(taskId: string): void;
20
+ private notify;
21
+ }
22
+ export {};
@@ -0,0 +1,88 @@
1
+ import { shapeTaskSnapshot } from '../bridge/decode';
2
+ import { isTransferKind } from '../labels';
3
+ import { TaskStatus } from '../types';
4
+ const EMPTY_SNAPSHOT = [];
5
+ export class TransferStore {
6
+ constructor(native) {
7
+ this.native = native;
8
+ this.tasks = new Map();
9
+ this.hidden = new Set();
10
+ this.listeners = new Set();
11
+ this.subId = null;
12
+ this.started = false;
13
+ this.snapshot = EMPTY_SNAPSHOT;
14
+ }
15
+ start() {
16
+ if (this.started)
17
+ return;
18
+ this.started = true;
19
+ for (const raw of this.native.getActiveTasks()) {
20
+ const snap = shapeTaskSnapshot(raw);
21
+ if (snap && isTransferKind(snap.kind)) {
22
+ this.tasks.set(snap.taskId, snap);
23
+ }
24
+ }
25
+ this.rebuildSnapshot();
26
+ this.subId = this.native.subscribeTaskEvents((raw) => {
27
+ try {
28
+ const snap = shapeTaskSnapshot(raw);
29
+ if (!snap || !isTransferKind(snap.kind))
30
+ return;
31
+ if (this.hidden.has(snap.taskId))
32
+ return;
33
+ this.tasks.set(snap.taskId, snap);
34
+ this.notify();
35
+ }
36
+ catch { }
37
+ });
38
+ }
39
+ stop() {
40
+ if (this.subId) {
41
+ this.native.unsubscribeTaskEvents(this.subId);
42
+ this.subId = null;
43
+ }
44
+ this.started = false;
45
+ }
46
+ subscribe(listener) {
47
+ this.start();
48
+ this.listeners.add(listener);
49
+ return () => this.listeners.delete(listener);
50
+ }
51
+ getSnapshot() {
52
+ this.start();
53
+ return this.snapshot;
54
+ }
55
+ rebuildSnapshot() {
56
+ if (this.tasks.size === 0) {
57
+ this.snapshot = EMPTY_SNAPSHOT;
58
+ return;
59
+ }
60
+ this.snapshot = Array.from(this.tasks.values())
61
+ .filter((t) => !this.hidden.has(t.taskId))
62
+ .sort((a, b) => b.updatedAt - a.updatedAt);
63
+ }
64
+ clearCompleted() {
65
+ for (const [id, snap] of this.tasks) {
66
+ if (snap.status === TaskStatus.Success ||
67
+ snap.status === TaskStatus.Error ||
68
+ snap.status === TaskStatus.Cancelled) {
69
+ this.tasks.delete(id);
70
+ }
71
+ }
72
+ this.notify();
73
+ }
74
+ hide(taskId) {
75
+ this.hidden.add(taskId);
76
+ this.tasks.delete(taskId);
77
+ this.notify();
78
+ }
79
+ notify() {
80
+ this.rebuildSnapshot();
81
+ this.listeners.forEach((l) => {
82
+ try {
83
+ l();
84
+ }
85
+ catch { }
86
+ });
87
+ }
88
+ }
@@ -0,0 +1 @@
1
+ export declare function generateTaskId(): string;
@@ -0,0 +1,3 @@
1
+ export function generateTaskId() {
2
+ return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3
+ }