@webority-technologies/mobile-core 0.0.1 → 0.0.2
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 +22 -1
- package/lib/commonjs/api/baseUrl.js +34 -0
- package/lib/commonjs/api/curl.js +109 -0
- package/lib/commonjs/api/publicClient.js +11 -20
- package/lib/commonjs/api/retry.js +75 -0
- package/lib/commonjs/api/userClient.js +46 -22
- package/lib/commonjs/auth/authStore.js +101 -33
- package/lib/commonjs/auth/jwt.js +32 -8
- package/lib/commonjs/config/index.js +2 -1
- package/lib/commonjs/deepLink/index.js +286 -0
- package/lib/commonjs/download/adapters/expoFs.js +100 -0
- package/lib/commonjs/download/adapters/shared.js +13 -0
- package/lib/commonjs/download/index.js +272 -0
- package/lib/commonjs/formatters/date.js +1 -1
- package/lib/commonjs/formatters/index.js +6 -0
- package/lib/commonjs/formatters/phone.js +103 -15
- package/lib/commonjs/geolocation/adapters/expoLocation.js +126 -0
- package/lib/commonjs/geolocation/index.js +339 -0
- package/lib/commonjs/index.js +133 -48
- package/lib/commonjs/initSDK.js +23 -2
- package/lib/commonjs/initUserAuth.js +2 -1
- package/lib/commonjs/logger/index.js +159 -5
- package/lib/commonjs/network/index.js +6 -0
- package/lib/commonjs/network/networkStatus.js +50 -15
- package/lib/commonjs/permissions/index.js +24 -1
- package/lib/commonjs/sqlite/adapters/expo.js +53 -0
- package/lib/commonjs/sqlite/adapters/op.js +43 -0
- package/lib/commonjs/sqlite/adapters/rows.js +33 -0
- package/lib/commonjs/sqlite/adapters/storage.js +50 -0
- package/lib/commonjs/sqlite/adapters/sync.js +45 -0
- package/lib/commonjs/sqlite/index.js +610 -0
- package/lib/commonjs/sqlite/nitro.js +17 -0
- package/lib/commonjs/sqlite/op.js +18 -0
- package/lib/commonjs/sqlite/quick.js +14 -0
- package/lib/commonjs/sqlite/storage.js +14 -0
- package/lib/commonjs/storage/index.js +40 -19
- package/lib/commonjs/types/globals.d.js +6 -0
- package/lib/commonjs/utils/imageCompression.js +51 -14
- package/lib/commonjs/utils/index.js +6 -0
- package/lib/commonjs/versionCheck/index.js +28 -4
- package/lib/module/api/baseUrl.js +30 -0
- package/lib/module/api/curl.js +104 -0
- package/lib/module/api/publicClient.js +11 -20
- package/lib/module/api/retry.js +69 -0
- package/lib/module/api/userClient.js +45 -21
- package/lib/module/auth/authStore.js +99 -32
- package/lib/module/auth/jwt.js +32 -8
- package/lib/module/config/index.js +2 -1
- package/lib/module/deepLink/index.js +280 -0
- package/lib/module/download/adapters/expoFs.js +95 -0
- package/lib/module/download/adapters/shared.js +8 -0
- package/lib/module/download/index.js +264 -0
- package/lib/module/formatters/date.js +1 -1
- package/lib/module/formatters/index.js +1 -1
- package/lib/module/formatters/phone.js +99 -13
- package/lib/module/geolocation/adapters/expoLocation.js +121 -0
- package/lib/module/geolocation/index.js +332 -0
- package/lib/module/index.js +28 -11
- package/lib/module/initSDK.js +23 -2
- package/lib/module/initUserAuth.js +2 -1
- package/lib/module/logger/index.js +156 -4
- package/lib/module/network/index.js +1 -1
- package/lib/module/network/networkStatus.js +47 -14
- package/lib/module/permissions/index.js +22 -0
- package/lib/module/sqlite/adapters/expo.js +48 -0
- package/lib/module/sqlite/adapters/op.js +38 -0
- package/lib/module/sqlite/adapters/rows.js +28 -0
- package/lib/module/sqlite/adapters/storage.js +46 -0
- package/lib/module/sqlite/adapters/sync.js +41 -0
- package/lib/module/sqlite/index.js +600 -0
- package/lib/module/sqlite/nitro.js +12 -0
- package/lib/module/sqlite/op.js +13 -0
- package/lib/module/sqlite/quick.js +9 -0
- package/lib/module/sqlite/storage.js +9 -0
- package/lib/module/storage/index.js +37 -18
- package/lib/module/types/globals.d.js +10 -0
- package/lib/module/utils/imageCompression.js +49 -13
- package/lib/module/utils/index.js +1 -1
- package/lib/module/versionCheck/index.js +27 -4
- package/lib/typescript/commonjs/api/baseUrl.d.ts +20 -0
- package/lib/typescript/commonjs/api/curl.d.ts +18 -0
- package/lib/typescript/commonjs/api/retry.d.ts +27 -0
- package/lib/typescript/commonjs/api/userClient.d.ts +11 -0
- package/lib/typescript/commonjs/auth/authStore.d.ts +29 -6
- package/lib/typescript/commonjs/config/index.d.ts +6 -0
- package/lib/typescript/commonjs/deepLink/index.d.ts +54 -0
- package/lib/typescript/commonjs/download/adapters/expoFs.d.ts +45 -0
- package/lib/typescript/commonjs/download/adapters/shared.d.ts +3 -0
- package/lib/typescript/commonjs/download/index.d.ts +76 -0
- package/lib/typescript/commonjs/formatters/index.d.ts +2 -1
- package/lib/typescript/commonjs/formatters/phone.d.ts +16 -1
- package/lib/typescript/commonjs/geolocation/adapters/expoLocation.d.ts +42 -0
- package/lib/typescript/commonjs/geolocation/index.d.ts +89 -0
- package/lib/typescript/commonjs/index.d.ts +30 -13
- package/lib/typescript/commonjs/initSDK.d.ts +32 -0
- package/lib/typescript/commonjs/logger/index.d.ts +39 -0
- package/lib/typescript/commonjs/network/index.d.ts +2 -2
- package/lib/typescript/commonjs/network/networkStatus.d.ts +16 -0
- package/lib/typescript/commonjs/permissions/index.d.ts +35 -0
- package/lib/typescript/commonjs/sqlite/adapters/expo.d.ts +30 -0
- package/lib/typescript/commonjs/sqlite/adapters/op.d.ts +27 -0
- package/lib/typescript/commonjs/sqlite/adapters/rows.d.ts +7 -0
- package/lib/typescript/commonjs/sqlite/adapters/storage.d.ts +30 -0
- package/lib/typescript/commonjs/sqlite/adapters/sync.d.ts +31 -0
- package/lib/typescript/commonjs/sqlite/index.d.ts +121 -0
- package/lib/typescript/commonjs/sqlite/nitro.d.ts +7 -0
- package/lib/typescript/commonjs/sqlite/op.d.ts +8 -0
- package/lib/typescript/commonjs/sqlite/quick.d.ts +4 -0
- package/lib/typescript/commonjs/sqlite/storage.d.ts +4 -0
- package/lib/typescript/commonjs/storage/index.d.ts +24 -2
- package/lib/typescript/commonjs/utils/imageCompression.d.ts +17 -0
- package/lib/typescript/commonjs/utils/index.d.ts +2 -2
- package/lib/typescript/module/api/baseUrl.d.ts +20 -0
- package/lib/typescript/module/api/curl.d.ts +18 -0
- package/lib/typescript/module/api/retry.d.ts +27 -0
- package/lib/typescript/module/api/userClient.d.ts +11 -0
- package/lib/typescript/module/auth/authStore.d.ts +29 -6
- package/lib/typescript/module/config/index.d.ts +6 -0
- package/lib/typescript/module/deepLink/index.d.ts +54 -0
- package/lib/typescript/module/download/adapters/expoFs.d.ts +45 -0
- package/lib/typescript/module/download/adapters/shared.d.ts +3 -0
- package/lib/typescript/module/download/index.d.ts +76 -0
- package/lib/typescript/module/formatters/index.d.ts +2 -1
- package/lib/typescript/module/formatters/phone.d.ts +16 -1
- package/lib/typescript/module/geolocation/adapters/expoLocation.d.ts +42 -0
- package/lib/typescript/module/geolocation/index.d.ts +89 -0
- package/lib/typescript/module/index.d.ts +30 -13
- package/lib/typescript/module/initSDK.d.ts +32 -0
- package/lib/typescript/module/logger/index.d.ts +39 -0
- package/lib/typescript/module/network/index.d.ts +2 -2
- package/lib/typescript/module/network/networkStatus.d.ts +16 -0
- package/lib/typescript/module/permissions/index.d.ts +35 -0
- package/lib/typescript/module/sqlite/adapters/expo.d.ts +30 -0
- package/lib/typescript/module/sqlite/adapters/op.d.ts +27 -0
- package/lib/typescript/module/sqlite/adapters/rows.d.ts +7 -0
- package/lib/typescript/module/sqlite/adapters/storage.d.ts +30 -0
- package/lib/typescript/module/sqlite/adapters/sync.d.ts +31 -0
- package/lib/typescript/module/sqlite/index.d.ts +121 -0
- package/lib/typescript/module/sqlite/nitro.d.ts +7 -0
- package/lib/typescript/module/sqlite/op.d.ts +8 -0
- package/lib/typescript/module/sqlite/quick.d.ts +4 -0
- package/lib/typescript/module/sqlite/storage.d.ts +4 -0
- package/lib/typescript/module/storage/index.d.ts +24 -2
- package/lib/typescript/module/utils/imageCompression.d.ts +17 -0
- package/lib/typescript/module/utils/index.d.ts +2 -2
- package/package.json +102 -14
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
import KvStore from 'expo-sqlite/kv-store';
|
|
3
4
|
import { Logger } from "../logger/index.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -7,25 +8,31 @@ import { Logger } from "../logger/index.js";
|
|
|
7
8
|
* Lets us avoid a hard import on `@react-native-async-storage/async-storage`.
|
|
8
9
|
*/
|
|
9
10
|
|
|
11
|
+
/** Only what a test or the showcase injected; null means use expo-sqlite/kv-store. */
|
|
10
12
|
let backend = null;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* expo-sqlite's key/value store, imported directly.
|
|
16
|
+
*
|
|
17
|
+
* It deliberately implements the AsyncStorage v1 surface — `getItem`,
|
|
18
|
+
* `setItem`, `removeItem`, `multiGet`, `multiSet`, `multiRemove`, `clear`,
|
|
19
|
+
* `getAllKeys`, with v1's shapes — which is exactly what this module already
|
|
20
|
+
* speaks, so there is nothing to convert. Verified against expo-sqlite 57.0.2.
|
|
21
|
+
*/
|
|
22
|
+
const resolveBackend = () => backend ?? KvStore;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Always true now that the backend ships with the library. Kept because callers
|
|
26
|
+
* whose use of storage is an OPTIMISATION branch on it, and removing it would
|
|
27
|
+
* be a breaking change for no gain.
|
|
28
|
+
*/
|
|
29
|
+
export const isStorageAvailable = () => resolveBackend() !== null;
|
|
25
30
|
const requireBackend = op => {
|
|
26
31
|
const b = resolveBackend();
|
|
27
32
|
if (!b) {
|
|
28
|
-
|
|
33
|
+
// Only reachable if a caller injected something falsy; the default backend
|
|
34
|
+
// ships with the library, so there is no "not installed" case any more.
|
|
35
|
+
const err = new Error(`[Storage] no storage backend available; cannot ${op}.`);
|
|
29
36
|
Logger.error(err.message);
|
|
30
37
|
throw err;
|
|
31
38
|
}
|
|
@@ -33,12 +40,11 @@ const requireBackend = op => {
|
|
|
33
40
|
};
|
|
34
41
|
|
|
35
42
|
/**
|
|
36
|
-
*
|
|
37
|
-
* Pass `null` to
|
|
43
|
+
* Replace the storage backend. Intended for TESTS and for the showcase; an app
|
|
44
|
+
* gets expo-sqlite/kv-store without wiring anything. Pass `null` to restore it.
|
|
38
45
|
*/
|
|
39
46
|
export const setStorageImplementation = impl => {
|
|
40
47
|
backend = impl;
|
|
41
|
-
resolved = true;
|
|
42
48
|
};
|
|
43
49
|
const safeJsonParse = raw => {
|
|
44
50
|
if (raw == null) {
|
|
@@ -92,6 +98,10 @@ const setJson = async (key, value) => {
|
|
|
92
98
|
const multiGet = async keys => {
|
|
93
99
|
try {
|
|
94
100
|
const b = requireBackend('multiGet');
|
|
101
|
+
// v3 first: its Record is already this function's return shape.
|
|
102
|
+
if (b.getMany) {
|
|
103
|
+
return await b.getMany([...keys]);
|
|
104
|
+
}
|
|
95
105
|
if (!b.multiGet) {
|
|
96
106
|
const out = {};
|
|
97
107
|
await Promise.all(keys.map(async k => {
|
|
@@ -113,6 +123,11 @@ const multiGet = async keys => {
|
|
|
113
123
|
const multiSet = async entries => {
|
|
114
124
|
try {
|
|
115
125
|
const b = requireBackend('multiSet');
|
|
126
|
+
// v3 first: it takes the Record this function already receives.
|
|
127
|
+
if (b.setMany) {
|
|
128
|
+
await b.setMany(entries);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
116
131
|
const pairs = Object.entries(entries);
|
|
117
132
|
if (!b.multiSet) {
|
|
118
133
|
await Promise.all(pairs.map(([k, v]) => b.setItem(k, v)));
|
|
@@ -128,6 +143,10 @@ const multiSet = async entries => {
|
|
|
128
143
|
const multiRemove = async keys => {
|
|
129
144
|
try {
|
|
130
145
|
const b = requireBackend('multiRemove');
|
|
146
|
+
if (b.removeMany) {
|
|
147
|
+
await b.removeMany([...keys]);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
131
150
|
if (!b.multiRemove) {
|
|
132
151
|
await Promise.all(keys.map(k => b.removeItem(k)));
|
|
133
152
|
return true;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The expo-application jest mock is exposed on globalThis so a test can blank a
|
|
5
|
+
* value to reach the "no identity anywhere" path. expo ships these as module
|
|
6
|
+
* constants, which cannot be reassigned through the ES binding from a test file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=globals.d.js.map
|
|
@@ -1,20 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
import { ImageManipulator } from 'expo-image-manipulator';
|
|
3
4
|
import { Logger } from "../logger/index.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
/** expo's SaveFormat values, inlined to keep this file free of enum imports. */
|
|
6
|
+
const EXPO_FORMAT = {
|
|
7
|
+
jpg: 'jpeg',
|
|
8
|
+
png: 'png',
|
|
9
|
+
webp: 'webp'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* expo-image-manipulator, adapted to the compressor shape this module speaks.
|
|
14
|
+
*
|
|
15
|
+
* Written against the CONTEXTUAL api rather than `manipulateAsync`, which 57
|
|
16
|
+
* marks deprecated. Only ONE edge is constrained: expo treats a given width and
|
|
17
|
+
* height as targets and would distort the image, where maxWidth/maxHeight here
|
|
18
|
+
* mean a box to fit inside. The smaller bound is used so the result fits
|
|
19
|
+
* whichever way round the image is.
|
|
20
|
+
*/
|
|
21
|
+
const expoCompressorBackend = {
|
|
22
|
+
Image: {
|
|
23
|
+
compress: async (uri, options) => {
|
|
24
|
+
const context = ImageManipulator.manipulate(uri);
|
|
25
|
+
const {
|
|
26
|
+
maxWidth,
|
|
27
|
+
maxHeight
|
|
28
|
+
} = options;
|
|
29
|
+
if (typeof maxWidth === 'number' || typeof maxHeight === 'number') {
|
|
30
|
+
context.resize({
|
|
31
|
+
width: Math.min(maxWidth ?? Number.POSITIVE_INFINITY, maxHeight ?? Number.POSITIVE_INFINITY)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const image = await context.renderAsync();
|
|
35
|
+
const result = await image.saveAsync({
|
|
36
|
+
compress: options.quality,
|
|
37
|
+
format: EXPO_FORMAT[options.output ?? 'jpg'] ?? 'jpeg'
|
|
38
|
+
});
|
|
39
|
+
return result.uri;
|
|
40
|
+
}
|
|
16
41
|
}
|
|
17
|
-
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Only what a test or the showcase injected; null means use expo-image-manipulator. */
|
|
45
|
+
let compressor = null;
|
|
46
|
+
const resolveCompressor = () => compressor ?? expoCompressorBackend;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Replace the compressor. Intended for TESTS and for the showcase; an app gets
|
|
50
|
+
* expo-image-manipulator without wiring anything. Pass `null` to restore it.
|
|
51
|
+
*/
|
|
52
|
+
export const setImageCompressorImplementation = impl => {
|
|
53
|
+
compressor = impl;
|
|
18
54
|
};
|
|
19
55
|
const EIGHT_MB = 8 * 1024 * 1024;
|
|
20
56
|
const THREE_MB = 3 * 1024 * 1024;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
import * as Application from 'expo-application';
|
|
3
4
|
import { useEffect, useState } from 'react';
|
|
4
5
|
// Type-only — erased at compile time; react-native stays lazily required below.
|
|
5
6
|
|
|
@@ -17,6 +18,26 @@ import { Logger } from "../logger/index.js";
|
|
|
17
18
|
* wire two config keys.
|
|
18
19
|
*/
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* expo-application, read at call time.
|
|
23
|
+
*
|
|
24
|
+
* `applicationId` and `nativeApplicationVersion` are module CONSTANTS rather
|
|
25
|
+
* than functions, so they are read inside the accessors rather than captured
|
|
26
|
+
* here — capturing would snapshot them before the native module has
|
|
27
|
+
* initialised.
|
|
28
|
+
*
|
|
29
|
+
* `setConfig({ appId, appVersion })` still WINS over this: a Webority app
|
|
30
|
+
* already carries both in appsettings.Compiled.json, and config is checked
|
|
31
|
+
* first. This is the fallback for an app that would rather read its identity
|
|
32
|
+
* from the binary it is actually running, which is the one place the two can
|
|
33
|
+
* disagree.
|
|
34
|
+
*/
|
|
35
|
+
const expoApplicationBackend = {
|
|
36
|
+
getBundleId: () => Application.applicationId ?? '',
|
|
37
|
+
getVersion: () => Application.nativeApplicationVersion ?? ''
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** Only what a test or the showcase injected; null means use expo-application. */
|
|
20
41
|
let deviceInfo = null;
|
|
21
42
|
|
|
22
43
|
/**
|
|
@@ -46,8 +67,9 @@ const getBundleId = () => {
|
|
|
46
67
|
if (fromConfig) {
|
|
47
68
|
return fromConfig;
|
|
48
69
|
}
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
const fromDevice = (deviceInfo ?? expoApplicationBackend).getBundleId();
|
|
71
|
+
if (fromDevice) {
|
|
72
|
+
return fromDevice;
|
|
51
73
|
}
|
|
52
74
|
throw missing('store identifier', 'appId');
|
|
53
75
|
};
|
|
@@ -56,8 +78,9 @@ const getVersion = () => {
|
|
|
56
78
|
if (fromConfig) {
|
|
57
79
|
return fromConfig;
|
|
58
80
|
}
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
const fromDevice = (deviceInfo ?? expoApplicationBackend).getVersion();
|
|
82
|
+
if (fromDevice) {
|
|
83
|
+
return fromDevice;
|
|
61
84
|
}
|
|
62
85
|
throw missing('version', 'appVersion');
|
|
63
86
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves `baseURL` PER REQUEST rather than at module evaluation.
|
|
4
|
+
*
|
|
5
|
+
* `axios.create({ baseURL: getConfigValue('baseUrl') })` reads the value once,
|
|
6
|
+
* when the module is first imported — which happens the moment anything touches
|
|
7
|
+
* the package barrel, long before an app's startup code can call `setConfig`.
|
|
8
|
+
* The result was a client permanently pinned to `undefined` and a `setConfig`
|
|
9
|
+
* that appeared to do nothing, with no error anywhere: requests just went to a
|
|
10
|
+
* relative URL.
|
|
11
|
+
*
|
|
12
|
+
* A consumer cannot fix that by ordering its own imports, because the import
|
|
13
|
+
* that loses the race is usually one it never wrote. So the clients stop
|
|
14
|
+
* capturing the value and ask for it per request instead.
|
|
15
|
+
*
|
|
16
|
+
* An explicit per-request `baseURL` still wins, which is what keeps a one-off
|
|
17
|
+
* call to a different host possible.
|
|
18
|
+
*/
|
|
19
|
+
export declare const applyConfiguredBaseUrl: (client: AxiosInstance) => void;
|
|
20
|
+
//# sourceMappingURL=baseUrl.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AxiosRequestConfig } from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a copy-pasteable curl command for a request, with every credential
|
|
4
|
+
* replaced by a placeholder.
|
|
5
|
+
*
|
|
6
|
+
* The redaction is the point, not a nicety. An unredacted version of this in a
|
|
7
|
+
* consumer app put `Authorization: Bearer <token>` and the login request's
|
|
8
|
+
* plaintext password into the device console of a *release* staging build.
|
|
9
|
+
* A curl line is worth having; a curl line that has to be trusted not to be
|
|
10
|
+
* enabled in the wrong build is not.
|
|
11
|
+
*/
|
|
12
|
+
export declare const buildCurl: (config: AxiosRequestConfig) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Logs the curl equivalent of a request. Never throws: a failure to describe a
|
|
15
|
+
* request must not be able to fail the request itself.
|
|
16
|
+
*/
|
|
17
|
+
export declare const logCurl: (config: AxiosRequestConfig) => void;
|
|
18
|
+
//# sourceMappingURL=curl.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AxiosError, AxiosInstance } from 'axios';
|
|
2
|
+
export interface RetryPolicy {
|
|
3
|
+
retries?: number;
|
|
4
|
+
/** `attempt` is 1-based: 1 is the first retry, not the original request. */
|
|
5
|
+
retryDelayMs?: (attempt: number) => number;
|
|
6
|
+
shouldRetry?: (error: AxiosError) => boolean;
|
|
7
|
+
onRetry?: (attempt: number, error: AxiosError) => void;
|
|
8
|
+
}
|
|
9
|
+
declare module 'axios' {
|
|
10
|
+
interface AxiosRequestConfig {
|
|
11
|
+
/** `false` opts a single request out of retrying; an object overrides the client policy. */
|
|
12
|
+
retry?: boolean | RetryPolicy;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Status-based ONLY, deliberately: a bare network error (no `error.response`)
|
|
17
|
+
* is never retryable. Both clients carry non-idempotent requests, login and OTP
|
|
18
|
+
* on the public one and every write on the user one, and a broken connection
|
|
19
|
+
* says nothing about whether the request reached the server. Retrying can
|
|
20
|
+
* therefore create a second session, or a duplicate record, that the user never
|
|
21
|
+
* sees. A generic network-error retry rule is not a substitute: it decides on
|
|
22
|
+
* the transport alone and never looks at the HTTP method, so it retries POSTs
|
|
23
|
+
* as readily as GETs.
|
|
24
|
+
*/
|
|
25
|
+
export declare const isRetryableStatus: (status: number | undefined) => boolean;
|
|
26
|
+
export declare const attachRetry: (client: AxiosInstance, policy?: RetryPolicy) => void;
|
|
27
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -45,5 +45,16 @@ export interface RefreshableStore {
|
|
|
45
45
|
declare const userClient: AxiosInstance;
|
|
46
46
|
export declare const injectStore: <S>(_store: S) => void;
|
|
47
47
|
export declare const injectAuthActions: (actions: AuthActions) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Clear any in-flight token refresh and reject everything queued behind it.
|
|
50
|
+
* Call this on logout.
|
|
51
|
+
*
|
|
52
|
+
* Without it, a refresh that was already in flight when the user logged out
|
|
53
|
+
* resolves afterwards and replays every queued request with a token for a
|
|
54
|
+
* session that has ended. The queue is module state, so it survives the logout
|
|
55
|
+
* entirely: nothing else clears it. A consumer app hit this and hand-wrote the
|
|
56
|
+
* same function locally, which is how it was found.
|
|
57
|
+
*/
|
|
58
|
+
export declare const resetRefreshState: () => void;
|
|
48
59
|
export default userClient;
|
|
49
60
|
//# sourceMappingURL=userClient.d.ts.map
|
|
@@ -2,6 +2,15 @@ import type * as KeychainModule from 'react-native-keychain';
|
|
|
2
2
|
/**
|
|
3
3
|
* Token data persisted in the keychain.
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* The two keys the library itself reads. Everything in the library that needs
|
|
7
|
+
* the bearer token, the HTTP client, the download module and the authenticated
|
|
8
|
+
* image cache, resolves it through these rather than repeating the literal, so
|
|
9
|
+
* one of them cannot silently drift and start reading a key nothing writes.
|
|
10
|
+
* Apps are free to store their own tokens under any other key.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ACCESS_TOKEN_KEY = "accessToken";
|
|
13
|
+
export declare const REFRESH_TOKEN_KEY = "refreshToken";
|
|
5
14
|
export interface StoredToken {
|
|
6
15
|
token: string;
|
|
7
16
|
expiry: string;
|
|
@@ -11,20 +20,34 @@ export interface StoredToken {
|
|
|
11
20
|
* Lets us avoid a hard import on `react-native-keychain`, so an app that never
|
|
12
21
|
* stores a token does not have to install it.
|
|
13
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* The GENERIC password API, not the internet-credentials one.
|
|
25
|
+
*
|
|
26
|
+
* `kSecClassInternetPassword` exists for credentials bound to a server, protocol
|
|
27
|
+
* and port, and it integrates with Safari and AutoFill. A bearer token keyed by
|
|
28
|
+
* a name like "accessToken" is none of those things, and the library was only
|
|
29
|
+
* satisfying that API's required `server` argument by passing the key twice,
|
|
30
|
+
* once as the server and once as the service. That is misuse of the class.
|
|
31
|
+
*
|
|
32
|
+
* `kSecClassGenericPassword` is the class for app-local secrets, which is what a
|
|
33
|
+
* token is. It is what expo-secure-store uses underneath, and what the consumer
|
|
34
|
+
* app being migrated had already chosen for itself.
|
|
35
|
+
*/
|
|
14
36
|
interface KeychainLike {
|
|
15
|
-
|
|
37
|
+
setGenericPassword: (username: string, password: string, options?: {
|
|
16
38
|
service?: string;
|
|
17
39
|
}) => Promise<unknown>;
|
|
18
|
-
|
|
40
|
+
getGenericPassword: (options?: {
|
|
19
41
|
service?: string;
|
|
20
42
|
}) => Promise<KeychainModule.UserCredentials | false>;
|
|
21
|
-
|
|
22
|
-
service
|
|
43
|
+
resetGenericPassword: (options?: {
|
|
44
|
+
service?: string;
|
|
23
45
|
}) => Promise<unknown>;
|
|
24
46
|
}
|
|
25
47
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
48
|
+
* Replace the secure-store backend. Intended for TESTS and for the showcase,
|
|
49
|
+
* which injects a failing store to demo the write-failure path; it is not how
|
|
50
|
+
* an app configures the library. Pass `null` to restore expo-secure-store.
|
|
28
51
|
*/
|
|
29
52
|
export declare const setKeychainImplementation: (impl: KeychainLike | null) => void;
|
|
30
53
|
/**
|
|
@@ -27,6 +27,12 @@ export interface Config {
|
|
|
27
27
|
appId: string | null;
|
|
28
28
|
/** The app's user-visible version string, e.g. `'1.4.2'`. Same rationale as `appId`. */
|
|
29
29
|
appVersion: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Log a copy-pasteable curl command for every API request. Credentials are
|
|
32
|
+
* redacted either way, but this is still request-level noise, so it stays off
|
|
33
|
+
* unless an app asks for it while debugging.
|
|
34
|
+
*/
|
|
35
|
+
logCurl: boolean;
|
|
30
36
|
}
|
|
31
37
|
/**
|
|
32
38
|
* Set global configuration for all Webority packages
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface ParsedLink {
|
|
2
|
+
/** The original URL, trimmed. */
|
|
3
|
+
url: string;
|
|
4
|
+
/** Lower-cased scheme without `://`, or '' when the URL carried none. */
|
|
5
|
+
scheme: string;
|
|
6
|
+
/**
|
|
7
|
+
* The authority for http(s) URLs. Custom schemes put the first route segment
|
|
8
|
+
* there (`myapp://order/12`), so for those `host` is `segments[0]` and stays
|
|
9
|
+
* part of `path` so one route pattern matches both link shapes.
|
|
10
|
+
*/
|
|
11
|
+
host: string;
|
|
12
|
+
/** Route path with no leading or trailing slash. */
|
|
13
|
+
path: string;
|
|
14
|
+
segments: string[];
|
|
15
|
+
/** Query values, decoded. A repeated key keeps its last occurrence. */
|
|
16
|
+
query: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
export interface DeepLinkRoute {
|
|
19
|
+
/** A path pattern with `:param` segments (`order/:id`), or a RegExp on `path`. */
|
|
20
|
+
match: string | RegExp;
|
|
21
|
+
requiresAuth?: boolean;
|
|
22
|
+
handler: (link: ParsedLink, params: Record<string, string>) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface DeepLinkConfig {
|
|
25
|
+
routes: DeepLinkRoute[];
|
|
26
|
+
/** Navigator readiness. Links arriving before this is true are queued. */
|
|
27
|
+
isReady?: () => boolean;
|
|
28
|
+
isAuthenticated?: () => boolean;
|
|
29
|
+
/** Called when an auth-gated link is stashed; the app sends the user to login. */
|
|
30
|
+
onUnauthenticated?: (link: ParsedLink) => void;
|
|
31
|
+
onUnmatched?: (link: ParsedLink) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse a deep-link URL. Returns null for anything that is not a usable URL so
|
|
35
|
+
* a hostile or truncated link can never throw on the native event path.
|
|
36
|
+
*/
|
|
37
|
+
export declare const parseDeepLink: (url: string) => ParsedLink | null;
|
|
38
|
+
export declare const DeepLink: {
|
|
39
|
+
configure: (next: DeepLinkConfig) => void;
|
|
40
|
+
start: () => Promise<void>;
|
|
41
|
+
stop: () => void;
|
|
42
|
+
handleUrl: (url: string) => void;
|
|
43
|
+
setReady: (ready: boolean) => void;
|
|
44
|
+
/** Replay the stashed link, once. Call after a successful login. */
|
|
45
|
+
replayPending: () => void;
|
|
46
|
+
getPending: () => ParsedLink | null;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Configure and start the deep-link service for the lifetime of a component.
|
|
50
|
+
* The stored config delegates to the latest render, so new route closures do
|
|
51
|
+
* not tear down and re-subscribe the native listener.
|
|
52
|
+
*/
|
|
53
|
+
export declare const useDeepLink: (deepLinkConfig: DeepLinkConfig) => void;
|
|
54
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FileSystemLike } from '../index';
|
|
2
|
+
/**
|
|
3
|
+
* expo-file-system. Shape verified against 57.0.6, where the legacy function
|
|
4
|
+
* API (`downloadAsync`, `getInfoAsync`) still exists on the main entry point
|
|
5
|
+
* but every one of those functions THROWS at runtime; they now live behind
|
|
6
|
+
* `expo-file-system/legacy`. This adapter therefore uses the class API only.
|
|
7
|
+
*
|
|
8
|
+
* The REQUIRE lives in the entry point beside this file, never here.
|
|
9
|
+
*/
|
|
10
|
+
interface ExpoFileLike {
|
|
11
|
+
readonly uri: string;
|
|
12
|
+
readonly exists: boolean;
|
|
13
|
+
readonly size: number;
|
|
14
|
+
delete: () => void;
|
|
15
|
+
}
|
|
16
|
+
interface ExpoDirectoryLike {
|
|
17
|
+
readonly uri: string;
|
|
18
|
+
create: (options?: {
|
|
19
|
+
intermediates?: boolean;
|
|
20
|
+
idempotent?: boolean;
|
|
21
|
+
}) => void;
|
|
22
|
+
}
|
|
23
|
+
interface ExpoDownloadTaskLike {
|
|
24
|
+
downloadAsync: () => Promise<ExpoFileLike | null>;
|
|
25
|
+
cancel: () => void;
|
|
26
|
+
}
|
|
27
|
+
export interface ExpoFileSystemModuleLike {
|
|
28
|
+
File: (new (uri: string) => ExpoFileLike) & {
|
|
29
|
+
createDownloadTask: (url: string, destination: ExpoFileLike, options?: {
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
onProgress?: (progress: {
|
|
32
|
+
bytesWritten: number;
|
|
33
|
+
totalBytes: number;
|
|
34
|
+
}) => void;
|
|
35
|
+
}) => ExpoDownloadTaskLike;
|
|
36
|
+
};
|
|
37
|
+
Directory: new (uri: string) => ExpoDirectoryLike;
|
|
38
|
+
Paths: {
|
|
39
|
+
document: ExpoDirectoryLike;
|
|
40
|
+
cache: ExpoDirectoryLike;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export declare const adaptExpoFileSystem: (mod: unknown) => FileSystemLike | null;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=expoFs.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface FileSystemDirs {
|
|
2
|
+
documents: string;
|
|
3
|
+
cache: string;
|
|
4
|
+
downloads: string;
|
|
5
|
+
}
|
|
6
|
+
export interface FileSystemDownloadRequest {
|
|
7
|
+
url: string;
|
|
8
|
+
path: string;
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
onProgress?: (received: number, total: number) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface FileSystemDownloadHandle {
|
|
13
|
+
promise: Promise<{
|
|
14
|
+
status?: number;
|
|
15
|
+
bytes?: number;
|
|
16
|
+
}>;
|
|
17
|
+
cancel?: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The slice of a native filesystem module this module actually uses. Both
|
|
21
|
+
* `react-native-blob-util` and `react-native-fs` are adapted onto it, and an app
|
|
22
|
+
* can inject its own with `setFileSystemImplementation`.
|
|
23
|
+
*/
|
|
24
|
+
export interface FileSystemLike {
|
|
25
|
+
dirs: FileSystemDirs;
|
|
26
|
+
download: (request: FileSystemDownloadRequest) => FileSystemDownloadHandle;
|
|
27
|
+
exists: (path: string) => Promise<boolean>;
|
|
28
|
+
stat: (path: string) => Promise<{
|
|
29
|
+
size: number;
|
|
30
|
+
}>;
|
|
31
|
+
unlink: (path: string) => Promise<void>;
|
|
32
|
+
mkdir: (path: string) => Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export type DownloadDestination = 'documents' | 'cache' | 'downloads';
|
|
35
|
+
export interface DownloadOptions {
|
|
36
|
+
url: string;
|
|
37
|
+
fileName?: string;
|
|
38
|
+
destination?: DownloadDestination;
|
|
39
|
+
headers?: Record<string, string>;
|
|
40
|
+
authenticated?: boolean;
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
onProgress?: (received: number, total: number, fraction: number) => void;
|
|
43
|
+
overwrite?: boolean;
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}
|
|
46
|
+
export interface DownloadResult {
|
|
47
|
+
path: string;
|
|
48
|
+
bytes: number;
|
|
49
|
+
mimeType?: string;
|
|
50
|
+
fromCache: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type DownloadErrorCode = 'unsupported' | 'permission-denied' | 'network' | 'http-error' | 'write-failed' | 'aborted' | 'empty-file';
|
|
53
|
+
export declare class DownloadError extends Error {
|
|
54
|
+
readonly code: DownloadErrorCode;
|
|
55
|
+
readonly status?: number;
|
|
56
|
+
constructor(code: DownloadErrorCode, message: string, status?: number);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Replace the filesystem backend. Intended for TESTS and for the showcase,
|
|
60
|
+
* which injects a denying backend to demo the permission error; an app gets
|
|
61
|
+
* expo-file-system without wiring anything. Pass `null` to restore it.
|
|
62
|
+
*/
|
|
63
|
+
export declare const setFileSystemImplementation: (impl: FileSystemLike | null) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Download a file to the device, attaching the stored bearer token by default.
|
|
66
|
+
*
|
|
67
|
+
* A finished download is always verified to be non-empty: a 0-byte file looks
|
|
68
|
+
* like a success to every caller and then wedges whatever consumes it, so it is
|
|
69
|
+
* deleted and reported as `empty-file`.
|
|
70
|
+
*/
|
|
71
|
+
export declare const downloadFile: (options: DownloadOptions) => Promise<DownloadResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Hand a downloaded file to the OS, to open in whichever app claims it.
|
|
74
|
+
*/
|
|
75
|
+
export declare const openFile: (path: string, mimeType?: string) => Promise<void>;
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,5 +4,6 @@ export type { DateInput, DateStyle, TimeStyle } from './date';
|
|
|
4
4
|
export { formatDate, formatDateTime, formatRelativeTime, formatTime } from './date';
|
|
5
5
|
export { getInitials } from './initials';
|
|
6
6
|
export { formatCompactNumber, formatNumber, formatPercent } from './number';
|
|
7
|
-
export {
|
|
7
|
+
export type { FormatPhoneOptions, PhoneCountry } from './phone';
|
|
8
|
+
export { detectPhoneCountry, formatPhone, normalizePhone } from './phone';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
+
export type PhoneCountry = 'IN' | 'US' | 'GB' | 'AE' | 'AU' | 'SG' | 'CA';
|
|
2
|
+
export interface FormatPhoneOptions {
|
|
3
|
+
defaultCountryCode?: string;
|
|
4
|
+
country?: PhoneCountry;
|
|
5
|
+
includeCountryCode?: boolean;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Strip everything except digits and a leading `+` (preserved if present).
|
|
3
9
|
*/
|
|
4
10
|
export declare const normalizePhone: (input: string) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Detect the country of a phone number: from its own `+` country code when
|
|
13
|
+
* present, otherwise from `defaultCountryCode`. Returns null when neither
|
|
14
|
+
* carries a recognised calling code.
|
|
15
|
+
*/
|
|
16
|
+
export declare const detectPhoneCountry: (input: string, defaultCountryCode?: string) => PhoneCountry | null;
|
|
5
17
|
/**
|
|
6
18
|
* Format a phone number for human display.
|
|
7
19
|
*
|
|
8
20
|
* - Indian mobile (10 digits) → `XXXXX XXXXX`
|
|
9
21
|
* - With `+91` country code → `+91 XXXXX XXXXX`
|
|
22
|
+
* - A number that already carries a recognised country code is grouped for
|
|
23
|
+
* that country regardless of `defaultCountryCode`.
|
|
10
24
|
* - Other inputs are returned as `+CC NNNN NNNN…` best-effort grouping.
|
|
11
25
|
*/
|
|
12
|
-
export declare
|
|
26
|
+
export declare function formatPhone(input: string, defaultCountryCode?: string): string;
|
|
27
|
+
export declare function formatPhone(input: string, options?: FormatPhoneOptions): string;
|
|
13
28
|
//# sourceMappingURL=phone.d.ts.map
|