@cowliss/sdk 0.17.0 → 0.18.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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@
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.18.1 (2026-10-01)
8
+
9
+ ### Fixes
10
+
11
+ - A retried emails.send carries one Idempotency-Key, so it never sends twice
12
+
13
+ ## 0.18.0 (2026-10-01)
14
+
15
+ ### Features
16
+
17
+ - cow.preferences.link asks for one profile's email preferences page
18
+
7
19
  ## 0.17.0 (2026-10-01)
8
20
 
9
21
  ### Features
package/README.md CHANGED
@@ -60,6 +60,14 @@ 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
+ Send someone to their hosted email preferences page from your own "Manage
64
+ email preferences" button. The link works for an hour, so ask for it on the
65
+ click:
66
+
67
+ ```ts
68
+ const { url, expiresAt } = await cow.preferences.link({ to: { userId: "shop_1" } });
69
+ ```
70
+
63
71
  Every call carries `identifiers`, a map from kind to value. Cowliss generates
64
72
  the profile id and resolves the map to it, so a call that carries two
65
73
  identifiers is what links two profiles. There is no alias call.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BatchBody, BatchResultDto, ErrorCode, EventDto, IdentifyInput, ProfileDto, SendEmailInput, SendEmailResult, TrackInput } from "./types.js";
1
+ import type { BatchBody, BatchResultDto, ErrorCode, EventDto, IdentifyInput, PreferencesLink, PreferencesLinkInput, ProfileDto, SendEmailInput, SendEmailResult, 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,11 +98,22 @@ 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.
101
+ * what happened to it. Each call carries its own Idempotency-Key on every
102
+ * attempt, so a retry after a lost reply answers with the first send's
103
+ * `deliveryId` instead of sending again.
102
104
  */
103
105
  emails: {
104
106
  send: (input: WithDefaultSource<SendEmailInput>) => Promise<SendEmailResult>;
105
107
  };
108
+ /**
109
+ * A link to one person's hosted email preferences page, for your app's own
110
+ * "Manage email preferences" button: `to` is one identifier naming them,
111
+ * as in `emails.send`. The page lists every purpose their app declares as
112
+ * a switch, and the link works for an hour, so ask for it when they click.
113
+ */
114
+ preferences: {
115
+ link: (input: WithDefaultSource<PreferencesLinkInput>) => Promise<PreferencesLink>;
116
+ };
106
117
  /**
107
118
  * Batch import: one source's identify and track calls in one request.
108
119
  * Track items must carry an explicit messageId: the API requires it and
package/dist/index.js CHANGED
@@ -120,10 +120,21 @@ 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.
123
+ * what happened to it. Each call carries its own Idempotency-Key on every
124
+ * attempt, so a retry after a lost reply answers with the first send's
125
+ * `deliveryId` instead of sending again.
124
126
  */
125
127
  emails = {
126
- send: (input) => this.#watch(async () => this.#post("/v1/emails", {
128
+ send: (input) => this.#watch(async () => this.#post("/v1/emails", { data: { ...input, sourceId: this.#sourceFor(input) } }, crypto.randomUUID())),
129
+ };
130
+ /**
131
+ * A link to one person's hosted email preferences page, for your app's own
132
+ * "Manage email preferences" button: `to` is one identifier naming them,
133
+ * as in `emails.send`. The page lists every purpose their app declares as
134
+ * a switch, and the link works for an hour, so ask for it when they click.
135
+ */
136
+ preferences = {
137
+ link: (input) => this.#watch(async () => this.#post("/v1/preferences-links", {
127
138
  data: { ...input, sourceId: this.#sourceFor(input) },
128
139
  })),
129
140
  };
@@ -153,8 +164,8 @@ export class Cow {
153
164
  });
154
165
  // Reading the body is part of the attempt: an abort or a truncated
155
166
  // response mid-read is a transport failure like any other, and
156
- // retrying it is safe (track carries its Idempotency-Key, identify
157
- // upserts on identifiers).
167
+ // retrying it is safe (track and emails.send carry an
168
+ // Idempotency-Key, identify upserts on identifiers).
158
169
  if (res.ok) {
159
170
  return (await res.json()).data;
160
171
  }
package/dist/types.d.ts CHANGED
@@ -161,6 +161,18 @@ export type SendEmailResult = {
161
161
  /** The delivery this send left behind: the row in Deliveries. */
162
162
  deliveryId: string;
163
163
  };
164
+ /** One profile, named the way a send to a profile names it. */
165
+ export type PreferencesLinkInput = {
166
+ sourceId: string;
167
+ /** Exactly one identifier naming a profile in the source's app. */
168
+ to: Identifiers;
169
+ };
170
+ export type PreferencesLink = {
171
+ /** The hosted preferences page for that profile. */
172
+ url: string;
173
+ /** ISO 8601: when the link stops working, an hour after it was minted. */
174
+ expiresAt: string;
175
+ };
164
176
  /**
165
177
  * The two runtime constants in this file, and the reason they live beside
166
178
  * the types rather than in `@cowliss/shared`: this module is the SDK's one
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "0.17.0";
1
+ export declare const SDK_VERSION = "0.18.1";
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/version.ts from package.json. Do not edit.
2
- export const SDK_VERSION = "0.17.0";
2
+ export const SDK_VERSION = "0.18.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cowliss/sdk",
3
- "version": "0.17.0",
3
+ "version": "0.18.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {