@harkenapp/sdk-react-native 0.0.1-alpha.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 +67 -0
- package/app.plugin.cjs +135 -0
- package/app.plugin.js +1 -0
- package/dist/api/client.d.ts +67 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +163 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/errors.d.ts +46 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +72 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +20 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/retry.d.ts +29 -0
- package/dist/api/retry.d.ts.map +1 -0
- package/dist/api/retry.js +74 -0
- package/dist/api/retry.js.map +1 -0
- package/dist/attachments/FeedbackSheet.d.ts +88 -0
- package/dist/attachments/FeedbackSheet.d.ts.map +1 -0
- package/dist/attachments/FeedbackSheet.js +250 -0
- package/dist/attachments/FeedbackSheet.js.map +1 -0
- package/dist/attachments/index.d.ts +20 -0
- package/dist/attachments/index.d.ts.map +1 -0
- package/dist/attachments/index.js +40 -0
- package/dist/attachments/index.js.map +1 -0
- package/dist/components/AttachmentGrid.d.ts +94 -0
- package/dist/components/AttachmentGrid.d.ts.map +1 -0
- package/dist/components/AttachmentGrid.js +132 -0
- package/dist/components/AttachmentGrid.js.map +1 -0
- package/dist/components/AttachmentPicker.d.ts +98 -0
- package/dist/components/AttachmentPicker.d.ts.map +1 -0
- package/dist/components/AttachmentPicker.js +297 -0
- package/dist/components/AttachmentPicker.js.map +1 -0
- package/dist/components/AttachmentPreview.d.ts +78 -0
- package/dist/components/AttachmentPreview.d.ts.map +1 -0
- package/dist/components/AttachmentPreview.js +133 -0
- package/dist/components/AttachmentPreview.js.map +1 -0
- package/dist/components/CategorySelector.d.ts +77 -0
- package/dist/components/CategorySelector.d.ts.map +1 -0
- package/dist/components/CategorySelector.js +117 -0
- package/dist/components/CategorySelector.js.map +1 -0
- package/dist/components/FeedbackForm.d.ts +50 -0
- package/dist/components/FeedbackForm.d.ts.map +1 -0
- package/dist/components/FeedbackForm.js +141 -0
- package/dist/components/FeedbackForm.js.map +1 -0
- package/dist/components/FeedbackSheet.d.ts +75 -0
- package/dist/components/FeedbackSheet.d.ts.map +1 -0
- package/dist/components/FeedbackSheet.js +215 -0
- package/dist/components/FeedbackSheet.js.map +1 -0
- package/dist/components/ThemedButton.d.ts +23 -0
- package/dist/components/ThemedButton.d.ts.map +1 -0
- package/dist/components/ThemedButton.js +77 -0
- package/dist/components/ThemedButton.js.map +1 -0
- package/dist/components/ThemedText.d.ts +16 -0
- package/dist/components/ThemedText.d.ts.map +1 -0
- package/dist/components/ThemedText.js +44 -0
- package/dist/components/ThemedText.js.map +1 -0
- package/dist/components/ThemedTextInput.d.ts +13 -0
- package/dist/components/ThemedTextInput.d.ts.map +1 -0
- package/dist/components/ThemedTextInput.js +76 -0
- package/dist/components/ThemedTextInput.js.map +1 -0
- package/dist/components/UploadStatusOverlay.d.ts +82 -0
- package/dist/components/UploadStatusOverlay.d.ts.map +1 -0
- package/dist/components/UploadStatusOverlay.js +319 -0
- package/dist/components/UploadStatusOverlay.js.map +1 -0
- package/dist/components/index.d.ts +19 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +28 -0
- package/dist/components/index.js.map +1 -0
- package/dist/context/HarkenContext.d.ts +62 -0
- package/dist/context/HarkenContext.d.ts.map +1 -0
- package/dist/context/HarkenContext.js +128 -0
- package/dist/context/HarkenContext.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +7 -0
- package/dist/context/index.js.map +1 -0
- package/dist/domain/index.d.ts +3 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +7 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/upload-queue.d.ts +116 -0
- package/dist/domain/upload-queue.d.ts.map +1 -0
- package/dist/domain/upload-queue.js +34 -0
- package/dist/domain/upload-queue.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +16 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useAnonymousId.d.ts +28 -0
- package/dist/hooks/useAnonymousId.d.ts.map +1 -0
- package/dist/hooks/useAnonymousId.js +59 -0
- package/dist/hooks/useAnonymousId.js.map +1 -0
- package/dist/hooks/useAttachmentPicker.d.ts +84 -0
- package/dist/hooks/useAttachmentPicker.d.ts.map +1 -0
- package/dist/hooks/useAttachmentPicker.js +181 -0
- package/dist/hooks/useAttachmentPicker.js.map +1 -0
- package/dist/hooks/useAttachmentStatus.d.ts +51 -0
- package/dist/hooks/useAttachmentStatus.d.ts.map +1 -0
- package/dist/hooks/useAttachmentStatus.js +69 -0
- package/dist/hooks/useAttachmentStatus.js.map +1 -0
- package/dist/hooks/useAttachmentUpload.d.ts +101 -0
- package/dist/hooks/useAttachmentUpload.d.ts.map +1 -0
- package/dist/hooks/useAttachmentUpload.js +293 -0
- package/dist/hooks/useAttachmentUpload.js.map +1 -0
- package/dist/hooks/useFeedback.d.ts +55 -0
- package/dist/hooks/useFeedback.d.ts.map +1 -0
- package/dist/hooks/useFeedback.js +96 -0
- package/dist/hooks/useFeedback.js.map +1 -0
- package/dist/hooks/useHarkenContext.d.ts +25 -0
- package/dist/hooks/useHarkenContext.d.ts.map +1 -0
- package/dist/hooks/useHarkenContext.js +35 -0
- package/dist/hooks/useHarkenContext.js.map +1 -0
- package/dist/hooks/useHarkenTheme.d.ts +26 -0
- package/dist/hooks/useHarkenTheme.d.ts.map +1 -0
- package/dist/hooks/useHarkenTheme.js +36 -0
- package/dist/hooks/useHarkenTheme.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +9 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/uploadQueueService.d.ts +193 -0
- package/dist/services/uploadQueueService.d.ts.map +1 -0
- package/dist/services/uploadQueueService.js +623 -0
- package/dist/services/uploadQueueService.js.map +1 -0
- package/dist/services/uploadQueueStorage.d.ts +30 -0
- package/dist/services/uploadQueueStorage.d.ts.map +1 -0
- package/dist/services/uploadQueueStorage.js +77 -0
- package/dist/services/uploadQueueStorage.js.map +1 -0
- package/dist/storage/IdentityStore.d.ts +38 -0
- package/dist/storage/IdentityStore.d.ts.map +1 -0
- package/dist/storage/IdentityStore.js +83 -0
- package/dist/storage/IdentityStore.js.map +1 -0
- package/dist/storage/SecureStoreAdapter.d.ts +28 -0
- package/dist/storage/SecureStoreAdapter.d.ts.map +1 -0
- package/dist/storage/SecureStoreAdapter.js +52 -0
- package/dist/storage/SecureStoreAdapter.js.map +1 -0
- package/dist/storage/defaultStorage.d.ts +20 -0
- package/dist/storage/defaultStorage.d.ts.map +1 -0
- package/dist/storage/defaultStorage.js +131 -0
- package/dist/storage/defaultStorage.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/types.d.ts +32 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +11 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/theme/defaults.d.ts +43 -0
- package/dist/theme/defaults.d.ts.map +1 -0
- package/dist/theme/defaults.js +128 -0
- package/dist/theme/defaults.js.map +1 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +14 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/types.d.ts +136 -0
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +3 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/types/config.d.ts +100 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/openapi.d.ts +601 -0
- package/dist/types/openapi.d.ts.map +1 -0
- package/dist/types/openapi.js +7 -0
- package/dist/types/openapi.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/uuid.d.ts +10 -0
- package/dist/utils/uuid.d.ts.map +1 -0
- package/dist/utils/uuid.js +60 -0
- package/dist/utils/uuid.js.map +1 -0
- package/package.json +124 -0
- package/src/@types/expo-file-system-legacy.d.ts +13 -0
- package/src/api/client.ts +250 -0
- package/src/api/errors.ts +84 -0
- package/src/api/index.ts +15 -0
- package/src/api/retry.ts +99 -0
- package/src/attachments/FeedbackSheet.tsx +400 -0
- package/src/attachments/index.ts +70 -0
- package/src/components/AttachmentGrid.tsx +247 -0
- package/src/components/AttachmentPicker.tsx +391 -0
- package/src/components/AttachmentPreview.tsx +210 -0
- package/src/components/CategorySelector.tsx +174 -0
- package/src/components/FeedbackForm.tsx +216 -0
- package/src/components/FeedbackSheet.tsx +321 -0
- package/src/components/ThemedButton.tsx +127 -0
- package/src/components/ThemedText.tsx +65 -0
- package/src/components/ThemedTextInput.tsx +65 -0
- package/src/components/UploadStatusOverlay.tsx +440 -0
- package/src/components/index.ts +39 -0
- package/src/context/HarkenContext.tsx +129 -0
- package/src/context/index.ts +2 -0
- package/src/domain/index.ts +12 -0
- package/src/domain/upload-queue.ts +131 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useAnonymousId.ts +68 -0
- package/src/hooks/useAttachmentPicker.ts +243 -0
- package/src/hooks/useAttachmentStatus.ts +86 -0
- package/src/hooks/useAttachmentUpload.ts +370 -0
- package/src/hooks/useFeedback.ts +139 -0
- package/src/hooks/useHarkenContext.ts +35 -0
- package/src/hooks/useHarkenTheme.ts +36 -0
- package/src/index.ts +168 -0
- package/src/services/index.ts +11 -0
- package/src/services/uploadQueueService.ts +727 -0
- package/src/services/uploadQueueStorage.ts +78 -0
- package/src/storage/IdentityStore.ts +89 -0
- package/src/storage/SecureStoreAdapter.ts +59 -0
- package/src/storage/defaultStorage.ts +109 -0
- package/src/storage/index.ts +5 -0
- package/src/storage/types.ts +34 -0
- package/src/theme/defaults.ts +151 -0
- package/src/theme/index.ts +23 -0
- package/src/theme/types.ts +157 -0
- package/src/types/config.ts +112 -0
- package/src/types/index.ts +10 -0
- package/src/types/openapi.ts +601 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/uuid.ts +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Harken React Native SDK
|
|
2
|
+
|
|
3
|
+
React Native / Expo SDK for submitting in-app feedback.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx expo install @harkenapp/sdk-react-native
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Permissions
|
|
12
|
+
|
|
13
|
+
The SDK requires camera and photo library permissions to support attachment features. The SDK includes an Expo config plugin that automatically configures these permissions.
|
|
14
|
+
|
|
15
|
+
### Automatic Configuration (Recommended)
|
|
16
|
+
|
|
17
|
+
Add the SDK to your `app.json` or `app.config.js` plugins:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"expo": {
|
|
22
|
+
"plugins": [
|
|
23
|
+
"@harkenapp/sdk-react-native"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This automatically configures:
|
|
30
|
+
|
|
31
|
+
**iOS (Info.plist):**
|
|
32
|
+
- `NSCameraUsageDescription` - Camera access for taking photos
|
|
33
|
+
- `NSPhotoLibraryUsageDescription` - Photo library access for selecting images
|
|
34
|
+
|
|
35
|
+
> **Note:** `NSDocumentsFolderUsageDescription` is not required. The SDK uses `expo-document-picker` which presents the system document picker UI, handling file access permissions automatically without needing an Info.plist entry.
|
|
36
|
+
|
|
37
|
+
**Android (AndroidManifest.xml):**
|
|
38
|
+
- `android.permission.CAMERA` - Camera access
|
|
39
|
+
- `android.permission.READ_MEDIA_IMAGES` - Photo library access (Android 13+)
|
|
40
|
+
- `android.permission.READ_EXTERNAL_STORAGE` - Photo library access (Android 12 and below)
|
|
41
|
+
|
|
42
|
+
### Custom Permission Strings
|
|
43
|
+
|
|
44
|
+
You can customize the iOS permission dialog strings:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"expo": {
|
|
49
|
+
"plugins": [
|
|
50
|
+
["@harkenapp/sdk-react-native", {
|
|
51
|
+
"cameraPermission": "Take photos to include with your feedback",
|
|
52
|
+
"photoLibraryPermission": "Select photos to include with your feedback"
|
|
53
|
+
}]
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### After Configuration
|
|
60
|
+
|
|
61
|
+
Run prebuild to apply the permissions:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx expo prebuild
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or if using EAS Build, permissions are applied automatically during the build process.
|
package/app.plugin.cjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo config plugin for @harkenapp/sdk-react-native
|
|
3
|
+
*
|
|
4
|
+
* Automatically configures iOS and Android permissions required for
|
|
5
|
+
* camera, photo library, and document picker functionality.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // app.json or app.config.js
|
|
9
|
+
* {
|
|
10
|
+
* "expo": {
|
|
11
|
+
* "plugins": [
|
|
12
|
+
* "@harkenapp/sdk-react-native"
|
|
13
|
+
* ]
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // With custom permission strings
|
|
19
|
+
* {
|
|
20
|
+
* "expo": {
|
|
21
|
+
* "plugins": [
|
|
22
|
+
* ["@harkenapp/sdk-react-native", {
|
|
23
|
+
* "cameraPermission": "Take photos to include with your feedback",
|
|
24
|
+
* "photoLibraryPermission": "Select photos to include with your feedback"
|
|
25
|
+
* }]
|
|
26
|
+
* ]
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
withInfoPlist,
|
|
33
|
+
withAndroidManifest,
|
|
34
|
+
} = require('@expo/config-plugins');
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default permission strings for iOS
|
|
38
|
+
*/
|
|
39
|
+
const DEFAULT_PERMISSIONS = {
|
|
40
|
+
cameraPermission: 'Allow $(PRODUCT_NAME) to access your camera to take photos for feedback',
|
|
41
|
+
photoLibraryPermission: 'Allow $(PRODUCT_NAME) to access your photos to include with feedback',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Configure iOS Info.plist permissions
|
|
46
|
+
*/
|
|
47
|
+
function withIosPermissions(config, options) {
|
|
48
|
+
return withInfoPlist(config, (config) => {
|
|
49
|
+
// Camera permission
|
|
50
|
+
// Custom option overrides existing; default only sets if missing
|
|
51
|
+
if (options.cameraPermission) {
|
|
52
|
+
config.modResults.NSCameraUsageDescription = options.cameraPermission;
|
|
53
|
+
} else if (!config.modResults.NSCameraUsageDescription) {
|
|
54
|
+
config.modResults.NSCameraUsageDescription = DEFAULT_PERMISSIONS.cameraPermission;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Photo library permission
|
|
58
|
+
// Custom option overrides existing; default only sets if missing
|
|
59
|
+
if (options.photoLibraryPermission) {
|
|
60
|
+
config.modResults.NSPhotoLibraryUsageDescription = options.photoLibraryPermission;
|
|
61
|
+
} else if (!config.modResults.NSPhotoLibraryUsageDescription) {
|
|
62
|
+
config.modResults.NSPhotoLibraryUsageDescription = DEFAULT_PERMISSIONS.photoLibraryPermission;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return config;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Configure Android AndroidManifest.xml permissions
|
|
71
|
+
*/
|
|
72
|
+
function withAndroidPermissions(config) {
|
|
73
|
+
return withAndroidManifest(config, (config) => {
|
|
74
|
+
const manifest = config.modResults.manifest;
|
|
75
|
+
|
|
76
|
+
// Ensure uses-permission array exists
|
|
77
|
+
if (!manifest['uses-permission']) {
|
|
78
|
+
manifest['uses-permission'] = [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const permissions = manifest['uses-permission'];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Add a permission if it doesn't already exist
|
|
85
|
+
*/
|
|
86
|
+
function addPermission(name, attributes = {}) {
|
|
87
|
+
const exists = permissions.some(
|
|
88
|
+
(p) => p.$?.['android:name'] === name
|
|
89
|
+
);
|
|
90
|
+
if (!exists) {
|
|
91
|
+
permissions.push({
|
|
92
|
+
$: {
|
|
93
|
+
'android:name': name,
|
|
94
|
+
...attributes,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Camera permission
|
|
101
|
+
addPermission('android.permission.CAMERA');
|
|
102
|
+
|
|
103
|
+
// Photo library permissions
|
|
104
|
+
// READ_MEDIA_IMAGES for Android 13+ (API 33+)
|
|
105
|
+
addPermission('android.permission.READ_MEDIA_IMAGES');
|
|
106
|
+
|
|
107
|
+
// READ_EXTERNAL_STORAGE for Android 12 and below
|
|
108
|
+
// Use maxSdkVersion to limit to older APIs
|
|
109
|
+
addPermission('android.permission.READ_EXTERNAL_STORAGE', {
|
|
110
|
+
'android:maxSdkVersion': '32',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return config;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Main plugin function
|
|
119
|
+
*
|
|
120
|
+
* @param {import('@expo/config-plugins').ExpoConfig} config - Expo config
|
|
121
|
+
* @param {Object} options - Plugin options
|
|
122
|
+
* @param {string} [options.cameraPermission] - Custom iOS camera permission string
|
|
123
|
+
* @param {string} [options.photoLibraryPermission] - Custom iOS photo library permission string
|
|
124
|
+
*/
|
|
125
|
+
function withHarkenPermissions(config, options = {}) {
|
|
126
|
+
// Apply iOS permissions
|
|
127
|
+
config = withIosPermissions(config, options);
|
|
128
|
+
|
|
129
|
+
// Apply Android permissions
|
|
130
|
+
config = withAndroidPermissions(config);
|
|
131
|
+
|
|
132
|
+
return config;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = withHarkenPermissions;
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./app.plugin.cjs");
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { components } from '../types/index.js';
|
|
2
|
+
import type { RetryConfig } from './retry';
|
|
3
|
+
type FeedbackSubmission = components['schemas']['FeedbackSubmission'];
|
|
4
|
+
type FeedbackSubmissionResponse = components['schemas']['FeedbackSubmissionResponse'];
|
|
5
|
+
type AttachmentPresignRequest = components['schemas']['AttachmentPresignRequest'];
|
|
6
|
+
type AttachmentPresignResponse = components['schemas']['AttachmentPresignResponse'];
|
|
7
|
+
type AttachmentConfirmRequest = components['schemas']['AttachmentConfirmRequest'];
|
|
8
|
+
type AttachmentStatusResponse = components['schemas']['AttachmentStatusResponse'];
|
|
9
|
+
export interface HarkenClientConfig {
|
|
10
|
+
/** Publishable API key */
|
|
11
|
+
publishableKey: string;
|
|
12
|
+
/** Optional user token for verified identity */
|
|
13
|
+
userToken?: string;
|
|
14
|
+
/** Base URL for API (defaults to production) */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
/** Retry configuration */
|
|
17
|
+
retry?: Partial<RetryConfig>;
|
|
18
|
+
/** Request timeout in ms (default: 30000) */
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Low-level API client for Harken.
|
|
23
|
+
*/
|
|
24
|
+
export declare class HarkenClient {
|
|
25
|
+
private readonly config;
|
|
26
|
+
constructor(config: HarkenClientConfig);
|
|
27
|
+
/**
|
|
28
|
+
* Submit feedback to the API.
|
|
29
|
+
*/
|
|
30
|
+
submitFeedback(submission: FeedbackSubmission): Promise<FeedbackSubmissionResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Create a presigned URL for attachment upload.
|
|
33
|
+
*/
|
|
34
|
+
createAttachmentUpload(request: AttachmentPresignRequest): Promise<AttachmentPresignResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Confirm successful attachment upload.
|
|
37
|
+
*/
|
|
38
|
+
confirmAttachment(attachmentId: string, request?: AttachmentConfirmRequest): Promise<AttachmentStatusResponse>;
|
|
39
|
+
/**
|
|
40
|
+
* Report attachment upload failure.
|
|
41
|
+
* This is a terminal state, so no retry is applied.
|
|
42
|
+
*/
|
|
43
|
+
reportAttachmentFailure(attachmentId: string, error?: string): Promise<AttachmentStatusResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Get attachment status and download URLs.
|
|
46
|
+
*/
|
|
47
|
+
getAttachmentStatus(attachmentId: string): Promise<AttachmentStatusResponse>;
|
|
48
|
+
/**
|
|
49
|
+
* Make an authenticated request to the API.
|
|
50
|
+
*/
|
|
51
|
+
private request;
|
|
52
|
+
/**
|
|
53
|
+
* Parse error response body, with fallback for non-JSON responses.
|
|
54
|
+
*/
|
|
55
|
+
private parseErrorResponse;
|
|
56
|
+
/**
|
|
57
|
+
* Parse Retry-After header value in seconds.
|
|
58
|
+
* Supports both delta-seconds and HTTP-date formats.
|
|
59
|
+
*/
|
|
60
|
+
private parseRetryAfter;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a configured Harken client.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createHarkenClient(config: HarkenClientConfig): HarkenClient;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACtE,KAAK,0BAA0B,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,4BAA4B,CAAC,CAAC;AAItF,KAAK,wBAAwB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,0BAA0B,CAAC,CAAC;AAClF,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,wBAAwB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,0BAA0B,CAAC,CAAC;AAClF,KAAK,wBAAwB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,0BAA0B,CAAC,CAAC;AAIlF,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAG2B;gBAEtC,MAAM,EAAE,kBAAkB;IAUtC;;OAEG;IACG,cAAc,CAClB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,0BAA0B,CAAC;IAUtC;;OAEG;IACG,sBAAsB,CAC1B,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,yBAAyB,CAAC;IAcrC;;OAEG;IACG,iBAAiB,CACrB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,wBAAwB,CAAC;IAcpC;;;OAGG;IACG,uBAAuB,CAC3B,YAAY,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC;IAUpC;;OAEG;IACG,mBAAmB,CACvB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,CAAC;IAMpC;;OAEG;YACW,OAAO;IAiErB;;OAEG;YACW,kBAAkB;IAchC;;;OAGG;IACH,OAAO,CAAC,eAAe;CAqBxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAE3E"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HarkenClient = void 0;
|
|
4
|
+
exports.createHarkenClient = createHarkenClient;
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const retry_1 = require("./retry");
|
|
7
|
+
const DEFAULT_API_BASE_URL = 'https://api.harken.app';
|
|
8
|
+
/**
|
|
9
|
+
* Low-level API client for Harken.
|
|
10
|
+
*/
|
|
11
|
+
class HarkenClient {
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = {
|
|
15
|
+
publishableKey: config.publishableKey,
|
|
16
|
+
userToken: config.userToken,
|
|
17
|
+
baseUrl: config.baseUrl ?? DEFAULT_API_BASE_URL,
|
|
18
|
+
retry: config.retry,
|
|
19
|
+
timeout: config.timeout ?? 30000,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Submit feedback to the API.
|
|
24
|
+
*/
|
|
25
|
+
async submitFeedback(submission) {
|
|
26
|
+
return (0, retry_1.withRetry)(() => this.request('/v1/feedback', {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
body: JSON.stringify(submission),
|
|
29
|
+
}), this.config.retry);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a presigned URL for attachment upload.
|
|
33
|
+
*/
|
|
34
|
+
async createAttachmentUpload(request) {
|
|
35
|
+
return (0, retry_1.withRetry)(() => this.request('/v1/feedback/attachments/presign', {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
body: JSON.stringify(request),
|
|
38
|
+
}), this.config.retry);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Confirm successful attachment upload.
|
|
42
|
+
*/
|
|
43
|
+
async confirmAttachment(attachmentId, request) {
|
|
44
|
+
return (0, retry_1.withRetry)(() => this.request(`/v1/feedback/attachments/${attachmentId}/confirm`, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
body: request ? JSON.stringify(request) : undefined,
|
|
47
|
+
}), this.config.retry);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Report attachment upload failure.
|
|
51
|
+
* This is a terminal state, so no retry is applied.
|
|
52
|
+
*/
|
|
53
|
+
async reportAttachmentFailure(attachmentId, error) {
|
|
54
|
+
return this.request(`/v1/feedback/attachments/${attachmentId}/fail`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
body: error ? JSON.stringify({ error }) : undefined,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get attachment status and download URLs.
|
|
61
|
+
*/
|
|
62
|
+
async getAttachmentStatus(attachmentId) {
|
|
63
|
+
return this.request(`/v1/feedback/attachments/${attachmentId}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Make an authenticated request to the API.
|
|
67
|
+
*/
|
|
68
|
+
async request(path, options = {}) {
|
|
69
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
70
|
+
const headers = {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'X-Publishable-Key': this.config.publishableKey,
|
|
73
|
+
...options.headers,
|
|
74
|
+
};
|
|
75
|
+
if (this.config.userToken) {
|
|
76
|
+
headers['X-User-Token'] = this.config.userToken;
|
|
77
|
+
}
|
|
78
|
+
// Create abort controller for timeout
|
|
79
|
+
const controller = new AbortController();
|
|
80
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
...options,
|
|
84
|
+
headers,
|
|
85
|
+
signal: controller.signal,
|
|
86
|
+
});
|
|
87
|
+
clearTimeout(timeoutId);
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const errorBody = await this.parseErrorResponse(response);
|
|
90
|
+
// Only parse Retry-After for 429 responses
|
|
91
|
+
const retryAfter = response.status === 429
|
|
92
|
+
? this.parseRetryAfter(response)
|
|
93
|
+
: undefined;
|
|
94
|
+
throw new errors_1.HarkenApiError(response.status, errorBody, { retryAfter });
|
|
95
|
+
}
|
|
96
|
+
return (await response.json());
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
clearTimeout(timeoutId);
|
|
100
|
+
// Re-throw HarkenApiError as-is
|
|
101
|
+
if (error instanceof errors_1.HarkenApiError) {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
// Handle abort (timeout)
|
|
105
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
106
|
+
throw new errors_1.HarkenNetworkError('Request timed out', error);
|
|
107
|
+
}
|
|
108
|
+
// Handle other fetch errors (network issues)
|
|
109
|
+
if (error instanceof TypeError) {
|
|
110
|
+
throw new errors_1.HarkenNetworkError('Network request failed', error);
|
|
111
|
+
}
|
|
112
|
+
// Unknown error
|
|
113
|
+
throw new errors_1.HarkenNetworkError(error instanceof Error ? error.message : 'Unknown error', error instanceof Error ? error : undefined);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parse error response body, with fallback for non-JSON responses.
|
|
118
|
+
*/
|
|
119
|
+
async parseErrorResponse(response) {
|
|
120
|
+
try {
|
|
121
|
+
return (await response.json());
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Fallback for non-JSON error responses
|
|
125
|
+
return {
|
|
126
|
+
error: {
|
|
127
|
+
code: `http_${response.status}`,
|
|
128
|
+
message: response.statusText || 'Request failed',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parse Retry-After header value in seconds.
|
|
135
|
+
* Supports both delta-seconds and HTTP-date formats.
|
|
136
|
+
*/
|
|
137
|
+
parseRetryAfter(response) {
|
|
138
|
+
const retryAfter = response.headers.get('Retry-After');
|
|
139
|
+
if (!retryAfter) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
// Try parsing as integer (delta-seconds)
|
|
143
|
+
const seconds = parseInt(retryAfter, 10);
|
|
144
|
+
if (!isNaN(seconds) && seconds >= 0) {
|
|
145
|
+
return seconds;
|
|
146
|
+
}
|
|
147
|
+
// Try parsing as HTTP-date
|
|
148
|
+
const date = Date.parse(retryAfter);
|
|
149
|
+
if (!isNaN(date)) {
|
|
150
|
+
const delayMs = date - Date.now();
|
|
151
|
+
return delayMs > 0 ? Math.ceil(delayMs / 1000) : 0;
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.HarkenClient = HarkenClient;
|
|
157
|
+
/**
|
|
158
|
+
* Create a configured Harken client.
|
|
159
|
+
*/
|
|
160
|
+
function createHarkenClient(config) {
|
|
161
|
+
return new HarkenClient(config);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { components } from '../types/index.js';
|
|
2
|
+
type ErrorResponse = components['schemas']['ErrorResponse'];
|
|
3
|
+
type ErrorDetail = components['schemas']['ErrorDetail'];
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for Harken API errors.
|
|
6
|
+
*/
|
|
7
|
+
export declare class HarkenError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when the API returns an error response.
|
|
12
|
+
*/
|
|
13
|
+
export declare class HarkenApiError extends HarkenError {
|
|
14
|
+
/** HTTP status code */
|
|
15
|
+
readonly status: number;
|
|
16
|
+
/** Machine-readable error code */
|
|
17
|
+
readonly code: string;
|
|
18
|
+
/** Validation error details (if present) */
|
|
19
|
+
readonly details?: ErrorDetail[];
|
|
20
|
+
/** Retry-After value in seconds (from 429 responses) */
|
|
21
|
+
readonly retryAfter?: number;
|
|
22
|
+
constructor(status: number, response: ErrorResponse, options?: {
|
|
23
|
+
retryAfter?: number;
|
|
24
|
+
});
|
|
25
|
+
/** True if this is a validation error (400) */
|
|
26
|
+
get isValidationError(): boolean;
|
|
27
|
+
/** True if this is an auth error (401) */
|
|
28
|
+
get isUnauthorized(): boolean;
|
|
29
|
+
/** True if this is a rate limit error (429) */
|
|
30
|
+
get isRateLimited(): boolean;
|
|
31
|
+
/** True if this is a server error (5xx) */
|
|
32
|
+
get isServerError(): boolean;
|
|
33
|
+
/** True if this error is retryable */
|
|
34
|
+
get isRetryable(): boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Error thrown when a network request fails.
|
|
38
|
+
*/
|
|
39
|
+
export declare class HarkenNetworkError extends HarkenError {
|
|
40
|
+
readonly cause?: Error;
|
|
41
|
+
constructor(message: string, cause?: Error);
|
|
42
|
+
/** Network errors are always retryable */
|
|
43
|
+
get isRetryable(): boolean;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/api/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,KAAK,aAAa,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,CAAC;AAC5D,KAAK,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,CAAC;AAExD;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,uBAAuB;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAG3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAUnC,+CAA+C;IAC/C,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED,0CAA0C;IAC1C,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,+CAA+C;IAC/C,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,2CAA2C;IAC3C,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,sCAAsC;IACtC,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;IAM1C,0CAA0C;IAC1C,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HarkenNetworkError = exports.HarkenApiError = exports.HarkenError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for Harken API errors.
|
|
6
|
+
*/
|
|
7
|
+
class HarkenError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'HarkenError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.HarkenError = HarkenError;
|
|
14
|
+
/**
|
|
15
|
+
* Error thrown when the API returns an error response.
|
|
16
|
+
*/
|
|
17
|
+
class HarkenApiError extends HarkenError {
|
|
18
|
+
/** HTTP status code */
|
|
19
|
+
status;
|
|
20
|
+
/** Machine-readable error code */
|
|
21
|
+
code;
|
|
22
|
+
/** Validation error details (if present) */
|
|
23
|
+
details;
|
|
24
|
+
/** Retry-After value in seconds (from 429 responses) */
|
|
25
|
+
retryAfter;
|
|
26
|
+
constructor(status, response, options) {
|
|
27
|
+
super(response.error.message);
|
|
28
|
+
this.name = 'HarkenApiError';
|
|
29
|
+
this.status = status;
|
|
30
|
+
this.code = response.error.code;
|
|
31
|
+
this.details = response.error.details;
|
|
32
|
+
this.retryAfter = options?.retryAfter;
|
|
33
|
+
}
|
|
34
|
+
/** True if this is a validation error (400) */
|
|
35
|
+
get isValidationError() {
|
|
36
|
+
return this.status === 400;
|
|
37
|
+
}
|
|
38
|
+
/** True if this is an auth error (401) */
|
|
39
|
+
get isUnauthorized() {
|
|
40
|
+
return this.status === 401;
|
|
41
|
+
}
|
|
42
|
+
/** True if this is a rate limit error (429) */
|
|
43
|
+
get isRateLimited() {
|
|
44
|
+
return this.status === 429;
|
|
45
|
+
}
|
|
46
|
+
/** True if this is a server error (5xx) */
|
|
47
|
+
get isServerError() {
|
|
48
|
+
return this.status >= 500;
|
|
49
|
+
}
|
|
50
|
+
/** True if this error is retryable */
|
|
51
|
+
get isRetryable() {
|
|
52
|
+
return this.isRateLimited || this.isServerError;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.HarkenApiError = HarkenApiError;
|
|
56
|
+
/**
|
|
57
|
+
* Error thrown when a network request fails.
|
|
58
|
+
*/
|
|
59
|
+
class HarkenNetworkError extends HarkenError {
|
|
60
|
+
cause;
|
|
61
|
+
constructor(message, cause) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = 'HarkenNetworkError';
|
|
64
|
+
this.cause = cause;
|
|
65
|
+
}
|
|
66
|
+
/** Network errors are always retryable */
|
|
67
|
+
get isRetryable() {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.HarkenNetworkError = HarkenNetworkError;
|
|
72
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/api/errors.ts"],"names":[],"mappings":";;;AAKA;;GAEG;AACH,MAAa,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AALD,kCAKC;AAED;;GAEG;AACH,MAAa,cAAe,SAAQ,WAAW;IAC7C,uBAAuB;IACd,MAAM,CAAS;IACxB,kCAAkC;IACzB,IAAI,CAAS;IACtB,4CAA4C;IACnC,OAAO,CAAiB;IACjC,wDAAwD;IAC/C,UAAU,CAAU;IAE7B,YACE,MAAc,EACd,QAAuB,EACvB,OAAiC;QAEjC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC;IACxC,CAAC;IAED,+CAA+C;IAC/C,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC;IAC7B,CAAC;IAED,0CAA0C;IAC1C,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC;IAC7B,CAAC;IAED,+CAA+C;IAC/C,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC;IAC7B,CAAC;IAED,2CAA2C;IAC3C,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAC5B,CAAC;IAED,sCAAsC;IACtC,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC;IAClD,CAAC;CACF;AA/CD,wCA+CC;AAED;;GAEG;AACH,MAAa,kBAAmB,SAAQ,WAAW;IACxC,KAAK,CAAS;IAEvB,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,0CAA0C;IAC1C,IAAI,WAAW;QACb,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAbD,gDAaC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { HarkenClient, createHarkenClient } from './client';
|
|
2
|
+
export type { HarkenClientConfig } from './client';
|
|
3
|
+
export { HarkenError, HarkenApiError, HarkenNetworkError, } from './errors';
|
|
4
|
+
export { withRetry, calculateRetryDelay, isRetryableError } from './retry';
|
|
5
|
+
export type { RetryConfig } from './retry';
|
|
6
|
+
export { DEFAULT_RETRY_CONFIG } from './retry';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,OAAO,EACL,WAAW,EACX,cAAc,EACd,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_RETRY_CONFIG = exports.isRetryableError = exports.calculateRetryDelay = exports.withRetry = exports.HarkenNetworkError = exports.HarkenApiError = exports.HarkenError = exports.createHarkenClient = exports.HarkenClient = void 0;
|
|
4
|
+
// Client
|
|
5
|
+
var client_1 = require("./client");
|
|
6
|
+
Object.defineProperty(exports, "HarkenClient", { enumerable: true, get: function () { return client_1.HarkenClient; } });
|
|
7
|
+
Object.defineProperty(exports, "createHarkenClient", { enumerable: true, get: function () { return client_1.createHarkenClient; } });
|
|
8
|
+
// Errors
|
|
9
|
+
var errors_1 = require("./errors");
|
|
10
|
+
Object.defineProperty(exports, "HarkenError", { enumerable: true, get: function () { return errors_1.HarkenError; } });
|
|
11
|
+
Object.defineProperty(exports, "HarkenApiError", { enumerable: true, get: function () { return errors_1.HarkenApiError; } });
|
|
12
|
+
Object.defineProperty(exports, "HarkenNetworkError", { enumerable: true, get: function () { return errors_1.HarkenNetworkError; } });
|
|
13
|
+
// Retry utilities
|
|
14
|
+
var retry_1 = require("./retry");
|
|
15
|
+
Object.defineProperty(exports, "withRetry", { enumerable: true, get: function () { return retry_1.withRetry; } });
|
|
16
|
+
Object.defineProperty(exports, "calculateRetryDelay", { enumerable: true, get: function () { return retry_1.calculateRetryDelay; } });
|
|
17
|
+
Object.defineProperty(exports, "isRetryableError", { enumerable: true, get: function () { return retry_1.isRetryableError; } });
|
|
18
|
+
var retry_2 = require("./retry");
|
|
19
|
+
Object.defineProperty(exports, "DEFAULT_RETRY_CONFIG", { enumerable: true, get: function () { return retry_2.DEFAULT_RETRY_CONFIG; } });
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":";;;AAAA,SAAS;AACT,mCAA4D;AAAnD,sGAAA,YAAY,OAAA;AAAE,4GAAA,kBAAkB,OAAA;AAGzC,SAAS;AACT,mCAIkB;AAHhB,qGAAA,WAAW,OAAA;AACX,wGAAA,cAAc,OAAA;AACd,4GAAA,kBAAkB,OAAA;AAGpB,kBAAkB;AAClB,iCAA2E;AAAlE,kGAAA,SAAS,OAAA;AAAE,4GAAA,mBAAmB,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAEzD,iCAA+C;AAAtC,6GAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { HarkenApiError, HarkenNetworkError } from './errors';
|
|
2
|
+
export interface RetryConfig {
|
|
3
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
4
|
+
maxRetries: number;
|
|
5
|
+
/** Base delay in ms for exponential backoff (default: 1000) */
|
|
6
|
+
baseDelay: number;
|
|
7
|
+
/** Maximum delay in ms (default: 30000) */
|
|
8
|
+
maxDelay: number;
|
|
9
|
+
/** Jitter factor 0-1 to randomize delays (default: 0.1) */
|
|
10
|
+
jitter: number;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
13
|
+
/**
|
|
14
|
+
* Calculate delay for a retry attempt with exponential backoff and jitter.
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateRetryDelay(attempt: number, config: RetryConfig, retryAfter?: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Check if an error is retryable.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isRetryableError(error: unknown): error is HarkenApiError | HarkenNetworkError;
|
|
21
|
+
/**
|
|
22
|
+
* Sleep for a given number of milliseconds.
|
|
23
|
+
*/
|
|
24
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Execute a function with retry logic.
|
|
27
|
+
*/
|
|
28
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
|
|
29
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/api/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,cAAc,GAAG,kBAAkB,CAQ9C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC,OAAO,CAAC,CAAC,CAAC,CA0BZ"}
|