@curviate/sdk 0.43.0 → 0.44.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 +67 -1
- package/README.md +24 -10
- package/dist/index.d.ts +2058 -538
- package/dist/index.js +611 -155
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,73 @@ Versioning: semantic. Minor for additive changes, patch for bug fixes; no stabil
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## [0.
|
|
10
|
+
## [0.44.0] - 2026-10-22
|
|
11
|
+
|
|
12
|
+
Dashboard v2 API. Fixture and types regenerated from deployed staging (server
|
|
13
|
+
`15b704443878c7b589e40c7955a202b5131a20f7`, 197 paths), and the Sequence
|
|
14
|
+
corpus re-vendored from the same server.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Contact `profile_picture_url`:** read-only, `string | null`. The person's
|
|
19
|
+
LinkedIn photo from profile data your team already holds; null when none is
|
|
20
|
+
held. The link is signed and expires.
|
|
21
|
+
- **Enrollments:** `enrollments.pause`, `enrollments.events` (send a custom
|
|
22
|
+
event to an `until event.<name>`), `enrollments.reassign` (move to another
|
|
23
|
+
sending account; `warnings` names Steps that will be skipped) and
|
|
24
|
+
`enrollments.bulk` (up to 1,000 by ids or filter, one result per
|
|
25
|
+
Enrollment, not atomic). `enrollments.resume` takes no body to lift your own
|
|
26
|
+
pause. `enrollments.retry(id)` retries a failed Step through the guarded
|
|
27
|
+
bulk path and throws `NOTHING_TO_RETRY` (or the Enrollment's other refusal)
|
|
28
|
+
as a `CurviateError`; `resume({ at })` is an explicit, unguarded jump to a
|
|
29
|
+
Step. New list filters:
|
|
30
|
+
`version`, `done_step` with `outcome`, `reason`, `variant_id`,
|
|
31
|
+
`relationship_at_enrollment`. Types `EnrollmentEventBody`,
|
|
32
|
+
`EnrollmentReassignBody`, `EnrollmentReassignResult`, `EnrollmentBulkBody`,
|
|
33
|
+
`EnrollmentBulkResult`, `EnrollmentBulkItem`, `EnrollmentReason` (the reasons catalogue).
|
|
34
|
+
- **Error codes** `SEQUENCE_CONFLICT` (with `err.current`: the stored
|
|
35
|
+
Sequence and its `sequence_revision`; send `if_sequence_revision` on
|
|
36
|
+
`motions.update`), `STEP_IN_FLIGHT`, `NOTHING_TO_RETRY`,
|
|
37
|
+
`ACCOUNT_ALREADY_ENGAGED`, `ALREADY_ENROLLED_ON_ACCOUNT`, `KNOWN_CHAT`,
|
|
38
|
+
`CHAT_NOT_ONE_TO_ONE`. Before, each decoded as `INTERNAL`.
|
|
39
|
+
- **Compiler-style Sequence errors:** every `validateSequence` entry, every
|
|
40
|
+
offline `SEQUENCE_INVALID` entry and every decoded wire `errors[]` entry of
|
|
41
|
+
a Sequence rule carries `code` (`R1` to `R24`, `W1` to `W13`), `message`,
|
|
42
|
+
`pointer` (a JSON Pointer into the document), `hint` and `docs_url`, beside
|
|
43
|
+
`path` and `rule`.
|
|
44
|
+
- **Sequence document:** short variables `{{first_name}}`,
|
|
45
|
+
`{{my_first_name}}` and `{{<key>}}` for a custom field (the long forms stay
|
|
46
|
+
valid); an optional `event` on `do` and `tag` steps; `until event.<name>`;
|
|
47
|
+
the `message.seen` predicate (`if` steps). Warnings `W11` (a short custom
|
|
48
|
+
field that looks like a typo of a standard field), `W12` (`message.seen`
|
|
49
|
+
before any message) and `W13` (a deprecated form).
|
|
50
|
+
- **`newStepId(document, kind, beforeId?)`:** the id the dashboard editor
|
|
51
|
+
gives a new step (`message`, `message_2`, `w_<step>`).
|
|
52
|
+
- **Webhooks:** `enrollment.accepted`, `enrollment.replied`, `enrollment.seen`,
|
|
53
|
+
`enrollment.reassigned` and `motion.custom_event` in `CurviateEvent`.
|
|
54
|
+
`account_ids` is optional (or `null`: every account you can operate) on
|
|
55
|
+
every source.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- **A/B variants are exactly 2** (`MAX_VARIANTS`). 3 to 5 are accepted with
|
|
60
|
+
warning `W13` until 2027-01-19, then refused (`R23`); 1, or 6 and more,
|
|
61
|
+
are refused as before, and 6 and more no longer compile.
|
|
62
|
+
- **`{{motion.<key>}}`** gives `W13` (Motion variables were removed) beside
|
|
63
|
+
`W9`; still not an error offline until 2027-01-19.
|
|
64
|
+
|
|
65
|
+
### Deprecated
|
|
66
|
+
|
|
67
|
+
- `enrollments.signal` and `EnrollmentSignalBody`: use `enrollments.events`;
|
|
68
|
+
accepted until 2027-01-19.
|
|
69
|
+
- `until signal.<name>` (use `until event.<name>`) and the `motion.signal`
|
|
70
|
+
webhook event (renamed `motion.custom_event`), each accepted until
|
|
71
|
+
2027-01-19.
|
|
72
|
+
- `emit` steps: legacy; put `event` on the `do` or `tag` step that matters.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## [0.43.0]
|
|
11
77
|
|
|
12
78
|
Fixture and types regenerated from deployed staging (server
|
|
13
79
|
`7359b1b1be0584f7f368f1367d39261f2de8f079`, 193 paths; earlier regens at
|
package/README.md
CHANGED
|
@@ -143,26 +143,32 @@ const all = await curviate.contacts.export({ format: "json", tag: "vip" });
|
|
|
143
143
|
|
|
144
144
|
## Sequences
|
|
145
145
|
|
|
146
|
-
A Motion runs one Sequence: a JSON document of steps (`do`, `wait`, `until`, `if`, `
|
|
146
|
+
A Motion runs one Sequence: a JSON document of steps (`do`, `wait`, `until`, `if`, `tag`, and the legacy `emit`), run from the first step and ended explicitly with `"end"`. The SDK has an offline module for it: a typed builder that emits exactly that document, and `validateSequence`, which gives the verdict the API gives. Nothing in it touches the network, a key or the file system, so it runs in CI, browsers and edge functions. It needs TypeScript 5.0 or later.
|
|
147
147
|
|
|
148
148
|
```ts
|
|
149
149
|
import { Sequence, step } from "@curviate/sdk";
|
|
150
150
|
|
|
151
151
|
const seq = Sequence.create({ on_reply: "end" }).add(
|
|
152
|
-
step.do("invite", "invite.send", { with: { note: null, withdraw_after: "21d" } }),
|
|
152
|
+
step.do("invite", "invite.send", { with: { note: null, withdraw_after: "21d" }, event: "invite_sent" }),
|
|
153
153
|
step.until("accepted", "invite.accepted", { timeout: "21d", then: "opener", else: "end" }),
|
|
154
154
|
step.do("opener", "message.send", {
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
variants: [
|
|
156
|
+
{ id: "named", text: "Hi {{first_name}}, {{opener}}" },
|
|
157
|
+
{ id: "plain", text: "{{opener}}" },
|
|
158
|
+
],
|
|
159
|
+
with: { fallback: "Hi, thanks for connecting." },
|
|
157
160
|
}),
|
|
161
|
+
step.until("r_opener", "message.replied", { timeout: "4d", then: "end" }),
|
|
162
|
+
step.if("seen", { "message.seen": true }, { then: "bump", else: "end" }),
|
|
163
|
+
step.do("bump", "message.send", { with: { text: "{{followup}}", fallback: "Quick follow-up in case this got buried." }, next: "end" }),
|
|
158
164
|
);
|
|
159
165
|
|
|
160
166
|
const document = seq.toDocument(); // the Sequence document, keys in canonical order
|
|
161
167
|
```
|
|
162
168
|
|
|
163
|
-
Field names are the document's keys (`on_reply`, `note_fallback`, `withdraw_after`). With literal arguments, the type checker refuses what the API would: a typo'd action, event, reaction or predicate, a `{{...}}` that is not a
|
|
169
|
+
Field names are the document's keys (`on_reply`, `note_fallback`, `withdraw_after`). Variables: `{{first_name}}` (any standard Contact field), `{{my_first_name}}`, `{{my_last_name}}`, `{{my_full_name}}` (the sending account), and any other `{{<key>}}` is the custom field `contact.extra.<key>`; the long forms `{{contact.first_name}}`, `{{contact.extra.opener}}` and `{{account.first_name}}` stay valid. A messaging step takes one text in `with` or exactly 2 `variants` (A/B). An optional `event` on a `do` or `tag` step sends a custom event each time the step runs; `until event.<name>` waits for one your agent sends (`enrollments.events`). With literal arguments, the type checker refuses what the API would: a typo'd action, event, reaction or predicate, a `{{...}}` that is not a variable (`{{firstName}}`, `{{my_title}}`, a `| default:` filter), a text with a variable and no fallback, one variant, a duration like `"1w"`, the reserved id `"end"`, and a jump to a step you never added (at `toDocument()`). Text the type checker cannot see (a `string` variable) is checked when you call `validate()` or `toDocument()`.
|
|
164
170
|
|
|
165
|
-
Every builder operation (`add`, `insertBefore`, `replace`, `remove`, `onReply`) returns a new builder. `toDocument()` throws `SEQUENCE_INVALID` with every error in `err.errors
|
|
171
|
+
Every builder operation (`add`, `insertBefore`, `replace`, `remove`, `onReply`) returns a new builder. `toDocument()` throws `SEQUENCE_INVALID` with every error in `err.errors`, the same list the API returns: `path`, `rule`, and the compiler-style `code` (`R1` to `R24`), `pointer` (a JSON Pointer into the document), `hint` (the fix) and `docs_url`. Warnings (`W1` to `W13`) never block, read them with `validate()`. `JSON.stringify(seq)` equals `JSON.stringify(seq.toDocument())`. `newStepId(document, kind)` names a new step as the dashboard editor does (`message`, `message_2`, `w_<step>` for a wait before a step).
|
|
166
172
|
|
|
167
173
|
Raw JSON stays first class. Validate a document you wrote by hand, or load one (a Motion's `sequence`) to edit it:
|
|
168
174
|
|
|
@@ -170,14 +176,14 @@ Raw JSON stays first class. Validate a document you wrote by hand, or load one (
|
|
|
170
176
|
import { Sequence, step, validateSequence } from "@curviate/sdk";
|
|
171
177
|
|
|
172
178
|
const { errors, warnings } = validateSequence(JSON.parse(text));
|
|
173
|
-
for (const e of errors) console.error(`${e.path}: ${e.rule}`);
|
|
179
|
+
for (const e of errors) console.error(`${e.path}: ${e.rule} (${e.code}: ${e.hint})`);
|
|
174
180
|
|
|
175
181
|
const edited = Sequence.fromDocument(motion.sequence) // throws SEQUENCE_INVALID when invalid
|
|
176
182
|
.insertBefore("opener", step.wait("settle", "1d"))
|
|
177
183
|
.toDocument();
|
|
178
184
|
```
|
|
179
185
|
|
|
180
|
-
`{{motion.<key>}}`
|
|
186
|
+
Deprecated forms are accepted with warning `W13` until 2027-01-19, then refused: 3 to 5 variants (use 2), `until signal.<name>` (use `until event.<name>`) and `{{motion.<key>}}` (write the text in place or use a custom field; offline it also gives `W9`). Warnings that need the Motion's sending accounts or settings come from the API only. `SEQUENCE_SCHEMA_V1` is the published JSON Schema (`SEQUENCE_SCHEMA_URL`) for editors and tooling. The validator knows the vocabulary of the schema it ships with: a document using an action or event added to the API later is refused offline while the API accepts it; upgrade the SDK.
|
|
181
187
|
|
|
182
188
|
## Motions and Enrollments
|
|
183
189
|
|
|
@@ -197,14 +203,22 @@ const motion = await curviate.motions.create({
|
|
|
197
203
|
const { paths, samples, projection } = await curviate.motions.preview(motion.id); // a read: nothing is sent to LinkedIn
|
|
198
204
|
await curviate.motions.start(motion.id);
|
|
199
205
|
|
|
200
|
-
// Edit later: load the stored document into a builder.
|
|
206
|
+
// Edit later: load the stored document into a builder. if_sequence_revision refuses the save
|
|
207
|
+
// with SEQUENCE_CONFLICT (the stored document in err.current) when someone saved since.
|
|
201
208
|
const current = await curviate.motions.get(motion.id);
|
|
202
209
|
await curviate.motions.update(motion.id, {
|
|
203
210
|
sequence: Sequence.fromDocument(current.sequence).insertBefore("opener", step.wait("settle", "1d")),
|
|
211
|
+
if_sequence_revision: current.sequence_revision,
|
|
204
212
|
});
|
|
213
|
+
|
|
214
|
+
// Enrollments: one Contact's run on one account.
|
|
215
|
+
const { items: failed } = await curviate.enrollments.list({ motion_id: motion.id, done_step: "opener", outcome: "failed" });
|
|
216
|
+
await curviate.enrollments.bulk({ action: "retry", ids: failed.map((e) => e.id) }); // one result per Enrollment
|
|
217
|
+
await curviate.enrollments.retry("enr_123"); // one: throws NOTHING_TO_RETRY unless its Step failed
|
|
218
|
+
await curviate.enrollments.events("enr_123", { name: "research_ready" }); // moves an `until event.research_ready`
|
|
205
219
|
```
|
|
206
220
|
|
|
207
|
-
A plain object goes as is and the API validates it; wrap hand-written JSON in `Sequence.fromDocument(json)` to have it checked offline first. `sequence: null` clears a draft's. Status operations: `start`, `pause`, `resume`, `archive` (irreversible), `delete` (drafts only); `addContacts` / `removeContacts` enroll or take out Contacts directly; `getSequenceVersion` reads a past version. `curviate.enrollments` lists one Contact's run per account (`list`, `get` with its Step history) and acts on it: `
|
|
221
|
+
A plain object goes as is and the API validates it; wrap hand-written JSON in `Sequence.fromDocument(json)` to have it checked offline first. `sequence: null` clears a draft's. Status operations: `start`, `pause`, `resume`, `archive` (irreversible), `delete` (drafts only); `addContacts` / `removeContacts` enroll or take out Contacts directly; `getSequenceVersion` reads a past version. `curviate.enrollments` lists one Contact's run per account (`list`, filtered by status, Step, Sequence version, or how a Step ended: `done_step` with `outcome`, `reason`, `variant_id`, `relationship_at_enrollment`; `get` with its Step history) and acts on it: `pause`, `resume()` (lift your pause), `retry(id)` (retry the failed Step; it acts only on a failure, else throws `NOTHING_TO_RETRY`, so a repeated call never sends a delivered message again), `resume({ at })` (an explicit jump to a Step, not guarded: it re-enters a Step that already sent; use `retry` for a failure), `events({ name })`, `reassign({ account_id })`, `stop`, and `bulk` for up to 1,000 at once by ids or filter. `signal` is the deprecated name of `events`, accepted until 2027-01-19. Refusals: `MOTION_NOT_STARTABLE` (every gap in `err.errors`), `MOTION_STATUS_CONFLICT`, `ENROLLMENT_NOT_ACTIVE`, `SEQUENCE_INVALID`, `SEQUENCE_CONFLICT`, `STEP_IN_FLIGHT` (retry in a minute), `NOTHING_TO_RETRY` (from `retry`, or per Enrollment in `bulk`), `ACCOUNT_ALREADY_ENGAGED`, `ALREADY_ENROLLED_ON_ACCOUNT`, `KNOWN_CHAT`.
|
|
208
222
|
|
|
209
223
|
## Network, Unibox and Analytics
|
|
210
224
|
|