@pushary/server 1.0.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pushary
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.
22
+
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @pushary/server
2
+
3
+ Server-side SDK for [Pushary](https://pushary.com) - Manage subscribers, campaigns, templates, and send push notifications from your backend.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @pushary/server
9
+ # or
10
+ yarn add @pushary/server
11
+ # or
12
+ pnpm add @pushary/server
13
+ # or
14
+ bun add @pushary/server
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { createPusharyServer } from '@pushary/server'
21
+
22
+ const pushary = createPusharyServer({
23
+ apiKey: process.env.PUSHARY_API_KEY, // Required: pk_xxx.sk_xxx
24
+ })
25
+
26
+ // Send a notification
27
+ await pushary.notifications.send({
28
+ title: 'Hello!',
29
+ body: 'Your order has shipped',
30
+ subscriberIds: ['sub_123'],
31
+ })
32
+ ```
33
+
34
+ ## API Key
35
+
36
+ The server SDK requires your full API key (`pk_xxx.sk_xxx`) which includes the secret portion. Never expose this in client-side code.
37
+
38
+ Get your API key from your [Pushary Dashboard](https://pushary.com/dashboard/settings).
39
+
40
+ ## Resources
41
+
42
+ ### Subscribers
43
+
44
+ ```typescript
45
+ // List subscribers
46
+ const { data, hasMore, nextCursor } = await pushary.subscribers.list({
47
+ limit: 100,
48
+ status: 'active',
49
+ })
50
+
51
+ // Get a subscriber
52
+ const subscriber = await pushary.subscribers.get('sub_123')
53
+
54
+ // Update subscriber
55
+ await pushary.subscribers.update('sub_123', {
56
+ tags: ['vip', 'newsletter'],
57
+ externalId: 'user-456',
58
+ })
59
+
60
+ // Delete subscriber
61
+ await pushary.subscribers.delete('sub_123')
62
+
63
+ // Get subscriber count
64
+ const count = await pushary.subscribers.count()
65
+ ```
66
+
67
+ ### Campaigns
68
+
69
+ ```typescript
70
+ // List campaigns
71
+ const { data } = await pushary.campaigns.list()
72
+
73
+ // Create campaign
74
+ const campaign = await pushary.campaigns.create({
75
+ name: 'Welcome Campaign',
76
+ title: 'Welcome!',
77
+ body: 'Thanks for subscribing',
78
+ actionUrl: 'https://example.com/welcome',
79
+ })
80
+
81
+ // Send campaign
82
+ await pushary.campaigns.send(campaign.id)
83
+
84
+ // Pause/Resume
85
+ await pushary.campaigns.pause(campaign.id)
86
+ await pushary.campaigns.resume(campaign.id)
87
+
88
+ // Get stats
89
+ const stats = await pushary.campaigns.stats(campaign.id)
90
+ ```
91
+
92
+ ### Templates
93
+
94
+ ```typescript
95
+ // List templates
96
+ const { data } = await pushary.templates.list()
97
+
98
+ // Create template
99
+ const template = await pushary.templates.create({
100
+ name: 'Order Update',
101
+ title: 'Order {{orderId}} Update',
102
+ body: 'Your order status: {{status}}',
103
+ })
104
+
105
+ // Update template
106
+ await pushary.templates.update(template.id, {
107
+ body: 'Your order {{orderId}} is now {{status}}',
108
+ })
109
+
110
+ // Delete template
111
+ await pushary.templates.delete(template.id)
112
+ ```
113
+
114
+ ### Notifications (Direct Send)
115
+
116
+ ```typescript
117
+ // Send to specific subscribers
118
+ await pushary.notifications.send({
119
+ title: 'Flash Sale!',
120
+ body: '50% off everything',
121
+ url: 'https://example.com/sale',
122
+ subscriberIds: ['sub_123', 'sub_456'],
123
+ })
124
+
125
+ // Send to external IDs (your user IDs)
126
+ await pushary.notifications.send({
127
+ title: 'New Message',
128
+ body: 'You have a new message',
129
+ externalIds: ['user-123'],
130
+ })
131
+
132
+ // Send to subscribers with tags
133
+ await pushary.notifications.send({
134
+ title: 'VIP Exclusive',
135
+ body: 'Special offer just for you',
136
+ tags: ['vip'],
137
+ })
138
+ ```
139
+
140
+ ## TypeScript
141
+
142
+ Full TypeScript support with exported types:
143
+
144
+ ```typescript
145
+ import {
146
+ createPusharyServer,
147
+ type Subscriber,
148
+ type Campaign,
149
+ type Template,
150
+ type SendNotification,
151
+ } from '@pushary/server'
152
+ ```
153
+
154
+ ## License
155
+
156
+ MIT
157
+
package/dist/index.cjs ADDED
@@ -0,0 +1,127 @@
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 src_exports = {};
22
+ __export(src_exports, {
23
+ createPusharyServer: () => createPusharyServer
24
+ });
25
+ module.exports = __toCommonJS(src_exports);
26
+
27
+ // src/request.ts
28
+ var buildUrl = (baseUrl, path, params) => {
29
+ const url = new URL(path, baseUrl);
30
+ if (params) {
31
+ Object.entries(params).forEach(([key, value]) => {
32
+ if (value !== void 0 && value !== null) {
33
+ url.searchParams.set(key, String(value));
34
+ }
35
+ });
36
+ }
37
+ return url.toString();
38
+ };
39
+ var handleResponse = async (response) => {
40
+ if (!response.ok) {
41
+ const error = await response.json().catch(() => ({ message: "Request failed" }));
42
+ throw new Error(error.message || `HTTP ${response.status}`);
43
+ }
44
+ return response.json();
45
+ };
46
+ var createRequest = (ctx) => async (method, path, body) => {
47
+ const isGet = method === "GET";
48
+ const url = isGet && body ? buildUrl(ctx.baseUrl, path, body) : `${ctx.baseUrl}${path}`;
49
+ const response = await fetch(url, {
50
+ method,
51
+ headers: ctx.headers,
52
+ body: !isGet && body ? JSON.stringify(body) : void 0
53
+ });
54
+ return handleResponse(response);
55
+ };
56
+
57
+ // src/resources/subscribers.ts
58
+ var createSubscribersResource = (request) => Object.freeze({
59
+ list: (params) => request("GET", "/subscribers", params),
60
+ get: (id) => request("GET", `/subscribers/${id}`),
61
+ update: (id, data) => request("PATCH", `/subscribers/${id}`, data),
62
+ delete: (id) => request("DELETE", `/subscribers/${id}`),
63
+ count: () => request("GET", "/subscribers/count")
64
+ });
65
+
66
+ // src/resources/campaigns.ts
67
+ var createCampaignsResource = (request) => Object.freeze({
68
+ list: (params) => request("GET", "/campaigns", params),
69
+ create: (data) => request("POST", "/campaigns", data),
70
+ get: (id) => request("GET", `/campaigns/${id}`),
71
+ update: (id, data) => request("PATCH", `/campaigns/${id}`, data),
72
+ delete: (id) => request("DELETE", `/campaigns/${id}`),
73
+ send: (id) => request("POST", `/campaigns/${id}/send`),
74
+ pause: (id) => request("POST", `/campaigns/${id}/pause`),
75
+ resume: (id) => request("POST", `/campaigns/${id}/resume`),
76
+ stats: (id) => request("GET", `/campaigns/${id}/stats`)
77
+ });
78
+
79
+ // src/resources/templates.ts
80
+ var createTemplatesResource = (request) => Object.freeze({
81
+ list: (params) => request("GET", "/templates", params),
82
+ create: (data) => request("POST", "/templates", data),
83
+ get: (id) => request("GET", `/templates/${id}`),
84
+ update: (id, data) => request("PATCH", `/templates/${id}`, data),
85
+ delete: (id) => request("DELETE", `/templates/${id}`)
86
+ });
87
+
88
+ // src/resources/notifications.ts
89
+ var createNotificationsResource = (request) => Object.freeze({
90
+ send: (data) => request("POST", "/send", data)
91
+ });
92
+
93
+ // src/client.ts
94
+ var DEFAULT_BASE_URL = "https://pushary.com/api/v1/server";
95
+ var validateApiKey = (apiKey) => {
96
+ if (!apiKey) {
97
+ throw new Error("API key is required. Get your API key from https://pushary.com/dashboard/settings");
98
+ }
99
+ if (!apiKey.includes(".")) {
100
+ throw new Error("Invalid API key format. Use the full API key (pk_xxx.sk_xxx)");
101
+ }
102
+ };
103
+ var createContext = (config) => {
104
+ validateApiKey(config.apiKey);
105
+ return Object.freeze({
106
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
107
+ headers: Object.freeze({
108
+ "Content-Type": "application/json",
109
+ "Authorization": `Bearer ${config.apiKey}`
110
+ })
111
+ });
112
+ };
113
+ var createPusharyServer = (config) => {
114
+ const ctx = createContext(config);
115
+ const request = createRequest(ctx);
116
+ return Object.freeze({
117
+ subscribers: createSubscribersResource(request),
118
+ campaigns: createCampaignsResource(request),
119
+ templates: createTemplatesResource(request),
120
+ notifications: createNotificationsResource(request)
121
+ });
122
+ };
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ createPusharyServer
126
+ });
127
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/request.ts","../src/resources/subscribers.ts","../src/resources/campaigns.ts","../src/resources/templates.ts","../src/resources/notifications.ts","../src/client.ts"],"sourcesContent":["export { createPusharyServer, type PusharyServer } from './client'\n\nexport type {\n PusharyConfig,\n Subscriber,\n SubscriberListParams,\n UpdateSubscriber,\n SubscriberCount,\n Campaign,\n CreateCampaign,\n UpdateCampaign,\n CampaignStats,\n Template,\n CreateTemplate,\n UpdateTemplate,\n SendNotification,\n SendResult,\n ListParams,\n PaginatedResponse,\n} from './types'\n\nexport type { SubscribersResource } from './resources/subscribers'\nexport type { CampaignsResource } from './resources/campaigns'\nexport type { TemplatesResource } from './resources/templates'\nexport type { NotificationsResource } from './resources/notifications'\n\n","import type { RequestContext, RequestFn } from './types'\n\nconst buildUrl = (baseUrl: string, path: string, params?: Record<string, unknown>): string => {\n const url = new URL(path, baseUrl)\n \n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n })\n }\n \n return url.toString()\n}\n\nconst handleResponse = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: 'Request failed' }))\n throw new Error(error.message || `HTTP ${response.status}`)\n }\n return response.json() as Promise<T>\n}\n\nexport const createRequest = (ctx: RequestContext): RequestFn =>\n async <T>(method: string, path: string, body?: unknown): Promise<T> => {\n const isGet = method === 'GET'\n const url = isGet && body \n ? buildUrl(ctx.baseUrl, path, body as Record<string, unknown>)\n : `${ctx.baseUrl}${path}`\n \n const response = await fetch(url, {\n method,\n headers: ctx.headers,\n body: !isGet && body ? JSON.stringify(body) : undefined,\n })\n \n return handleResponse<T>(response)\n }\n\n","import type {\n RequestFn,\n Subscriber,\n SubscriberListParams,\n UpdateSubscriber,\n PaginatedResponse,\n SubscriberCount,\n} from '../types'\n\nexport interface SubscribersResource {\n readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>\n readonly get: (id: string) => Promise<Subscriber>\n readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>\n readonly delete: (id: string) => Promise<void>\n readonly count: () => Promise<SubscriberCount>\n}\n\nexport const createSubscribersResource = (request: RequestFn): SubscribersResource =>\n Object.freeze({\n list: (params?: SubscriberListParams) =>\n request<PaginatedResponse<Subscriber>>('GET', '/subscribers', params),\n \n get: (id: string) =>\n request<Subscriber>('GET', `/subscribers/${id}`),\n \n update: (id: string, data: UpdateSubscriber) =>\n request<Subscriber>('PATCH', `/subscribers/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/subscribers/${id}`),\n \n count: () =>\n request<SubscriberCount>('GET', '/subscribers/count'),\n })\n\n","import type {\n RequestFn,\n Campaign,\n CreateCampaign,\n UpdateCampaign,\n ListParams,\n PaginatedResponse,\n CampaignStats,\n} from '../types'\n\nexport interface CampaignsResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>\n readonly create: (data: CreateCampaign) => Promise<Campaign>\n readonly get: (id: string) => Promise<Campaign>\n readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>\n readonly delete: (id: string) => Promise<void>\n readonly send: (id: string) => Promise<Campaign>\n readonly pause: (id: string) => Promise<Campaign>\n readonly resume: (id: string) => Promise<Campaign>\n readonly stats: (id: string) => Promise<CampaignStats>\n}\n\nexport const createCampaignsResource = (request: RequestFn): CampaignsResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Campaign>>('GET', '/campaigns', params),\n \n create: (data: CreateCampaign) =>\n request<Campaign>('POST', '/campaigns', data),\n \n get: (id: string) =>\n request<Campaign>('GET', `/campaigns/${id}`),\n \n update: (id: string, data: UpdateCampaign) =>\n request<Campaign>('PATCH', `/campaigns/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/campaigns/${id}`),\n \n send: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/send`),\n \n pause: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/pause`),\n \n resume: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/resume`),\n \n stats: (id: string) =>\n request<CampaignStats>('GET', `/campaigns/${id}/stats`),\n })\n\n","import type {\n RequestFn,\n Template,\n CreateTemplate,\n UpdateTemplate,\n ListParams,\n PaginatedResponse,\n} from '../types'\n\nexport interface TemplatesResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>\n readonly create: (data: CreateTemplate) => Promise<Template>\n readonly get: (id: string) => Promise<Template>\n readonly update: (id: string, data: UpdateTemplate) => Promise<Template>\n readonly delete: (id: string) => Promise<void>\n}\n\nexport const createTemplatesResource = (request: RequestFn): TemplatesResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Template>>('GET', '/templates', params),\n \n create: (data: CreateTemplate) =>\n request<Template>('POST', '/templates', data),\n \n get: (id: string) =>\n request<Template>('GET', `/templates/${id}`),\n \n update: (id: string, data: UpdateTemplate) =>\n request<Template>('PATCH', `/templates/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/templates/${id}`),\n })\n\n","import type { RequestFn, SendNotification, SendResult } from '../types'\n\nexport interface NotificationsResource {\n readonly send: (data: SendNotification) => Promise<SendResult>\n}\n\nexport const createNotificationsResource = (request: RequestFn): NotificationsResource =>\n Object.freeze({\n send: (data: SendNotification) =>\n request<SendResult>('POST', '/send', data),\n })\n\n","import type { PusharyConfig, RequestContext } from './types'\nimport { createRequest } from './request'\nimport { createSubscribersResource, type SubscribersResource } from './resources/subscribers'\nimport { createCampaignsResource, type CampaignsResource } from './resources/campaigns'\nimport { createTemplatesResource, type TemplatesResource } from './resources/templates'\nimport { createNotificationsResource, type NotificationsResource } from './resources/notifications'\n\nconst DEFAULT_BASE_URL = 'https://pushary.com/api/v1/server'\n\nexport interface PusharyServer {\n readonly subscribers: SubscribersResource\n readonly campaigns: CampaignsResource\n readonly templates: TemplatesResource\n readonly notifications: NotificationsResource\n}\n\nconst validateApiKey = (apiKey: string): void => {\n if (!apiKey) {\n throw new Error('API key is required. Get your API key from https://pushary.com/dashboard/settings')\n }\n \n if (!apiKey.includes('.')) {\n throw new Error('Invalid API key format. Use the full API key (pk_xxx.sk_xxx)')\n }\n}\n\nconst createContext = (config: PusharyConfig): RequestContext => {\n validateApiKey(config.apiKey)\n \n return Object.freeze({\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n headers: Object.freeze({\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n }),\n })\n}\n\nexport const createPusharyServer = (config: PusharyConfig): PusharyServer => {\n const ctx = createContext(config)\n const request = createRequest(ctx)\n \n return Object.freeze({\n subscribers: createSubscribersResource(request),\n campaigns: createCampaignsResource(request),\n templates: createTemplatesResource(request),\n notifications: createNotificationsResource(request),\n })\n}\n\n"],"mappings":"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","names":[]}
@@ -0,0 +1,180 @@
1
+ interface PusharyConfig {
2
+ readonly apiKey: string;
3
+ readonly baseUrl?: string;
4
+ }
5
+ interface ListParams {
6
+ readonly limit?: number;
7
+ readonly cursor?: string;
8
+ }
9
+ interface PaginatedResponse<T> {
10
+ readonly data: readonly T[];
11
+ readonly nextCursor?: string;
12
+ readonly hasMore: boolean;
13
+ }
14
+ interface Subscriber {
15
+ readonly id: string;
16
+ readonly siteId: string;
17
+ readonly endpoint: string;
18
+ readonly status: 'active' | 'unsubscribed' | 'expired' | 'bounced';
19
+ readonly browser?: string;
20
+ readonly os?: string;
21
+ readonly deviceType?: string;
22
+ readonly country?: string;
23
+ readonly city?: string;
24
+ readonly timezone?: string;
25
+ readonly language?: string;
26
+ readonly tags?: readonly string[];
27
+ readonly externalId?: string;
28
+ readonly createdAt: string;
29
+ readonly lastActiveAt?: string;
30
+ }
31
+ interface SubscriberListParams extends ListParams {
32
+ readonly status?: 'active' | 'unsubscribed' | 'expired' | 'bounced';
33
+ readonly tags?: readonly string[];
34
+ readonly externalId?: string;
35
+ }
36
+ interface UpdateSubscriber {
37
+ readonly tags?: readonly string[];
38
+ readonly externalId?: string;
39
+ readonly customData?: Readonly<Record<string, unknown>>;
40
+ }
41
+ interface Campaign {
42
+ readonly id: string;
43
+ readonly siteId: string;
44
+ readonly name: string;
45
+ readonly title: string;
46
+ readonly body: string;
47
+ readonly iconUrl?: string;
48
+ readonly imageUrl?: string;
49
+ readonly actionUrl?: string;
50
+ readonly status: 'draft' | 'scheduled' | 'sending' | 'active' | 'paused' | 'completed' | 'cancelled';
51
+ readonly scheduledAt?: string;
52
+ readonly totalTargeted: number;
53
+ readonly totalSent: number;
54
+ readonly totalDelivered: number;
55
+ readonly totalClicked: number;
56
+ readonly createdAt: string;
57
+ }
58
+ interface CreateCampaign {
59
+ readonly name: string;
60
+ readonly title: string;
61
+ readonly body: string;
62
+ readonly iconUrl?: string;
63
+ readonly imageUrl?: string;
64
+ readonly actionUrl?: string;
65
+ readonly scheduledAt?: string;
66
+ readonly segmentId?: string;
67
+ readonly tags?: readonly string[];
68
+ }
69
+ interface UpdateCampaign {
70
+ readonly name?: string;
71
+ readonly title?: string;
72
+ readonly body?: string;
73
+ readonly iconUrl?: string;
74
+ readonly imageUrl?: string;
75
+ readonly actionUrl?: string;
76
+ readonly scheduledAt?: string;
77
+ readonly status?: 'draft' | 'paused' | 'cancelled';
78
+ }
79
+ interface Template {
80
+ readonly id: string;
81
+ readonly siteId: string;
82
+ readonly name: string;
83
+ readonly title: string;
84
+ readonly body: string;
85
+ readonly iconUrl?: string;
86
+ readonly imageUrl?: string;
87
+ readonly actionUrl?: string;
88
+ readonly createdAt: string;
89
+ }
90
+ interface CreateTemplate {
91
+ readonly name: string;
92
+ readonly title: string;
93
+ readonly body: string;
94
+ readonly iconUrl?: string;
95
+ readonly imageUrl?: string;
96
+ readonly actionUrl?: string;
97
+ }
98
+ interface UpdateTemplate {
99
+ readonly name?: string;
100
+ readonly title?: string;
101
+ readonly body?: string;
102
+ readonly iconUrl?: string;
103
+ readonly imageUrl?: string;
104
+ readonly actionUrl?: string;
105
+ }
106
+ interface SendNotification {
107
+ readonly title: string;
108
+ readonly body: string;
109
+ readonly iconUrl?: string;
110
+ readonly imageUrl?: string;
111
+ readonly url?: string;
112
+ readonly subscriberIds?: readonly string[];
113
+ readonly externalIds?: readonly string[];
114
+ readonly tags?: readonly string[];
115
+ readonly data?: Readonly<Record<string, unknown>>;
116
+ }
117
+ interface SendResult {
118
+ readonly success: boolean;
119
+ readonly campaignId?: string;
120
+ readonly sent: number;
121
+ readonly limits: {
122
+ readonly remaining: number;
123
+ readonly limit: number;
124
+ };
125
+ }
126
+ interface SubscriberCount {
127
+ readonly total: number;
128
+ readonly active: number;
129
+ readonly unsubscribed: number;
130
+ }
131
+ interface CampaignStats {
132
+ readonly totalSent: number;
133
+ readonly totalDelivered: number;
134
+ readonly totalClicked: number;
135
+ readonly totalFailed: number;
136
+ readonly deliveryRate: number;
137
+ readonly clickRate: number;
138
+ }
139
+
140
+ interface SubscribersResource {
141
+ readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>;
142
+ readonly get: (id: string) => Promise<Subscriber>;
143
+ readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>;
144
+ readonly delete: (id: string) => Promise<void>;
145
+ readonly count: () => Promise<SubscriberCount>;
146
+ }
147
+
148
+ interface CampaignsResource {
149
+ readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>;
150
+ readonly create: (data: CreateCampaign) => Promise<Campaign>;
151
+ readonly get: (id: string) => Promise<Campaign>;
152
+ readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>;
153
+ readonly delete: (id: string) => Promise<void>;
154
+ readonly send: (id: string) => Promise<Campaign>;
155
+ readonly pause: (id: string) => Promise<Campaign>;
156
+ readonly resume: (id: string) => Promise<Campaign>;
157
+ readonly stats: (id: string) => Promise<CampaignStats>;
158
+ }
159
+
160
+ interface TemplatesResource {
161
+ readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>;
162
+ readonly create: (data: CreateTemplate) => Promise<Template>;
163
+ readonly get: (id: string) => Promise<Template>;
164
+ readonly update: (id: string, data: UpdateTemplate) => Promise<Template>;
165
+ readonly delete: (id: string) => Promise<void>;
166
+ }
167
+
168
+ interface NotificationsResource {
169
+ readonly send: (data: SendNotification) => Promise<SendResult>;
170
+ }
171
+
172
+ interface PusharyServer {
173
+ readonly subscribers: SubscribersResource;
174
+ readonly campaigns: CampaignsResource;
175
+ readonly templates: TemplatesResource;
176
+ readonly notifications: NotificationsResource;
177
+ }
178
+ declare const createPusharyServer: (config: PusharyConfig) => PusharyServer;
179
+
180
+ export { type Campaign, type CampaignStats, type CampaignsResource, type CreateCampaign, type CreateTemplate, type ListParams, type NotificationsResource, type PaginatedResponse, type PusharyConfig, type PusharyServer, type SendNotification, type SendResult, type Subscriber, type SubscriberCount, type SubscriberListParams, type SubscribersResource, type Template, type TemplatesResource, type UpdateCampaign, type UpdateSubscriber, type UpdateTemplate, createPusharyServer };
@@ -0,0 +1,180 @@
1
+ interface PusharyConfig {
2
+ readonly apiKey: string;
3
+ readonly baseUrl?: string;
4
+ }
5
+ interface ListParams {
6
+ readonly limit?: number;
7
+ readonly cursor?: string;
8
+ }
9
+ interface PaginatedResponse<T> {
10
+ readonly data: readonly T[];
11
+ readonly nextCursor?: string;
12
+ readonly hasMore: boolean;
13
+ }
14
+ interface Subscriber {
15
+ readonly id: string;
16
+ readonly siteId: string;
17
+ readonly endpoint: string;
18
+ readonly status: 'active' | 'unsubscribed' | 'expired' | 'bounced';
19
+ readonly browser?: string;
20
+ readonly os?: string;
21
+ readonly deviceType?: string;
22
+ readonly country?: string;
23
+ readonly city?: string;
24
+ readonly timezone?: string;
25
+ readonly language?: string;
26
+ readonly tags?: readonly string[];
27
+ readonly externalId?: string;
28
+ readonly createdAt: string;
29
+ readonly lastActiveAt?: string;
30
+ }
31
+ interface SubscriberListParams extends ListParams {
32
+ readonly status?: 'active' | 'unsubscribed' | 'expired' | 'bounced';
33
+ readonly tags?: readonly string[];
34
+ readonly externalId?: string;
35
+ }
36
+ interface UpdateSubscriber {
37
+ readonly tags?: readonly string[];
38
+ readonly externalId?: string;
39
+ readonly customData?: Readonly<Record<string, unknown>>;
40
+ }
41
+ interface Campaign {
42
+ readonly id: string;
43
+ readonly siteId: string;
44
+ readonly name: string;
45
+ readonly title: string;
46
+ readonly body: string;
47
+ readonly iconUrl?: string;
48
+ readonly imageUrl?: string;
49
+ readonly actionUrl?: string;
50
+ readonly status: 'draft' | 'scheduled' | 'sending' | 'active' | 'paused' | 'completed' | 'cancelled';
51
+ readonly scheduledAt?: string;
52
+ readonly totalTargeted: number;
53
+ readonly totalSent: number;
54
+ readonly totalDelivered: number;
55
+ readonly totalClicked: number;
56
+ readonly createdAt: string;
57
+ }
58
+ interface CreateCampaign {
59
+ readonly name: string;
60
+ readonly title: string;
61
+ readonly body: string;
62
+ readonly iconUrl?: string;
63
+ readonly imageUrl?: string;
64
+ readonly actionUrl?: string;
65
+ readonly scheduledAt?: string;
66
+ readonly segmentId?: string;
67
+ readonly tags?: readonly string[];
68
+ }
69
+ interface UpdateCampaign {
70
+ readonly name?: string;
71
+ readonly title?: string;
72
+ readonly body?: string;
73
+ readonly iconUrl?: string;
74
+ readonly imageUrl?: string;
75
+ readonly actionUrl?: string;
76
+ readonly scheduledAt?: string;
77
+ readonly status?: 'draft' | 'paused' | 'cancelled';
78
+ }
79
+ interface Template {
80
+ readonly id: string;
81
+ readonly siteId: string;
82
+ readonly name: string;
83
+ readonly title: string;
84
+ readonly body: string;
85
+ readonly iconUrl?: string;
86
+ readonly imageUrl?: string;
87
+ readonly actionUrl?: string;
88
+ readonly createdAt: string;
89
+ }
90
+ interface CreateTemplate {
91
+ readonly name: string;
92
+ readonly title: string;
93
+ readonly body: string;
94
+ readonly iconUrl?: string;
95
+ readonly imageUrl?: string;
96
+ readonly actionUrl?: string;
97
+ }
98
+ interface UpdateTemplate {
99
+ readonly name?: string;
100
+ readonly title?: string;
101
+ readonly body?: string;
102
+ readonly iconUrl?: string;
103
+ readonly imageUrl?: string;
104
+ readonly actionUrl?: string;
105
+ }
106
+ interface SendNotification {
107
+ readonly title: string;
108
+ readonly body: string;
109
+ readonly iconUrl?: string;
110
+ readonly imageUrl?: string;
111
+ readonly url?: string;
112
+ readonly subscriberIds?: readonly string[];
113
+ readonly externalIds?: readonly string[];
114
+ readonly tags?: readonly string[];
115
+ readonly data?: Readonly<Record<string, unknown>>;
116
+ }
117
+ interface SendResult {
118
+ readonly success: boolean;
119
+ readonly campaignId?: string;
120
+ readonly sent: number;
121
+ readonly limits: {
122
+ readonly remaining: number;
123
+ readonly limit: number;
124
+ };
125
+ }
126
+ interface SubscriberCount {
127
+ readonly total: number;
128
+ readonly active: number;
129
+ readonly unsubscribed: number;
130
+ }
131
+ interface CampaignStats {
132
+ readonly totalSent: number;
133
+ readonly totalDelivered: number;
134
+ readonly totalClicked: number;
135
+ readonly totalFailed: number;
136
+ readonly deliveryRate: number;
137
+ readonly clickRate: number;
138
+ }
139
+
140
+ interface SubscribersResource {
141
+ readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>;
142
+ readonly get: (id: string) => Promise<Subscriber>;
143
+ readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>;
144
+ readonly delete: (id: string) => Promise<void>;
145
+ readonly count: () => Promise<SubscriberCount>;
146
+ }
147
+
148
+ interface CampaignsResource {
149
+ readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>;
150
+ readonly create: (data: CreateCampaign) => Promise<Campaign>;
151
+ readonly get: (id: string) => Promise<Campaign>;
152
+ readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>;
153
+ readonly delete: (id: string) => Promise<void>;
154
+ readonly send: (id: string) => Promise<Campaign>;
155
+ readonly pause: (id: string) => Promise<Campaign>;
156
+ readonly resume: (id: string) => Promise<Campaign>;
157
+ readonly stats: (id: string) => Promise<CampaignStats>;
158
+ }
159
+
160
+ interface TemplatesResource {
161
+ readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>;
162
+ readonly create: (data: CreateTemplate) => Promise<Template>;
163
+ readonly get: (id: string) => Promise<Template>;
164
+ readonly update: (id: string, data: UpdateTemplate) => Promise<Template>;
165
+ readonly delete: (id: string) => Promise<void>;
166
+ }
167
+
168
+ interface NotificationsResource {
169
+ readonly send: (data: SendNotification) => Promise<SendResult>;
170
+ }
171
+
172
+ interface PusharyServer {
173
+ readonly subscribers: SubscribersResource;
174
+ readonly campaigns: CampaignsResource;
175
+ readonly templates: TemplatesResource;
176
+ readonly notifications: NotificationsResource;
177
+ }
178
+ declare const createPusharyServer: (config: PusharyConfig) => PusharyServer;
179
+
180
+ export { type Campaign, type CampaignStats, type CampaignsResource, type CreateCampaign, type CreateTemplate, type ListParams, type NotificationsResource, type PaginatedResponse, type PusharyConfig, type PusharyServer, type SendNotification, type SendResult, type Subscriber, type SubscriberCount, type SubscriberListParams, type SubscribersResource, type Template, type TemplatesResource, type UpdateCampaign, type UpdateSubscriber, type UpdateTemplate, createPusharyServer };
package/dist/index.js ADDED
@@ -0,0 +1,100 @@
1
+ // src/request.ts
2
+ var buildUrl = (baseUrl, path, params) => {
3
+ const url = new URL(path, baseUrl);
4
+ if (params) {
5
+ Object.entries(params).forEach(([key, value]) => {
6
+ if (value !== void 0 && value !== null) {
7
+ url.searchParams.set(key, String(value));
8
+ }
9
+ });
10
+ }
11
+ return url.toString();
12
+ };
13
+ var handleResponse = async (response) => {
14
+ if (!response.ok) {
15
+ const error = await response.json().catch(() => ({ message: "Request failed" }));
16
+ throw new Error(error.message || `HTTP ${response.status}`);
17
+ }
18
+ return response.json();
19
+ };
20
+ var createRequest = (ctx) => async (method, path, body) => {
21
+ const isGet = method === "GET";
22
+ const url = isGet && body ? buildUrl(ctx.baseUrl, path, body) : `${ctx.baseUrl}${path}`;
23
+ const response = await fetch(url, {
24
+ method,
25
+ headers: ctx.headers,
26
+ body: !isGet && body ? JSON.stringify(body) : void 0
27
+ });
28
+ return handleResponse(response);
29
+ };
30
+
31
+ // src/resources/subscribers.ts
32
+ var createSubscribersResource = (request) => Object.freeze({
33
+ list: (params) => request("GET", "/subscribers", params),
34
+ get: (id) => request("GET", `/subscribers/${id}`),
35
+ update: (id, data) => request("PATCH", `/subscribers/${id}`, data),
36
+ delete: (id) => request("DELETE", `/subscribers/${id}`),
37
+ count: () => request("GET", "/subscribers/count")
38
+ });
39
+
40
+ // src/resources/campaigns.ts
41
+ var createCampaignsResource = (request) => Object.freeze({
42
+ list: (params) => request("GET", "/campaigns", params),
43
+ create: (data) => request("POST", "/campaigns", data),
44
+ get: (id) => request("GET", `/campaigns/${id}`),
45
+ update: (id, data) => request("PATCH", `/campaigns/${id}`, data),
46
+ delete: (id) => request("DELETE", `/campaigns/${id}`),
47
+ send: (id) => request("POST", `/campaigns/${id}/send`),
48
+ pause: (id) => request("POST", `/campaigns/${id}/pause`),
49
+ resume: (id) => request("POST", `/campaigns/${id}/resume`),
50
+ stats: (id) => request("GET", `/campaigns/${id}/stats`)
51
+ });
52
+
53
+ // src/resources/templates.ts
54
+ var createTemplatesResource = (request) => Object.freeze({
55
+ list: (params) => request("GET", "/templates", params),
56
+ create: (data) => request("POST", "/templates", data),
57
+ get: (id) => request("GET", `/templates/${id}`),
58
+ update: (id, data) => request("PATCH", `/templates/${id}`, data),
59
+ delete: (id) => request("DELETE", `/templates/${id}`)
60
+ });
61
+
62
+ // src/resources/notifications.ts
63
+ var createNotificationsResource = (request) => Object.freeze({
64
+ send: (data) => request("POST", "/send", data)
65
+ });
66
+
67
+ // src/client.ts
68
+ var DEFAULT_BASE_URL = "https://pushary.com/api/v1/server";
69
+ var validateApiKey = (apiKey) => {
70
+ if (!apiKey) {
71
+ throw new Error("API key is required. Get your API key from https://pushary.com/dashboard/settings");
72
+ }
73
+ if (!apiKey.includes(".")) {
74
+ throw new Error("Invalid API key format. Use the full API key (pk_xxx.sk_xxx)");
75
+ }
76
+ };
77
+ var createContext = (config) => {
78
+ validateApiKey(config.apiKey);
79
+ return Object.freeze({
80
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
81
+ headers: Object.freeze({
82
+ "Content-Type": "application/json",
83
+ "Authorization": `Bearer ${config.apiKey}`
84
+ })
85
+ });
86
+ };
87
+ var createPusharyServer = (config) => {
88
+ const ctx = createContext(config);
89
+ const request = createRequest(ctx);
90
+ return Object.freeze({
91
+ subscribers: createSubscribersResource(request),
92
+ campaigns: createCampaignsResource(request),
93
+ templates: createTemplatesResource(request),
94
+ notifications: createNotificationsResource(request)
95
+ });
96
+ };
97
+ export {
98
+ createPusharyServer
99
+ };
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/request.ts","../src/resources/subscribers.ts","../src/resources/campaigns.ts","../src/resources/templates.ts","../src/resources/notifications.ts","../src/client.ts"],"sourcesContent":["import type { RequestContext, RequestFn } from './types'\n\nconst buildUrl = (baseUrl: string, path: string, params?: Record<string, unknown>): string => {\n const url = new URL(path, baseUrl)\n \n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n })\n }\n \n return url.toString()\n}\n\nconst handleResponse = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: 'Request failed' }))\n throw new Error(error.message || `HTTP ${response.status}`)\n }\n return response.json() as Promise<T>\n}\n\nexport const createRequest = (ctx: RequestContext): RequestFn =>\n async <T>(method: string, path: string, body?: unknown): Promise<T> => {\n const isGet = method === 'GET'\n const url = isGet && body \n ? buildUrl(ctx.baseUrl, path, body as Record<string, unknown>)\n : `${ctx.baseUrl}${path}`\n \n const response = await fetch(url, {\n method,\n headers: ctx.headers,\n body: !isGet && body ? JSON.stringify(body) : undefined,\n })\n \n return handleResponse<T>(response)\n }\n\n","import type {\n RequestFn,\n Subscriber,\n SubscriberListParams,\n UpdateSubscriber,\n PaginatedResponse,\n SubscriberCount,\n} from '../types'\n\nexport interface SubscribersResource {\n readonly list: (params?: SubscriberListParams) => Promise<PaginatedResponse<Subscriber>>\n readonly get: (id: string) => Promise<Subscriber>\n readonly update: (id: string, data: UpdateSubscriber) => Promise<Subscriber>\n readonly delete: (id: string) => Promise<void>\n readonly count: () => Promise<SubscriberCount>\n}\n\nexport const createSubscribersResource = (request: RequestFn): SubscribersResource =>\n Object.freeze({\n list: (params?: SubscriberListParams) =>\n request<PaginatedResponse<Subscriber>>('GET', '/subscribers', params),\n \n get: (id: string) =>\n request<Subscriber>('GET', `/subscribers/${id}`),\n \n update: (id: string, data: UpdateSubscriber) =>\n request<Subscriber>('PATCH', `/subscribers/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/subscribers/${id}`),\n \n count: () =>\n request<SubscriberCount>('GET', '/subscribers/count'),\n })\n\n","import type {\n RequestFn,\n Campaign,\n CreateCampaign,\n UpdateCampaign,\n ListParams,\n PaginatedResponse,\n CampaignStats,\n} from '../types'\n\nexport interface CampaignsResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Campaign>>\n readonly create: (data: CreateCampaign) => Promise<Campaign>\n readonly get: (id: string) => Promise<Campaign>\n readonly update: (id: string, data: UpdateCampaign) => Promise<Campaign>\n readonly delete: (id: string) => Promise<void>\n readonly send: (id: string) => Promise<Campaign>\n readonly pause: (id: string) => Promise<Campaign>\n readonly resume: (id: string) => Promise<Campaign>\n readonly stats: (id: string) => Promise<CampaignStats>\n}\n\nexport const createCampaignsResource = (request: RequestFn): CampaignsResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Campaign>>('GET', '/campaigns', params),\n \n create: (data: CreateCampaign) =>\n request<Campaign>('POST', '/campaigns', data),\n \n get: (id: string) =>\n request<Campaign>('GET', `/campaigns/${id}`),\n \n update: (id: string, data: UpdateCampaign) =>\n request<Campaign>('PATCH', `/campaigns/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/campaigns/${id}`),\n \n send: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/send`),\n \n pause: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/pause`),\n \n resume: (id: string) =>\n request<Campaign>('POST', `/campaigns/${id}/resume`),\n \n stats: (id: string) =>\n request<CampaignStats>('GET', `/campaigns/${id}/stats`),\n })\n\n","import type {\n RequestFn,\n Template,\n CreateTemplate,\n UpdateTemplate,\n ListParams,\n PaginatedResponse,\n} from '../types'\n\nexport interface TemplatesResource {\n readonly list: (params?: ListParams) => Promise<PaginatedResponse<Template>>\n readonly create: (data: CreateTemplate) => Promise<Template>\n readonly get: (id: string) => Promise<Template>\n readonly update: (id: string, data: UpdateTemplate) => Promise<Template>\n readonly delete: (id: string) => Promise<void>\n}\n\nexport const createTemplatesResource = (request: RequestFn): TemplatesResource =>\n Object.freeze({\n list: (params?: ListParams) =>\n request<PaginatedResponse<Template>>('GET', '/templates', params),\n \n create: (data: CreateTemplate) =>\n request<Template>('POST', '/templates', data),\n \n get: (id: string) =>\n request<Template>('GET', `/templates/${id}`),\n \n update: (id: string, data: UpdateTemplate) =>\n request<Template>('PATCH', `/templates/${id}`, data),\n \n delete: (id: string) =>\n request<void>('DELETE', `/templates/${id}`),\n })\n\n","import type { RequestFn, SendNotification, SendResult } from '../types'\n\nexport interface NotificationsResource {\n readonly send: (data: SendNotification) => Promise<SendResult>\n}\n\nexport const createNotificationsResource = (request: RequestFn): NotificationsResource =>\n Object.freeze({\n send: (data: SendNotification) =>\n request<SendResult>('POST', '/send', data),\n })\n\n","import type { PusharyConfig, RequestContext } from './types'\nimport { createRequest } from './request'\nimport { createSubscribersResource, type SubscribersResource } from './resources/subscribers'\nimport { createCampaignsResource, type CampaignsResource } from './resources/campaigns'\nimport { createTemplatesResource, type TemplatesResource } from './resources/templates'\nimport { createNotificationsResource, type NotificationsResource } from './resources/notifications'\n\nconst DEFAULT_BASE_URL = 'https://pushary.com/api/v1/server'\n\nexport interface PusharyServer {\n readonly subscribers: SubscribersResource\n readonly campaigns: CampaignsResource\n readonly templates: TemplatesResource\n readonly notifications: NotificationsResource\n}\n\nconst validateApiKey = (apiKey: string): void => {\n if (!apiKey) {\n throw new Error('API key is required. Get your API key from https://pushary.com/dashboard/settings')\n }\n \n if (!apiKey.includes('.')) {\n throw new Error('Invalid API key format. Use the full API key (pk_xxx.sk_xxx)')\n }\n}\n\nconst createContext = (config: PusharyConfig): RequestContext => {\n validateApiKey(config.apiKey)\n \n return Object.freeze({\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n headers: Object.freeze({\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n }),\n })\n}\n\nexport const createPusharyServer = (config: PusharyConfig): PusharyServer => {\n const ctx = createContext(config)\n const request = createRequest(ctx)\n \n return Object.freeze({\n subscribers: createSubscribersResource(request),\n campaigns: createCampaignsResource(request),\n templates: createTemplatesResource(request),\n notifications: createNotificationsResource(request),\n })\n}\n\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@pushary/server",
3
+ "version": "1.0.0",
4
+ "description": "Pushary Server SDK - Manage subscribers, campaigns, templates, and send notifications",
5
+ "author": "Pushary <business@ralphnex.com>",
6
+ "homepage": "https://pushary.com",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/pushary/pushary.git",
10
+ "directory": "packages/server"
11
+ },
12
+ "license": "MIT",
13
+ "type": "module",
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "sideEffects": false,
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsup --watch",
36
+ "typecheck": "tsc --noEmit",
37
+ "clean": "rm -rf dist",
38
+ "prepublishOnly": "npm run build && npm run typecheck"
39
+ },
40
+ "devDependencies": {
41
+ "tsup": "^8.0.0",
42
+ "typescript": "^5.0.0"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "keywords": [
48
+ "pushary",
49
+ "push-notifications",
50
+ "web-push",
51
+ "notifications",
52
+ "server-sdk",
53
+ "api-client"
54
+ ]
55
+ }
56
+