@sagepilot-ai/react-native-camera-addon 0.3.0 → 0.3.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/README.md +15 -7
- package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraActivity.java +4 -9
- package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraImageProcessor.java +2 -5
- package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraModule.java +4 -23
- package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraOverlay.java +4 -9
- package/dist/index.d.mts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +3 -110
- package/dist/index.mjs +4 -111
- package/package.json +2 -2
- package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraDebugEvents.java +0 -63
package/README.md
CHANGED
|
@@ -6,18 +6,29 @@ Install this package only when you want Sagepilot to provide an in-app Android C
|
|
|
6
6
|
|
|
7
7
|
This is not a replacement SDK. Your app always installs and configures `@sagepilot-ai/react-native-sdk` first, then adds this package only when it wants the optional CameraX picker.
|
|
8
8
|
|
|
9
|
+
## Peer Dependency
|
|
10
|
+
|
|
11
|
+
This addon declares `@sagepilot-ai/react-native-sdk` as a peer dependency. It imports the base SDK's file-picker types, shared file limits, and Android camera-permission helper, but the host app must still install the base SDK directly so there is only one configured `SagepilotChat` instance.
|
|
12
|
+
|
|
13
|
+
For this release line, use:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @sagepilot-ai/react-native-sdk@latest react-native-webview
|
|
17
|
+
npm install @sagepilot-ai/react-native-camera-addon@latest
|
|
18
|
+
```
|
|
19
|
+
|
|
9
20
|
## Install Flow
|
|
10
21
|
|
|
11
22
|
Install the base SDK and WebView:
|
|
12
23
|
|
|
13
24
|
```bash
|
|
14
|
-
npm install @sagepilot-ai/react-native-sdk react-native-webview
|
|
25
|
+
npm install @sagepilot-ai/react-native-sdk@latest react-native-webview
|
|
15
26
|
```
|
|
16
27
|
|
|
17
28
|
Then install the CameraX addon:
|
|
18
29
|
|
|
19
30
|
```bash
|
|
20
|
-
npm install @sagepilot-ai/react-native-camera-addon
|
|
31
|
+
npm install @sagepilot-ai/react-native-camera-addon@latest
|
|
21
32
|
```
|
|
22
33
|
|
|
23
34
|
If your app already has the base SDK installed, run only the addon install command.
|
|
@@ -35,11 +46,8 @@ Expo apps should run a fresh native build, for example:
|
|
|
35
46
|
npx expo run:android
|
|
36
47
|
```
|
|
37
48
|
|
|
38
|
-
On device, verify the
|
|
39
|
-
|
|
40
|
-
```text
|
|
41
|
-
[SagepilotSDK][CameraXAddon] adapter created ... sources:["camera","library","documents"]
|
|
42
|
-
```
|
|
49
|
+
On device, verify the chat attachment menu shows the native addon sources:
|
|
50
|
+
Take photo, Choose from gallery, and Browse files.
|
|
43
51
|
|
|
44
52
|
If the app was only Metro-reloaded after installing the addon, `NativeModules.SagepilotInAppCamera` is not registered yet. In that state `createSagepilotCameraXFilePicker()` returns `undefined`, the base SDK receives no `filePicker`, and the widget falls back to the WebView file input.
|
|
45
53
|
|
package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraActivity.java
CHANGED
|
@@ -1523,27 +1523,22 @@ public class SagepilotInAppCameraActivity extends ComponentActivity {
|
|
|
1523
1523
|
return Math.round(value * getResources().getDisplayMetrics().density);
|
|
1524
1524
|
}
|
|
1525
1525
|
|
|
1526
|
-
/**
|
|
1526
|
+
/** Keeps temporary debug instrumentation silent in published builds. */
|
|
1527
1527
|
private void logDebug(String message) {
|
|
1528
|
-
Log.d(TAG, message);
|
|
1529
|
-
SagepilotInAppCameraDebugEvents.debug(message);
|
|
1530
1528
|
}
|
|
1531
1529
|
|
|
1532
|
-
/** Writes a native warning log
|
|
1530
|
+
/** Writes a native warning log. */
|
|
1533
1531
|
private void logWarn(String message) {
|
|
1534
1532
|
Log.w(TAG, message);
|
|
1535
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
1536
1533
|
}
|
|
1537
1534
|
|
|
1538
|
-
/** Writes a native warning log with a cause
|
|
1535
|
+
/** Writes a native warning log with a cause. */
|
|
1539
1536
|
private void logWarn(String message, Throwable error) {
|
|
1540
1537
|
Log.w(TAG, message, error);
|
|
1541
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
1542
1538
|
}
|
|
1543
1539
|
|
|
1544
|
-
/** Writes a native error log
|
|
1540
|
+
/** Writes a native error log. */
|
|
1545
1541
|
private void logError(String message, Throwable error) {
|
|
1546
1542
|
Log.e(TAG, message, error);
|
|
1547
|
-
SagepilotInAppCameraDebugEvents.error(message, error);
|
|
1548
1543
|
}
|
|
1549
1544
|
}
|
|
@@ -244,16 +244,13 @@ final class SagepilotInAppCameraImageProcessor {
|
|
|
244
244
|
+ " bytes=" + bitmap.getByteCount());
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
/**
|
|
247
|
+
/** Keeps temporary debug instrumentation silent in published builds. */
|
|
248
248
|
private void logDebug(String message) {
|
|
249
|
-
Log.d(TAG, message);
|
|
250
|
-
SagepilotInAppCameraDebugEvents.debug(message);
|
|
251
249
|
}
|
|
252
250
|
|
|
253
|
-
/** Writes a native warning log
|
|
251
|
+
/** Writes a native warning log. */
|
|
254
252
|
private void logWarn(String message) {
|
|
255
253
|
Log.w(TAG, message);
|
|
256
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
257
254
|
}
|
|
258
255
|
|
|
259
256
|
static final class ProcessedImage {
|
package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraModule.java
CHANGED
|
@@ -107,7 +107,6 @@ public class SagepilotInAppCameraModule extends ReactContextBaseJavaModule imple
|
|
|
107
107
|
this.reactContext = reactContext;
|
|
108
108
|
reactContext.addActivityEventListener(activityEventListener);
|
|
109
109
|
reactContext.addLifecycleEventListener(this);
|
|
110
|
-
SagepilotInAppCameraDebugEvents.register(reactContext);
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
/** Returns the NativeModules registration name consumed by the JS wrapper. */
|
|
@@ -333,18 +332,6 @@ public class SagepilotInAppCameraModule extends ReactContextBaseJavaModule imple
|
|
|
333
332
|
);
|
|
334
333
|
}
|
|
335
334
|
|
|
336
|
-
/** Accepts JavaScript debug-event subscriptions required by NativeEventEmitter. */
|
|
337
|
-
@ReactMethod
|
|
338
|
-
public void addListener(String eventName) {
|
|
339
|
-
// Events are emitted through RCTDeviceEventEmitter; no per-event native setup is needed.
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/** Accepts JavaScript debug-event unsubscriptions required by NativeEventEmitter. */
|
|
343
|
-
@ReactMethod
|
|
344
|
-
public void removeListeners(double count) {
|
|
345
|
-
// Events are emitted through RCTDeviceEventEmitter; no per-event native teardown is needed.
|
|
346
|
-
}
|
|
347
|
-
|
|
348
335
|
/** Keeps the pending capture alive while the SDK camera Activity is foregrounded. */
|
|
349
336
|
@Override
|
|
350
337
|
public void onHostPause() {
|
|
@@ -375,7 +362,6 @@ public class SagepilotInAppCameraModule extends ReactContextBaseJavaModule imple
|
|
|
375
362
|
destroyActiveCameraOverlay();
|
|
376
363
|
reactContext.removeActivityEventListener(activityEventListener);
|
|
377
364
|
reactContext.removeLifecycleEventListener(this);
|
|
378
|
-
SagepilotInAppCameraDebugEvents.unregister(reactContext);
|
|
379
365
|
rejectPendingPromise(
|
|
380
366
|
ERROR_CAMERA_UNAVAILABLE,
|
|
381
367
|
"Camera capture was cancelled because the React Native instance was invalidated.",
|
|
@@ -953,28 +939,23 @@ public class SagepilotInAppCameraModule extends ReactContextBaseJavaModule imple
|
|
|
953
939
|
rejectPromise(promise, code, message, null);
|
|
954
940
|
}
|
|
955
941
|
|
|
956
|
-
/**
|
|
942
|
+
/** Keeps temporary debug instrumentation silent in published builds. */
|
|
957
943
|
private void logDebug(String message) {
|
|
958
|
-
Log.d(TAG, message);
|
|
959
|
-
SagepilotInAppCameraDebugEvents.debug(message);
|
|
960
944
|
}
|
|
961
945
|
|
|
962
|
-
/** Writes a native warning log
|
|
946
|
+
/** Writes a native warning log. */
|
|
963
947
|
private void logWarn(String message) {
|
|
964
948
|
Log.w(TAG, message);
|
|
965
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
966
949
|
}
|
|
967
950
|
|
|
968
|
-
/** Writes a native warning log with a cause
|
|
951
|
+
/** Writes a native warning log with a cause. */
|
|
969
952
|
private void logWarn(String message, Throwable error) {
|
|
970
953
|
Log.w(TAG, message, error);
|
|
971
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
972
954
|
}
|
|
973
955
|
|
|
974
|
-
/** Writes a native error log
|
|
956
|
+
/** Writes a native error log. */
|
|
975
957
|
private void logError(String message, Throwable error) {
|
|
976
958
|
Log.e(TAG, message, error);
|
|
977
|
-
SagepilotInAppCameraDebugEvents.error(message, error);
|
|
978
959
|
}
|
|
979
960
|
|
|
980
961
|
private static final class PendingPicker {
|
package/android/src/main/java/ai/sagepilot/reactnativecameraaddon/SagepilotInAppCameraOverlay.java
CHANGED
|
@@ -1382,28 +1382,23 @@ final class SagepilotInAppCameraOverlay {
|
|
|
1382
1382
|
return Math.round(value * activity.getResources().getDisplayMetrics().density);
|
|
1383
1383
|
}
|
|
1384
1384
|
|
|
1385
|
-
/**
|
|
1385
|
+
/** Keeps temporary debug instrumentation silent in published builds. */
|
|
1386
1386
|
private void logDebug(String message) {
|
|
1387
|
-
Log.d(TAG, message);
|
|
1388
|
-
SagepilotInAppCameraDebugEvents.debug(message);
|
|
1389
1387
|
}
|
|
1390
1388
|
|
|
1391
|
-
/** Writes a native warning log
|
|
1389
|
+
/** Writes a native warning log. */
|
|
1392
1390
|
private void logWarn(String message) {
|
|
1393
1391
|
Log.w(TAG, message);
|
|
1394
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
1395
1392
|
}
|
|
1396
1393
|
|
|
1397
|
-
/** Writes a native warning log with a cause
|
|
1394
|
+
/** Writes a native warning log with a cause. */
|
|
1398
1395
|
private void logWarn(String message, Throwable error) {
|
|
1399
1396
|
Log.w(TAG, message, error);
|
|
1400
|
-
SagepilotInAppCameraDebugEvents.warn(message);
|
|
1401
1397
|
}
|
|
1402
1398
|
|
|
1403
|
-
/** Writes a native error log
|
|
1399
|
+
/** Writes a native error log. */
|
|
1404
1400
|
private void logError(String message, Throwable error) {
|
|
1405
1401
|
Log.e(TAG, message, error);
|
|
1406
|
-
SagepilotInAppCameraDebugEvents.error(message, error);
|
|
1407
1402
|
}
|
|
1408
1403
|
|
|
1409
1404
|
interface Listener {
|
package/dist/index.d.mts
CHANGED
|
@@ -22,8 +22,6 @@ type SagepilotNativeCameraModule = {
|
|
|
22
22
|
supportsInAppCamera?: boolean;
|
|
23
23
|
supportsImageLibrary?: boolean;
|
|
24
24
|
supportsDocumentPicker?: boolean;
|
|
25
|
-
addListener?: (eventName: string) => void;
|
|
26
|
-
removeListeners?: (count: number) => void;
|
|
27
25
|
};
|
|
28
26
|
type SagepilotNativeCameraCapabilities = {
|
|
29
27
|
moduleCapabilitiesVersion: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,8 +22,6 @@ type SagepilotNativeCameraModule = {
|
|
|
22
22
|
supportsInAppCamera?: boolean;
|
|
23
23
|
supportsImageLibrary?: boolean;
|
|
24
24
|
supportsDocumentPicker?: boolean;
|
|
25
|
-
addListener?: (eventName: string) => void;
|
|
26
|
-
removeListeners?: (count: number) => void;
|
|
27
25
|
};
|
|
28
26
|
type SagepilotNativeCameraCapabilities = {
|
|
29
27
|
moduleCapabilitiesVersion: number;
|
package/dist/index.js
CHANGED
|
@@ -33,40 +33,7 @@ var import_react_native_sdk2 = require("@sagepilot-ai/react-native-sdk");
|
|
|
33
33
|
var import_react_native = require("react-native");
|
|
34
34
|
var import_react_native_sdk = require("@sagepilot-ai/react-native-sdk");
|
|
35
35
|
var NATIVE_CAMERA_MODULE_NAME = "SagepilotInAppCamera";
|
|
36
|
-
var NATIVE_CAMERA_DEBUG_EVENT_NAME = "SagepilotInAppCameraDebug";
|
|
37
|
-
var DEBUG_PREFIX = "[SagepilotSDK][InAppCamera]";
|
|
38
36
|
var REQUIRED_NATIVE_CAMERA_CAPABILITIES_VERSION = 2;
|
|
39
|
-
function debugNativeCamera(message, details) {
|
|
40
|
-
console.log(`${DEBUG_PREFIX} ${message}`, details ?? "");
|
|
41
|
-
}
|
|
42
|
-
function readNativeDebugString(event, key) {
|
|
43
|
-
const value = event[key];
|
|
44
|
-
return typeof value === "string" ? value : void 0;
|
|
45
|
-
}
|
|
46
|
-
function readNativeCameraDebugEvent(event) {
|
|
47
|
-
if (!event || typeof event !== "object") return {};
|
|
48
|
-
const record = event;
|
|
49
|
-
return {
|
|
50
|
-
level: readNativeDebugString(record, "level"),
|
|
51
|
-
message: readNativeDebugString(record, "message"),
|
|
52
|
-
error: readNativeDebugString(record, "error")
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function subscribeNativeCameraDebugEvents(nativeCamera) {
|
|
56
|
-
const eventEmitter = new import_react_native.NativeEventEmitter(nativeCamera);
|
|
57
|
-
const subscription = eventEmitter.addListener(
|
|
58
|
-
NATIVE_CAMERA_DEBUG_EVENT_NAME,
|
|
59
|
-
(event) => {
|
|
60
|
-
const debugEvent = readNativeCameraDebugEvent(event);
|
|
61
|
-
debugNativeCamera("native event", {
|
|
62
|
-
level: debugEvent.level,
|
|
63
|
-
message: debugEvent.message,
|
|
64
|
-
error: debugEvent.error
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
return () => subscription.remove();
|
|
69
|
-
}
|
|
70
37
|
function getSagepilotNativeCameraModule() {
|
|
71
38
|
const nativeModules = import_react_native.NativeModules;
|
|
72
39
|
const module2 = nativeModules[NATIVE_CAMERA_MODULE_NAME];
|
|
@@ -164,35 +131,12 @@ function toSagepilotNativeCameraError(error) {
|
|
|
164
131
|
async function openSagepilotCamera(options = {}) {
|
|
165
132
|
const nativeCamera = getSagepilotNativeCameraModule();
|
|
166
133
|
if (!nativeCamera) {
|
|
167
|
-
debugNativeCamera("native module unavailable", {
|
|
168
|
-
moduleName: NATIVE_CAMERA_MODULE_NAME,
|
|
169
|
-
registeredModules: Object.keys(import_react_native.NativeModules).filter(
|
|
170
|
-
(key) => key.toLowerCase().includes("sagepilot")
|
|
171
|
-
)
|
|
172
|
-
});
|
|
173
134
|
throw new import_react_native_sdk.SagepilotFilePickerError("camera_unavailable", "The in-app camera is not available in this build.");
|
|
174
135
|
}
|
|
175
136
|
try {
|
|
176
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
177
137
|
const normalizedOptions = normalizeNativeCameraOptions(options);
|
|
178
|
-
|
|
179
|
-
debugNativeCamera("opening native camera", normalizedOptions);
|
|
180
|
-
const file = await nativeCamera.openCamera(normalizedOptions) ?? null;
|
|
181
|
-
debugNativeCamera("native camera resolved", file ? {
|
|
182
|
-
fileName: file.file_name,
|
|
183
|
-
mimeType: file.mime_type,
|
|
184
|
-
size: file.size,
|
|
185
|
-
base64Length: file.data_base64.length
|
|
186
|
-
} : { cancelled: true });
|
|
187
|
-
return file;
|
|
188
|
-
} finally {
|
|
189
|
-
unsubscribeNativeDebugEvents();
|
|
190
|
-
}
|
|
138
|
+
return await nativeCamera.openCamera(normalizedOptions) ?? null;
|
|
191
139
|
} catch (error) {
|
|
192
|
-
debugNativeCamera("native camera rejected", {
|
|
193
|
-
code: getNativeCameraErrorCode(error),
|
|
194
|
-
message: getNativeCameraErrorMessage(error)
|
|
195
|
-
});
|
|
196
140
|
throw toSagepilotNativeCameraError(error);
|
|
197
141
|
}
|
|
198
142
|
}
|
|
@@ -205,28 +149,10 @@ async function pickSagepilotImageLibraryFiles(options) {
|
|
|
205
149
|
if (!nativeCamera?.openImageLibrary) {
|
|
206
150
|
throw new import_react_native_sdk.SagepilotFilePickerError("camera_unavailable", "The image library picker is not available in this build.");
|
|
207
151
|
}
|
|
208
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
209
152
|
try {
|
|
210
|
-
|
|
211
|
-
const files = await nativeCamera.openImageLibrary(options) ?? [];
|
|
212
|
-
debugNativeCamera("native image library resolved", {
|
|
213
|
-
count: files.length,
|
|
214
|
-
files: files.map((file) => ({
|
|
215
|
-
fileName: file.file_name,
|
|
216
|
-
mimeType: file.mime_type,
|
|
217
|
-
size: file.size,
|
|
218
|
-
base64Length: file.data_base64.length
|
|
219
|
-
}))
|
|
220
|
-
});
|
|
221
|
-
return files;
|
|
153
|
+
return await nativeCamera.openImageLibrary(options) ?? [];
|
|
222
154
|
} catch (error) {
|
|
223
|
-
debugNativeCamera("native image library rejected", {
|
|
224
|
-
code: getNativeCameraErrorCode(error),
|
|
225
|
-
message: getNativeCameraErrorMessage(error)
|
|
226
|
-
});
|
|
227
155
|
throw toSagepilotNativeCameraError(error);
|
|
228
|
-
} finally {
|
|
229
|
-
unsubscribeNativeDebugEvents();
|
|
230
156
|
}
|
|
231
157
|
}
|
|
232
158
|
async function pickSagepilotDocumentFiles(options) {
|
|
@@ -234,37 +160,15 @@ async function pickSagepilotDocumentFiles(options) {
|
|
|
234
160
|
if (!nativeCamera?.openDocumentPicker) {
|
|
235
161
|
throw new import_react_native_sdk.SagepilotFilePickerError("camera_unavailable", "The document picker is not available in this build.");
|
|
236
162
|
}
|
|
237
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
238
163
|
try {
|
|
239
|
-
|
|
240
|
-
const files = await nativeCamera.openDocumentPicker(options) ?? [];
|
|
241
|
-
debugNativeCamera("native document picker resolved", {
|
|
242
|
-
count: files.length,
|
|
243
|
-
files: files.map((file) => ({
|
|
244
|
-
fileName: file.file_name,
|
|
245
|
-
mimeType: file.mime_type,
|
|
246
|
-
size: file.size,
|
|
247
|
-
base64Length: file.data_base64.length
|
|
248
|
-
}))
|
|
249
|
-
});
|
|
250
|
-
return files;
|
|
164
|
+
return await nativeCamera.openDocumentPicker(options) ?? [];
|
|
251
165
|
} catch (error) {
|
|
252
|
-
debugNativeCamera("native document picker rejected", {
|
|
253
|
-
code: getNativeCameraErrorCode(error),
|
|
254
|
-
message: getNativeCameraErrorMessage(error)
|
|
255
|
-
});
|
|
256
166
|
throw toSagepilotNativeCameraError(error);
|
|
257
|
-
} finally {
|
|
258
|
-
unsubscribeNativeDebugEvents();
|
|
259
167
|
}
|
|
260
168
|
}
|
|
261
169
|
|
|
262
170
|
// src/index.ts
|
|
263
|
-
var DEBUG_PREFIX2 = "[SagepilotSDK][CameraXAddon]";
|
|
264
171
|
var DEFAULT_DOCUMENT_MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024;
|
|
265
|
-
function debugCameraXFilePicker(message, details) {
|
|
266
|
-
console.log(`${DEBUG_PREFIX2} ${message}`, details ?? "");
|
|
267
|
-
}
|
|
268
172
|
function isSourceEnabled(sources, source) {
|
|
269
173
|
return sources.includes(source);
|
|
270
174
|
}
|
|
@@ -289,19 +193,9 @@ function resolveCameraXFilePickerSources(options) {
|
|
|
289
193
|
}
|
|
290
194
|
function createSagepilotCameraXFilePicker(options = {}) {
|
|
291
195
|
if (import_react_native2.Platform.OS !== "android") return void 0;
|
|
292
|
-
const capabilities = getSagepilotNativeCameraCapabilities();
|
|
293
196
|
const sources = resolveCameraXFilePickerSources(options);
|
|
294
197
|
const imageMaxFileSizeBytes = options.imageMaxFileSizeBytes ?? import_react_native_sdk2.SAGEPILOT_DEFAULT_IMAGE_MAX_FILE_SIZE_BYTES;
|
|
295
198
|
const documentMaxFileSizeBytes = options.documentMaxFileSizeBytes ?? DEFAULT_DOCUMENT_MAX_FILE_SIZE_BYTES;
|
|
296
|
-
debugCameraXFilePicker("adapter created", {
|
|
297
|
-
platform: import_react_native2.Platform.OS,
|
|
298
|
-
capabilities,
|
|
299
|
-
sources,
|
|
300
|
-
imageMaxDimension: options.imageMaxDimension,
|
|
301
|
-
imageQuality: options.imageQuality,
|
|
302
|
-
imageMaxFileSizeBytes,
|
|
303
|
-
documentMaxFileSizeBytes
|
|
304
|
-
});
|
|
305
199
|
if (sources.length === 0) return void 0;
|
|
306
200
|
async function pickCamera() {
|
|
307
201
|
if (!isSourceEnabled(sources, "camera")) rejectUnavailableSource("camera");
|
|
@@ -323,7 +217,6 @@ function createSagepilotCameraXFilePicker(options = {}) {
|
|
|
323
217
|
return {
|
|
324
218
|
sources,
|
|
325
219
|
async pickFiles(request) {
|
|
326
|
-
debugCameraXFilePicker("pickFiles request", request);
|
|
327
220
|
if (request.source === "camera") return pickCamera();
|
|
328
221
|
if (request.source === "library") return pickLibrary(request.multiple);
|
|
329
222
|
return pickDocuments(request.multiple);
|
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "@sagepilot-ai/react-native-sdk";
|
|
8
8
|
|
|
9
9
|
// src/nativeCamera.ts
|
|
10
|
-
import {
|
|
10
|
+
import { NativeModules } from "react-native";
|
|
11
11
|
import {
|
|
12
12
|
SAGEPILOT_DEFAULT_IMAGE_MAX_DIMENSION,
|
|
13
13
|
SAGEPILOT_DEFAULT_IMAGE_MAX_FILE_SIZE_BYTES,
|
|
@@ -15,40 +15,7 @@ import {
|
|
|
15
15
|
SagepilotFilePickerError
|
|
16
16
|
} from "@sagepilot-ai/react-native-sdk";
|
|
17
17
|
var NATIVE_CAMERA_MODULE_NAME = "SagepilotInAppCamera";
|
|
18
|
-
var NATIVE_CAMERA_DEBUG_EVENT_NAME = "SagepilotInAppCameraDebug";
|
|
19
|
-
var DEBUG_PREFIX = "[SagepilotSDK][InAppCamera]";
|
|
20
18
|
var REQUIRED_NATIVE_CAMERA_CAPABILITIES_VERSION = 2;
|
|
21
|
-
function debugNativeCamera(message, details) {
|
|
22
|
-
console.log(`${DEBUG_PREFIX} ${message}`, details ?? "");
|
|
23
|
-
}
|
|
24
|
-
function readNativeDebugString(event, key) {
|
|
25
|
-
const value = event[key];
|
|
26
|
-
return typeof value === "string" ? value : void 0;
|
|
27
|
-
}
|
|
28
|
-
function readNativeCameraDebugEvent(event) {
|
|
29
|
-
if (!event || typeof event !== "object") return {};
|
|
30
|
-
const record = event;
|
|
31
|
-
return {
|
|
32
|
-
level: readNativeDebugString(record, "level"),
|
|
33
|
-
message: readNativeDebugString(record, "message"),
|
|
34
|
-
error: readNativeDebugString(record, "error")
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function subscribeNativeCameraDebugEvents(nativeCamera) {
|
|
38
|
-
const eventEmitter = new NativeEventEmitter(nativeCamera);
|
|
39
|
-
const subscription = eventEmitter.addListener(
|
|
40
|
-
NATIVE_CAMERA_DEBUG_EVENT_NAME,
|
|
41
|
-
(event) => {
|
|
42
|
-
const debugEvent = readNativeCameraDebugEvent(event);
|
|
43
|
-
debugNativeCamera("native event", {
|
|
44
|
-
level: debugEvent.level,
|
|
45
|
-
message: debugEvent.message,
|
|
46
|
-
error: debugEvent.error
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
return () => subscription.remove();
|
|
51
|
-
}
|
|
52
19
|
function getSagepilotNativeCameraModule() {
|
|
53
20
|
const nativeModules = NativeModules;
|
|
54
21
|
const module = nativeModules[NATIVE_CAMERA_MODULE_NAME];
|
|
@@ -146,35 +113,12 @@ function toSagepilotNativeCameraError(error) {
|
|
|
146
113
|
async function openSagepilotCamera(options = {}) {
|
|
147
114
|
const nativeCamera = getSagepilotNativeCameraModule();
|
|
148
115
|
if (!nativeCamera) {
|
|
149
|
-
debugNativeCamera("native module unavailable", {
|
|
150
|
-
moduleName: NATIVE_CAMERA_MODULE_NAME,
|
|
151
|
-
registeredModules: Object.keys(NativeModules).filter(
|
|
152
|
-
(key) => key.toLowerCase().includes("sagepilot")
|
|
153
|
-
)
|
|
154
|
-
});
|
|
155
116
|
throw new SagepilotFilePickerError("camera_unavailable", "The in-app camera is not available in this build.");
|
|
156
117
|
}
|
|
157
118
|
try {
|
|
158
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
159
119
|
const normalizedOptions = normalizeNativeCameraOptions(options);
|
|
160
|
-
|
|
161
|
-
debugNativeCamera("opening native camera", normalizedOptions);
|
|
162
|
-
const file = await nativeCamera.openCamera(normalizedOptions) ?? null;
|
|
163
|
-
debugNativeCamera("native camera resolved", file ? {
|
|
164
|
-
fileName: file.file_name,
|
|
165
|
-
mimeType: file.mime_type,
|
|
166
|
-
size: file.size,
|
|
167
|
-
base64Length: file.data_base64.length
|
|
168
|
-
} : { cancelled: true });
|
|
169
|
-
return file;
|
|
170
|
-
} finally {
|
|
171
|
-
unsubscribeNativeDebugEvents();
|
|
172
|
-
}
|
|
120
|
+
return await nativeCamera.openCamera(normalizedOptions) ?? null;
|
|
173
121
|
} catch (error) {
|
|
174
|
-
debugNativeCamera("native camera rejected", {
|
|
175
|
-
code: getNativeCameraErrorCode(error),
|
|
176
|
-
message: getNativeCameraErrorMessage(error)
|
|
177
|
-
});
|
|
178
122
|
throw toSagepilotNativeCameraError(error);
|
|
179
123
|
}
|
|
180
124
|
}
|
|
@@ -187,28 +131,10 @@ async function pickSagepilotImageLibraryFiles(options) {
|
|
|
187
131
|
if (!nativeCamera?.openImageLibrary) {
|
|
188
132
|
throw new SagepilotFilePickerError("camera_unavailable", "The image library picker is not available in this build.");
|
|
189
133
|
}
|
|
190
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
191
134
|
try {
|
|
192
|
-
|
|
193
|
-
const files = await nativeCamera.openImageLibrary(options) ?? [];
|
|
194
|
-
debugNativeCamera("native image library resolved", {
|
|
195
|
-
count: files.length,
|
|
196
|
-
files: files.map((file) => ({
|
|
197
|
-
fileName: file.file_name,
|
|
198
|
-
mimeType: file.mime_type,
|
|
199
|
-
size: file.size,
|
|
200
|
-
base64Length: file.data_base64.length
|
|
201
|
-
}))
|
|
202
|
-
});
|
|
203
|
-
return files;
|
|
135
|
+
return await nativeCamera.openImageLibrary(options) ?? [];
|
|
204
136
|
} catch (error) {
|
|
205
|
-
debugNativeCamera("native image library rejected", {
|
|
206
|
-
code: getNativeCameraErrorCode(error),
|
|
207
|
-
message: getNativeCameraErrorMessage(error)
|
|
208
|
-
});
|
|
209
137
|
throw toSagepilotNativeCameraError(error);
|
|
210
|
-
} finally {
|
|
211
|
-
unsubscribeNativeDebugEvents();
|
|
212
138
|
}
|
|
213
139
|
}
|
|
214
140
|
async function pickSagepilotDocumentFiles(options) {
|
|
@@ -216,37 +142,15 @@ async function pickSagepilotDocumentFiles(options) {
|
|
|
216
142
|
if (!nativeCamera?.openDocumentPicker) {
|
|
217
143
|
throw new SagepilotFilePickerError("camera_unavailable", "The document picker is not available in this build.");
|
|
218
144
|
}
|
|
219
|
-
const unsubscribeNativeDebugEvents = subscribeNativeCameraDebugEvents(nativeCamera);
|
|
220
145
|
try {
|
|
221
|
-
|
|
222
|
-
const files = await nativeCamera.openDocumentPicker(options) ?? [];
|
|
223
|
-
debugNativeCamera("native document picker resolved", {
|
|
224
|
-
count: files.length,
|
|
225
|
-
files: files.map((file) => ({
|
|
226
|
-
fileName: file.file_name,
|
|
227
|
-
mimeType: file.mime_type,
|
|
228
|
-
size: file.size,
|
|
229
|
-
base64Length: file.data_base64.length
|
|
230
|
-
}))
|
|
231
|
-
});
|
|
232
|
-
return files;
|
|
146
|
+
return await nativeCamera.openDocumentPicker(options) ?? [];
|
|
233
147
|
} catch (error) {
|
|
234
|
-
debugNativeCamera("native document picker rejected", {
|
|
235
|
-
code: getNativeCameraErrorCode(error),
|
|
236
|
-
message: getNativeCameraErrorMessage(error)
|
|
237
|
-
});
|
|
238
148
|
throw toSagepilotNativeCameraError(error);
|
|
239
|
-
} finally {
|
|
240
|
-
unsubscribeNativeDebugEvents();
|
|
241
149
|
}
|
|
242
150
|
}
|
|
243
151
|
|
|
244
152
|
// src/index.ts
|
|
245
|
-
var DEBUG_PREFIX2 = "[SagepilotSDK][CameraXAddon]";
|
|
246
153
|
var DEFAULT_DOCUMENT_MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024;
|
|
247
|
-
function debugCameraXFilePicker(message, details) {
|
|
248
|
-
console.log(`${DEBUG_PREFIX2} ${message}`, details ?? "");
|
|
249
|
-
}
|
|
250
154
|
function isSourceEnabled(sources, source) {
|
|
251
155
|
return sources.includes(source);
|
|
252
156
|
}
|
|
@@ -271,19 +175,9 @@ function resolveCameraXFilePickerSources(options) {
|
|
|
271
175
|
}
|
|
272
176
|
function createSagepilotCameraXFilePicker(options = {}) {
|
|
273
177
|
if (Platform.OS !== "android") return void 0;
|
|
274
|
-
const capabilities = getSagepilotNativeCameraCapabilities();
|
|
275
178
|
const sources = resolveCameraXFilePickerSources(options);
|
|
276
179
|
const imageMaxFileSizeBytes = options.imageMaxFileSizeBytes ?? SAGEPILOT_DEFAULT_IMAGE_MAX_FILE_SIZE_BYTES2;
|
|
277
180
|
const documentMaxFileSizeBytes = options.documentMaxFileSizeBytes ?? DEFAULT_DOCUMENT_MAX_FILE_SIZE_BYTES;
|
|
278
|
-
debugCameraXFilePicker("adapter created", {
|
|
279
|
-
platform: Platform.OS,
|
|
280
|
-
capabilities,
|
|
281
|
-
sources,
|
|
282
|
-
imageMaxDimension: options.imageMaxDimension,
|
|
283
|
-
imageQuality: options.imageQuality,
|
|
284
|
-
imageMaxFileSizeBytes,
|
|
285
|
-
documentMaxFileSizeBytes
|
|
286
|
-
});
|
|
287
181
|
if (sources.length === 0) return void 0;
|
|
288
182
|
async function pickCamera() {
|
|
289
183
|
if (!isSourceEnabled(sources, "camera")) rejectUnavailableSource("camera");
|
|
@@ -305,7 +199,6 @@ function createSagepilotCameraXFilePicker(options = {}) {
|
|
|
305
199
|
return {
|
|
306
200
|
sources,
|
|
307
201
|
async pickFiles(request) {
|
|
308
|
-
debugCameraXFilePicker("pickFiles request", request);
|
|
309
202
|
if (request.source === "camera") return pickCamera();
|
|
310
203
|
if (request.source === "library") return pickLibrary(request.multiple);
|
|
311
204
|
return pickDocuments(request.multiple);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sagepilot-ai/react-native-camera-addon",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Optional CameraX attachment picker addon for the Sagepilot React Native SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sagepilot",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"prepublishOnly": "npm run typecheck && npm run build"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@sagepilot-ai/react-native-sdk": ">=0.3.
|
|
40
|
+
"@sagepilot-ai/react-native-sdk": ">=0.3.1",
|
|
41
41
|
"react": ">=18",
|
|
42
42
|
"react-native": ">=0.72"
|
|
43
43
|
},
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
package ai.sagepilot.reactnativecameraaddon;
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.bridge.Arguments;
|
|
4
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
5
|
-
import com.facebook.react.bridge.WritableMap;
|
|
6
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
7
|
-
import java.lang.ref.WeakReference;
|
|
8
|
-
|
|
9
|
-
final class SagepilotInAppCameraDebugEvents {
|
|
10
|
-
static final String EVENT_NAME = "SagepilotInAppCameraDebug";
|
|
11
|
-
|
|
12
|
-
private static WeakReference<ReactApplicationContext> reactContextRef = new WeakReference<>(null);
|
|
13
|
-
|
|
14
|
-
/** Prevents construction of the static camera debug-event bridge. */
|
|
15
|
-
private SagepilotInAppCameraDebugEvents() {}
|
|
16
|
-
|
|
17
|
-
/** Registers the active React context used to emit native camera debug events. */
|
|
18
|
-
static void register(ReactApplicationContext reactContext) {
|
|
19
|
-
reactContextRef = new WeakReference<>(reactContext);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Clears the active React context when the owning module is invalidated. */
|
|
23
|
-
static void unregister(ReactApplicationContext reactContext) {
|
|
24
|
-
ReactApplicationContext activeContext = reactContextRef.get();
|
|
25
|
-
if (activeContext == reactContext) {
|
|
26
|
-
reactContextRef.clear();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Emits an informational native camera debug event to JavaScript. */
|
|
31
|
-
static void debug(String message) {
|
|
32
|
-
emit("debug", message, null);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Emits a warning native camera debug event to JavaScript. */
|
|
36
|
-
static void warn(String message) {
|
|
37
|
-
emit("warn", message, null);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Emits an error native camera debug event to JavaScript. */
|
|
41
|
-
static void error(String message, Throwable error) {
|
|
42
|
-
emit("error", message, error == null ? null : error.getMessage());
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Emits a native camera debug event when a live React context is available. */
|
|
46
|
-
private static void emit(String level, String message, String errorMessage) {
|
|
47
|
-
ReactApplicationContext reactContext = reactContextRef.get();
|
|
48
|
-
if (reactContext == null || !reactContext.hasActiveCatalystInstance()) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
WritableMap payload = Arguments.createMap();
|
|
53
|
-
payload.putString("level", level);
|
|
54
|
-
payload.putString("message", message);
|
|
55
|
-
if (errorMessage != null) {
|
|
56
|
-
payload.putString("error", errorMessage);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
reactContext
|
|
60
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
61
|
-
.emit(EVENT_NAME, payload);
|
|
62
|
-
}
|
|
63
|
-
}
|