@myapihq/sdk 2.4.0 → 2.4.2

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/src/services.ts DELETED
@@ -1,323 +0,0 @@
1
- // Canonical service registry — the single source of truth for everything
2
- // downstream (skill plugin.json generators, mirror-repo publisher, docs site,
3
- // scaffolders, etc.).
4
- //
5
- // To add a service: append an entry here. To rename, change description, or
6
- // re-categorize: edit here. Run `npm run canonical-sync` to propagate to
7
- // every rendered artifact (plugin.json files today; npm/PyPI metadata,
8
- // GitHub repo descriptions, docs site landing pages tomorrow).
9
- //
10
- // CI enforces no drift: `services-sync.test.ts` runs `canonical-sync
11
- // --check` and fails on any difference.
12
- //
13
- // Skill names MUST match the directory names under skills/<name>/ and the
14
- // repo names we want to claim on GitHub/npm. Don't paraphrase.
15
-
16
- export type ServiceStatus = 'ga' | 'preview' | 'planned';
17
-
18
- export type ServiceCategory =
19
- | 'send' // outbound: email, funnel, url, image-render
20
- | 'capture' // inbound: webhook, pixel
21
- | 'data' // read/filter the data layer: people, company, audience, crm
22
- | 'store' // persist bytes/JSON: storage, database
23
- | 'compute' // run code or inference: llm, fn
24
- | 'orchestrate' // control flow: workflow, queue, task
25
- | 'identity' // auth/billing/account: hq
26
- | 'infra'; // platform glue: domain
27
-
28
- export interface ServiceMeta {
29
- /** SDK namespace (also OpenAPI tag and CLI top-level command). */
30
- module: string;
31
- /** Skill name — used for: GitHub repo name, npm package name, plugin.json `name`, README headings. */
32
- skill: string;
33
- /** Brand domain we own (or want to own). Used for canonical links + npm/GitHub homepage. */
34
- domain: string;
35
- /** One-line description — used verbatim in npm description, GitHub repo description, plugin.json. */
36
- description: string;
37
- category: ServiceCategory;
38
- status: ServiceStatus;
39
- /** npm keywords + GitHub topics + PyPI classifiers. The first five are shared boilerplate. */
40
- keywords: string[];
41
- }
42
-
43
- const SHARED_KEYWORDS = ['mcp', 'claude-skill', 'ai-agent', 'cli', 'myapi'] as const;
44
- const k = (...extra: string[]): string[] => [...SHARED_KEYWORDS, ...extra];
45
-
46
- export const SERVICES: readonly ServiceMeta[] = [
47
- // ── identity / infra ────────────────────────────────────────────────
48
- {
49
- module: 'hq',
50
- skill: 'my-api-hq',
51
- domain: 'myapihq.com',
52
- description: 'Core identity and billing hub. Manage auth, organizations, and billing.',
53
- category: 'identity',
54
- status: 'ga',
55
- keywords: k('auth', 'identity', 'billing', 'organization'),
56
- },
57
- {
58
- module: 'auth',
59
- skill: 'my-auth-api',
60
- domain: 'myauthapi.com',
61
- description: 'Managed OIDC identity provider for the end users of apps built on MyAPI. Per-org auth tenant + OIDC clients, RS256/JWKS, hosted login, managed Google sign-in. A Kinde alternative.',
62
- category: 'identity',
63
- status: 'ga',
64
- keywords: k('auth', 'oidc', 'oauth', 'login', 'identity', 'sso'),
65
- },
66
- {
67
- module: 'domain',
68
- skill: 'my-domain-api',
69
- domain: 'mydomainapi.com',
70
- description: 'Domain registration and check with automated DNS and email infrastructure.',
71
- category: 'infra',
72
- status: 'ga',
73
- keywords: k('domain', 'dns', 'registration'),
74
- },
75
-
76
- // ── send ────────────────────────────────────────────────────────────
77
- {
78
- // Customer-facing email surface — mailboxes, transactional send,
79
- // templates, warmup. Launched 2026-05-17: the backend lifted the pre-launch gate
80
- // (the [disabled, pre-launch] / 503 SERVICE_NOT_LAUNCHED state is gone).
81
- // Sibling `my-email-verify-api` is the sync single-address verifier.
82
- module: 'email',
83
- skill: 'my-email-api',
84
- domain: 'myemailapi.com',
85
- description: 'Send transactional and bulk email from your own domain. Mailboxes, AI templates, and warmup.',
86
- category: 'send',
87
- status: 'ga',
88
- keywords: k('email', 'transactional', 'smtp', 'mailbox'),
89
- },
90
- {
91
- module: 'email',
92
- skill: 'my-email-verify-api',
93
- domain: 'myemailapi.com',
94
- description: 'Sync single-address email verification — syntax + DNS + Microsoft probe. Pre-send quality gate for outbound.',
95
- category: 'send',
96
- status: 'ga',
97
- keywords: k('email', 'verification', 'deliverability', 'syntax', 'dns'),
98
- },
99
- {
100
- module: 'funnel',
101
- skill: 'my-funnel-api',
102
- domain: 'myfunnelapi.com',
103
- description: 'Build multi-page sites and funnels with headless HTML upload.',
104
- category: 'send',
105
- status: 'ga',
106
- keywords: k('funnel', 'landing-page', 'website', 'static-site'),
107
- },
108
- {
109
- module: 'url',
110
- skill: 'my-url-to',
111
- domain: 'myurlto.com',
112
- description: 'Stateless link routing and URL shortening for the MyAPI ecosystem.',
113
- category: 'send',
114
- status: 'preview',
115
- keywords: k('url', 'shortener', 'redirect', 'link'),
116
- },
117
- {
118
- module: 'image',
119
- skill: 'my-image-api',
120
- domain: 'myimageapi.com',
121
- description: 'Generate AI images from a text prompt. Async, polls until ready, returns a public CDN URL.',
122
- category: 'compute',
123
- status: 'ga',
124
- keywords: k('image', 'ai-image', 'gemini', 'text-to-image'),
125
- },
126
-
127
- // ── capture ─────────────────────────────────────────────────────────
128
- {
129
- module: 'webhook',
130
- skill: 'my-webhook-api',
131
- domain: 'mywebhookapi.com',
132
- description: 'Receive inbound HTTP webhooks. Per-org endpoints with full delivery history.',
133
- category: 'capture',
134
- status: 'ga',
135
- keywords: k('webhook', 'inbound', 'event'),
136
- },
137
- {
138
- module: 'pixel',
139
- skill: 'my-pixel-api',
140
- domain: 'mypixelapi.com',
141
- description: 'Tracking pixel + identity resolution. Capture visits, events, and stitch known users to anonymous sessions.',
142
- category: 'capture',
143
- // Ingestion pipeline live in prod; CLI (visits/events/interactions/
144
- // identity/audience) + skill shipped. Not ga: preview-subdomain ownership
145
- // gap (TODO.md Gap 4) blocks the primary funnel flow.
146
- status: 'preview',
147
- keywords: k('pixel', 'analytics', 'tracking', 'visit', 'identity'),
148
- },
149
-
150
- // ── data ────────────────────────────────────────────────────────────
151
- {
152
- // Goldfox-backed people search is gated pre-launch — 503 SERVICE_NOT_LAUNCHED.
153
- // Internal Goldfox lookups still work (`crm contacts promote` resolves a
154
- // goldfox_person_id server-side), but the agent-facing search/get path
155
- // is hidden until backend lifts the gate.
156
- module: 'people',
157
- skill: 'my-people-api',
158
- domain: 'mypeopleapi.com',
159
- description: 'Contact database backed by the Goldfox crawl. Filter people by confidence tier, seniority, email type, country, link confidence, plus rich behavioral company signals (has_c_level, has_careers_page, has_decision_maker). The targeting layer for outbound campaigns.',
160
- category: 'data',
161
- status: 'preview',
162
- keywords: k('people', 'contact', 'b2b', 'targeting', 'goldfox'),
163
- },
164
- {
165
- // Goldfox-backed company search gated pre-launch (same reason as people).
166
- module: 'company',
167
- skill: 'my-company-api',
168
- domain: 'mycompanyapi.com',
169
- description: 'Company database backed by the Goldfox crawl. Filter companies by confidence tier, country/TLD consistency, behavioral page signals (has_careers_page, has_investors_page, has_shop_page, has_c_level, has_decision_maker), legal-entity status, headcount, and source-URL count.',
170
- category: 'data',
171
- status: 'preview',
172
- keywords: k('company', 'firmographics', 'b2b', 'goldfox'),
173
- },
174
- {
175
- // Saved audiences sit on top of people/company — gated together with them.
176
- module: 'audience',
177
- skill: 'my-audience-api',
178
- domain: 'myaudienceapi.com',
179
- description: 'Saved audiences = named filter snapshots over people/company database. Reuse across campaigns; refresh re-evaluates against current data.',
180
- category: 'data',
181
- status: 'preview',
182
- keywords: k('audience', 'segment', 'filter'),
183
- },
184
- {
185
- module: 'crm',
186
- skill: 'my-crm-api',
187
- // Brand domain — mycrmapi.com was unavailable; mypipelineapi.com chosen
188
- // and acquired. (Skill stays my-crm-api — domain/skill mismatch accepted.)
189
- domain: 'mypipelineapi.com',
190
- description: 'The canonical store of engaged people + companies. Auto-ingest from inbound webhooks (configurable dot-path). Fixed lifecycle_stage enum, soft delete, event timeline.',
191
- category: 'data',
192
- status: 'ga',
193
- keywords: k('crm', 'contact', 'pipeline', 'engagement'),
194
- },
195
-
196
- // ── store ───────────────────────────────────────────────────────────
197
- {
198
- module: 'storage',
199
- skill: 'my-storage-api',
200
- domain: 'mystorageapi.com',
201
- description: 'Edge-hosted asset storage. Upload local files or ingest from URLs, each gets a stable public CDN URL.',
202
- category: 'store',
203
- status: 'ga',
204
- keywords: k('storage', 'cdn', 'asset', 'upload'),
205
- },
206
- {
207
- module: 'database',
208
- skill: 'my-database-api',
209
- domain: 'mydatabaseapi.com',
210
- description: 'Per-org KV store with namespaces + compare-and-swap. JSON values up to 256 KB. The substrate for stateful agent-built apps.',
211
- category: 'store',
212
- status: 'ga',
213
- keywords: k('kv-store', 'database', 'state'),
214
- },
215
-
216
- // ── compute ─────────────────────────────────────────────────────────
217
- {
218
- module: 'llm',
219
- skill: 'my-llm-api',
220
- domain: 'myllmapi.com',
221
- description: 'Self-hosted open-source LLM: raw chat completions (you pick the model) + objective verbs (classify/extract/summarize/draft). Billed in cents per 1M tokens from your balance. Use in workflow steps, not for your own reasoning.',
222
- category: 'compute',
223
- status: 'ga',
224
- keywords: k('llm', 'completion', 'qwen', 'classify'),
225
- },
226
- {
227
- // CLI top-level command is `fn`; SDK namespace is `fn`; skill directory is
228
- // `my-function-api` (the agent-discoverable brand name).
229
- //
230
- // Backend status: deploy/env/runs shipped (CF Workers bundle upload,
231
- // invocation URL, Worker Secrets, run history). /logs still pending —
232
- // 'preview' reflects "usable, not yet stable GA."
233
- module: 'fn',
234
- skill: 'my-function-api',
235
- domain: 'myfunctionapi.com',
236
- description: 'Run JavaScript functions on the edge. HTTP or cron triggers. Pre-injected MYAPI SDK scoped to the org — no auth tokens in user code.',
237
- category: 'compute',
238
- status: 'preview',
239
- keywords: k('function', 'serverless', 'edge', 'cloudflare-workers', 'http-handler', 'cron'),
240
- },
241
- {
242
- // CLI top-level command + SDK namespace are both `payments`; skill
243
- // directory is `my-payments-api`.
244
- //
245
- // Backend status: T0 (BYO Stripe) shipped — connect, charges (Checkout
246
- // Sessions), refunds, per-org webhook. T1 (Connect Express) is deferred
247
- // (connect returns 501 T1_DEFERRED). 'preview' reflects "T0 usable, T1
248
- // pending."
249
- module: 'payments',
250
- skill: 'my-payments-api',
251
- domain: 'mypaymentsapi.com',
252
- description: 'Take payments with Stripe Checkout. Connect your Stripe account, create one-off or recurring charges, and refund — hosted checkout, no card handling.',
253
- category: 'compute',
254
- status: 'preview',
255
- keywords: k('payments', 'stripe', 'checkout', 'billing', 'subscription'),
256
- },
257
- {
258
- // CLI top-level command + SDK namespace are both `container`; skill
259
- // directory is `my-container-api`.
260
- //
261
- // Backend status: Phase 1 shipped (metadata + scoped API key). The
262
- // Cloud Run build/deploy pipeline is Phase 2 — deploy returns
263
- // RUNTIME_UNAVAILABLE until it lands. 'preview' reflects "usable
264
- // surface, deploy not yet GA."
265
- module: 'container',
266
- skill: 'my-container-api',
267
- domain: 'mycontainerapi.com',
268
- description: 'Run containers on demand — long-running services, background workers, and scheduled jobs. The heavier-duty sibling of edge functions, for native deps and long execution.',
269
- category: 'compute',
270
- status: 'preview',
271
- keywords: k('container', 'cloud-run', 'service', 'worker', 'job'),
272
- },
273
- {
274
- // CLI top-level command + SDK namespace are both `git`; skill directory
275
- // is `my-git-api`. A stateless git-over-HTTP surface (go-git engine;
276
- // objects in GCS, refs in Postgres) — repos, commits, branches, history.
277
- module: 'git',
278
- skill: 'my-git-api',
279
- domain: 'mygitapi.com',
280
- description: 'Hosted git repositories over HTTP — create repos, commit files, manage branches and tags, read trees, blobs, history, and diffs. No local clone required.',
281
- category: 'store',
282
- status: 'ga',
283
- keywords: k('git', 'repository', 'version-control', 'commit', 'scm'),
284
- },
285
-
286
- // ── orchestrate ─────────────────────────────────────────────────────
287
- // Control flow, not actions. workflow = event→action, queue = durable
288
- // async machine work, task = work that needs an agent/human decision.
289
- // See docs/orchestration-decision-guide.md.
290
- {
291
- module: 'workflow',
292
- skill: 'my-workflow-api',
293
- domain: 'myworkflowapi.com',
294
- description: 'React to inbound webhooks with step chains: send email, post to Slack, call HTTP URLs.',
295
- category: 'orchestrate',
296
- status: 'ga',
297
- keywords: k('workflow', 'automation', 'orchestration'),
298
- },
299
- {
300
- // CLI top-level command + SDK namespace are both `queue`; skill
301
- // directory is `my-queue-api`. A durable HTTP-consumer job queue —
302
- // retry/backoff, concurrency caps, dependency DAG.
303
- module: 'queue',
304
- skill: 'my-queue-api',
305
- domain: 'myqueueapi.com',
306
- description: 'Durable job queue — enqueue work and have it retried against your HTTP consumer, with concurrency caps and a dependency DAG.',
307
- category: 'orchestrate',
308
- status: 'preview',
309
- keywords: k('queue', 'job-queue', 'background-jobs', 'retry', 'async'),
310
- },
311
- {
312
- // CLI top-level command + SDK namespace are both `task`; skill
313
- // directory is `my-task-api`. The agent-task queue — the agent-loop
314
- // hot path: file, claim under a lease, resolve.
315
- module: 'task',
316
- skill: 'my-task-api',
317
- domain: 'mytaskapi.com',
318
- description: 'Agent-task queue — file units of work, rank them, claim under a lease, then resolve, fail, or cancel. The agent-loop hot path.',
319
- category: 'orchestrate',
320
- status: 'preview',
321
- keywords: k('task', 'task-queue', 'agent-loop', 'work-queue', 'lease'),
322
- },
323
- ] as const;
package/src/storage.ts DELETED
@@ -1,80 +0,0 @@
1
- import { request, MyApiError } from './client';
2
- import { ApiResponse } from './types';
3
- import { STORAGE_BASE as BASE_URL } from './config';
4
- import type { Exposes } from './exposes';
5
-
6
- export const EXPOSES: Exposes = [
7
- 'POST /storage/orgs/{org_id}/assets/ingest',
8
- 'POST /storage/orgs/{org_id}/assets/upload',
9
- 'GET /storage/orgs/{org_id}/assets',
10
- 'DELETE /storage/orgs/{org_id}/assets/{asset_id}',
11
- ];
12
-
13
-
14
-
15
- export interface Asset { asset_id: string; url: string; name: string; created_at: string }
16
-
17
- export async function ingestAsset(apiKey: string, orgId: string, url: string, name?: string): Promise<Asset> {
18
- return request('POST', `${BASE_URL}/storage/orgs/${encodeURIComponent(orgId)}/assets/ingest`, apiKey, { url, name });
19
- }
20
-
21
- // Content types accepted by uploadAsset. Mirrors the backend's
22
- // detectAsset() allowlist (routes/org/org.go). Images go up to a few MB;
23
- // videos cap at 200 MB. PDFs/SVGs and other types still need to go through
24
- // `ingestAsset` (URL fetch) — they're not in the upload allowlist yet.
25
- export type UploadContentType =
26
- | 'image/jpeg'
27
- | 'image/png'
28
- | 'image/gif'
29
- | 'image/webp'
30
- | 'image/svg+xml'
31
- | 'application/pdf'
32
- | 'video/mp4'
33
- | 'video/webm';
34
-
35
- export async function uploadAsset(apiKey: string, orgId: string, file: Blob | Buffer, contentType: UploadContentType, name?: string): Promise<Asset> {
36
- const headers: Record<string, string> = {
37
- 'Authorization': `Bearer ${apiKey}`
38
- };
39
-
40
- const formData = new FormData();
41
- formData.append('file', new Blob([file as any], { type: contentType }));
42
- if (name) {
43
- formData.append('name', name);
44
- }
45
-
46
- const response = await fetch(`${BASE_URL}/storage/orgs/${encodeURIComponent(orgId)}/assets/upload`, {
47
- method: 'POST',
48
- headers,
49
- body: formData as any
50
- });
51
-
52
- let result: any;
53
- try {
54
- result = await response.json();
55
- } catch {
56
- throw new MyApiError('invalid_json_response', response.status);
57
- }
58
-
59
- // Mirror client.ts error handling: the backend's modern error shape is an
60
- // object {code, message, ...}. The old string-only handling here made
61
- // err.code an object, so e.g. funds.isInsufficientFunds could never match
62
- // a 402 on a billable upload.
63
- if (!response.ok || !(result as ApiResponse<Asset>).success) {
64
- const err = result?.error;
65
- const code = typeof err === 'object' && err !== null ? (err?.code || 'unknown_error') : (err || 'unknown_error');
66
- const detail = typeof err === 'object' && err !== null ? (err?.message || undefined) : undefined;
67
- const errBody = typeof err === 'object' && err !== null ? err : undefined;
68
- throw new MyApiError(code, response.status, detail, errBody);
69
- }
70
-
71
- return (result as ApiResponse<Asset>).data as Asset;
72
- }
73
-
74
- export async function listAssets(apiKey: string, orgId: string): Promise<Asset[]> {
75
- return request('GET', `${BASE_URL}/storage/orgs/${encodeURIComponent(orgId)}/assets`, apiKey);
76
- }
77
-
78
- export async function deleteAsset(apiKey: string, orgId: string, assetId: string): Promise<void> {
79
- return request('DELETE', `${BASE_URL}/storage/orgs/${encodeURIComponent(orgId)}/assets/${encodeURIComponent(assetId)}`, apiKey);
80
- }
package/src/task.ts DELETED
@@ -1,198 +0,0 @@
1
- import { request } from './client';
2
- import { TASK_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- // Backend: my-task-api per myapi-hq/internal/routes/task/. An agent-task
6
- // queue — the agent-loop hot path. Tasks are created, ranked by score,
7
- // claimed under a lease, then resolved/failed/cancelled. A task with
8
- // unresolved depends_on starts blocked; lease expiry auto-reverts a claimed
9
- // task to open.
10
- export const EXPOSES: Exposes = [
11
- 'POST /task/orgs/{org_id}/tasks',
12
- 'GET /task/orgs/{org_id}/tasks',
13
- 'GET /task/orgs/{org_id}/tasks/{id}',
14
- 'DELETE /task/orgs/{org_id}/tasks/{id}',
15
- 'GET /task/orgs/{org_id}/tasks/{id}/body',
16
- 'POST /task/orgs/{org_id}/tasks/{id}/claim',
17
- 'POST /task/orgs/{org_id}/tasks/{id}/extend',
18
- 'POST /task/orgs/{org_id}/tasks/{id}/fail',
19
- 'POST /task/orgs/{org_id}/tasks/{id}/resolve',
20
- ];
21
-
22
- export type TaskStatus = 'open' | 'claimed' | 'blocked' | 'resolved' | 'failed' | 'cancelled';
23
-
24
- export type TaskImportance = 'low' | 'normal' | 'high' | 'critical';
25
-
26
- // Event matcher: a matching platform_events delivery auto-resolves the task.
27
- export interface ResolveOn {
28
- event_type: string;
29
- field?: string;
30
- value?: string;
31
- }
32
-
33
- // The projected list row — list deliberately returns only this triage-sized
34
- // shape, not the full task. Read the body tier separately via getTaskBody.
35
- export interface TaskRef {
36
- id: string;
37
- description: string;
38
- score: number;
39
- }
40
-
41
- // Full task object. `claim` and `extend` return this — lease state is read
42
- // off `lease_expires_at` / `claimed_by`, not a separate lease object.
43
- export interface Task {
44
- id: string;
45
- org_id: string;
46
- description: string;
47
- status: TaskStatus;
48
- importance: TaskImportance;
49
- score: number;
50
- tags: string[];
51
- source: string;
52
- depends_on: string[];
53
- payload_url: string;
54
- assignee?: string;
55
- resolve_on?: ResolveOn;
56
- dedup_key?: string;
57
- claimed_by?: string;
58
- lease_expires_at?: string;
59
- due_at?: string;
60
- fail_reason?: string;
61
- resolved_at?: string;
62
- created_at: string;
63
- updated_at: string;
64
- }
65
-
66
- // Backlog health from the list envelope's meta — the agent's "am I keeping
67
- // up" signal. `shown` is how many rows came back; `total_open` is the whole
68
- // open queue depth.
69
- export interface TaskListMeta {
70
- shown: number;
71
- total_open: number;
72
- }
73
-
74
- export interface TaskListResult {
75
- tasks: TaskRef[];
76
- meta: TaskListMeta;
77
- }
78
-
79
- export interface CreateTaskOptions {
80
- description: string;
81
- // Full Markdown context. Staged to the body tier; read once via getTaskBody.
82
- body?: string;
83
- importance?: TaskImportance;
84
- dueAt?: string;
85
- assignee?: string;
86
- tags?: string[];
87
- // Task ids this task waits on. Immutable — declared only at creation.
88
- // Same shape as queue.enqueue's depends_on.
89
- dependsOn?: string[];
90
- dedupKey?: string;
91
- resolveOn?: ResolveOn;
92
- source?: string;
93
- }
94
-
95
- export interface ListTaskOptions {
96
- status?: string;
97
- tag?: string;
98
- importance?: string;
99
- assignee?: string;
100
- source?: string;
101
- limit?: number;
102
- }
103
-
104
- function tasksBase(orgId: string): string {
105
- return `${BASE_URL}/task/orgs/${encodeURIComponent(orgId)}/tasks`;
106
- }
107
-
108
- function taskBase(orgId: string, id: string): string {
109
- return `${tasksBase(orgId)}/${encodeURIComponent(id)}`;
110
- }
111
-
112
- // createTask is idempotent on (org_id, dedup_key). A task with unresolved
113
- // depends_on starts blocked; one with an assignee emails them a magic link.
114
- export async function createTask(apiKey: string, orgId: string, opts: CreateTaskOptions): Promise<Task> {
115
- const body: Record<string, unknown> = { description: opts.description };
116
- if (opts.body !== undefined) body.body = opts.body;
117
- if (opts.importance !== undefined) body.importance = opts.importance;
118
- if (opts.dueAt !== undefined) body.due_at = opts.dueAt;
119
- if (opts.assignee !== undefined) body.assignee = opts.assignee;
120
- if (opts.tags !== undefined) body.tags = opts.tags;
121
- if (opts.dependsOn !== undefined) body.depends_on = opts.dependsOn;
122
- if (opts.dedupKey !== undefined) body.dedup_key = opts.dedupKey;
123
- if (opts.resolveOn !== undefined) body.resolve_on = opts.resolveOn;
124
- if (opts.source !== undefined) body.source = opts.source;
125
- return request('POST', tasksBase(orgId), apiKey, body);
126
- }
127
-
128
- // listTasks returns the ranked open queue (projected to TaskRef) plus the
129
- // backlog counts. Default: top 20 open tasks by score. The backend nests
130
- // {shown, total_open} inside the response `data.meta` (not the envelope meta).
131
- export async function listTasks(apiKey: string, orgId: string, opts: ListTaskOptions = {}): Promise<TaskListResult> {
132
- const q = new URLSearchParams();
133
- if (opts.status) q.set('status', opts.status);
134
- if (opts.tag) q.set('tag', opts.tag);
135
- if (opts.importance) q.set('importance', opts.importance);
136
- if (opts.assignee) q.set('assignee', opts.assignee);
137
- if (opts.source) q.set('source', opts.source);
138
- if (opts.limit !== undefined) q.set('limit', String(opts.limit));
139
- const qs = q.toString();
140
- const res = await request<{ tasks?: TaskRef[]; meta?: Partial<TaskListMeta> }>(
141
- 'GET', `${tasksBase(orgId)}${qs ? `?${qs}` : ''}`, apiKey,
142
- );
143
- const tasks = res?.tasks ?? [];
144
- const m = res?.meta ?? {};
145
- return {
146
- tasks,
147
- meta: {
148
- shown: typeof m.shown === 'number' ? m.shown : tasks.length,
149
- total_open: typeof m.total_open === 'number' ? m.total_open : tasks.length,
150
- },
151
- };
152
- }
153
-
154
- // getTask returns the full task object. It deliberately does NOT fetch the
155
- // Markdown body tier — call getTaskBody for that, once, on commit.
156
- export async function getTask(apiKey: string, orgId: string, id: string): Promise<Task> {
157
- return request('GET', taskBase(orgId, id), apiKey);
158
- }
159
-
160
- // getTaskBody fetches the body tier — the full Markdown context. Separate
161
- // call by design: it keeps the list/get path token-cheap. The endpoint
162
- // returns { task_id, body }.
163
- export async function getTaskBody(apiKey: string, orgId: string, id: string): Promise<string> {
164
- const res = await request<{ task_id: string; body: string }>('GET', `${taskBase(orgId, id)}/body`, apiKey);
165
- return res?.body ?? '';
166
- }
167
-
168
- // claimTask takes an atomic lease (default 10 min) and returns the full
169
- // updated task — lease state is on `lease_expires_at` / `claimed_by`.
170
- export async function claimTask(apiKey: string, orgId: string, id: string, opts: { leaseSeconds?: number; worker?: string } = {}): Promise<Task> {
171
- const body: Record<string, unknown> = {};
172
- if (opts.leaseSeconds !== undefined) body.lease_seconds = opts.leaseSeconds;
173
- if (opts.worker !== undefined) body.worker = opts.worker;
174
- return request('POST', `${taskBase(orgId, id)}/claim`, apiKey, body);
175
- }
176
-
177
- // extendTask is a heartbeat for long work — extends a live claim.
178
- export async function extendTask(apiKey: string, orgId: string, id: string, opts: { leaseSeconds?: number } = {}): Promise<Task> {
179
- const body: Record<string, unknown> = {};
180
- if (opts.leaseSeconds !== undefined) body.lease_seconds = opts.leaseSeconds;
181
- return request('POST', `${taskBase(orgId, id)}/extend`, apiKey, body);
182
- }
183
-
184
- // resolveTask resolves a task (terminal) — unblocks any dependents.
185
- export async function resolveTask(apiKey: string, orgId: string, id: string): Promise<Task> {
186
- return request('POST', `${taskBase(orgId, id)}/resolve`, apiKey, {});
187
- }
188
-
189
- // failTask fails a task (terminal, with a reason). Does not auto-retry;
190
- // dependents that can never proceed are auto-failed.
191
- export async function failTask(apiKey: string, orgId: string, id: string, reason: string): Promise<Task> {
192
- return request('POST', `${taskBase(orgId, id)}/fail`, apiKey, { reason });
193
- }
194
-
195
- // cancelTask cancels a task (terminal, distinct from fail).
196
- export async function cancelTask(apiKey: string, orgId: string, id: string): Promise<void> {
197
- return request('DELETE', taskBase(orgId, id), apiKey);
198
- }
package/src/types.ts DELETED
@@ -1,15 +0,0 @@
1
- export interface ApiResponse<T> {
2
- success: boolean;
3
- data: T | null;
4
- error: string | null;
5
- // Pagination fields (next_cursor / has_more / limit) appear on keyset-paginated
6
- // list endpoints (backend `envelope.WrapPage`) — read via `requestPage`.
7
- meta: { request_id: string; latency_ms: number; service: string; version: string; next_cursor?: string; has_more?: boolean; limit?: number };
8
- }
9
-
10
- export interface PaginatedResponse<T> {
11
- data: T[];
12
- total: number;
13
- limit: number;
14
- offset: number;
15
- }
package/src/url.ts DELETED
@@ -1,18 +0,0 @@
1
- import { request } from './client';
2
- import { URL_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'POST /url/orgs/{org_id}/shorten',
7
- ];
8
-
9
-
10
-
11
- export interface ShortenResponse {
12
- short_code: string;
13
- short_url: string;
14
- }
15
-
16
- export async function shortenUrl(apiKey: string, orgId: string, url: string): Promise<ShortenResponse> {
17
- return request('POST', `${BASE_URL}/url/orgs/${encodeURIComponent(orgId)}/shorten`, apiKey, { url });
18
- }