@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 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
- const client = new postmark.ServerClient(POSTMARK_KEY)
9
-
10
- export default function Postmark(options) {
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.1.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
- "./google": "./google.js",
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.5.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.0.0",
31
- "@splendidlabz/prettier-config": "1.1.0"
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