@yougrowai/node 0.3.0 → 0.4.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/README.md CHANGED
@@ -10,8 +10,8 @@ https://yougrow.ai/developers are the contract. The source on GitHub isn't: its
10
10
  main branch can be ahead of what's been released.
11
11
 
12
12
  > **2026-09-25:** API v1 (`POST /api/v1/events`, HMAC signing) was removed.
13
- > 0.3.0 is the client for API v2; 0.1.x only spoke v1, so upgrade to keep
14
- > sending. See [Upgrading from 0.1.x](#upgrading-from-01x).
13
+ > 0.3.0 and later are the client for API v2; 0.1.x only spoke v1, so upgrade to
14
+ > keep sending. See [Upgrading from 0.1.x](#upgrading-from-01x).
15
15
 
16
16
  ```sh
17
17
  npm install @yougrowai/node
@@ -41,6 +41,9 @@ const yg = new YouGrow({
41
41
  origin: process.env.YOUGROW_ORIGIN, // optional; defaults to https://yougrow.ai
42
42
  });
43
43
 
44
+ // Check the key (e.g. when you deploy): which connection and environment it's for
45
+ const { connection } = await yg.me(); // { name, environment: "production", status: "active", … }
46
+
44
47
  // At sign-up: who they are, and the basis for emailing them
45
48
  await yg.users.update(user.id, {
46
49
  email: user.email,
@@ -135,8 +138,10 @@ record an event twice. A key that was already recorded resolves
135
138
  - A step's value is when it was done (`null`: not done). Timestamps are ISO 8601
136
139
  with a zone (`Z` or `+01:00`), e.g. from `toISOString()`.
137
140
  - `email`, `firstName`, `lastName`, `timezone` and `locale` are fields of their
138
- own, never traits. Unknown fields are refused (400), so a typo can't be
139
- silently dropped.
141
+ own, never traits. An invalid one doesn't sink the update: the rest applies,
142
+ that field keeps its stored value, and the result lists it in
143
+ `ignoredFields`. Anything else invalid, including an unknown field, is
144
+ refused (400), so a typo can't be silently dropped.
140
145
  - Up to 50 steps, 50 facts and 50 traits per user. Step ids are lower-case
141
146
  letters, digits, `_` and `-`; trait keys start with a letter.
142
147
 
@@ -178,8 +183,13 @@ Every method returns a promise; await it.
178
183
  `code` (the API's `error`, e.g. `invalid`, `unauthorized`, `body_too_large`),
179
184
  `fields` for a 400, and a message such as
180
185
  `YouGrow API 400 invalid: traits.plan: …`. A 429 or 5xx that outlasts the
181
- retries rejects the same way; a network error or timeout rejects with that
182
- error.
186
+ retries rejects the same way, and so does a network failure or timeout
187
+ (`status` 0, `code` `network_error` or `timeout`, the original error as
188
+ `cause`).
189
+ - `err.retryable` says whether trying again later may work: true for a 429, a
190
+ 5xx, a timeout or a network failure. In a queue worker, or a trigger with
191
+ retries on, rethrow those so the work is redelivered, and log the rest: a
192
+ 400 won't succeed as it is. Every write is safe to repeat.
183
193
  - A user id the API can't take (empty, over 256 characters, `"batch"`, `"."`
184
194
  or `".."`) rejects with a `TypeError` before anything is sent.
185
195
 
@@ -189,8 +199,9 @@ import { YouGrowError } from "@yougrowai/node";
189
199
  try {
190
200
  await yg.users.update(user.id, patch);
191
201
  } catch (err) {
192
- if (err instanceof YouGrowError && err.status === 400) console.error(err.message, err.fields); // [{ path, message }]
193
- throw err;
202
+ if (err instanceof YouGrowError && err.retryable) throw err; // 429, 5xx, timeout, network: let it be retried
203
+ if (err instanceof YouGrowError) console.error(err.message, err.fields); // e.g. a 400: [{ path, message }]; fix it
204
+ else throw err;
194
205
  }
195
206
  ```
196
207
 
@@ -285,10 +296,20 @@ never invents them.
285
296
 
286
297
  ### Webhooks
287
298
 
288
- YouGrow tells your webhook endpoint about preference changes, e.g. an
289
- unsubscribe from onboarding tips. Verify it with
290
- `verifier.verify({ …, direction: "webhook" })`. Webhook ids (`jti` in the
291
- token, `id` in the body) are unique, so you can drop duplicates.
299
+ YouGrow tells your webhook endpoint about changes to mirror. Verify each request
300
+ with `verifier.verify({ …, direction: "webhook" })`, then read the body as a
301
+ `WebhookEvent` (a type from `@yougrowai/node/server`):
302
+
303
+ - `email_preferences.updated`: the person unsubscribed from one of YouGrow's
304
+ emails (`data.scope` is `all` or `category`).
305
+ - `email.suppressed`: YouGrow stopped emailing them, because their address
306
+ hard-bounced (`data.reason` `hard_bounce`) or they reported an email as spam
307
+ (`complaint`).
308
+ - `connection.test`: the Test webhook button.
309
+
310
+ Reply 2xx to any type you don't handle. Webhook ids (`jti` in the token, `id` in
311
+ the body) are unique and the same on every retry, so you can drop duplicates.
312
+ API writes never trigger a webhook, so echoing a change back can't loop.
292
313
 
293
314
  ## Without the SDK
294
315
 
@@ -322,9 +343,17 @@ at https://yougrow.ai/developers.
322
343
  `test/vectors.json` (included in this package) holds reference tokens for
323
344
  checking your own verifier.
324
345
 
346
+ ## Upgrading from 0.3
347
+
348
+ - A network failure or timeout that outlasts the retries now rejects with a
349
+ `YouGrowError` (`status` 0, `code` `network_error` or `timeout`) instead of
350
+ the raw error, which is its `cause`.
351
+ - New: `yg.me()`, `err.retryable`, `ignoredFields` on update results (and
352
+ `fields_ignored` in batch results), and the `WebhookEvent` type.
353
+
325
354
  ## Upgrading from 0.1.x
326
355
 
327
- | 0.1.x (API v1) | 0.3.0 (API v2) |
356
+ | 0.1.x (API v1) | 0.3.0 and later (API v2) |
328
357
  |---|---|
329
358
  | `identify({ userId, traits, consent })` | `users.update(userId, { email, firstName, …, consent, traits })`: profile fields are top-level, and `consent` is the basis itself, e.g. `"soft_opt_in"` |
330
359
  | `track({ event: "user.signed_up" })` | `signedUpAt` in `users.update` |
@@ -81,9 +81,12 @@ export interface UserView extends UserState {
81
81
  }
82
82
  /** Why a write was ignored: older than the stored state, or than the user's deletion. */
83
83
  export type SkipReason = "stale_write" | "deleted_later";
84
- export type PatchResponse = {
84
+ export type PatchResponse =
85
+ /** `ignoredFields`: profile fields whose value was invalid, so left as they were; the rest applied. */
86
+ {
85
87
  applied: true;
86
88
  user: UserState;
89
+ ignoredFields?: FieldError[];
87
90
  } | {
88
91
  applied: false;
89
92
  reason: SkipReason;
@@ -103,15 +106,30 @@ export interface BatchResponse {
103
106
  applied: number;
104
107
  ignored: number;
105
108
  failed: number;
106
- /** Only the ignored and failed items; applied ones are counted. `index` is the item's position in your array. */
109
+ /**
110
+ * The ignored and failed items, and applied ones whose invalid profile fields were
111
+ * left as they were (reason `fields_ignored`). `index` is the item's position in your array.
112
+ */
107
113
  results: Array<{
108
114
  index: number;
109
115
  userId: string | null;
110
- status: "ignored" | "failed";
116
+ status: "applied" | "ignored" | "failed";
111
117
  reason: string;
112
118
  fields?: FieldError[];
113
119
  }>;
114
120
  }
121
+ /** The connection behind your key (`GET /api/v2/me`). */
122
+ export interface MeResponse {
123
+ connection: {
124
+ id: string;
125
+ name: string;
126
+ environment: "staging" | "production" | null;
127
+ status: "active" | "paused" | "revoked";
128
+ };
129
+ keyId: string;
130
+ /** A new secret was issued in the last 24 hours; the previous one works until then. */
131
+ rotating: boolean;
132
+ }
115
133
  export interface EventResult {
116
134
  recorded: boolean;
117
135
  duplicate: boolean;
@@ -166,15 +184,26 @@ export interface EventsApi {
166
184
  /** Record a milestone, e.g. "report.exported". Optional: journeys run on state. */
167
185
  track(userId: string, event: string, opts?: TrackOptions): Promise<EventResult>;
168
186
  }
169
- /** The API refused a request, or still failed (429, 5xx) after the retries. */
187
+ /**
188
+ * The API refused a request, or it still failed after the retries: a 429, a 5xx,
189
+ * or a timeout or network failure (`status` 0, `code` `timeout` or `network_error`).
190
+ */
170
191
  export declare class YouGrowError extends Error {
171
192
  readonly status: number;
172
193
  readonly body?: unknown | undefined;
173
- /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), or `http_<status>` when the body has none. */
194
+ /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), `timeout` or `network_error`, or `http_<status>`. */
174
195
  readonly code: string;
175
196
  /** For a 400: which fields were wrong, and why. */
176
197
  readonly fields?: FieldError[];
177
- constructor(message: string, status: number, body?: unknown | undefined);
198
+ /**
199
+ * True for a 429, a 5xx, a timeout or a network failure: trying again later may
200
+ * work, so a queue or trigger should rethrow it for redelivery. Anything else
201
+ * (a 400, 401, 404…) won't succeed as it is.
202
+ */
203
+ readonly retryable: boolean;
204
+ constructor(message: string, status: number, body?: unknown | undefined, options?: {
205
+ cause?: unknown;
206
+ });
178
207
  }
179
208
  /** From `users.batch` with `throwOnItemError`: some items failed. The rest were applied; `result` says which. */
180
209
  export declare class YouGrowBatchError extends Error {
@@ -186,4 +215,9 @@ export declare class YouGrow {
186
215
  readonly users: UsersApi;
187
216
  readonly events: EventsApi;
188
217
  constructor(opts: YouGrowOptions);
218
+ /**
219
+ * The connection behind your key: its name, environment and status. A credential
220
+ * check — and a way to catch a key from the wrong environment — before you send.
221
+ */
222
+ me(): Promise<MeResponse>;
189
223
  }
package/dist/cjs/index.js CHANGED
@@ -11,16 +11,25 @@ const BATCH_ENVELOPE_BYTES = '{"users":[]}'.length;
11
11
  const MAX_USER_ID = 256;
12
12
  /** The longest delay a Node timer accepts. */
13
13
  const MAX_TIMER_MS = 2_147_483_647;
14
- /** The API refused a request, or still failed (429, 5xx) after the retries. */
14
+ /**
15
+ * The API refused a request, or it still failed after the retries: a 429, a 5xx,
16
+ * or a timeout or network failure (`status` 0, `code` `timeout` or `network_error`).
17
+ */
15
18
  class YouGrowError extends Error {
16
19
  status;
17
20
  body;
18
- /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), or `http_<status>` when the body has none. */
21
+ /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), `timeout` or `network_error`, or `http_<status>`. */
19
22
  code;
20
23
  /** For a 400: which fields were wrong, and why. */
21
24
  fields;
22
- constructor(message, status, body) {
23
- super(message);
25
+ /**
26
+ * True for a 429, a 5xx, a timeout or a network failure: trying again later may
27
+ * work, so a queue or trigger should rethrow it for redelivery. Anything else
28
+ * (a 400, 401, 404…) won't succeed as it is.
29
+ */
30
+ retryable;
31
+ constructor(message, status, body, options) {
32
+ super(message, options);
24
33
  this.status = status;
25
34
  this.body = body;
26
35
  this.name = "YouGrowError";
@@ -28,6 +37,7 @@ class YouGrowError extends Error {
28
37
  this.code = typeof b?.error === "string" ? b.error : `http_${status}`;
29
38
  if (Array.isArray(b?.fields))
30
39
  this.fields = b.fields;
40
+ this.retryable = status === 0 || status === 429 || status >= 500;
31
41
  }
32
42
  }
33
43
  exports.YouGrowError = YouGrowError;
@@ -90,6 +100,13 @@ class YouGrow {
90
100
  },
91
101
  };
92
102
  }
103
+ /**
104
+ * The connection behind your key: its name, environment and status. A credential
105
+ * check — and a way to catch a key from the wrong environment — before you send.
106
+ */
107
+ async me() {
108
+ return (await this.#send("GET", "/api/v2/me"));
109
+ }
93
110
  async #patchMany(items, opts = {}) {
94
111
  if (!Array.isArray(items))
95
112
  throw new TypeError("YouGrow: users.batch takes an array of { userId, ...patch }");
@@ -137,7 +154,7 @@ class YouGrow {
137
154
  catch (err) {
138
155
  // Network error or timeout.
139
156
  if (attempt >= this.#maxRetries)
140
- throw err;
157
+ throw transportError(err);
141
158
  await sleep(this.#retryWait(attempt));
142
159
  continue;
143
160
  }
@@ -212,6 +229,12 @@ function failureSummary(r, count) {
212
229
  return `users.batch: ${r.failed} of ${count} users failed${shown.length > 0 ? ` (${shown.join(", ")})` : ""}`;
213
230
  }
214
231
  /** e.g. "YouGrow API 400 invalid: traits.plan: …". */
232
+ /** A timeout or network failure that outlasted the retries: status 0, retryable, the original error as `cause`. */
233
+ function transportError(err) {
234
+ const code = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError") ? "timeout" : "network_error";
235
+ const detail = err instanceof Error ? err.message : String(err);
236
+ return new YouGrowError(`YouGrow API ${code}: ${detail}`, 0, { error: code }, { cause: err });
237
+ }
215
238
  function apiError(status, body) {
216
239
  const b = asRecord(body);
217
240
  const fields = Array.isArray(b?.fields) ? b.fields : [];
@@ -28,6 +28,30 @@ export type VerifyResult = {
28
28
  ok: false;
29
29
  reason: JwtFailure | "keys_unavailable";
30
30
  };
31
+ /** What YouGrow POSTs to your webhook endpoint: one of these, by `type`. Reply 2xx to any type you don't handle. */
32
+ export type WebhookEvent = WebhookEnvelope<"email_preferences.updated",
33
+ /** The person unsubscribed from one of YouGrow's emails: from one category, or all of them. */
34
+ {
35
+ userId: string;
36
+ category: string;
37
+ subscribed: false;
38
+ scope: "all" | "category";
39
+ source: string;
40
+ }>
41
+ /** YouGrow stopped emailing the person: their address hard-bounced, or they reported an email as spam. */
42
+ | WebhookEnvelope<"email.suppressed", {
43
+ userId: string;
44
+ reason: "hard_bounce" | "complaint";
45
+ }>
46
+ /** The Test webhook button. */
47
+ | WebhookEnvelope<"connection.test", Record<string, never>>;
48
+ export interface WebhookEnvelope<T extends string, D> {
49
+ /** Unique per webhook, and the same on every retry: drop ones you've seen. */
50
+ id: string;
51
+ type: T;
52
+ createdAt: string;
53
+ data: D;
54
+ }
31
55
  export interface VerifierOptions {
32
56
  /** Your connection's key id — the token's audience. */
33
57
  keyId: string;
package/dist/index.d.ts CHANGED
@@ -81,9 +81,12 @@ export interface UserView extends UserState {
81
81
  }
82
82
  /** Why a write was ignored: older than the stored state, or than the user's deletion. */
83
83
  export type SkipReason = "stale_write" | "deleted_later";
84
- export type PatchResponse = {
84
+ export type PatchResponse =
85
+ /** `ignoredFields`: profile fields whose value was invalid, so left as they were; the rest applied. */
86
+ {
85
87
  applied: true;
86
88
  user: UserState;
89
+ ignoredFields?: FieldError[];
87
90
  } | {
88
91
  applied: false;
89
92
  reason: SkipReason;
@@ -103,15 +106,30 @@ export interface BatchResponse {
103
106
  applied: number;
104
107
  ignored: number;
105
108
  failed: number;
106
- /** Only the ignored and failed items; applied ones are counted. `index` is the item's position in your array. */
109
+ /**
110
+ * The ignored and failed items, and applied ones whose invalid profile fields were
111
+ * left as they were (reason `fields_ignored`). `index` is the item's position in your array.
112
+ */
107
113
  results: Array<{
108
114
  index: number;
109
115
  userId: string | null;
110
- status: "ignored" | "failed";
116
+ status: "applied" | "ignored" | "failed";
111
117
  reason: string;
112
118
  fields?: FieldError[];
113
119
  }>;
114
120
  }
121
+ /** The connection behind your key (`GET /api/v2/me`). */
122
+ export interface MeResponse {
123
+ connection: {
124
+ id: string;
125
+ name: string;
126
+ environment: "staging" | "production" | null;
127
+ status: "active" | "paused" | "revoked";
128
+ };
129
+ keyId: string;
130
+ /** A new secret was issued in the last 24 hours; the previous one works until then. */
131
+ rotating: boolean;
132
+ }
115
133
  export interface EventResult {
116
134
  recorded: boolean;
117
135
  duplicate: boolean;
@@ -166,15 +184,26 @@ export interface EventsApi {
166
184
  /** Record a milestone, e.g. "report.exported". Optional: journeys run on state. */
167
185
  track(userId: string, event: string, opts?: TrackOptions): Promise<EventResult>;
168
186
  }
169
- /** The API refused a request, or still failed (429, 5xx) after the retries. */
187
+ /**
188
+ * The API refused a request, or it still failed after the retries: a 429, a 5xx,
189
+ * or a timeout or network failure (`status` 0, `code` `timeout` or `network_error`).
190
+ */
170
191
  export declare class YouGrowError extends Error {
171
192
  readonly status: number;
172
193
  readonly body?: unknown | undefined;
173
- /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), or `http_<status>` when the body has none. */
194
+ /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), `timeout` or `network_error`, or `http_<status>`. */
174
195
  readonly code: string;
175
196
  /** For a 400: which fields were wrong, and why. */
176
197
  readonly fields?: FieldError[];
177
- constructor(message: string, status: number, body?: unknown | undefined);
198
+ /**
199
+ * True for a 429, a 5xx, a timeout or a network failure: trying again later may
200
+ * work, so a queue or trigger should rethrow it for redelivery. Anything else
201
+ * (a 400, 401, 404…) won't succeed as it is.
202
+ */
203
+ readonly retryable: boolean;
204
+ constructor(message: string, status: number, body?: unknown | undefined, options?: {
205
+ cause?: unknown;
206
+ });
178
207
  }
179
208
  /** From `users.batch` with `throwOnItemError`: some items failed. The rest were applied; `result` says which. */
180
209
  export declare class YouGrowBatchError extends Error {
@@ -186,4 +215,9 @@ export declare class YouGrow {
186
215
  readonly users: UsersApi;
187
216
  readonly events: EventsApi;
188
217
  constructor(opts: YouGrowOptions);
218
+ /**
219
+ * The connection behind your key: its name, environment and status. A credential
220
+ * check — and a way to catch a key from the wrong environment — before you send.
221
+ */
222
+ me(): Promise<MeResponse>;
189
223
  }
package/dist/index.js CHANGED
@@ -8,16 +8,25 @@ const BATCH_ENVELOPE_BYTES = '{"users":[]}'.length;
8
8
  const MAX_USER_ID = 256;
9
9
  /** The longest delay a Node timer accepts. */
10
10
  const MAX_TIMER_MS = 2_147_483_647;
11
- /** The API refused a request, or still failed (429, 5xx) after the retries. */
11
+ /**
12
+ * The API refused a request, or it still failed after the retries: a 429, a 5xx,
13
+ * or a timeout or network failure (`status` 0, `code` `timeout` or `network_error`).
14
+ */
12
15
  export class YouGrowError extends Error {
13
16
  status;
14
17
  body;
15
- /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), or `http_<status>` when the body has none. */
18
+ /** The API's error code (`invalid`, `unauthorized`, `rate_limited`…), `timeout` or `network_error`, or `http_<status>`. */
16
19
  code;
17
20
  /** For a 400: which fields were wrong, and why. */
18
21
  fields;
19
- constructor(message, status, body) {
20
- super(message);
22
+ /**
23
+ * True for a 429, a 5xx, a timeout or a network failure: trying again later may
24
+ * work, so a queue or trigger should rethrow it for redelivery. Anything else
25
+ * (a 400, 401, 404…) won't succeed as it is.
26
+ */
27
+ retryable;
28
+ constructor(message, status, body, options) {
29
+ super(message, options);
21
30
  this.status = status;
22
31
  this.body = body;
23
32
  this.name = "YouGrowError";
@@ -25,6 +34,7 @@ export class YouGrowError extends Error {
25
34
  this.code = typeof b?.error === "string" ? b.error : `http_${status}`;
26
35
  if (Array.isArray(b?.fields))
27
36
  this.fields = b.fields;
37
+ this.retryable = status === 0 || status === 429 || status >= 500;
28
38
  }
29
39
  }
30
40
  /** From `users.batch` with `throwOnItemError`: some items failed. The rest were applied; `result` says which. */
@@ -85,6 +95,13 @@ export class YouGrow {
85
95
  },
86
96
  };
87
97
  }
98
+ /**
99
+ * The connection behind your key: its name, environment and status. A credential
100
+ * check — and a way to catch a key from the wrong environment — before you send.
101
+ */
102
+ async me() {
103
+ return (await this.#send("GET", "/api/v2/me"));
104
+ }
88
105
  async #patchMany(items, opts = {}) {
89
106
  if (!Array.isArray(items))
90
107
  throw new TypeError("YouGrow: users.batch takes an array of { userId, ...patch }");
@@ -132,7 +149,7 @@ export class YouGrow {
132
149
  catch (err) {
133
150
  // Network error or timeout.
134
151
  if (attempt >= this.#maxRetries)
135
- throw err;
152
+ throw transportError(err);
136
153
  await sleep(this.#retryWait(attempt));
137
154
  continue;
138
155
  }
@@ -206,6 +223,12 @@ function failureSummary(r, count) {
206
223
  return `users.batch: ${r.failed} of ${count} users failed${shown.length > 0 ? ` (${shown.join(", ")})` : ""}`;
207
224
  }
208
225
  /** e.g. "YouGrow API 400 invalid: traits.plan: …". */
226
+ /** A timeout or network failure that outlasted the retries: status 0, retryable, the original error as `cause`. */
227
+ function transportError(err) {
228
+ const code = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError") ? "timeout" : "network_error";
229
+ const detail = err instanceof Error ? err.message : String(err);
230
+ return new YouGrowError(`YouGrow API ${code}: ${detail}`, 0, { error: code }, { cause: err });
231
+ }
209
232
  function apiError(status, body) {
210
233
  const b = asRecord(body);
211
234
  const fields = Array.isArray(b?.fields) ? b.fields : [];
package/dist/server.d.ts CHANGED
@@ -28,6 +28,30 @@ export type VerifyResult = {
28
28
  ok: false;
29
29
  reason: JwtFailure | "keys_unavailable";
30
30
  };
31
+ /** What YouGrow POSTs to your webhook endpoint: one of these, by `type`. Reply 2xx to any type you don't handle. */
32
+ export type WebhookEvent = WebhookEnvelope<"email_preferences.updated",
33
+ /** The person unsubscribed from one of YouGrow's emails: from one category, or all of them. */
34
+ {
35
+ userId: string;
36
+ category: string;
37
+ subscribed: false;
38
+ scope: "all" | "category";
39
+ source: string;
40
+ }>
41
+ /** YouGrow stopped emailing the person: their address hard-bounced, or they reported an email as spam. */
42
+ | WebhookEnvelope<"email.suppressed", {
43
+ userId: string;
44
+ reason: "hard_bounce" | "complaint";
45
+ }>
46
+ /** The Test webhook button. */
47
+ | WebhookEnvelope<"connection.test", Record<string, never>>;
48
+ export interface WebhookEnvelope<T extends string, D> {
49
+ /** Unique per webhook, and the same on every retry: drop ones you've seen. */
50
+ id: string;
51
+ type: T;
52
+ createdAt: string;
53
+ data: D;
54
+ }
31
55
  export interface VerifierOptions {
32
56
  /** Your connection's key id — the token's audience. */
33
57
  keyId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yougrowai/node",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Keep your users' state in YouGrow lifecycle journeys, and verify the requests YouGrow sends you.",
5
5
  "license": "MIT",
6
6
  "author": "YouGrow.AI Limited",
@@ -22,7 +22,8 @@
22
22
  "./server": {
23
23
  "import": { "types": "./dist/server.d.ts", "default": "./dist/server.js" },
24
24
  "require": { "types": "./dist/cjs/server.d.ts", "default": "./dist/cjs/server.js" }
25
- }
25
+ },
26
+ "./package.json": "./package.json"
26
27
  },
27
28
  "typesVersions": {
28
29
  "*": { "server": ["./dist/cjs/server.d.ts"] }