@bangkeut-technology/supportdock-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -0
- package/dist/client.d.ts +31 -0
- package/dist/client.js +95 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -0
- package/dist/react.d.ts +22 -0
- package/dist/react.js +49 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +2 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @bangkeut-technology/supportdock-sdk
|
|
2
|
+
|
|
3
|
+
Official SDK for [SupportDock](https://supportdock.io) — submit feedback and manage FAQs from your React Native / Expo app.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bangkeut-technology/supportdock-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { SupportDockClient } from '@bangkeut-technology/supportdock-sdk';
|
|
15
|
+
|
|
16
|
+
const sdk = new SupportDockClient({
|
|
17
|
+
apiKey: 'sdk_your_api_key',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Submit feedback
|
|
21
|
+
await sdk.sendFeedback({
|
|
22
|
+
type: 'bug',
|
|
23
|
+
message: 'App crashes when opening settings',
|
|
24
|
+
email: 'user@example.com',
|
|
25
|
+
metadata: { appVersion: '2.1.0', platform: 'ios' },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// List FAQs
|
|
29
|
+
const faqs = await sdk.listFAQs();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## React Hook (Expo / React Native)
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { useSupportDock } from '@bangkeut-technology/supportdock-sdk';
|
|
36
|
+
import { Platform } from 'react-native';
|
|
37
|
+
|
|
38
|
+
function FeedbackScreen() {
|
|
39
|
+
const { sendFeedback, loading, error, success } = useSupportDock({
|
|
40
|
+
apiKey: 'sdk_your_api_key',
|
|
41
|
+
defaultMetadata: {
|
|
42
|
+
appVersion: '2.1.0',
|
|
43
|
+
platform: Platform.OS,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const handleSubmit = async () => {
|
|
48
|
+
await sendFeedback({
|
|
49
|
+
type: 'bug',
|
|
50
|
+
message: 'Something went wrong',
|
|
51
|
+
email: userEmail,
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (success) return <Text>Thanks for your feedback!</Text>;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View>
|
|
59
|
+
<Button onPress={handleSubmit} disabled={loading} title="Send Feedback" />
|
|
60
|
+
{error && <Text style={{ color: 'red' }}>{error}</Text>}
|
|
61
|
+
</View>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
### `SupportDockClient`
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const sdk = new SupportDockClient({
|
|
72
|
+
apiKey: string; // Required — your app's API key (starts with sdk_)
|
|
73
|
+
baseUrl?: string; // Default: 'https://supportdock.io'
|
|
74
|
+
defaultMetadata?: Record<string, string>; // Merged into every feedback submission
|
|
75
|
+
timeout?: number; // Request timeout in ms (default: 10000)
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Feedback
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// Submit feedback
|
|
83
|
+
await sdk.sendFeedback({
|
|
84
|
+
type: 'bug' | 'feature' | 'question' | 'general', // default: 'general'
|
|
85
|
+
message: string, // required
|
|
86
|
+
email?: string,
|
|
87
|
+
name?: string,
|
|
88
|
+
subject?: string, // auto-generated from type if omitted
|
|
89
|
+
metadata?: Record<string, string>,
|
|
90
|
+
source?: string, // default: 'mobile-app'
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### FAQs
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// List all FAQs
|
|
98
|
+
const faqs = await sdk.listFAQs();
|
|
99
|
+
|
|
100
|
+
// Create FAQ
|
|
101
|
+
const faq = await sdk.createFAQ({ question: '...', answer: '...', sortOrder: 0 });
|
|
102
|
+
|
|
103
|
+
// Update FAQ
|
|
104
|
+
await sdk.updateFAQ(faqId, { answer: 'Updated answer' });
|
|
105
|
+
|
|
106
|
+
// Delete FAQ
|
|
107
|
+
await sdk.deleteFAQ(faqId);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Error Handling
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { SupportDockError } from '@bangkeut-technology/supportdock-sdk';
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await sdk.sendFeedback({ message: '...' });
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err instanceof SupportDockError) {
|
|
119
|
+
console.log(err.message); // Error message from API
|
|
120
|
+
console.log(err.status); // HTTP status code (401, 429, etc.)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Get Your API Key
|
|
126
|
+
|
|
127
|
+
1. Go to your app dashboard on [supportdock.io](https://supportdock.io)
|
|
128
|
+
2. Click **Generate API key**
|
|
129
|
+
3. Copy the key (starts with `sdk_`)
|
|
130
|
+
|
|
131
|
+
Requires a Pro plan.
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SupportDockConfig, FeedbackOptions, FeedbackResult, FAQ, CreateFAQOptions, UpdateFAQOptions } from './types';
|
|
2
|
+
export declare class SupportDockClient {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private baseUrl;
|
|
5
|
+
private defaultMetadata;
|
|
6
|
+
private timeout;
|
|
7
|
+
constructor(config: SupportDockConfig);
|
|
8
|
+
private request;
|
|
9
|
+
/**
|
|
10
|
+
* Submit feedback from your app.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* await sdk.sendFeedback({ type: 'bug', message: 'App crashes on launch' });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
sendFeedback(options: FeedbackOptions): Promise<FeedbackResult>;
|
|
17
|
+
/** List all FAQ entries for this app. */
|
|
18
|
+
listFAQs(): Promise<FAQ[]>;
|
|
19
|
+
/** Create a new FAQ entry. */
|
|
20
|
+
createFAQ(options: CreateFAQOptions): Promise<FAQ>;
|
|
21
|
+
/** Update an existing FAQ entry. */
|
|
22
|
+
updateFAQ(faqId: string, options: UpdateFAQOptions): Promise<FAQ>;
|
|
23
|
+
/** Delete a FAQ entry. */
|
|
24
|
+
deleteFAQ(faqId: string): Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export declare class SupportDockError extends Error {
|
|
29
|
+
status: number;
|
|
30
|
+
constructor(message: string, status: number);
|
|
31
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SupportDockError = exports.SupportDockClient = void 0;
|
|
4
|
+
const DEFAULT_BASE_URL = 'https://supportdock.io';
|
|
5
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
6
|
+
class SupportDockClient {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
if (!config.apiKey)
|
|
9
|
+
throw new Error('SupportDock: apiKey is required');
|
|
10
|
+
this.apiKey = config.apiKey;
|
|
11
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
12
|
+
this.defaultMetadata = config.defaultMetadata ?? {};
|
|
13
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
14
|
+
}
|
|
15
|
+
async request(path, options = {}) {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
20
|
+
...options,
|
|
21
|
+
signal: controller.signal,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
'x-api-key': this.apiKey,
|
|
25
|
+
...options.headers,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const data = await res.json();
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
throw new SupportDockError(data.error ?? `Request failed with status ${res.status}`, res.status);
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ─── Feedback ────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Submit feedback from your app.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* await sdk.sendFeedback({ type: 'bug', message: 'App crashes on launch' });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
async sendFeedback(options) {
|
|
47
|
+
const metadata = { ...this.defaultMetadata, ...options.metadata };
|
|
48
|
+
return this.request('/api/feedback/remote', {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
type: options.type ?? 'general',
|
|
52
|
+
message: options.message,
|
|
53
|
+
email: options.email,
|
|
54
|
+
name: options.name,
|
|
55
|
+
subject: options.subject,
|
|
56
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
57
|
+
source: options.source ?? 'mobile-app',
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// ─── FAQ ─────────────────────────────────────────────────────
|
|
62
|
+
/** List all FAQ entries for this app. */
|
|
63
|
+
async listFAQs() {
|
|
64
|
+
return this.request('/api/faqs/remote');
|
|
65
|
+
}
|
|
66
|
+
/** Create a new FAQ entry. */
|
|
67
|
+
async createFAQ(options) {
|
|
68
|
+
return this.request('/api/faqs/remote', {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
body: JSON.stringify(options),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Update an existing FAQ entry. */
|
|
74
|
+
async updateFAQ(faqId, options) {
|
|
75
|
+
return this.request(`/api/faqs/remote/${faqId}`, {
|
|
76
|
+
method: 'PATCH',
|
|
77
|
+
body: JSON.stringify(options),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Delete a FAQ entry. */
|
|
81
|
+
async deleteFAQ(faqId) {
|
|
82
|
+
return this.request(`/api/faqs/remote/${faqId}`, {
|
|
83
|
+
method: 'DELETE',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.SupportDockClient = SupportDockClient;
|
|
88
|
+
class SupportDockError extends Error {
|
|
89
|
+
constructor(message, status) {
|
|
90
|
+
super(message);
|
|
91
|
+
this.name = 'SupportDockError';
|
|
92
|
+
this.status = status;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.SupportDockError = SupportDockError;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSupportDock = exports.SupportDockError = exports.SupportDockClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "SupportDockClient", { enumerable: true, get: function () { return client_1.SupportDockClient; } });
|
|
6
|
+
Object.defineProperty(exports, "SupportDockError", { enumerable: true, get: function () { return client_1.SupportDockError; } });
|
|
7
|
+
var react_1 = require("./react");
|
|
8
|
+
Object.defineProperty(exports, "useSupportDock", { enumerable: true, get: function () { return react_1.useSupportDock; } });
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SupportDockClient } from './client';
|
|
2
|
+
import type { SupportDockConfig, FeedbackOptions, FeedbackResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* React hook for submitting feedback from your Expo / React Native app.
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const { sendFeedback, loading, error, success } = useSupportDock({
|
|
8
|
+
* apiKey: 'sdk_your_key',
|
|
9
|
+
* defaultMetadata: { appVersion: '2.0.0', platform: Platform.OS },
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* await sendFeedback({ type: 'bug', message: 'Something went wrong' });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function useSupportDock(config: SupportDockConfig): {
|
|
16
|
+
sendFeedback: (options: FeedbackOptions) => Promise<FeedbackResult>;
|
|
17
|
+
loading: boolean;
|
|
18
|
+
error: string | null;
|
|
19
|
+
success: boolean;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
client: SupportDockClient;
|
|
22
|
+
};
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSupportDock = useSupportDock;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const client_1 = require("./client");
|
|
6
|
+
/**
|
|
7
|
+
* React hook for submitting feedback from your Expo / React Native app.
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const { sendFeedback, loading, error, success } = useSupportDock({
|
|
11
|
+
* apiKey: 'sdk_your_key',
|
|
12
|
+
* defaultMetadata: { appVersion: '2.0.0', platform: Platform.OS },
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* await sendFeedback({ type: 'bug', message: 'Something went wrong' });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function useSupportDock(config) {
|
|
19
|
+
const clientRef = (0, react_1.useRef)(null);
|
|
20
|
+
if (!clientRef.current) {
|
|
21
|
+
clientRef.current = new client_1.SupportDockClient(config);
|
|
22
|
+
}
|
|
23
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
24
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
25
|
+
const [success, setSuccess] = (0, react_1.useState)(false);
|
|
26
|
+
const sendFeedback = (0, react_1.useCallback)(async (options) => {
|
|
27
|
+
setLoading(true);
|
|
28
|
+
setError(null);
|
|
29
|
+
setSuccess(false);
|
|
30
|
+
try {
|
|
31
|
+
const result = await clientRef.current.sendFeedback(options);
|
|
32
|
+
setSuccess(true);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const message = err instanceof Error ? err.message : 'Failed to send feedback';
|
|
37
|
+
setError(message);
|
|
38
|
+
return { success: false, error: message };
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
}, []);
|
|
44
|
+
const reset = (0, react_1.useCallback)(() => {
|
|
45
|
+
setError(null);
|
|
46
|
+
setSuccess(false);
|
|
47
|
+
}, []);
|
|
48
|
+
return { sendFeedback, loading, error, success, reset, client: clientRef.current };
|
|
49
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type FeedbackType = 'bug' | 'feature' | 'question' | 'general';
|
|
2
|
+
export interface FeedbackOptions {
|
|
3
|
+
/** Feedback type. Defaults to 'general'. */
|
|
4
|
+
type?: FeedbackType;
|
|
5
|
+
/** The feedback message (required). */
|
|
6
|
+
message: string;
|
|
7
|
+
/** Sender email (optional). */
|
|
8
|
+
email?: string;
|
|
9
|
+
/** Sender name (optional). */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** Subject line (optional — auto-generated from type if omitted). */
|
|
12
|
+
subject?: string;
|
|
13
|
+
/** Arbitrary metadata (e.g. appVersion, platform, deviceModel). */
|
|
14
|
+
metadata?: Record<string, string>;
|
|
15
|
+
/** Source identifier (defaults to 'mobile-app'). */
|
|
16
|
+
source?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface FeedbackResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface FAQ {
|
|
23
|
+
id: string;
|
|
24
|
+
question: string;
|
|
25
|
+
answer: string;
|
|
26
|
+
sortOrder: number;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CreateFAQOptions {
|
|
31
|
+
question: string;
|
|
32
|
+
answer: string;
|
|
33
|
+
sortOrder?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface UpdateFAQOptions {
|
|
36
|
+
question?: string;
|
|
37
|
+
answer?: string;
|
|
38
|
+
sortOrder?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface SupportDockConfig {
|
|
41
|
+
/** Your app's API key (starts with sdk_). */
|
|
42
|
+
apiKey: string;
|
|
43
|
+
/** Base URL. Defaults to https://supportdock.io. */
|
|
44
|
+
baseUrl?: string;
|
|
45
|
+
/** Default metadata merged into every feedback submission. */
|
|
46
|
+
defaultMetadata?: Record<string, string>;
|
|
47
|
+
/** Request timeout in ms. Defaults to 10000. */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bangkeut-technology/supportdock-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SupportDock SDK — submit feedback and manage FAQs from your React Native / Expo app",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": ["dist"],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["supportdock", "feedback", "faq", "react-native", "expo", "sdk"],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": ">=18.0.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependenciesMeta": {
|
|
21
|
+
"react": {
|
|
22
|
+
"optional": true
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/react": "^19.0.0",
|
|
27
|
+
"typescript": "^5.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|