@splendidlabz/third-party 1.1.1 → 1.2.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/CHANGELOG.md +11 -0
- package/{buttondown.js → lib/buttondown.js} +0 -1
- package/lib/logger.js +49 -0
- package/lib/logger.md +45 -0
- package/{postmark.js → lib/postmark.js} +3 -4
- package/lib/sendy.js +202 -0
- package/package.json +7 -8
- /package/{buttondown.spec.js → lib/buttondown.spec.js} +0 -0
- /package/{google.js → lib/google.js} +0 -0
- /package/{stripe.js → lib/stripe.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @splendidlabz/third-party
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Many many upgrades which I didn't document properly 😅. The details are in Github history, but too many details to talk about now.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @splendidlabz/utils@1.6.0
|
|
13
|
+
|
|
3
14
|
## 1.1.1
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -52,7 +52,6 @@ export async function createSubscriber(
|
|
|
52
52
|
|
|
53
53
|
if (response) return response.body
|
|
54
54
|
if (error) {
|
|
55
|
-
console.log(error)
|
|
56
55
|
// Button down throws this error if the email is invalid. Though this only occurs after using fake emails for many times. Shouldn't be a problem to ignore.
|
|
57
56
|
if (error.code === 'email_invalid') return
|
|
58
57
|
return reject(error)
|
package/lib/logger.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import pino from 'pino'
|
|
2
|
+
|
|
3
|
+
// Potentially can put into logtail for production
|
|
4
|
+
// Potentially can use pino-http for logging requests
|
|
5
|
+
|
|
6
|
+
const isDev = import.meta.env.DEV
|
|
7
|
+
|
|
8
|
+
export function createLogger({ verbose = false, level = 'info' } = {}) {
|
|
9
|
+
return pino({
|
|
10
|
+
level,
|
|
11
|
+
transport: isDev
|
|
12
|
+
? {
|
|
13
|
+
target: 'pino-pretty', // Nice formatting for dev
|
|
14
|
+
options: { colorize: true },
|
|
15
|
+
}
|
|
16
|
+
: undefined, // Raw JSON for production
|
|
17
|
+
hooks: {
|
|
18
|
+
logMethod(inputArgs, method, level) {
|
|
19
|
+
if (!verbose) return method.apply(this, inputArgs)
|
|
20
|
+
if (inputArgs.length >= 2) {
|
|
21
|
+
const arg1 = inputArgs.shift()
|
|
22
|
+
const arg2 = inputArgs.shift()
|
|
23
|
+
return method.apply(this, [arg2, arg1, ...inputArgs])
|
|
24
|
+
}
|
|
25
|
+
return method.apply(this, inputArgs)
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// For fast usage, but will be verbose by default
|
|
32
|
+
export const logger = pino({
|
|
33
|
+
transport: isDev
|
|
34
|
+
? {
|
|
35
|
+
target: 'pino-pretty', // Nice formatting for dev
|
|
36
|
+
options: { colorize: true },
|
|
37
|
+
}
|
|
38
|
+
: undefined, // Raw JSON for production
|
|
39
|
+
hooks: {
|
|
40
|
+
logMethod(inputArgs, method, level) {
|
|
41
|
+
if (inputArgs.length >= 2) {
|
|
42
|
+
const arg1 = inputArgs.shift()
|
|
43
|
+
const arg2 = inputArgs.shift()
|
|
44
|
+
return method.apply(this, [arg2, arg1, ...inputArgs])
|
|
45
|
+
}
|
|
46
|
+
return method.apply(this, inputArgs)
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
})
|
package/lib/logger.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Logger
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install @splendidlabz/third-party
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Basic Usage
|
|
10
|
+
|
|
11
|
+
Import `logger` from the package to log messages. This will be verbose by default.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { logger } from '@splendidlabz/third-party/logger'
|
|
15
|
+
logger.info('Message', { data: 'data' })
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Advanced Usage
|
|
19
|
+
|
|
20
|
+
You can create a logger with a custom verbosity and log level.
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
import { createLogger } from '@splendidlabz/third-party/logger'
|
|
24
|
+
|
|
25
|
+
export const logger = createLogger({
|
|
26
|
+
level: 'info',
|
|
27
|
+
verbose: false,
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Log Levels
|
|
32
|
+
|
|
33
|
+
Pino default log levels are:
|
|
34
|
+
|
|
35
|
+
| Level | Value |
|
|
36
|
+
| ------ | -------- |
|
|
37
|
+
| trace | 10 |
|
|
38
|
+
| debug | 20 |
|
|
39
|
+
| info | 30 |
|
|
40
|
+
| warn | 40 |
|
|
41
|
+
| error | 50 |
|
|
42
|
+
| fatal | 60 |
|
|
43
|
+
| silent | Infinity |
|
|
44
|
+
|
|
45
|
+
Default log level is `info`
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import postmark from 'postmark'
|
|
2
2
|
|
|
3
|
-
const POSTMARK_KEY = process.env.POSTMARK_KEY
|
|
4
3
|
const DEFAULT_OPTIONS = {
|
|
5
4
|
MessageStream: 'outbound', // outbound | broadcast
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export default function Postmark(API_KEY, options) {
|
|
8
|
+
const POSTMARK_KEY = API_KEY || process.env.POSTMARK_KEY
|
|
9
|
+
const client = new postmark.ServerClient(POSTMARK_KEY)
|
|
11
10
|
const baseOpts = Object.assign({}, DEFAULT_OPTIONS, options)
|
|
12
11
|
|
|
13
12
|
return {
|
package/lib/sendy.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { omitEmpty } from '@splendidlabz/utils'
|
|
2
|
+
import zlFetch, { toQueryString } from 'zl-fetch'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Sendy API client instance
|
|
6
|
+
* @param {string} baseURL - The base URL of your Sendy installation (e.g., 'https://your-domain.com/sendy')
|
|
7
|
+
* @param {Object} config - Configuration object
|
|
8
|
+
* @param {string} config.apiKey - Your Sendy API key (available in Settings)
|
|
9
|
+
* @return {Object} Sendy client with available methods
|
|
10
|
+
* @property {Function} subscribe - Subscribe a user to a mailing list
|
|
11
|
+
*/
|
|
12
|
+
export function createSendy({
|
|
13
|
+
baseURL,
|
|
14
|
+
listId,
|
|
15
|
+
brandId,
|
|
16
|
+
apiKey,
|
|
17
|
+
getReferrer = null,
|
|
18
|
+
getIpAddress = null,
|
|
19
|
+
} = {}) {
|
|
20
|
+
const api_key = apiKey
|
|
21
|
+
const list = listId
|
|
22
|
+
const brand = brandId
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
async subscriberStatus({ email, listId }) {
|
|
26
|
+
const response = await zlFetch.post(
|
|
27
|
+
`${baseURL}/api/subscribers/subscription-status.php`,
|
|
28
|
+
{
|
|
29
|
+
body: toQueryString({
|
|
30
|
+
boolean: true,
|
|
31
|
+
api_key,
|
|
32
|
+
list_id: listId || list,
|
|
33
|
+
email,
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const successMessages = [
|
|
39
|
+
'Subscribed',
|
|
40
|
+
'Unsubscribed',
|
|
41
|
+
'Unconfirmed',
|
|
42
|
+
'Bounced',
|
|
43
|
+
'Soft bounced',
|
|
44
|
+
'Complained',
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
if (successMessages.includes(response.body)) return response.body
|
|
48
|
+
else throw new Error(response.body)
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
async subscriberCount({ listId } = {}) {
|
|
52
|
+
const response = await zlFetch.post(
|
|
53
|
+
`${baseURL}/api/subscribers/subscribers-count.php`,
|
|
54
|
+
{
|
|
55
|
+
body: toQueryString({
|
|
56
|
+
boolean: true,
|
|
57
|
+
api_key,
|
|
58
|
+
list_id: listId || list,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const result = response.body
|
|
64
|
+
const count = Number(result)
|
|
65
|
+
if (isNaN(count)) throw new Error(result)
|
|
66
|
+
return count
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
async subscribe({
|
|
70
|
+
context,
|
|
71
|
+
email,
|
|
72
|
+
listId,
|
|
73
|
+
gdpr = false,
|
|
74
|
+
silent = false,
|
|
75
|
+
...rest
|
|
76
|
+
}) {
|
|
77
|
+
const ip = getIpAddress && context && getIpAddress(context)
|
|
78
|
+
const referrer = getReferrer && context && getReferrer(context)
|
|
79
|
+
|
|
80
|
+
const body = omitEmpty({
|
|
81
|
+
boolean: true,
|
|
82
|
+
api_key,
|
|
83
|
+
list: listId || list,
|
|
84
|
+
email,
|
|
85
|
+
ipaddress: ip,
|
|
86
|
+
referrer,
|
|
87
|
+
gdpr,
|
|
88
|
+
silent,
|
|
89
|
+
...rest,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const response = await zlFetch.post(`${baseURL}/subscribe`, {
|
|
93
|
+
body: toQueryString(body),
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const result = response.body
|
|
97
|
+
if (result === '1') return true
|
|
98
|
+
|
|
99
|
+
// Details will be updated when users are subscribed. So this strictly doesn't count as an error. Better to use subscriberStatus to check for status.
|
|
100
|
+
if (result === 'Already subscribed.') return true
|
|
101
|
+
else throw new Error(result)
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async unsubscribe({ email, listId, ...rest }) {
|
|
105
|
+
const response = await zlFetch.post(`${baseURL}/unsubscribe`, {
|
|
106
|
+
body: toQueryString({
|
|
107
|
+
boolean: true,
|
|
108
|
+
api_key,
|
|
109
|
+
email,
|
|
110
|
+
list: listId || list,
|
|
111
|
+
...rest,
|
|
112
|
+
}),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const result = response.body
|
|
116
|
+
if (result === '1') return true
|
|
117
|
+
else throw new Error(result)
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
async delete({ email, listId }) {
|
|
121
|
+
const response = await zlFetch.post(
|
|
122
|
+
`${baseURL}/api/subscribers/delete.php`,
|
|
123
|
+
{
|
|
124
|
+
body: toQueryString({
|
|
125
|
+
boolean: true,
|
|
126
|
+
api_key,
|
|
127
|
+
email,
|
|
128
|
+
list_id: listId || list,
|
|
129
|
+
}),
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const result = response.body
|
|
134
|
+
if (result === '1') return true
|
|
135
|
+
// No harm in returning true for this
|
|
136
|
+
if (result === 'Subscriber does not exist') return true
|
|
137
|
+
else throw new Error(result)
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
async createCampaign({
|
|
141
|
+
listIds = [],
|
|
142
|
+
excludeListIds = [],
|
|
143
|
+
segmentIds = [],
|
|
144
|
+
excludeSegmentIds = [],
|
|
145
|
+
brandId = brand,
|
|
146
|
+
|
|
147
|
+
send = false,
|
|
148
|
+
subject,
|
|
149
|
+
fromName,
|
|
150
|
+
fromEmail,
|
|
151
|
+
replyTo,
|
|
152
|
+
plainText,
|
|
153
|
+
htmlText,
|
|
154
|
+
|
|
155
|
+
queryString = '',
|
|
156
|
+
trackOpens = 1,
|
|
157
|
+
trackClicks = 1,
|
|
158
|
+
scheduleDateTime,
|
|
159
|
+
scheduleTimezone,
|
|
160
|
+
}) {
|
|
161
|
+
const send_campaign = send ? 1 : 0
|
|
162
|
+
const response = await zlFetch.post(
|
|
163
|
+
`${baseURL}/api/campaigns/create.php`,
|
|
164
|
+
{
|
|
165
|
+
body: toQueryString(
|
|
166
|
+
omitEmpty({
|
|
167
|
+
boolean: true,
|
|
168
|
+
api_key,
|
|
169
|
+
brand_id: brandId,
|
|
170
|
+
list_ids: listIds.join(','),
|
|
171
|
+
segment_ids: segmentIds.join(','),
|
|
172
|
+
exclude_list_ids: excludeListIds.join(','),
|
|
173
|
+
exclude_segment_ids: excludeSegmentIds.join(','),
|
|
174
|
+
send_campaign,
|
|
175
|
+
from_name: fromName,
|
|
176
|
+
from_email: fromEmail,
|
|
177
|
+
reply_to: replyTo || fromEmail,
|
|
178
|
+
subject,
|
|
179
|
+
plain_text: plainText,
|
|
180
|
+
html_text: htmlText,
|
|
181
|
+
query_string: queryString,
|
|
182
|
+
track_opens: trackOpens,
|
|
183
|
+
track_clicks: trackClicks,
|
|
184
|
+
schedule_date_time: scheduleDateTime,
|
|
185
|
+
schedule_timezone: scheduleTimezone,
|
|
186
|
+
}),
|
|
187
|
+
),
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
const successMessages = [
|
|
192
|
+
'Campaign created',
|
|
193
|
+
'Campaign created and now sending',
|
|
194
|
+
'Campaign scheduled',
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
const result = response.body
|
|
198
|
+
if (successMessages.includes(result)) return result
|
|
199
|
+
else throw new Error(result)
|
|
200
|
+
},
|
|
201
|
+
}
|
|
202
|
+
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@splendidlabz/third-party",
|
|
3
3
|
"prettier": "@splendidlabz/prettier-config",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"exports": {
|
|
10
|
-
"
|
|
11
|
-
"./postmark": "./postmark.js",
|
|
12
|
-
"./buttondown": "./buttondown.js",
|
|
13
|
-
"./stripe": "./stripe.js"
|
|
10
|
+
"./*": "./lib/*.js"
|
|
14
11
|
},
|
|
15
12
|
"scripts": {
|
|
16
13
|
"lint": "eslint . --fix",
|
|
@@ -19,15 +16,17 @@
|
|
|
19
16
|
},
|
|
20
17
|
"author": "Zell Liew <zellwk@gmail.com>",
|
|
21
18
|
"dependencies": {
|
|
22
|
-
"@splendidlabz/utils": "1.
|
|
19
|
+
"@splendidlabz/utils": "1.6.0",
|
|
23
20
|
"googleapis": "^148.0.0",
|
|
24
21
|
"http-errors": "^2.0.0",
|
|
22
|
+
"pino": "^9.7.0",
|
|
23
|
+
"pino-pretty": "^13.0.0",
|
|
25
24
|
"postmark": "^4.0.5",
|
|
26
25
|
"vitest": "^3.1.4",
|
|
27
26
|
"zl-fetch": "^6.0.6"
|
|
28
27
|
},
|
|
29
28
|
"devDependencies": {
|
|
30
|
-
"@splendidlabz/eslint-config": "2.
|
|
31
|
-
"@splendidlabz/prettier-config": "1.
|
|
29
|
+
"@splendidlabz/eslint-config": "2.1.0",
|
|
30
|
+
"@splendidlabz/prettier-config": "1.2.0"
|
|
32
31
|
}
|
|
33
32
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|