@medalsocial/sdk 0.1.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/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/index.d.mts +108 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +116 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Medal Social
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
## Medal Social SDK (TypeScript)
|
|
2
|
+
|
|
3
|
+
Simple, typed client for the Medal Social API. Supports authentication via Client ID/Secret (Basic) today and Bearer token. Provides convenience methods for common create actions.
|
|
4
|
+
|
|
5
|
+
### Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
corepack enable
|
|
9
|
+
pnpm add @medalsocial/sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Quick start
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import MedalSocialClient from '@medalsocial/sdk';
|
|
16
|
+
|
|
17
|
+
const client = new MedalSocialClient({
|
|
18
|
+
auth: { kind: 'basic', clientId: process.env.MEDAL_CLIENT_ID!, clientSecret: process.env.MEDAL_CLIENT_SECRET! },
|
|
19
|
+
// or: auth: { kind: 'bearer', token: process.env.MEDAL_API_TOKEN! },
|
|
20
|
+
// optional: baseUrl: 'https://api.medalsocial.com',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Create lead(s)
|
|
24
|
+
await client.createLead([
|
|
25
|
+
{
|
|
26
|
+
name: 'Alex Example',
|
|
27
|
+
email: 'lead.test@example.com',
|
|
28
|
+
company: '',
|
|
29
|
+
source: 'website',
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
// Create a note
|
|
34
|
+
await client.createNote({
|
|
35
|
+
name: 'Test Testnes',
|
|
36
|
+
email: 'test@medalsocial.com',
|
|
37
|
+
company: 'Medal Social Test company',
|
|
38
|
+
phone: '+47 99887766',
|
|
39
|
+
content: 'Hei jeg skal gjerne sende to konteinere til USA.',
|
|
40
|
+
metadata: { Budsjett: '$100,000' },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Record cookie consent
|
|
44
|
+
await client.createCookieConsent({
|
|
45
|
+
domain: 'example.com',
|
|
46
|
+
consentStatus: 'partial',
|
|
47
|
+
consentTimestamp: '2025-06-04T10:30:00Z',
|
|
48
|
+
ipAddress: '88.151.164.19',
|
|
49
|
+
userAgent: 'Mozilla/5.0',
|
|
50
|
+
cookiePreferences: {
|
|
51
|
+
necessary: {
|
|
52
|
+
allowed: true,
|
|
53
|
+
cookieRecords: [
|
|
54
|
+
{ cookie: 'session_id', duration: 'Session', description: 'Essential for user authentication and session management' },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
analytics: { allowed: false },
|
|
58
|
+
marketing: { allowed: true },
|
|
59
|
+
functional: { allowed: true },
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Create event signup
|
|
64
|
+
await client.createEventSignup({
|
|
65
|
+
contact: {
|
|
66
|
+
name: 'Test Testnes',
|
|
67
|
+
email: 'test@medalsocial.com',
|
|
68
|
+
company: 'Medal Social Test company',
|
|
69
|
+
},
|
|
70
|
+
event: {
|
|
71
|
+
externalId: 'eksadaasdasd',
|
|
72
|
+
name: 'Product saus asd',
|
|
73
|
+
description: 'Learn about our new product asd',
|
|
74
|
+
time: '2025-06-15T14:00:00Z',
|
|
75
|
+
location: 'Online',
|
|
76
|
+
thumbnail: 'https://medalsocialdevstorage.blob.core.windows.net/images/d05bad9e-bc52-4f8e-8191-d6944d34055c.jpg',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### API
|
|
82
|
+
|
|
83
|
+
- `new MedalSocialClient(options)`
|
|
84
|
+
- **auth** (required):
|
|
85
|
+
- `{ kind: 'basic', clientId: string, clientSecret: string }`
|
|
86
|
+
- `{ kind: 'bearer', token: string }`
|
|
87
|
+
- **baseUrl** (optional): string. Defaults to `https://api.medalsocial.com`.
|
|
88
|
+
- **timeoutMs** (optional): number. Defaults to 30000.
|
|
89
|
+
- **userAgent** (optional): string.
|
|
90
|
+
- **fetch** (optional): custom fetch implementation to override transport.
|
|
91
|
+
|
|
92
|
+
- `createLead(items: { name, email, company?, source? }[])` -> `{ status, data, headers }`
|
|
93
|
+
- `createNote(input)` -> `{ status, data, headers }`
|
|
94
|
+
- `createCookieConsent(input)` -> `{ status, data, headers }`
|
|
95
|
+
- `createEventSignup(input)` -> `{ status, data, headers }`
|
|
96
|
+
- `sendTransactionalEmail(input)` -> `{ status, data, headers }`
|
|
97
|
+
|
|
98
|
+
Responses throw on non-2xx with an error containing `status` and `details` (parsed body when available).
|
|
99
|
+
|
|
100
|
+
### Runtime support
|
|
101
|
+
|
|
102
|
+
- Node 20+ and modern browsers. The client uses `fetch`; in Node 20+ `fetch` is built-in. For older environments, provide a global `fetch` polyfill.
|
|
103
|
+
|
|
104
|
+
### Docs
|
|
105
|
+
|
|
106
|
+
- API Reference (TypeDoc): published automatically from the `prod` branch via GitHub Pages.
|
|
107
|
+
- Local: `pnpm docs` then open `docs/index.html`.
|
|
108
|
+
|
|
109
|
+
### Contributing
|
|
110
|
+
|
|
111
|
+
PRs welcome! Use pnpm. Useful scripts:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pnpm install
|
|
115
|
+
pnpm build
|
|
116
|
+
pnpm test
|
|
117
|
+
pnpm docs
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### License
|
|
121
|
+
|
|
122
|
+
MIT
|
|
123
|
+
|
|
124
|
+
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
type AuthOptions = {
|
|
2
|
+
kind: "basic";
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "bearer";
|
|
7
|
+
token: string;
|
|
8
|
+
};
|
|
9
|
+
interface ClientOptions {
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
auth: AuthOptions;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
userAgent?: string;
|
|
14
|
+
}
|
|
15
|
+
interface LeadItem {
|
|
16
|
+
name: string;
|
|
17
|
+
email: string;
|
|
18
|
+
company?: string;
|
|
19
|
+
source?: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface ContactNoteInput {
|
|
23
|
+
contactId: string;
|
|
24
|
+
note: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
interface NoteInput {
|
|
28
|
+
name: string;
|
|
29
|
+
email: string;
|
|
30
|
+
firstName?: string;
|
|
31
|
+
lastName?: string;
|
|
32
|
+
company?: string;
|
|
33
|
+
phone?: string;
|
|
34
|
+
content?: string;
|
|
35
|
+
metadata?: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
interface CookieRecord {
|
|
38
|
+
cookie: string;
|
|
39
|
+
duration: string;
|
|
40
|
+
description: string;
|
|
41
|
+
}
|
|
42
|
+
interface CookieCategoryConsent {
|
|
43
|
+
allowed: boolean;
|
|
44
|
+
cookieRecords?: CookieRecord[];
|
|
45
|
+
}
|
|
46
|
+
interface CookieConsentInput {
|
|
47
|
+
domain: string;
|
|
48
|
+
consentStatus: "granted" | "denied" | "partial" | string;
|
|
49
|
+
consentTimestamp: string;
|
|
50
|
+
ipAddress?: string;
|
|
51
|
+
userAgent?: string;
|
|
52
|
+
cookiePreferences: {
|
|
53
|
+
necessary?: CookieCategoryConsent;
|
|
54
|
+
analytics?: CookieCategoryConsent;
|
|
55
|
+
marketing?: CookieCategoryConsent;
|
|
56
|
+
functional?: CookieCategoryConsent;
|
|
57
|
+
[key: string]: CookieCategoryConsent | undefined;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
interface EventSignupInput {
|
|
61
|
+
contact: {
|
|
62
|
+
name: string;
|
|
63
|
+
email: string;
|
|
64
|
+
company?: string;
|
|
65
|
+
};
|
|
66
|
+
event: {
|
|
67
|
+
externalId: string;
|
|
68
|
+
name: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
time: string;
|
|
71
|
+
location?: string;
|
|
72
|
+
thumbnail?: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
interface ApiResponse<T> {
|
|
76
|
+
status: number;
|
|
77
|
+
data: T;
|
|
78
|
+
headers: Record<string, string>;
|
|
79
|
+
}
|
|
80
|
+
interface TransactionalEmailInput {
|
|
81
|
+
to: string;
|
|
82
|
+
slug: string;
|
|
83
|
+
additionalData?: Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
declare class MedalSocialClient {
|
|
86
|
+
private readonly baseUrl;
|
|
87
|
+
private readonly auth;
|
|
88
|
+
private readonly timeoutMs;
|
|
89
|
+
private readonly userAgent;
|
|
90
|
+
constructor(options: ClientOptions);
|
|
91
|
+
/** Create one or more leads */
|
|
92
|
+
createLead<T = unknown>(items: LeadItem[]): Promise<ApiResponse<T>>;
|
|
93
|
+
/** Create a note attached to a contact by id */
|
|
94
|
+
createContactNote<T = unknown>(input: ContactNoteInput): Promise<ApiResponse<T>>;
|
|
95
|
+
/** Record a user’s cookie consent preferences */
|
|
96
|
+
createCookieConsent<T = unknown>(input: CookieConsentInput): Promise<ApiResponse<T>>;
|
|
97
|
+
/** Create an event signup with contact and event details */
|
|
98
|
+
createEventSignup<T = unknown>(input: EventSignupInput): Promise<ApiResponse<T>>;
|
|
99
|
+
/** Create a free-form note for inbound messages */
|
|
100
|
+
createNote<T = unknown>(input: NoteInput): Promise<ApiResponse<T>>;
|
|
101
|
+
/** Send a transactional email by template slug */
|
|
102
|
+
sendTransactionalEmail<T = unknown>(input: TransactionalEmailInput): Promise<ApiResponse<T>>;
|
|
103
|
+
private post;
|
|
104
|
+
private fetchWithAuth;
|
|
105
|
+
private handleResponse;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { type ApiResponse, type AuthOptions, type ClientOptions, type ContactNoteInput, type CookieCategoryConsent, type CookieConsentInput, type CookieRecord, type EventSignupInput, type LeadItem, MedalSocialClient, type NoteInput, type TransactionalEmailInput, MedalSocialClient as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
type AuthOptions = {
|
|
2
|
+
kind: "basic";
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "bearer";
|
|
7
|
+
token: string;
|
|
8
|
+
};
|
|
9
|
+
interface ClientOptions {
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
auth: AuthOptions;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
userAgent?: string;
|
|
14
|
+
}
|
|
15
|
+
interface LeadItem {
|
|
16
|
+
name: string;
|
|
17
|
+
email: string;
|
|
18
|
+
company?: string;
|
|
19
|
+
source?: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface ContactNoteInput {
|
|
23
|
+
contactId: string;
|
|
24
|
+
note: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
interface NoteInput {
|
|
28
|
+
name: string;
|
|
29
|
+
email: string;
|
|
30
|
+
firstName?: string;
|
|
31
|
+
lastName?: string;
|
|
32
|
+
company?: string;
|
|
33
|
+
phone?: string;
|
|
34
|
+
content?: string;
|
|
35
|
+
metadata?: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
interface CookieRecord {
|
|
38
|
+
cookie: string;
|
|
39
|
+
duration: string;
|
|
40
|
+
description: string;
|
|
41
|
+
}
|
|
42
|
+
interface CookieCategoryConsent {
|
|
43
|
+
allowed: boolean;
|
|
44
|
+
cookieRecords?: CookieRecord[];
|
|
45
|
+
}
|
|
46
|
+
interface CookieConsentInput {
|
|
47
|
+
domain: string;
|
|
48
|
+
consentStatus: "granted" | "denied" | "partial" | string;
|
|
49
|
+
consentTimestamp: string;
|
|
50
|
+
ipAddress?: string;
|
|
51
|
+
userAgent?: string;
|
|
52
|
+
cookiePreferences: {
|
|
53
|
+
necessary?: CookieCategoryConsent;
|
|
54
|
+
analytics?: CookieCategoryConsent;
|
|
55
|
+
marketing?: CookieCategoryConsent;
|
|
56
|
+
functional?: CookieCategoryConsent;
|
|
57
|
+
[key: string]: CookieCategoryConsent | undefined;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
interface EventSignupInput {
|
|
61
|
+
contact: {
|
|
62
|
+
name: string;
|
|
63
|
+
email: string;
|
|
64
|
+
company?: string;
|
|
65
|
+
};
|
|
66
|
+
event: {
|
|
67
|
+
externalId: string;
|
|
68
|
+
name: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
time: string;
|
|
71
|
+
location?: string;
|
|
72
|
+
thumbnail?: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
interface ApiResponse<T> {
|
|
76
|
+
status: number;
|
|
77
|
+
data: T;
|
|
78
|
+
headers: Record<string, string>;
|
|
79
|
+
}
|
|
80
|
+
interface TransactionalEmailInput {
|
|
81
|
+
to: string;
|
|
82
|
+
slug: string;
|
|
83
|
+
additionalData?: Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
declare class MedalSocialClient {
|
|
86
|
+
private readonly baseUrl;
|
|
87
|
+
private readonly auth;
|
|
88
|
+
private readonly timeoutMs;
|
|
89
|
+
private readonly userAgent;
|
|
90
|
+
constructor(options: ClientOptions);
|
|
91
|
+
/** Create one or more leads */
|
|
92
|
+
createLead<T = unknown>(items: LeadItem[]): Promise<ApiResponse<T>>;
|
|
93
|
+
/** Create a note attached to a contact by id */
|
|
94
|
+
createContactNote<T = unknown>(input: ContactNoteInput): Promise<ApiResponse<T>>;
|
|
95
|
+
/** Record a user’s cookie consent preferences */
|
|
96
|
+
createCookieConsent<T = unknown>(input: CookieConsentInput): Promise<ApiResponse<T>>;
|
|
97
|
+
/** Create an event signup with contact and event details */
|
|
98
|
+
createEventSignup<T = unknown>(input: EventSignupInput): Promise<ApiResponse<T>>;
|
|
99
|
+
/** Create a free-form note for inbound messages */
|
|
100
|
+
createNote<T = unknown>(input: NoteInput): Promise<ApiResponse<T>>;
|
|
101
|
+
/** Send a transactional email by template slug */
|
|
102
|
+
sendTransactionalEmail<T = unknown>(input: TransactionalEmailInput): Promise<ApiResponse<T>>;
|
|
103
|
+
private post;
|
|
104
|
+
private fetchWithAuth;
|
|
105
|
+
private handleResponse;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { type ApiResponse, type AuthOptions, type ClientOptions, type ContactNoteInput, type CookieCategoryConsent, type CookieConsentInput, type CookieRecord, type EventSignupInput, type LeadItem, MedalSocialClient, type NoteInput, type TransactionalEmailInput, MedalSocialClient as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
MedalSocialClient: () => MedalSocialClient,
|
|
24
|
+
default: () => index_default
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var MedalSocialClient = class {
|
|
28
|
+
baseUrl;
|
|
29
|
+
auth;
|
|
30
|
+
timeoutMs;
|
|
31
|
+
userAgent;
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this.baseUrl = (options.baseUrl ?? "https://api.medalsocial.com").replace(/\/$/, "");
|
|
34
|
+
this.auth = options.auth;
|
|
35
|
+
this.timeoutMs = options.timeoutMs ?? 3e4;
|
|
36
|
+
this.userAgent = options.userAgent ?? "medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)";
|
|
37
|
+
}
|
|
38
|
+
// Public endpoints
|
|
39
|
+
/** Create one or more leads */
|
|
40
|
+
async createLead(items) {
|
|
41
|
+
return this.post("/v1/leads", items);
|
|
42
|
+
}
|
|
43
|
+
/** Create a note attached to a contact by id */
|
|
44
|
+
async createContactNote(input) {
|
|
45
|
+
return this.post("/v1/contacts/notes", input);
|
|
46
|
+
}
|
|
47
|
+
/** Record a user’s cookie consent preferences */
|
|
48
|
+
async createCookieConsent(input) {
|
|
49
|
+
return this.post("/v1/cookie-consent", input);
|
|
50
|
+
}
|
|
51
|
+
/** Create an event signup with contact and event details */
|
|
52
|
+
async createEventSignup(input) {
|
|
53
|
+
return this.post("/v1/event-signup", input);
|
|
54
|
+
}
|
|
55
|
+
/** Create a free-form note for inbound messages */
|
|
56
|
+
async createNote(input) {
|
|
57
|
+
return this.post("/v1/notes", input);
|
|
58
|
+
}
|
|
59
|
+
/** Send a transactional email by template slug */
|
|
60
|
+
async sendTransactionalEmail(input) {
|
|
61
|
+
return this.post("/v1/send-transactional-email", input);
|
|
62
|
+
}
|
|
63
|
+
// Internal HTTP helpers
|
|
64
|
+
async post(path, body) {
|
|
65
|
+
const maxAttempts = 3;
|
|
66
|
+
let attempt = 0;
|
|
67
|
+
while (attempt < maxAttempts) {
|
|
68
|
+
attempt++;
|
|
69
|
+
const res = await this.fetchWithAuth(path, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "content-type": "application/json" },
|
|
72
|
+
body: JSON.stringify(body)
|
|
73
|
+
});
|
|
74
|
+
if (res.status === 429 || res.status >= 500 && res.status <= 599) {
|
|
75
|
+
if (attempt < maxAttempts) {
|
|
76
|
+
const retryAfter = res.headers.get("retry-after");
|
|
77
|
+
let delayMs = 0;
|
|
78
|
+
if (retryAfter) {
|
|
79
|
+
const seconds = Number(retryAfter);
|
|
80
|
+
delayMs = Number.isFinite(seconds) ? seconds * 1e3 : 0;
|
|
81
|
+
}
|
|
82
|
+
if (delayMs <= 0) {
|
|
83
|
+
delayMs = 250 * attempt;
|
|
84
|
+
}
|
|
85
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return this.handleResponse(res);
|
|
90
|
+
}
|
|
91
|
+
throw new Error("Request failed after retries");
|
|
92
|
+
}
|
|
93
|
+
async fetchWithAuth(path, init) {
|
|
94
|
+
const url = `${this.baseUrl}${path}`;
|
|
95
|
+
const headers = new Headers(init.headers);
|
|
96
|
+
try {
|
|
97
|
+
headers.set("user-agent", this.userAgent);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
if (this.auth.kind === "bearer") {
|
|
101
|
+
headers.set("authorization", `Bearer ${this.auth.token}`);
|
|
102
|
+
} else if (this.auth.kind === "basic") {
|
|
103
|
+
headers.set("Client-Id", this.auth.clientId);
|
|
104
|
+
headers.set("Client-Secret", this.auth.clientSecret);
|
|
105
|
+
}
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
108
|
+
try {
|
|
109
|
+
const res = await fetch(url, { ...init, headers, signal: controller.signal });
|
|
110
|
+
return res;
|
|
111
|
+
} finally {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async handleResponse(res) {
|
|
116
|
+
const text = await res.text();
|
|
117
|
+
let parsed = void 0;
|
|
118
|
+
try {
|
|
119
|
+
parsed = text ? JSON.parse(text) : void 0;
|
|
120
|
+
} catch {
|
|
121
|
+
parsed = text;
|
|
122
|
+
}
|
|
123
|
+
const headers = {};
|
|
124
|
+
res.headers.forEach((v, k) => {
|
|
125
|
+
headers[k] = v;
|
|
126
|
+
});
|
|
127
|
+
if (!res.ok) {
|
|
128
|
+
const error = new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
129
|
+
error.status = res.status;
|
|
130
|
+
error.details = parsed;
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
return { status: res.status, data: parsed, headers };
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var index_default = MedalSocialClient;
|
|
137
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
138
|
+
0 && (module.exports = {
|
|
139
|
+
MedalSocialClient
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type AuthOptions =\n | { kind: \"basic\"; clientId: string; clientSecret: string }\n | { kind: \"bearer\"; token: string };\n\nexport interface ClientOptions {\n baseUrl?: string;\n auth: AuthOptions;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport interface LeadItem {\n name: string;\n email: string;\n company?: string;\n source?: string;\n [key: string]: unknown;\n}\n\nexport interface ContactNoteInput {\n contactId: string;\n note: string;\n [key: string]: unknown;\n}\n\nexport interface NoteInput {\n name: string;\n email: string;\n firstName?: string;\n lastName?: string;\n company?: string;\n phone?: string;\n content?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CookieRecord {\n cookie: string;\n duration: string;\n description: string;\n}\n\nexport interface CookieCategoryConsent {\n allowed: boolean;\n cookieRecords?: CookieRecord[];\n}\n\nexport interface CookieConsentInput {\n domain: string;\n consentStatus: \"granted\" | \"denied\" | \"partial\" | string;\n consentTimestamp: string; // ISO-8601\n ipAddress?: string;\n userAgent?: string;\n cookiePreferences: {\n necessary?: CookieCategoryConsent;\n analytics?: CookieCategoryConsent;\n marketing?: CookieCategoryConsent;\n functional?: CookieCategoryConsent;\n [key: string]: CookieCategoryConsent | undefined;\n };\n}\n\nexport interface EventSignupInput {\n contact: {\n name: string;\n email: string;\n company?: string;\n };\n event: {\n externalId: string;\n name: string;\n description?: string;\n time: string; // ISO-8601\n location?: string;\n thumbnail?: string;\n };\n}\n\nexport interface ApiResponse<T> {\n status: number;\n data: T;\n headers: Record<string, string>;\n}\n\nexport interface TransactionalEmailInput {\n to: string;\n slug: string;\n additionalData?: Record<string, unknown>;\n}\n\nexport class MedalSocialClient {\n private readonly baseUrl: string;\n private readonly auth: AuthOptions;\n private readonly timeoutMs: number;\n private readonly userAgent: string;\n\n constructor(options: ClientOptions) {\n this.baseUrl = (options.baseUrl ?? \"https://api.medalsocial.com\").replace(/\\/$/, \"\");\n this.auth = options.auth;\n this.timeoutMs = options.timeoutMs ?? 30000;\n this.userAgent =\n options.userAgent ??\n \"medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)\";\n }\n\n // Public endpoints\n /** Create one or more leads */\n async createLead<T = unknown>(items: LeadItem[]): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/leads\", items);\n }\n\n /** Create a note attached to a contact by id */\n async createContactNote<T = unknown>(input: ContactNoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/contacts/notes\", input);\n }\n\n /** Record a user’s cookie consent preferences */\n async createCookieConsent<T = unknown>(input: CookieConsentInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/cookie-consent\", input);\n }\n\n /** Create an event signup with contact and event details */\n async createEventSignup<T = unknown>(input: EventSignupInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/event-signup\", input);\n }\n\n /** Create a free-form note for inbound messages */\n async createNote<T = unknown>(input: NoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/notes\", input);\n }\n\n /** Send a transactional email by template slug */\n async sendTransactionalEmail<T = unknown>(\n input: TransactionalEmailInput,\n ): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/send-transactional-email\", input);\n }\n\n // Internal HTTP helpers\n private async post<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n const maxAttempts = 3;\n let attempt = 0;\n\n while (attempt < maxAttempts) {\n attempt++;\n const res = await this.fetchWithAuth(path, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n // Retry on 429/5xx with basic backoff and Retry-After support\n if (res.status === 429 || (res.status >= 500 && res.status <= 599)) {\n if (attempt < maxAttempts) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt; // linear backoff\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n }\n\n return this.handleResponse<T>(res);\n }\n\n throw new Error(\"Request failed after retries\");\n }\n\n private async fetchWithAuth(path: string, init: RequestInit): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers = new Headers(init.headers);\n try {\n headers.set(\"user-agent\", this.userAgent);\n } catch {\n // Some environments (e.g., browsers) disallow setting user-agent; ignore.\n }\n\n if (this.auth.kind === \"bearer\") {\n headers.set(\"authorization\", `Bearer ${this.auth.token}`);\n } else if (this.auth.kind === \"basic\") {\n // Medal Social API expects explicit headers for client credentials\n headers.set(\"Client-Id\", this.auth.clientId);\n headers.set(\"Client-Secret\", this.auth.clientSecret);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const res = await fetch(url, { ...init, headers, signal: controller.signal });\n return res;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async handleResponse<T>(res: Response): Promise<ApiResponse<T>> {\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text as unknown;\n }\n\n const headers: Record<string, string> = {};\n res.headers.forEach((v, k) => {\n headers[k] = v;\n });\n\n if (!res.ok) {\n const error = new Error(`HTTP ${res.status}: ${res.statusText}`) as Error & {\n status?: number;\n details?: unknown;\n };\n error.status = res.status;\n error.details = parsed;\n throw error;\n }\n\n return { status: res.status, data: parsed as T, headers };\n }\n}\n\nexport default MedalSocialClient;\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var MedalSocialClient = class {
|
|
3
|
+
baseUrl;
|
|
4
|
+
auth;
|
|
5
|
+
timeoutMs;
|
|
6
|
+
userAgent;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.baseUrl = (options.baseUrl ?? "https://api.medalsocial.com").replace(/\/$/, "");
|
|
9
|
+
this.auth = options.auth;
|
|
10
|
+
this.timeoutMs = options.timeoutMs ?? 3e4;
|
|
11
|
+
this.userAgent = options.userAgent ?? "medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)";
|
|
12
|
+
}
|
|
13
|
+
// Public endpoints
|
|
14
|
+
/** Create one or more leads */
|
|
15
|
+
async createLead(items) {
|
|
16
|
+
return this.post("/v1/leads", items);
|
|
17
|
+
}
|
|
18
|
+
/** Create a note attached to a contact by id */
|
|
19
|
+
async createContactNote(input) {
|
|
20
|
+
return this.post("/v1/contacts/notes", input);
|
|
21
|
+
}
|
|
22
|
+
/** Record a user’s cookie consent preferences */
|
|
23
|
+
async createCookieConsent(input) {
|
|
24
|
+
return this.post("/v1/cookie-consent", input);
|
|
25
|
+
}
|
|
26
|
+
/** Create an event signup with contact and event details */
|
|
27
|
+
async createEventSignup(input) {
|
|
28
|
+
return this.post("/v1/event-signup", input);
|
|
29
|
+
}
|
|
30
|
+
/** Create a free-form note for inbound messages */
|
|
31
|
+
async createNote(input) {
|
|
32
|
+
return this.post("/v1/notes", input);
|
|
33
|
+
}
|
|
34
|
+
/** Send a transactional email by template slug */
|
|
35
|
+
async sendTransactionalEmail(input) {
|
|
36
|
+
return this.post("/v1/send-transactional-email", input);
|
|
37
|
+
}
|
|
38
|
+
// Internal HTTP helpers
|
|
39
|
+
async post(path, body) {
|
|
40
|
+
const maxAttempts = 3;
|
|
41
|
+
let attempt = 0;
|
|
42
|
+
while (attempt < maxAttempts) {
|
|
43
|
+
attempt++;
|
|
44
|
+
const res = await this.fetchWithAuth(path, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: { "content-type": "application/json" },
|
|
47
|
+
body: JSON.stringify(body)
|
|
48
|
+
});
|
|
49
|
+
if (res.status === 429 || res.status >= 500 && res.status <= 599) {
|
|
50
|
+
if (attempt < maxAttempts) {
|
|
51
|
+
const retryAfter = res.headers.get("retry-after");
|
|
52
|
+
let delayMs = 0;
|
|
53
|
+
if (retryAfter) {
|
|
54
|
+
const seconds = Number(retryAfter);
|
|
55
|
+
delayMs = Number.isFinite(seconds) ? seconds * 1e3 : 0;
|
|
56
|
+
}
|
|
57
|
+
if (delayMs <= 0) {
|
|
58
|
+
delayMs = 250 * attempt;
|
|
59
|
+
}
|
|
60
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return this.handleResponse(res);
|
|
65
|
+
}
|
|
66
|
+
throw new Error("Request failed after retries");
|
|
67
|
+
}
|
|
68
|
+
async fetchWithAuth(path, init) {
|
|
69
|
+
const url = `${this.baseUrl}${path}`;
|
|
70
|
+
const headers = new Headers(init.headers);
|
|
71
|
+
try {
|
|
72
|
+
headers.set("user-agent", this.userAgent);
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
if (this.auth.kind === "bearer") {
|
|
76
|
+
headers.set("authorization", `Bearer ${this.auth.token}`);
|
|
77
|
+
} else if (this.auth.kind === "basic") {
|
|
78
|
+
headers.set("Client-Id", this.auth.clientId);
|
|
79
|
+
headers.set("Client-Secret", this.auth.clientSecret);
|
|
80
|
+
}
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(url, { ...init, headers, signal: controller.signal });
|
|
85
|
+
return res;
|
|
86
|
+
} finally {
|
|
87
|
+
clearTimeout(timeout);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async handleResponse(res) {
|
|
91
|
+
const text = await res.text();
|
|
92
|
+
let parsed = void 0;
|
|
93
|
+
try {
|
|
94
|
+
parsed = text ? JSON.parse(text) : void 0;
|
|
95
|
+
} catch {
|
|
96
|
+
parsed = text;
|
|
97
|
+
}
|
|
98
|
+
const headers = {};
|
|
99
|
+
res.headers.forEach((v, k) => {
|
|
100
|
+
headers[k] = v;
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
const error = new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
104
|
+
error.status = res.status;
|
|
105
|
+
error.details = parsed;
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
return { status: res.status, data: parsed, headers };
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var index_default = MedalSocialClient;
|
|
112
|
+
export {
|
|
113
|
+
MedalSocialClient,
|
|
114
|
+
index_default as default
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type AuthOptions =\n | { kind: \"basic\"; clientId: string; clientSecret: string }\n | { kind: \"bearer\"; token: string };\n\nexport interface ClientOptions {\n baseUrl?: string;\n auth: AuthOptions;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport interface LeadItem {\n name: string;\n email: string;\n company?: string;\n source?: string;\n [key: string]: unknown;\n}\n\nexport interface ContactNoteInput {\n contactId: string;\n note: string;\n [key: string]: unknown;\n}\n\nexport interface NoteInput {\n name: string;\n email: string;\n firstName?: string;\n lastName?: string;\n company?: string;\n phone?: string;\n content?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CookieRecord {\n cookie: string;\n duration: string;\n description: string;\n}\n\nexport interface CookieCategoryConsent {\n allowed: boolean;\n cookieRecords?: CookieRecord[];\n}\n\nexport interface CookieConsentInput {\n domain: string;\n consentStatus: \"granted\" | \"denied\" | \"partial\" | string;\n consentTimestamp: string; // ISO-8601\n ipAddress?: string;\n userAgent?: string;\n cookiePreferences: {\n necessary?: CookieCategoryConsent;\n analytics?: CookieCategoryConsent;\n marketing?: CookieCategoryConsent;\n functional?: CookieCategoryConsent;\n [key: string]: CookieCategoryConsent | undefined;\n };\n}\n\nexport interface EventSignupInput {\n contact: {\n name: string;\n email: string;\n company?: string;\n };\n event: {\n externalId: string;\n name: string;\n description?: string;\n time: string; // ISO-8601\n location?: string;\n thumbnail?: string;\n };\n}\n\nexport interface ApiResponse<T> {\n status: number;\n data: T;\n headers: Record<string, string>;\n}\n\nexport interface TransactionalEmailInput {\n to: string;\n slug: string;\n additionalData?: Record<string, unknown>;\n}\n\nexport class MedalSocialClient {\n private readonly baseUrl: string;\n private readonly auth: AuthOptions;\n private readonly timeoutMs: number;\n private readonly userAgent: string;\n\n constructor(options: ClientOptions) {\n this.baseUrl = (options.baseUrl ?? \"https://api.medalsocial.com\").replace(/\\/$/, \"\");\n this.auth = options.auth;\n this.timeoutMs = options.timeoutMs ?? 30000;\n this.userAgent =\n options.userAgent ??\n \"medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)\";\n }\n\n // Public endpoints\n /** Create one or more leads */\n async createLead<T = unknown>(items: LeadItem[]): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/leads\", items);\n }\n\n /** Create a note attached to a contact by id */\n async createContactNote<T = unknown>(input: ContactNoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/contacts/notes\", input);\n }\n\n /** Record a user’s cookie consent preferences */\n async createCookieConsent<T = unknown>(input: CookieConsentInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/cookie-consent\", input);\n }\n\n /** Create an event signup with contact and event details */\n async createEventSignup<T = unknown>(input: EventSignupInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/event-signup\", input);\n }\n\n /** Create a free-form note for inbound messages */\n async createNote<T = unknown>(input: NoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/notes\", input);\n }\n\n /** Send a transactional email by template slug */\n async sendTransactionalEmail<T = unknown>(\n input: TransactionalEmailInput,\n ): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/send-transactional-email\", input);\n }\n\n // Internal HTTP helpers\n private async post<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n const maxAttempts = 3;\n let attempt = 0;\n\n while (attempt < maxAttempts) {\n attempt++;\n const res = await this.fetchWithAuth(path, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n // Retry on 429/5xx with basic backoff and Retry-After support\n if (res.status === 429 || (res.status >= 500 && res.status <= 599)) {\n if (attempt < maxAttempts) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt; // linear backoff\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n }\n\n return this.handleResponse<T>(res);\n }\n\n throw new Error(\"Request failed after retries\");\n }\n\n private async fetchWithAuth(path: string, init: RequestInit): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers = new Headers(init.headers);\n try {\n headers.set(\"user-agent\", this.userAgent);\n } catch {\n // Some environments (e.g., browsers) disallow setting user-agent; ignore.\n }\n\n if (this.auth.kind === \"bearer\") {\n headers.set(\"authorization\", `Bearer ${this.auth.token}`);\n } else if (this.auth.kind === \"basic\") {\n // Medal Social API expects explicit headers for client credentials\n headers.set(\"Client-Id\", this.auth.clientId);\n headers.set(\"Client-Secret\", this.auth.clientSecret);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const res = await fetch(url, { ...init, headers, signal: controller.signal });\n return res;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async handleResponse<T>(res: Response): Promise<ApiResponse<T>> {\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text as unknown;\n }\n\n const headers: Record<string, string> = {};\n res.headers.forEach((v, k) => {\n headers[k] = v;\n });\n\n if (!res.ok) {\n const error = new Error(`HTTP ${res.status}: ${res.statusText}`) as Error & {\n status?: number;\n details?: unknown;\n };\n error.status = res.status;\n error.details = parsed;\n throw error;\n }\n\n return { status: res.status, data: parsed as T, headers };\n }\n}\n\nexport default MedalSocialClient;\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@medalsocial/sdk",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "TypeScript client for Medal Social API (create leads, notes, cookie consents, event signups)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Medal Social / Ali Aljumaili",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Medal-Social/MedalSocial.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Medal-Social/MedalSocial/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/Medal-Social/MedalSocial#readme",
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"module": "dist/index.mjs",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs",
|
|
22
|
+
"require": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"keywords": [
|
|
36
|
+
"medal",
|
|
37
|
+
"social",
|
|
38
|
+
"sdk",
|
|
39
|
+
"api",
|
|
40
|
+
"typescript",
|
|
41
|
+
"client"
|
|
42
|
+
],
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^24.3.2",
|
|
45
|
+
"@vitest/coverage-v8": "^2.0.5",
|
|
46
|
+
"typedoc": "^0.26.6",
|
|
47
|
+
"tsup": "^8.3.0",
|
|
48
|
+
"typescript": "^5.5.4",
|
|
49
|
+
"vitest": "^2.0.5",
|
|
50
|
+
"@biomejs/biome": "^1.8.3",
|
|
51
|
+
"@commitlint/cli": "^19.4.0",
|
|
52
|
+
"@commitlint/config-conventional": "^19.4.0",
|
|
53
|
+
"husky": "^9.1.6"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup src/index.ts --dts --format esm,cjs --sourcemap",
|
|
57
|
+
"dev": "tsup src/index.ts --watch",
|
|
58
|
+
"clean": "rm -rf dist",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:watch": "vitest",
|
|
61
|
+
"docs": "typedoc",
|
|
62
|
+
"lint": "biome check .",
|
|
63
|
+
"format": "biome format ."
|
|
64
|
+
}
|
|
65
|
+
}
|