@oneie/sdk 0.14.8 → 0.14.10
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 +16 -1
- package/dist/broadcast.d.ts +25 -0
- package/dist/broadcast.d.ts.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +27 -4
- package/dist/client.js.map +1 -1
- package/dist/gateway.d.ts +17 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +40 -10
- package/dist/gateway.js.map +1 -1
- package/dist/receivers.d.ts +230 -1
- package/dist/receivers.d.ts.map +1 -1
- package/dist/receivers.js +267 -9
- package/dist/receivers.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/work-contract-grammar.json +19 -1
- package/package.json +1 -1
package/dist/receivers.js
CHANGED
|
@@ -776,6 +776,36 @@ export const RECEIVERS = {
|
|
|
776
776
|
name: z.string(),
|
|
777
777
|
tags: z.array(z.string()),
|
|
778
778
|
weight: z.number(),
|
|
779
|
+
// The context a puller needs to act: notes = the prose goal / what "done" looks
|
|
780
|
+
// like; contextDocs = the doc stems (`<slug>-plan`, `<slug>-todo`, …) to load
|
|
781
|
+
// before running /do <slug>. Empty until the task is enriched (seed/backfill).
|
|
782
|
+
notes: z.string().optional(),
|
|
783
|
+
contextDocs: z.array(z.string()).optional(),
|
|
784
|
+
})),
|
|
785
|
+
}),
|
|
786
|
+
effect: "ask", idempotent: true,
|
|
787
|
+
}),
|
|
788
|
+
"tasks:everywhere": receiver({
|
|
789
|
+
receiver: "tasks:everywhere",
|
|
790
|
+
summary: "Every workspace I belong to, one queue: open+picked tasks visible by assignment/follow/ownership, with claimable + mine + offeredByMe flags; closed:true returns the logbook (done/verified, newest first)",
|
|
791
|
+
request: z.object({ limit: z.number().optional(), closed: z.boolean().optional() }),
|
|
792
|
+
response: z.object({
|
|
793
|
+
ok: z.boolean(),
|
|
794
|
+
tasks: z.array(z.object({
|
|
795
|
+
id: z.string(),
|
|
796
|
+
name: z.string(),
|
|
797
|
+
tags: z.array(z.string()),
|
|
798
|
+
weight: z.number(),
|
|
799
|
+
notes: z.string().optional(),
|
|
800
|
+
contextDocs: z.array(z.string()).optional(),
|
|
801
|
+
workspace: z.string(),
|
|
802
|
+
status: z.string(),
|
|
803
|
+
dueAt: z.string().optional(),
|
|
804
|
+
assignee: z.string().optional(),
|
|
805
|
+
mine: z.boolean(),
|
|
806
|
+
claimable: z.boolean(),
|
|
807
|
+
offeredByMe: z.boolean(),
|
|
808
|
+
closedAt: z.string().optional(),
|
|
779
809
|
})),
|
|
780
810
|
}),
|
|
781
811
|
effect: "ask", idempotent: true,
|
|
@@ -787,6 +817,9 @@ export const RECEIVERS = {
|
|
|
787
817
|
title: z.string(),
|
|
788
818
|
tags: z.array(z.string()).optional(),
|
|
789
819
|
assignee: z.string().optional(),
|
|
820
|
+
// Prose goal / what "done" looks like — the context a human attaches at create so
|
|
821
|
+
// the task is pickable by an agent or a Claude Code session without a round trip.
|
|
822
|
+
notes: z.string().optional(),
|
|
790
823
|
// The viewed /u/<slug> workspace to file the task under. Honored only when the
|
|
791
824
|
// caller is authorized for it (attested staff or owner-tree control); otherwise
|
|
792
825
|
// the resolver falls back to the caller's own slug. Reconciles the create tag
|
|
@@ -796,6 +829,78 @@ export const RECEIVERS = {
|
|
|
796
829
|
response: z.object({ ok: z.boolean(), tid: z.string().optional(), tags: z.array(z.string()).optional() }),
|
|
797
830
|
effect: "ask", idempotent: false,
|
|
798
831
|
}),
|
|
832
|
+
"tasks:claim": receiver({
|
|
833
|
+
receiver: "tasks:claim",
|
|
834
|
+
summary: "Take a task off the queue: blocker-gate → status picked → tag the claimant @<slug>. The claimant is the attested caller, never a body field",
|
|
835
|
+
request: z.object({
|
|
836
|
+
tid: z.string(),
|
|
837
|
+
// Viewed workspace — same authorization contract as tasks:create's workspace.
|
|
838
|
+
workspace: z.string().optional(),
|
|
839
|
+
}),
|
|
840
|
+
response: z.object({
|
|
841
|
+
ok: z.boolean().optional(),
|
|
842
|
+
tid: z.string().optional(),
|
|
843
|
+
status: z.string().optional(),
|
|
844
|
+
claimant: z.string().optional(),
|
|
845
|
+
error: z.string().optional(),
|
|
846
|
+
}),
|
|
847
|
+
effect: "ask", idempotent: true,
|
|
848
|
+
}),
|
|
849
|
+
"tasks:undepend": receiver({
|
|
850
|
+
receiver: "tasks:undepend",
|
|
851
|
+
summary: "Remove one blocks edge — the inverse of tasks:depend. Deletes exactly the (blockedBy → tid) pair; does not touch task status. Auth: attested caller only, both ends in the caller's workspace",
|
|
852
|
+
request: z.object({
|
|
853
|
+
tid: z.string(),
|
|
854
|
+
blockedBy: z.string(),
|
|
855
|
+
workspace: z.string().optional(),
|
|
856
|
+
}),
|
|
857
|
+
response: z.object({
|
|
858
|
+
ok: z.boolean().optional(),
|
|
859
|
+
tid: z.string().optional(),
|
|
860
|
+
blockedBy: z.string().optional(),
|
|
861
|
+
error: z.string().optional(),
|
|
862
|
+
}),
|
|
863
|
+
effect: "ask", idempotent: true,
|
|
864
|
+
}),
|
|
865
|
+
"tasks:launch": receiver({
|
|
866
|
+
receiver: "tasks:launch",
|
|
867
|
+
summary: "Batch-launch ready agent-assigned tasks: per task re-check blockers, resolve the @assignee, set picked, fire agent:run, mark owner→assignee on success or revert to open + warn on failure. Per-task receipts — a batch is never all-or-nothing. Caps at 20 tids; skips human assignees",
|
|
868
|
+
request: z.object({
|
|
869
|
+
tids: z.array(z.string()),
|
|
870
|
+
workspace: z.string().optional(),
|
|
871
|
+
}),
|
|
872
|
+
response: z.object({
|
|
873
|
+
ok: z.boolean(),
|
|
874
|
+
results: z.array(z.object({
|
|
875
|
+
tid: z.string(),
|
|
876
|
+
ok: z.boolean(),
|
|
877
|
+
actorId: z.string().optional(),
|
|
878
|
+
reason: z.enum(["unassigned", "human-assignee", "blocked", "forbidden", "fire_failed"]).optional(),
|
|
879
|
+
})),
|
|
880
|
+
}),
|
|
881
|
+
effect: "ask", idempotent: false,
|
|
882
|
+
}),
|
|
883
|
+
"tasks:link": receiver({
|
|
884
|
+
receiver: "tasks:link",
|
|
885
|
+
summary: "Close the handoff: record that a claimed task was built via /do <slug> — append a provenance line to the task's notes (the id back-ref + doc stems) and move it to done. Auth: attested caller only",
|
|
886
|
+
request: z.object({
|
|
887
|
+
tid: z.string(),
|
|
888
|
+
// The kebab /do slug the task was built into (the docs backfilled under text/<slug>*).
|
|
889
|
+
slug: z.string(),
|
|
890
|
+
// Doc stems the /do run produced (e.g. ["usage-billing", "usage-billing-plan"]).
|
|
891
|
+
docs: z.array(z.string()).optional(),
|
|
892
|
+
workspace: z.string().optional(),
|
|
893
|
+
}),
|
|
894
|
+
response: z.object({
|
|
895
|
+
ok: z.boolean().optional(),
|
|
896
|
+
tid: z.string().optional(),
|
|
897
|
+
slug: z.string().optional(),
|
|
898
|
+
docs: z.array(z.string()).optional(),
|
|
899
|
+
status: z.string().optional(),
|
|
900
|
+
error: z.string().optional(),
|
|
901
|
+
}),
|
|
902
|
+
effect: "ask", idempotent: true,
|
|
903
|
+
}),
|
|
799
904
|
// ── agents (TRADE / lifecycle) ──
|
|
800
905
|
"agents:register": receiver({
|
|
801
906
|
receiver: "agents:register",
|
|
@@ -1266,12 +1371,13 @@ export const RECEIVERS = {
|
|
|
1266
1371
|
}),
|
|
1267
1372
|
"notify": receiver({
|
|
1268
1373
|
receiver: "notify",
|
|
1269
|
-
summary: "Notify any actor (human or agent) by uid — channels routes the door (Telegram/Discord/peer inbox), mirrors into the web inbox,
|
|
1374
|
+
summary: "Notify any actor (human or agent) by uid — channels routes the door (Telegram/Discord/peer inbox), mirrors into the web inbox, nudges an open client live, and sends a web push if the recipient subscribed. One verb, both actor kinds. An optional action renders as one tap-through link.",
|
|
1270
1375
|
request: z.object({
|
|
1271
1376
|
receiver: z.string(),
|
|
1272
1377
|
kind: z.string().optional(),
|
|
1273
1378
|
body: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
1274
1379
|
content: z.string().optional(),
|
|
1380
|
+
action: z.object({ label: z.string(), redirect: z.string() }).optional(),
|
|
1275
1381
|
}),
|
|
1276
1382
|
response: z.object({
|
|
1277
1383
|
ok: z.boolean(),
|
|
@@ -1306,6 +1412,17 @@ export const RECEIVERS = {
|
|
|
1306
1412
|
response: z.object({ ok: z.boolean(), ts: z.number().optional(), error: z.string().optional() }),
|
|
1307
1413
|
effect: "ask", idempotent: true,
|
|
1308
1414
|
}),
|
|
1415
|
+
"push:subscribe": receiver({
|
|
1416
|
+
receiver: "push:subscribe",
|
|
1417
|
+
summary: "Store a browser's Web Push subscription so notify() can reach the caller off-screen — the send side behind the shipped inbox service worker. Optional slug keys the row to a workspace the caller controls (else their own slug).",
|
|
1418
|
+
request: z.object({
|
|
1419
|
+
endpoint: z.string(),
|
|
1420
|
+
keys: z.object({ p256dh: z.string(), auth: z.string() }),
|
|
1421
|
+
slug: z.string().optional(),
|
|
1422
|
+
}),
|
|
1423
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
1424
|
+
effect: "ask", idempotent: true,
|
|
1425
|
+
}),
|
|
1309
1426
|
"thread:append": receiver({
|
|
1310
1427
|
receiver: "thread:append",
|
|
1311
1428
|
summary: "Gateway-callable write into web threads — carries tags into entity_tags so slug/in renders every channel by tag. Called by the channels bridge after every inbound signal.",
|
|
@@ -1977,6 +2094,14 @@ export const RECEIVERS = {
|
|
|
1977
2094
|
service: z.object({
|
|
1978
2095
|
service_id: z.string(), name: z.string(), duration_min: z.number(),
|
|
1979
2096
|
price: z.number(), currency: z.string(),
|
|
2097
|
+
description: z.string().nullable().optional(), // shown on /book, read by the agent (§12.2)
|
|
2098
|
+
location: z.string().nullable().optional(), // 'video' | 'phone' | free-text address
|
|
2099
|
+
intake: z.array(z.object({
|
|
2100
|
+
key: z.string(), label: z.string(),
|
|
2101
|
+
type: z.enum(["text", "number", "choice"]).optional(),
|
|
2102
|
+
required: z.boolean().optional(),
|
|
2103
|
+
options: z.array(z.string()).optional(),
|
|
2104
|
+
})).optional(), // per-service intake questions — both doors ask them
|
|
1980
2105
|
}).nullable(),
|
|
1981
2106
|
slots: z.array(z.object({ date: z.string(), times: z.array(z.string()) })), // CalendarCard shape
|
|
1982
2107
|
error: z.string().optional(),
|
|
@@ -1984,6 +2109,35 @@ export const RECEIVERS = {
|
|
|
1984
2109
|
effect: "ask", cost: "free", idempotent: true, simulatable: false,
|
|
1985
2110
|
examples: [{ slug: "clearwater", date: "2026-06-10" }],
|
|
1986
2111
|
}),
|
|
2112
|
+
// booking:list-services — public discover: the service menu (§12.3). Lets the
|
|
2113
|
+
// chat agent offer "in-home survey, video walkthrough, or storage?" instead of
|
|
2114
|
+
// silently defaulting to the first active row. Active services, public fields
|
|
2115
|
+
// only (hours/buffer are inferable from list-slots output, so not secrets).
|
|
2116
|
+
"booking:list-services": receiver({
|
|
2117
|
+
receiver: "booking:list-services",
|
|
2118
|
+
summary: "List a workspace's active bookable services (menu: name, duration, price, description, location, intake)",
|
|
2119
|
+
request: z.object({ slug: z.string() }),
|
|
2120
|
+
response: z.object({
|
|
2121
|
+
services: z.array(z.object({
|
|
2122
|
+
service_id: z.string(), name: z.string(), duration_min: z.number(),
|
|
2123
|
+
price: z.number(), currency: z.string(),
|
|
2124
|
+
description: z.string().nullable().optional(),
|
|
2125
|
+
location: z.string().nullable().optional(),
|
|
2126
|
+
buffer_min: z.number().optional(),
|
|
2127
|
+
tz: z.string().optional(),
|
|
2128
|
+
hours_json: z.array(z.array(z.object({ start: z.string(), end: z.string() }))).optional(),
|
|
2129
|
+
intake: z.array(z.object({
|
|
2130
|
+
key: z.string(), label: z.string(),
|
|
2131
|
+
type: z.enum(["text", "number", "choice"]).optional(),
|
|
2132
|
+
required: z.boolean().optional(),
|
|
2133
|
+
options: z.array(z.string()).optional(),
|
|
2134
|
+
})).optional(),
|
|
2135
|
+
})),
|
|
2136
|
+
error: z.string().optional(),
|
|
2137
|
+
}),
|
|
2138
|
+
effect: "ask", cost: "free", idempotent: true, auth: "public",
|
|
2139
|
+
examples: [{ slug: "clearwater" }],
|
|
2140
|
+
}),
|
|
1987
2141
|
"booking:create": receiver({
|
|
1988
2142
|
receiver: "booking:create",
|
|
1989
2143
|
summary: "Hold a slot for a customer; returns a ref and a payment intent when price > 0",
|
|
@@ -1992,7 +2146,12 @@ export const RECEIVERS = {
|
|
|
1992
2146
|
service: z.string(),
|
|
1993
2147
|
slotDate: z.string(), // 'YYYY-MM-DD'
|
|
1994
2148
|
slotTime: z.string(), // 'HH:MM' 24h, slot start
|
|
1995
|
-
customer: z.object({
|
|
2149
|
+
customer: z.object({
|
|
2150
|
+
name: z.string(),
|
|
2151
|
+
email: z.string().email().optional(),
|
|
2152
|
+
phone: z.string().optional(), // speed-to-lead callback number (§12.3)
|
|
2153
|
+
}),
|
|
2154
|
+
details: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(), // intake answers OR free text; 2KB serialized cap at the resolver, never shape-validated
|
|
1996
2155
|
paymentRail: z.enum(["stripe", "sui"]).optional(), // resolver overrides by caller kind
|
|
1997
2156
|
}),
|
|
1998
2157
|
response: z.object({
|
|
@@ -2002,7 +2161,7 @@ export const RECEIVERS = {
|
|
|
2002
2161
|
paymentRail: z.enum(["stripe", "sui"]).nullable().optional(),
|
|
2003
2162
|
paymentIntent: z.object({ clientSecret: z.string(), amount: z.number() }).optional(), // human, price>0
|
|
2004
2163
|
escrow: z.object({ escrowId: z.string(), bounty: z.number(), deadline: z.string() }).optional(), // agent
|
|
2005
|
-
error: z.string().optional(), // 'slot_taken' | 'closed' | 'unknown_service'
|
|
2164
|
+
error: z.string().optional(), // 'slot_taken' | 'closed' | 'unknown_service' | 'details_too_large'
|
|
2006
2165
|
}),
|
|
2007
2166
|
effect: "ask", cost: "variable", settles: "offchain", reversible: false,
|
|
2008
2167
|
simulatable: true, idempotent: true, // idempotencyKey dedupes a retried hold
|
|
@@ -2027,6 +2186,15 @@ export const RECEIVERS = {
|
|
|
2027
2186
|
hours_json: z.array(z.array(z.object({ start: z.string(), end: z.string() }))), // 7 entries, 0=Sun
|
|
2028
2187
|
tz: z.string().optional(),
|
|
2029
2188
|
active: z.boolean().optional(),
|
|
2189
|
+
description: z.string().optional(), // shown on /book + read by the agent (§12.1)
|
|
2190
|
+
location: z.string().optional(), // 'video' | 'phone' | free-text address
|
|
2191
|
+
buffer_min: z.number().int().nonnegative().optional(), // drive time between slots (§12.5)
|
|
2192
|
+
intake: z.array(z.object({
|
|
2193
|
+
key: z.string(), label: z.string(),
|
|
2194
|
+
type: z.enum(["text", "number", "choice"]).optional(),
|
|
2195
|
+
required: z.boolean().optional(),
|
|
2196
|
+
options: z.array(z.string()).optional(),
|
|
2197
|
+
})).optional(), // per-service intake questions (§12.2); full-body upsert — omitted clears
|
|
2030
2198
|
}),
|
|
2031
2199
|
response: z.object({ ok: z.boolean(), service_id: z.string().optional(), error: z.string().optional() }),
|
|
2032
2200
|
effect: "ask", cost: "free", idempotent: true, reversible: true, auth: "manage_clients",
|
|
@@ -2048,25 +2216,56 @@ export const RECEIVERS = {
|
|
|
2048
2216
|
id: z.string(), ref: z.string(), service_name: z.string(),
|
|
2049
2217
|
slot_date: z.string(), slot_time: z.string(),
|
|
2050
2218
|
customer_name: z.string(), status: z.string(),
|
|
2219
|
+
customer_phone: z.string().nullable().optional(), // §12.3 — the job, not just the name
|
|
2220
|
+
details: z.union([z.string(), z.record(z.string(), z.unknown())]).nullable().optional(), // parsed details_json (record) or verbatim free text; untrusted display data
|
|
2051
2221
|
})),
|
|
2052
2222
|
error: z.string().optional(),
|
|
2053
2223
|
}),
|
|
2054
2224
|
effect: "ask", cost: "free", idempotent: true, auth: "manage_clients",
|
|
2055
2225
|
examples: [{ slug: "clearwater", month: "2026-06" }],
|
|
2056
2226
|
}),
|
|
2057
|
-
// booking:cancel —
|
|
2058
|
-
//
|
|
2059
|
-
//
|
|
2227
|
+
// booking:cancel — dual-path (§12.6). Provider dissolves by ref (ctx-gated to
|
|
2228
|
+
// the attested owner). Customer self-cancels with ref + matching contact (public;
|
|
2229
|
+
// possession IS the gate, exactly like the public book path). Either way
|
|
2230
|
+
// status='dissolved' releases the slot via the partial unique index (§9).
|
|
2060
2231
|
"booking:cancel": receiver({
|
|
2061
2232
|
receiver: "booking:cancel",
|
|
2062
|
-
summary: "
|
|
2233
|
+
summary: "Dissolve a booking by ref — provider (ctx-gated) or customer (ref + matching contact)",
|
|
2063
2234
|
request: z.object({
|
|
2064
2235
|
slug: z.string(),
|
|
2065
2236
|
ref: z.string(),
|
|
2237
|
+
email: z.string().email().optional(), // customer path: possession = ref + matching contact
|
|
2238
|
+
phone: z.string().optional(),
|
|
2066
2239
|
}),
|
|
2067
2240
|
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
2068
|
-
effect: "ask", cost: "free", idempotent: true, reversible: false, auth: "
|
|
2069
|
-
examples: [{ slug: "clearwater", ref: "CLE-2026-4821" }],
|
|
2241
|
+
effect: "ask", cost: "free", idempotent: true, reversible: false, auth: "public",
|
|
2242
|
+
examples: [{ slug: "clearwater", ref: "CLE-2026-4821", email: "s@ex.com" }],
|
|
2243
|
+
}),
|
|
2244
|
+
// booking:reschedule — customer self-serve move (§12.6). Public; the gate is
|
|
2245
|
+
// ref + matching contact. Hold-new-first: the resolver INSERTs the new slot
|
|
2246
|
+
// (same guarded INSERT — can lose with slot_taken) THEN dissolves the old row,
|
|
2247
|
+
// so a lost race leaves the original booking standing. Payment rail/ref carry over.
|
|
2248
|
+
"booking:reschedule": receiver({
|
|
2249
|
+
receiver: "booking:reschedule",
|
|
2250
|
+
summary: "Customer self-serve: move a booking to a new slot by ref + matching contact (hold-new-first)",
|
|
2251
|
+
request: z.object({
|
|
2252
|
+
slug: z.string(),
|
|
2253
|
+
ref: z.string(),
|
|
2254
|
+
email: z.string().email().optional(),
|
|
2255
|
+
phone: z.string().optional(),
|
|
2256
|
+
newDate: z.string(), // 'YYYY-MM-DD'
|
|
2257
|
+
newTime: z.string(), // 'HH:MM' 24h slot start
|
|
2258
|
+
}),
|
|
2259
|
+
response: z.object({
|
|
2260
|
+
ok: z.boolean(),
|
|
2261
|
+
ref: z.string().optional(), // the NEW booking ref (ref is UNIQUE — a moved booking gets a fresh ref)
|
|
2262
|
+
status: z.enum(["pending", "confirmed"]).optional(),
|
|
2263
|
+
slotDate: z.string().optional(),
|
|
2264
|
+
slotTime: z.string().optional(),
|
|
2265
|
+
error: z.string().optional(), // 'not_found' | 'slot_taken' | 'closed' | 'unknown_service'
|
|
2266
|
+
}),
|
|
2267
|
+
effect: "ask", cost: "free", idempotent: true, reversible: false, auth: "public",
|
|
2268
|
+
examples: [{ slug: "clearwater", ref: "CLE-2026-4821", email: "s@ex.com", newDate: "2026-06-12", newTime: "10:30" }],
|
|
2070
2269
|
}),
|
|
2071
2270
|
// ── workflows — define an SOP, run it, watch it learn (text/workflows-plan.md) ──
|
|
2072
2271
|
// Every workflow op is a typed receiver. No new REST routes. apply-diff is
|
|
@@ -2127,6 +2326,23 @@ export const RECEIVERS = {
|
|
|
2127
2326
|
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "view_workflows",
|
|
2128
2327
|
examples: [{ workflowId: "wf_abc", limit: 20 }, { workflowId: "wf_abc", runId: "run_1" }],
|
|
2129
2328
|
}),
|
|
2329
|
+
"workflow:preview-step": receiver({
|
|
2330
|
+
receiver: "workflow:preview-step",
|
|
2331
|
+
summary: "Resolve one step's receiver + args through the real substitution code, with an optional mock trigger/step payload standing in for run history — never dispatches, reads no run history",
|
|
2332
|
+
request: z.object({
|
|
2333
|
+
workflowId: z.string(),
|
|
2334
|
+
stepId: z.string(),
|
|
2335
|
+
mockTrigger: z.record(z.string(), z.unknown()).optional(),
|
|
2336
|
+
mockSteps: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),
|
|
2337
|
+
}),
|
|
2338
|
+
response: z.object({
|
|
2339
|
+
receiver: z.string().nullable(),
|
|
2340
|
+
data: z.record(z.string(), z.unknown()),
|
|
2341
|
+
error: z.string().optional(),
|
|
2342
|
+
}),
|
|
2343
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, simulatable: false, auth: "view_workflows",
|
|
2344
|
+
examples: [{ workflowId: "wf_abc", stepId: "step_1", mockTrigger: { email: "a@b.com" } }],
|
|
2345
|
+
}),
|
|
2130
2346
|
"workflow:create": receiver({
|
|
2131
2347
|
receiver: "workflow:create",
|
|
2132
2348
|
summary: "Create a blank workflow (group group-type=workflow) — optionally cloned from a template",
|
|
@@ -2639,6 +2855,48 @@ export const RECEIVERS = {
|
|
|
2639
2855
|
response: z.object({ broadcast: z.record(z.string(), z.unknown()) }),
|
|
2640
2856
|
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
2641
2857
|
}),
|
|
2858
|
+
"segment:create": receiver({
|
|
2859
|
+
receiver: "segment:create",
|
|
2860
|
+
summary: "Create an audience segment from a rule definition (SegmentDef: {all, any?})",
|
|
2861
|
+
request: z.object({ workspace: z.string(), name: z.string(), description: z.string().optional(), definition: z.record(z.string(), z.unknown()) }),
|
|
2862
|
+
response: z.object({ id: z.string() }),
|
|
2863
|
+
effect: "ask", cost: "free", reversible: true, idempotent: false, auth: "write",
|
|
2864
|
+
}),
|
|
2865
|
+
"segment:update": receiver({
|
|
2866
|
+
receiver: "segment:update",
|
|
2867
|
+
summary: "Update an audience segment — name, description, or definition",
|
|
2868
|
+
request: z.object({ workspace: z.string(), id: z.string(), name: z.string().optional(), description: z.string().optional(), definition: z.record(z.string(), z.unknown()).optional() }),
|
|
2869
|
+
response: z.object({ ok: z.boolean() }),
|
|
2870
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "write",
|
|
2871
|
+
}),
|
|
2872
|
+
"segment:list": receiver({
|
|
2873
|
+
receiver: "segment:list",
|
|
2874
|
+
summary: "List audience segments for a workspace",
|
|
2875
|
+
request: z.object({ workspace: z.string() }),
|
|
2876
|
+
response: z.object({ segments: z.array(z.record(z.string(), z.unknown())) }),
|
|
2877
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
2878
|
+
}),
|
|
2879
|
+
"segment:get": receiver({
|
|
2880
|
+
receiver: "segment:get",
|
|
2881
|
+
summary: "Get one audience segment with its rule definition",
|
|
2882
|
+
request: z.object({ workspace: z.string(), id: z.string() }),
|
|
2883
|
+
response: z.object({ segment: z.record(z.string(), z.unknown()) }),
|
|
2884
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
2885
|
+
}),
|
|
2886
|
+
"segment:preview": receiver({
|
|
2887
|
+
receiver: "segment:preview",
|
|
2888
|
+
summary: "Preview an audience segment — live count + up to 10 sample addresses (read-only)",
|
|
2889
|
+
request: z.object({ workspace: z.string(), definition: z.record(z.string(), z.unknown()), channel: z.enum(["email", "sms", "whatsapp"]).optional() }),
|
|
2890
|
+
response: z.object({ count: z.number(), sample: z.array(z.string()) }),
|
|
2891
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
2892
|
+
}),
|
|
2893
|
+
"segment:delete": receiver({
|
|
2894
|
+
receiver: "segment:delete",
|
|
2895
|
+
summary: "Delete an audience segment and its membership snapshot",
|
|
2896
|
+
request: z.object({ workspace: z.string(), id: z.string() }),
|
|
2897
|
+
response: z.object({ ok: z.boolean() }),
|
|
2898
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "write",
|
|
2899
|
+
}),
|
|
2642
2900
|
"broadcast:test": receiver({
|
|
2643
2901
|
receiver: "broadcast:test",
|
|
2644
2902
|
summary: "Send a test email for a broadcast to one address",
|