@cowliss/sdk 0.18.1 → 0.20.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 +13 -0
- package/README.md +7 -0
- package/dist/index.d.ts +28 -8
- package/dist/index.js +31 -7
- package/dist/types.d.ts +37 -0
- package/dist/version.autogenerated.d.ts +1 -1
- package/dist/version.autogenerated.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
What changed in each version of `@cowliss/sdk` after 0.16.0, newest first. Earlier versions are listed on [npm](https://www.npmjs.com/package/@cowliss/sdk?activeTab=versions).
|
|
6
6
|
|
|
7
|
+
## 0.20.0 (2026-10-02)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- cow.templates.preview renders a template with your own props
|
|
12
|
+
|
|
13
|
+
## 0.19.0 (2026-10-02)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- emails.send takes an idempotencyKey and creates the person it emails
|
|
18
|
+
- cow.preferences.get and set, the hosted preferences page as data
|
|
19
|
+
|
|
7
20
|
## 0.18.1 (2026-10-01)
|
|
8
21
|
|
|
9
22
|
### Fixes
|
package/README.md
CHANGED
|
@@ -60,6 +60,13 @@ delivery id. A message to a profile goes to its `email` trait, skips anyone
|
|
|
60
60
|
who turned that purpose off, and carries an unsubscribe link. Mail that
|
|
61
61
|
follows a rule or a wait belongs in a journey.
|
|
62
62
|
|
|
63
|
+
Render a pushed template with your own props, exactly as a send to an address
|
|
64
|
+
would, without sending it:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const { subject, html } = await cow.templates.preview({ key: "receipt", props: { name: "Ada" } });
|
|
68
|
+
```
|
|
69
|
+
|
|
63
70
|
Send someone to their hosted email preferences page from your own "Manage
|
|
64
71
|
email preferences" button. The link works for an hour, so ask for it on the
|
|
65
72
|
click:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BatchBody, BatchResultDto, ErrorCode, EventDto, IdentifyInput, PreferencesLink, PreferencesLinkInput, ProfileDto, SendEmailInput, SendEmailResult, TrackInput } from "./types.js";
|
|
1
|
+
import type { BatchBody, BatchResultDto, ErrorCode, EventDto, GetPreferencesInput, IdentifyInput, Preferences, PreferencesLink, PreferencesLinkInput, PreviewEmailInput, ProfileDto, SendEmailInput, SendEmailResult, SetPreferencesInput, TemplatePreview, TrackInput } from "./types.js";
|
|
2
2
|
export type * from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* The Cowliss TS client SDK. Small typed surface over the ingestion API:
|
|
@@ -98,20 +98,40 @@ export declare class Cow {
|
|
|
98
98
|
*
|
|
99
99
|
* Synchronous like the rest of the client: the promise resolves once the
|
|
100
100
|
* message has been handed over, and `deliveryId` is the row that records
|
|
101
|
-
* what happened to it. Each call carries
|
|
101
|
+
* what happened to it. Each call carries an Idempotency-Key on every
|
|
102
102
|
* attempt, so a retry after a lost reply answers with the first send's
|
|
103
|
-
* `deliveryId` instead of sending again.
|
|
103
|
+
* `deliveryId` instead of sending again. Pass your own `idempotencyKey`
|
|
104
|
+
* (an order id, a job id) and a second run of your own code dedupes too;
|
|
105
|
+
* without one, each call is a send of its own.
|
|
106
|
+
*
|
|
107
|
+
* Addressed to `{ email }` that no profile in the app holds yet, the send
|
|
108
|
+
* creates that profile first, as `identify` would.
|
|
104
109
|
*/
|
|
105
110
|
emails: {
|
|
106
|
-
send: (input: WithDefaultSource<SendEmailInput>
|
|
111
|
+
send: ({ idempotencyKey, ...input }: WithDefaultSource<SendEmailInput> & {
|
|
112
|
+
idempotencyKey?: string;
|
|
113
|
+
}) => Promise<SendEmailResult>;
|
|
107
114
|
};
|
|
108
115
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
|
|
116
|
+
* Templates as a send renders them. `preview` renders a pushed template
|
|
117
|
+
* with your own props, exactly as `emails.send` to an address would, and
|
|
118
|
+
* sends nothing: for showing your operators the message before it goes.
|
|
119
|
+
*/
|
|
120
|
+
templates: {
|
|
121
|
+
preview: (input: WithDefaultSource<PreviewEmailInput>) => Promise<TemplatePreview>;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* One person's email preferences, `to` naming them as in `emails.send`.
|
|
125
|
+
*
|
|
126
|
+
* `link` is the hosted page, for a "Manage email preferences" button: it
|
|
127
|
+
* lists every purpose their app declares as a switch, and the link works
|
|
128
|
+
* for an hour, so ask for it when they click. `get` and `set` are the same
|
|
129
|
+
* page as data, for an app that draws its own: `set` saves what the person
|
|
130
|
+
* chose, where `identify({ consent })` records what the app decided.
|
|
113
131
|
*/
|
|
114
132
|
preferences: {
|
|
133
|
+
get: (input: WithDefaultSource<GetPreferencesInput>) => Promise<Preferences>;
|
|
134
|
+
set: (input: WithDefaultSource<SetPreferencesInput>) => Promise<Preferences>;
|
|
115
135
|
link: (input: WithDefaultSource<PreferencesLinkInput>) => Promise<PreferencesLink>;
|
|
116
136
|
};
|
|
117
137
|
/**
|
package/dist/index.js
CHANGED
|
@@ -120,20 +120,44 @@ export class Cow {
|
|
|
120
120
|
*
|
|
121
121
|
* Synchronous like the rest of the client: the promise resolves once the
|
|
122
122
|
* message has been handed over, and `deliveryId` is the row that records
|
|
123
|
-
* what happened to it. Each call carries
|
|
123
|
+
* what happened to it. Each call carries an Idempotency-Key on every
|
|
124
124
|
* attempt, so a retry after a lost reply answers with the first send's
|
|
125
|
-
* `deliveryId` instead of sending again.
|
|
125
|
+
* `deliveryId` instead of sending again. Pass your own `idempotencyKey`
|
|
126
|
+
* (an order id, a job id) and a second run of your own code dedupes too;
|
|
127
|
+
* without one, each call is a send of its own.
|
|
128
|
+
*
|
|
129
|
+
* Addressed to `{ email }` that no profile in the app holds yet, the send
|
|
130
|
+
* creates that profile first, as `identify` would.
|
|
126
131
|
*/
|
|
127
132
|
emails = {
|
|
128
|
-
send: (input) => this.#watch(async () => this.#post("/v1/emails", { data: { ...input, sourceId: this.#sourceFor(input) } }, crypto.randomUUID())),
|
|
133
|
+
send: ({ idempotencyKey, ...input }) => this.#watch(async () => this.#post("/v1/emails", { data: { ...input, sourceId: this.#sourceFor(input) } }, idempotencyKey ?? crypto.randomUUID())),
|
|
129
134
|
};
|
|
130
135
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
|
|
136
|
+
* Templates as a send renders them. `preview` renders a pushed template
|
|
137
|
+
* with your own props, exactly as `emails.send` to an address would, and
|
|
138
|
+
* sends nothing: for showing your operators the message before it goes.
|
|
139
|
+
*/
|
|
140
|
+
templates = {
|
|
141
|
+
preview: (input) => this.#watch(async () => this.#post("/v1/email-previews", {
|
|
142
|
+
data: { ...input, sourceId: this.#sourceFor(input) },
|
|
143
|
+
})),
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* One person's email preferences, `to` naming them as in `emails.send`.
|
|
147
|
+
*
|
|
148
|
+
* `link` is the hosted page, for a "Manage email preferences" button: it
|
|
149
|
+
* lists every purpose their app declares as a switch, and the link works
|
|
150
|
+
* for an hour, so ask for it when they click. `get` and `set` are the same
|
|
151
|
+
* page as data, for an app that draws its own: `set` saves what the person
|
|
152
|
+
* chose, where `identify({ consent })` records what the app decided.
|
|
135
153
|
*/
|
|
136
154
|
preferences = {
|
|
155
|
+
get: (input) => this.#watch(async () => this.#post("/v1/profile-preferences/find", {
|
|
156
|
+
data: { ...input, sourceId: this.#sourceFor(input) },
|
|
157
|
+
})),
|
|
158
|
+
set: (input) => this.#watch(async () => this.#post("/v1/profile-preferences", {
|
|
159
|
+
data: { ...input, sourceId: this.#sourceFor(input) },
|
|
160
|
+
})),
|
|
137
161
|
link: (input) => this.#watch(async () => this.#post("/v1/preferences-links", {
|
|
138
162
|
data: { ...input, sourceId: this.#sourceFor(input) },
|
|
139
163
|
})),
|
package/dist/types.d.ts
CHANGED
|
@@ -161,12 +161,49 @@ export type SendEmailResult = {
|
|
|
161
161
|
/** The delivery this send left behind: the row in Deliveries. */
|
|
162
162
|
deliveryId: string;
|
|
163
163
|
};
|
|
164
|
+
/** A template key and the props a send would pass it. */
|
|
165
|
+
export type PreviewEmailInput = {
|
|
166
|
+
sourceId: string;
|
|
167
|
+
key: string;
|
|
168
|
+
props?: Record<string, unknown>;
|
|
169
|
+
};
|
|
170
|
+
/** What a send of the template would carry. */
|
|
171
|
+
export type TemplatePreview = {
|
|
172
|
+
subject: string;
|
|
173
|
+
html: string;
|
|
174
|
+
text: string;
|
|
175
|
+
/** The version that rendered it: the latest one that finished compiling. */
|
|
176
|
+
versionId: string;
|
|
177
|
+
};
|
|
164
178
|
/** One profile, named the way a send to a profile names it. */
|
|
165
179
|
export type PreferencesLinkInput = {
|
|
166
180
|
sourceId: string;
|
|
167
181
|
/** Exactly one identifier naming a profile in the source's app. */
|
|
168
182
|
to: Identifiers;
|
|
169
183
|
};
|
|
184
|
+
/** One profile's switches, read or saved from your app's own page. */
|
|
185
|
+
export type GetPreferencesInput = PreferencesLinkInput;
|
|
186
|
+
export type SetPreferencesInput = PreferencesLinkInput & {
|
|
187
|
+
/**
|
|
188
|
+
* The switches to change: `marketing` or a purpose your app declares.
|
|
189
|
+
* Keys left out keep their answer.
|
|
190
|
+
*/
|
|
191
|
+
consent: ConsentPatch;
|
|
192
|
+
};
|
|
193
|
+
/** One switch: `marketing`, or a purpose your app declares. */
|
|
194
|
+
export type Preference = {
|
|
195
|
+
key: string;
|
|
196
|
+
label: string;
|
|
197
|
+
description: string | null;
|
|
198
|
+
/** Whether a send under this purpose would reach them now. */
|
|
199
|
+
enabled: boolean;
|
|
200
|
+
/** Whether they hold their own answer, rather than the default. */
|
|
201
|
+
answered: boolean;
|
|
202
|
+
};
|
|
203
|
+
export type Preferences = {
|
|
204
|
+
/** `marketing` first, then your app's purposes by key. */
|
|
205
|
+
purposes: Preference[];
|
|
206
|
+
};
|
|
170
207
|
export type PreferencesLink = {
|
|
171
208
|
/** The hosted preferences page for that profile. */
|
|
172
209
|
url: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.
|
|
1
|
+
export declare const SDK_VERSION = "0.20.0";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/version.ts from package.json. Do not edit.
|
|
2
|
-
export const SDK_VERSION = "0.
|
|
2
|
+
export const SDK_VERSION = "0.20.0";
|