@myapihq/sdk 1.2.8 → 1.3.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/dist/task.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ import type { Exposes } from './exposes';
2
+ export declare const EXPOSES: Exposes;
3
+ export type TaskStatus = 'open' | 'claimed' | 'blocked' | 'resolved' | 'failed' | 'cancelled';
4
+ export type TaskImportance = 'low' | 'normal' | 'high' | 'critical';
5
+ export interface ResolveOn {
6
+ event_type: string;
7
+ field?: string;
8
+ value?: string;
9
+ }
10
+ export interface TaskRef {
11
+ id: string;
12
+ description: string;
13
+ score: number;
14
+ }
15
+ export interface Task {
16
+ id: string;
17
+ org_id: string;
18
+ description: string;
19
+ status: TaskStatus;
20
+ importance: TaskImportance;
21
+ score: number;
22
+ tags: string[];
23
+ source: string;
24
+ depends_on: string[];
25
+ payload_url: string;
26
+ assignee?: string;
27
+ resolve_on?: ResolveOn;
28
+ dedup_key?: string;
29
+ claimed_by?: string;
30
+ lease_expires_at?: string;
31
+ due_at?: string;
32
+ fail_reason?: string;
33
+ resolved_at?: string;
34
+ created_at: string;
35
+ updated_at: string;
36
+ }
37
+ export interface TaskListMeta {
38
+ shown: number;
39
+ total_open: number;
40
+ }
41
+ export interface TaskListResult {
42
+ tasks: TaskRef[];
43
+ meta: TaskListMeta;
44
+ }
45
+ export interface CreateTaskOptions {
46
+ description: string;
47
+ body?: string;
48
+ importance?: TaskImportance;
49
+ dueAt?: string;
50
+ assignee?: string;
51
+ tags?: string[];
52
+ dependsOn?: string[];
53
+ dedupKey?: string;
54
+ resolveOn?: ResolveOn;
55
+ source?: string;
56
+ }
57
+ export interface ListTaskOptions {
58
+ status?: string;
59
+ tag?: string;
60
+ importance?: string;
61
+ assignee?: string;
62
+ source?: string;
63
+ limit?: number;
64
+ }
65
+ export declare function createTask(apiKey: string, orgId: string, opts: CreateTaskOptions): Promise<Task>;
66
+ export declare function listTasks(apiKey: string, orgId: string, opts?: ListTaskOptions): Promise<TaskListResult>;
67
+ export declare function getTask(apiKey: string, orgId: string, id: string): Promise<Task>;
68
+ export declare function getTaskBody(apiKey: string, orgId: string, id: string): Promise<string>;
69
+ export declare function claimTask(apiKey: string, orgId: string, id: string, opts?: {
70
+ leaseSeconds?: number;
71
+ worker?: string;
72
+ }): Promise<Task>;
73
+ export declare function extendTask(apiKey: string, orgId: string, id: string, opts?: {
74
+ leaseSeconds?: number;
75
+ }): Promise<Task>;
76
+ export declare function resolveTask(apiKey: string, orgId: string, id: string): Promise<Task>;
77
+ export declare function failTask(apiKey: string, orgId: string, id: string, reason: string): Promise<Task>;
78
+ export declare function cancelTask(apiKey: string, orgId: string, id: string): Promise<void>;
package/dist/task.js ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EXPOSES = void 0;
4
+ exports.createTask = createTask;
5
+ exports.listTasks = listTasks;
6
+ exports.getTask = getTask;
7
+ exports.getTaskBody = getTaskBody;
8
+ exports.claimTask = claimTask;
9
+ exports.extendTask = extendTask;
10
+ exports.resolveTask = resolveTask;
11
+ exports.failTask = failTask;
12
+ exports.cancelTask = cancelTask;
13
+ const client_1 = require("./client");
14
+ const config_1 = require("./config");
15
+ // Backend: my-task-api per myapi-hq/internal/routes/task/. An agent-task
16
+ // queue — the agent-loop hot path. Tasks are created, ranked by score,
17
+ // claimed under a lease, then resolved/failed/cancelled. A task with
18
+ // unresolved depends_on starts blocked; lease expiry auto-reverts a claimed
19
+ // task to open.
20
+ exports.EXPOSES = [
21
+ 'POST /task/orgs/{org_id}/tasks',
22
+ 'GET /task/orgs/{org_id}/tasks',
23
+ 'GET /task/orgs/{org_id}/tasks/{id}',
24
+ 'DELETE /task/orgs/{org_id}/tasks/{id}',
25
+ 'GET /task/orgs/{org_id}/tasks/{id}/body',
26
+ 'POST /task/orgs/{org_id}/tasks/{id}/claim',
27
+ 'POST /task/orgs/{org_id}/tasks/{id}/extend',
28
+ 'POST /task/orgs/{org_id}/tasks/{id}/fail',
29
+ 'POST /task/orgs/{org_id}/tasks/{id}/resolve',
30
+ ];
31
+ function tasksBase(orgId) {
32
+ return `${config_1.TASK_BASE}/task/orgs/${encodeURIComponent(orgId)}/tasks`;
33
+ }
34
+ function taskBase(orgId, id) {
35
+ return `${tasksBase(orgId)}/${encodeURIComponent(id)}`;
36
+ }
37
+ // createTask is idempotent on (org_id, dedup_key). A task with unresolved
38
+ // depends_on starts blocked; one with an assignee emails them a magic link.
39
+ async function createTask(apiKey, orgId, opts) {
40
+ const body = { description: opts.description };
41
+ if (opts.body !== undefined)
42
+ body.body = opts.body;
43
+ if (opts.importance !== undefined)
44
+ body.importance = opts.importance;
45
+ if (opts.dueAt !== undefined)
46
+ body.due_at = opts.dueAt;
47
+ if (opts.assignee !== undefined)
48
+ body.assignee = opts.assignee;
49
+ if (opts.tags !== undefined)
50
+ body.tags = opts.tags;
51
+ if (opts.dependsOn !== undefined)
52
+ body.depends_on = opts.dependsOn;
53
+ if (opts.dedupKey !== undefined)
54
+ body.dedup_key = opts.dedupKey;
55
+ if (opts.resolveOn !== undefined)
56
+ body.resolve_on = opts.resolveOn;
57
+ if (opts.source !== undefined)
58
+ body.source = opts.source;
59
+ return (0, client_1.request)('POST', tasksBase(orgId), apiKey, body);
60
+ }
61
+ // listTasks returns the ranked open queue (projected to TaskRef) plus the
62
+ // backlog counts. Default: top 20 open tasks by score. The backend nests
63
+ // {shown, total_open} inside the response `data.meta` (not the envelope meta).
64
+ async function listTasks(apiKey, orgId, opts = {}) {
65
+ const q = new URLSearchParams();
66
+ if (opts.status)
67
+ q.set('status', opts.status);
68
+ if (opts.tag)
69
+ q.set('tag', opts.tag);
70
+ if (opts.importance)
71
+ q.set('importance', opts.importance);
72
+ if (opts.assignee)
73
+ q.set('assignee', opts.assignee);
74
+ if (opts.source)
75
+ q.set('source', opts.source);
76
+ if (opts.limit !== undefined)
77
+ q.set('limit', String(opts.limit));
78
+ const qs = q.toString();
79
+ const res = await (0, client_1.request)('GET', `${tasksBase(orgId)}${qs ? `?${qs}` : ''}`, apiKey);
80
+ const tasks = res?.tasks ?? [];
81
+ const m = res?.meta ?? {};
82
+ return {
83
+ tasks,
84
+ meta: {
85
+ shown: typeof m.shown === 'number' ? m.shown : tasks.length,
86
+ total_open: typeof m.total_open === 'number' ? m.total_open : tasks.length,
87
+ },
88
+ };
89
+ }
90
+ // getTask returns the full task object. It deliberately does NOT fetch the
91
+ // Markdown body tier — call getTaskBody for that, once, on commit.
92
+ async function getTask(apiKey, orgId, id) {
93
+ return (0, client_1.request)('GET', taskBase(orgId, id), apiKey);
94
+ }
95
+ // getTaskBody fetches the body tier — the full Markdown context. Separate
96
+ // call by design: it keeps the list/get path token-cheap. The endpoint
97
+ // returns { task_id, body }.
98
+ async function getTaskBody(apiKey, orgId, id) {
99
+ const res = await (0, client_1.request)('GET', `${taskBase(orgId, id)}/body`, apiKey);
100
+ return res?.body ?? '';
101
+ }
102
+ // claimTask takes an atomic lease (default 10 min) and returns the full
103
+ // updated task — lease state is on `lease_expires_at` / `claimed_by`.
104
+ async function claimTask(apiKey, orgId, id, opts = {}) {
105
+ const body = {};
106
+ if (opts.leaseSeconds !== undefined)
107
+ body.lease_seconds = opts.leaseSeconds;
108
+ if (opts.worker !== undefined)
109
+ body.worker = opts.worker;
110
+ return (0, client_1.request)('POST', `${taskBase(orgId, id)}/claim`, apiKey, body);
111
+ }
112
+ // extendTask is a heartbeat for long work — extends a live claim.
113
+ async function extendTask(apiKey, orgId, id, opts = {}) {
114
+ const body = {};
115
+ if (opts.leaseSeconds !== undefined)
116
+ body.lease_seconds = opts.leaseSeconds;
117
+ return (0, client_1.request)('POST', `${taskBase(orgId, id)}/extend`, apiKey, body);
118
+ }
119
+ // resolveTask resolves a task (terminal) — unblocks any dependents.
120
+ async function resolveTask(apiKey, orgId, id) {
121
+ return (0, client_1.request)('POST', `${taskBase(orgId, id)}/resolve`, apiKey, {});
122
+ }
123
+ // failTask fails a task (terminal, with a reason). Does not auto-retry;
124
+ // dependents that can never proceed are auto-failed.
125
+ async function failTask(apiKey, orgId, id, reason) {
126
+ return (0, client_1.request)('POST', `${taskBase(orgId, id)}/fail`, apiKey, { reason });
127
+ }
128
+ // cancelTask cancels a task (terminal, distinct from fail).
129
+ async function cancelTask(apiKey, orgId, id) {
130
+ return (0, client_1.request)('DELETE', taskBase(orgId, id), apiKey);
131
+ }
@@ -28,6 +28,12 @@ export type WorkflowStep = {
28
28
  method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
29
29
  body?: string;
30
30
  headers?: Record<string, string>;
31
+ } | {
32
+ type: 'enqueue_job' | 'enqueue';
33
+ queue: string;
34
+ payload?: string;
35
+ dedup_key?: string;
36
+ delay_seconds?: number;
31
37
  };
32
38
  export interface Workflow {
33
39
  id: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@myapihq/sdk",
3
3
  "license": "Apache-2.0",
4
- "version": "1.2.8",
4
+ "version": "1.3.0",
5
5
  "description": "TypeScript SDK for the MyAPI ecosystem",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
package/src/client.ts CHANGED
@@ -72,8 +72,8 @@ export async function request<T>(
72
72
  const err = result?.error;
73
73
  const code = typeof err === 'object' ? (err?.code || 'unknown_error') : (err || 'unknown_error');
74
74
  const detail = typeof err === 'object' ? (err?.message || undefined) : undefined;
75
- const body = typeof err === 'object' ? err : undefined;
76
- throw new MyApiError(code, response.status, detail, body);
75
+ const errBody = typeof err === 'object' ? err : undefined;
76
+ throw new MyApiError(code, response.status, detail, errBody);
77
77
  }
78
78
 
79
79
  const apiResponse = result as ApiResponse<T>;
@@ -81,8 +81,8 @@ export async function request<T>(
81
81
  const err = apiResponse.error as any;
82
82
  const code = typeof err === 'object' ? (err?.code || 'unknown_error') : (err || 'unknown_error');
83
83
  const detail = typeof err === 'object' ? (err?.message || undefined) : undefined;
84
- const body = typeof err === 'object' ? err : undefined;
85
- throw new MyApiError(code, response.status, detail, body);
84
+ const errBody = typeof err === 'object' ? err : undefined;
85
+ throw new MyApiError(code, response.status, detail, errBody);
86
86
  }
87
87
 
88
88
  return apiResponse.data as T;
package/src/config.ts CHANGED
@@ -17,6 +17,9 @@ export const FUNNEL_BASE = process.env.MYAPI_FUNNEL_URL ?? 'https://api.myfunn
17
17
  export const FUNCTION_BASE= process.env.MYAPI_FUNCTION_URL?? GATEWAY;
18
18
  export const PAYMENTS_BASE= process.env.MYAPI_PAYMENTS_URL?? GATEWAY;
19
19
  export const CONTAINER_BASE=process.env.MYAPI_CONTAINER_URL?? GATEWAY;
20
+ export const GIT_BASE = process.env.MYAPI_GIT_URL ?? GATEWAY;
21
+ export const QUEUE_BASE = process.env.MYAPI_QUEUE_URL ?? GATEWAY;
22
+ export const TASK_BASE = process.env.MYAPI_TASK_URL ?? GATEWAY;
20
23
  export const IMAGE_BASE = process.env.MYAPI_IMAGE_URL ?? 'https://api.myimageapi.com';
21
24
  export const WEBHOOK_BASE = process.env.MYAPI_WEBHOOK_URL ?? 'https://api.mywebhookapi.com';
22
25
  export const WORKFLOW_BASE= process.env.MYAPI_WORKFLOW_URL?? 'https://api.myworkflowapi.com';
package/src/email.ts CHANGED
@@ -6,6 +6,8 @@ export const EXPOSES: Exposes = [
6
6
  // Mailbox / sending activation
7
7
  'POST /email/mailboxes/create',
8
8
  'GET /email/mailboxes',
9
+ 'PUT /email/mailboxes/{address}/forwarding',
10
+ 'DELETE /email/mailboxes/{address}/forwarding',
9
11
  'POST /email/sending/activate',
10
12
  // Send + read
11
13
  'POST /email/send',
@@ -43,6 +45,8 @@ export const EXPOSES: Exposes = [
43
45
  'GET /email/orgs/{org_id}/campaigns/{campaign_id}/stats',
44
46
  // Verify
45
47
  'POST /email/orgs/{org_id}/verify',
48
+ 'POST /email/orgs/{org_id}/verify-bulk',
49
+ 'GET /email/orgs/{org_id}/verify-jobs/{id}',
46
50
  ];
47
51
 
48
52
  export interface EmailMessage { message_id: string; from: string; subject: string; body?: string; received_at: string }
@@ -90,6 +94,43 @@ export async function verifyEmail(apiKey: string, orgId: string, email: string):
90
94
  return request('POST', `${BASE_URL}/email/orgs/${encodeURIComponent(orgId)}/verify`, apiKey, { email });
91
95
  }
92
96
 
97
+ // One address's outcome in a bulk-verification job.
98
+ export interface BulkVerifyResult {
99
+ email: string;
100
+ verdict: string; // deliverable | undeliverable | risky | unknown
101
+ confidence: number;
102
+ source: string; // phase1 | strategist | smtp
103
+ classification?: string;
104
+ mx?: string;
105
+ rcpt_code?: number;
106
+ catch_all?: boolean;
107
+ detail?: string;
108
+ }
109
+
110
+ export interface VerifyJob {
111
+ job_id: string;
112
+ status: string; // pending | running | done | failed
113
+ total: number;
114
+ completed?: number;
115
+ catch_all?: boolean;
116
+ results?: BulkVerifyResult[];
117
+ error?: string;
118
+ }
119
+
120
+ // verifyBulk kicks off an asynchronous bulk verification (1-500 addresses)
121
+ // and returns immediately with a job_id. `catchAll` toggles the catch-all
122
+ // check on SMTP-probed addresses (default true). Poll getVerifyJob for
123
+ // status + results.
124
+ export async function verifyBulk(apiKey: string, orgId: string, emails: string[], catchAll?: boolean): Promise<VerifyJob> {
125
+ const body: { emails: string[]; catch_all?: boolean } = { emails };
126
+ if (catchAll !== undefined) body.catch_all = catchAll;
127
+ return request('POST', `${BASE_URL}/email/orgs/${encodeURIComponent(orgId)}/verify-bulk`, apiKey, body);
128
+ }
129
+
130
+ export async function getVerifyJob(apiKey: string, orgId: string, jobId: string): Promise<VerifyJob> {
131
+ return request('GET', `${BASE_URL}/email/orgs/${encodeURIComponent(orgId)}/verify-jobs/${encodeURIComponent(jobId)}`, apiKey);
132
+ }
133
+
93
134
  // ── Mailbox ops (account-scoped) ─────────────────────────────────────────────
94
135
 
95
136
  export async function createMailbox(apiKey: string, domain: string, username: string, displayName?: string): Promise<{ address: string; created_at: string }> {
@@ -112,6 +153,18 @@ export async function activateSending(apiKey: string, address: string): Promise<
112
153
  return request('POST', `${BASE_URL}/email/sending/activate`, apiKey, { address });
113
154
  }
114
155
 
156
+ // setForwarding redirects a copy of every incoming message to an external
157
+ // address (server-side; the original is kept in the mailbox). `forwardTo`
158
+ // must be a valid address and cannot equal the mailbox itself.
159
+ export async function setForwarding(apiKey: string, address: string, forwardTo: string): Promise<{ address: string; forward_to: string }> {
160
+ return request('PUT', `${BASE_URL}/email/mailboxes/${encodeURIComponent(address)}/forwarding`, apiKey, { forward_to: forwardTo });
161
+ }
162
+
163
+ // deleteForwarding stops forwarding for a mailbox.
164
+ export async function deleteForwarding(apiKey: string, address: string): Promise<void> {
165
+ return request('DELETE', `${BASE_URL}/email/mailboxes/${encodeURIComponent(address)}/forwarding`, apiKey);
166
+ }
167
+
115
168
  // ── Sending and reading (account-scoped) ─────────────────────────────────────
116
169
 
117
170
  export async function sendEmail(apiKey: string, payload: { from: string; to: string[]; subject: string; html?: string; text?: string; template_id?: string; template_vars?: Record<string, string> }): Promise<{ message_id: string }> {
package/src/git.ts ADDED
@@ -0,0 +1,171 @@
1
+ import { request } from './client';
2
+ import { GIT_BASE as BASE_URL } from './config';
3
+ import type { Exposes } from './exposes';
4
+
5
+ // Backend: my-git-api per myapi-hq/internal/routes/git/. A stateless
6
+ // git-over-HTTP surface — repositories, refs, commits, and history served
7
+ // by a go-git engine (objects in GCS packfiles, refs in Postgres).
8
+ export const EXPOSES: Exposes = [
9
+ 'POST /git/orgs/{org_id}/repos',
10
+ 'GET /git/orgs/{org_id}/repos',
11
+ 'GET /git/orgs/{org_id}/repos/{repo}',
12
+ 'DELETE /git/orgs/{org_id}/repos/{repo}',
13
+ 'GET /git/orgs/{org_id}/repos/{repo}/refs',
14
+ 'GET /git/orgs/{org_id}/repos/{repo}/tree/{ref}',
15
+ 'GET /git/orgs/{org_id}/repos/{repo}/blob/{ref}/{path}',
16
+ 'GET /git/orgs/{org_id}/repos/{repo}/commits',
17
+ 'GET /git/orgs/{org_id}/repos/{repo}/commits/{sha}',
18
+ 'GET /git/orgs/{org_id}/repos/{repo}/diff',
19
+ 'POST /git/orgs/{org_id}/repos/{repo}/commits',
20
+ 'POST /git/orgs/{org_id}/repos/{repo}/branches',
21
+ 'DELETE /git/orgs/{org_id}/repos/{repo}/branches/{branch}',
22
+ 'POST /git/orgs/{org_id}/repos/{repo}/tags',
23
+ 'POST /git/orgs/{org_id}/repos/{repo}/merges',
24
+ 'POST /git/orgs/{org_id}/repos/{repo}/repack',
25
+ ];
26
+
27
+ export interface RepoSummary { name: string }
28
+ export interface Repo {
29
+ name: string;
30
+ default_branch: string;
31
+ branches: number;
32
+ tags: number;
33
+ }
34
+ export interface RefInfo { name: string; sha: string }
35
+ export interface Refs {
36
+ head: string; // symbolic HEAD target, e.g. "refs/heads/main"
37
+ branches: RefInfo[];
38
+ tags: RefInfo[];
39
+ }
40
+ export interface TreeEntry {
41
+ name: string;
42
+ path: string;
43
+ type: 'file' | 'dir';
44
+ mode: string;
45
+ sha: string;
46
+ size: number;
47
+ }
48
+ export interface CommitInfo {
49
+ sha: string;
50
+ message: string;
51
+ author: string;
52
+ email: string;
53
+ when: string;
54
+ parents: string[];
55
+ }
56
+ export interface CommitResult { sha: string; tree: string; branch: string }
57
+ export interface RepackResult { packs_before: number; packs_after: number; objects: number }
58
+ export interface Blob { path: string; size: number; content_base64: string }
59
+
60
+ // One file edit in an atomic commit. Either `content` (UTF-8 text) or
61
+ // `content_base64` (binary); set `delete` to remove the path instead.
62
+ export interface FileChange {
63
+ path: string;
64
+ content?: string;
65
+ content_base64?: string;
66
+ delete?: boolean;
67
+ mode?: string; // "100644" (default), "100755" (exec), "120000" (symlink)
68
+ }
69
+ export interface CommitPayload {
70
+ branch: string; // required — short name or full ref
71
+ base?: string; // expected branch tip; "" => branch must not exist
72
+ message: string;
73
+ author?: { name: string; email: string };
74
+ changes: FileChange[];
75
+ }
76
+
77
+ function repoBase(orgId: string, repo: string): string {
78
+ return `${BASE_URL}/git/orgs/${encodeURIComponent(orgId)}/repos/${encodeURIComponent(repo)}`;
79
+ }
80
+
81
+ // ── Repos ────────────────────────────────────────────────────────────────────
82
+
83
+ export async function createRepo(apiKey: string, orgId: string, name: string, defaultBranch?: string): Promise<{ name: string; default_branch: string }> {
84
+ const body: Record<string, string> = { name };
85
+ if (defaultBranch) body.default_branch = defaultBranch;
86
+ return request('POST', `${BASE_URL}/git/orgs/${encodeURIComponent(orgId)}/repos`, apiKey, body);
87
+ }
88
+
89
+ export async function listRepos(apiKey: string, orgId: string): Promise<RepoSummary[]> {
90
+ const res = await request<{ repos?: RepoSummary[] }>('GET', `${BASE_URL}/git/orgs/${encodeURIComponent(orgId)}/repos`, apiKey);
91
+ return res?.repos ?? [];
92
+ }
93
+
94
+ export async function getRepo(apiKey: string, orgId: string, repo: string): Promise<Repo> {
95
+ return request('GET', repoBase(orgId, repo), apiKey);
96
+ }
97
+
98
+ export async function deleteRepo(apiKey: string, orgId: string, repo: string): Promise<void> {
99
+ return request('DELETE', repoBase(orgId, repo), apiKey);
100
+ }
101
+
102
+ // ── Refs / history ───────────────────────────────────────────────────────────
103
+
104
+ export async function listRefs(apiKey: string, orgId: string, repo: string): Promise<Refs> {
105
+ return request('GET', `${repoBase(orgId, repo)}/refs`, apiKey);
106
+ }
107
+
108
+ // listCommits walks history from `ref` (default HEAD); `limit` is 1-500.
109
+ export async function listCommits(apiKey: string, orgId: string, repo: string, opts: { ref?: string; limit?: number } = {}): Promise<CommitInfo[]> {
110
+ const q = new URLSearchParams();
111
+ if (opts.ref) q.set('ref', opts.ref);
112
+ if (opts.limit !== undefined) q.set('limit', String(opts.limit));
113
+ const qs = q.toString();
114
+ const res = await request<{ commits?: CommitInfo[] }>('GET', `${repoBase(orgId, repo)}/commits${qs ? `?${qs}` : ''}`, apiKey);
115
+ return res?.commits ?? [];
116
+ }
117
+
118
+ export async function getCommit(apiKey: string, orgId: string, repo: string, sha: string): Promise<CommitInfo> {
119
+ return request('GET', `${repoBase(orgId, repo)}/commits/${encodeURIComponent(sha)}`, apiKey);
120
+ }
121
+
122
+ // getDiff returns the unified diff text between two refs.
123
+ export async function getDiff(apiKey: string, orgId: string, repo: string, base: string, head: string): Promise<string> {
124
+ const q = new URLSearchParams({ base, head });
125
+ const res = await request<{ diff?: string }>('GET', `${repoBase(orgId, repo)}/diff?${q}`, apiKey);
126
+ return res?.diff ?? '';
127
+ }
128
+
129
+ // listTree lists a ref's tree; `path` scopes it to a subdirectory.
130
+ export async function listTree(apiKey: string, orgId: string, repo: string, ref: string, path?: string): Promise<TreeEntry[]> {
131
+ const qs = path ? `?path=${encodeURIComponent(path)}` : '';
132
+ const res = await request<{ entries?: TreeEntry[] }>('GET', `${repoBase(orgId, repo)}/tree/${encodeURIComponent(ref)}${qs}`, apiKey);
133
+ return res?.entries ?? [];
134
+ }
135
+
136
+ // readBlob returns a file's content (base64-encoded — safe for binary).
137
+ export async function readBlob(apiKey: string, orgId: string, repo: string, ref: string, path: string): Promise<Blob> {
138
+ // The backend route is /blob/{ref}/{path...} — a catch-all — so slashes
139
+ // in the path must survive; encode each segment, not the separators.
140
+ const encPath = path.split('/').map(encodeURIComponent).join('/');
141
+ return request('GET', `${repoBase(orgId, repo)}/blob/${encodeURIComponent(ref)}/${encPath}`, apiKey);
142
+ }
143
+
144
+ // ── Writes ───────────────────────────────────────────────────────────────────
145
+
146
+ // commit applies all `changes` atomically onto `branch`.
147
+ export async function commit(apiKey: string, orgId: string, repo: string, payload: CommitPayload): Promise<CommitResult> {
148
+ return request('POST', `${repoBase(orgId, repo)}/commits`, apiKey, payload);
149
+ }
150
+
151
+ export async function createBranch(apiKey: string, orgId: string, repo: string, name: string, from: string): Promise<{ name: string }> {
152
+ return request('POST', `${repoBase(orgId, repo)}/branches`, apiKey, { name, from });
153
+ }
154
+
155
+ export async function deleteBranch(apiKey: string, orgId: string, repo: string, branch: string): Promise<void> {
156
+ return request('DELETE', `${repoBase(orgId, repo)}/branches/${encodeURIComponent(branch)}`, apiKey);
157
+ }
158
+
159
+ export async function createTag(apiKey: string, orgId: string, repo: string, name: string, ref: string): Promise<{ name: string }> {
160
+ return request('POST', `${repoBase(orgId, repo)}/tags`, apiKey, { name, ref });
161
+ }
162
+
163
+ // merge fast-forwards `target` to `source` (fast-forward only).
164
+ export async function merge(apiKey: string, orgId: string, repo: string, target: string, source: string): Promise<{ sha: string }> {
165
+ return request('POST', `${repoBase(orgId, repo)}/merges`, apiKey, { target, source });
166
+ }
167
+
168
+ // repack compacts the repository's incremental packfiles into one.
169
+ export async function repack(apiKey: string, orgId: string, repo: string): Promise<RepackResult> {
170
+ return request('POST', `${repoBase(orgId, repo)}/repack`, apiKey);
171
+ }
package/src/index.ts CHANGED
@@ -25,3 +25,6 @@ export * as crm from './crm';
25
25
  export * as fn from './function';
26
26
  export * as payments from './payments';
27
27
  export * as container from './container';
28
+ export * as git from './git';
29
+ export * as queue from './queue';
30
+ export * as task from './task';
package/src/pixel.ts CHANGED
@@ -66,8 +66,10 @@ export async function getEvents(apiKey: string, orgId: string, params: { campaig
66
66
  return request('GET', url, apiKey);
67
67
  }
68
68
 
69
- export async function getIdentity(apiKey: string, orgId: string, pixelId: string): Promise<{ uuid: string; is_resolved: boolean; nodes: Record<string, { type: string; probability: number }>; latency_ms: number }> {
70
- return request('GET', `${BASE_URL}/pixel/orgs/${encodeURIComponent(orgId)}/identity/${encodeURIComponent(pixelId)}`, apiKey);
69
+ // getIdentity resolves a pixel's identity graph. `website` is required
70
+ // the backend scopes the lookup to a domain the org owns.
71
+ export async function getIdentity(apiKey: string, orgId: string, pixelId: string, website: string): Promise<{ uuid: string; is_resolved: boolean; nodes: Record<string, { type: string; probability: number }>; latency_ms: number }> {
72
+ return request('GET', `${BASE_URL}/pixel/orgs/${encodeURIComponent(orgId)}/identity/${encodeURIComponent(pixelId)}?website=${encodeURIComponent(website)}`, apiKey);
71
73
  }
72
74
 
73
75
  // Sample of geographic distribution of the org's pixel audience. Backend
package/src/queue.ts ADDED
@@ -0,0 +1,110 @@
1
+ import { request } from './client';
2
+ import { QUEUE_BASE as BASE_URL } from './config';
3
+ import type { Exposes } from './exposes';
4
+
5
+ // Backend: my-queue-api per myapi-hq/internal/routes/queue/. A durable
6
+ // HTTP-consumer job queue — each named queue POSTs its jobs to a configured
7
+ // consumer_url, with retry/backoff to max_attempts, a concurrency cap, and a
8
+ // dependency DAG (a job with unsucceeded depends_on starts blocked).
9
+ export const EXPOSES: Exposes = [
10
+ 'POST /queue/orgs/{org_id}/queues',
11
+ 'GET /queue/orgs/{org_id}/queues',
12
+ 'GET /queue/orgs/{org_id}/queues/{name}',
13
+ 'POST /queue/orgs/{org_id}/queues/{name}/jobs',
14
+ 'GET /queue/orgs/{org_id}/queues/{name}/jobs',
15
+ 'GET /queue/orgs/{org_id}/jobs/{id}',
16
+ ];
17
+
18
+ export interface Queue {
19
+ id: string;
20
+ org_id: string;
21
+ name: string;
22
+ consumer_url: string;
23
+ max_attempts: number;
24
+ max_concurrency: number;
25
+ created_at: string;
26
+ }
27
+
28
+ // A job that exhausts max_attempts goes straight to `dead` — there is no
29
+ // separate `failed` state.
30
+ export type JobStatus = 'pending' | 'blocked' | 'running' | 'succeeded' | 'dead';
31
+
32
+ export interface Job {
33
+ id: string;
34
+ queue_id: string;
35
+ org_id: string;
36
+ payload: unknown;
37
+ status: JobStatus;
38
+ attempt: number;
39
+ max_attempts: number;
40
+ not_before: string;
41
+ depends_on: string[];
42
+ dedup_key?: string;
43
+ last_error?: string;
44
+ started_at?: string;
45
+ created_at: string;
46
+ updated_at: string;
47
+ }
48
+
49
+ export interface CreateQueueOptions {
50
+ name: string;
51
+ consumerUrl: string;
52
+ maxAttempts?: number;
53
+ maxConcurrency?: number;
54
+ }
55
+
56
+ export interface EnqueueOptions {
57
+ payload?: unknown;
58
+ dedupKey?: string;
59
+ delaySeconds?: number;
60
+ // Job ids this job waits on. Immutable — the DAG is declared at enqueue.
61
+ // Same shape as task.create's depends_on.
62
+ dependsOn?: string[];
63
+ }
64
+
65
+ function queuesBase(orgId: string): string {
66
+ return `${BASE_URL}/queue/orgs/${encodeURIComponent(orgId)}/queues`;
67
+ }
68
+
69
+ // createQueue registers a named queue with its retry + concurrency policy
70
+ // and the HTTP consumer that runs its jobs.
71
+ export async function createQueue(apiKey: string, orgId: string, opts: CreateQueueOptions): Promise<Queue> {
72
+ const body: Record<string, unknown> = { name: opts.name, consumer_url: opts.consumerUrl };
73
+ if (opts.maxAttempts !== undefined) body.max_attempts = opts.maxAttempts;
74
+ if (opts.maxConcurrency !== undefined) body.max_concurrency = opts.maxConcurrency;
75
+ return request('POST', queuesBase(orgId), apiKey, body);
76
+ }
77
+
78
+ export async function listQueues(apiKey: string, orgId: string): Promise<Queue[]> {
79
+ const res = await request<{ queues?: Queue[] }>('GET', queuesBase(orgId), apiKey);
80
+ return res?.queues ?? [];
81
+ }
82
+
83
+ export async function getQueue(apiKey: string, orgId: string, name: string): Promise<Queue> {
84
+ return request('GET', `${queuesBase(orgId)}/${encodeURIComponent(name)}`, apiKey);
85
+ }
86
+
87
+ // enqueueJob is idempotent on (queue, dedup_key). A job with unsucceeded
88
+ // depends_on starts blocked.
89
+ export async function enqueueJob(apiKey: string, orgId: string, name: string, opts: EnqueueOptions = {}): Promise<Job> {
90
+ const body: Record<string, unknown> = {};
91
+ if (opts.payload !== undefined) body.payload = opts.payload;
92
+ if (opts.dedupKey !== undefined) body.dedup_key = opts.dedupKey;
93
+ if (opts.delaySeconds !== undefined) body.delay_seconds = opts.delaySeconds;
94
+ if (opts.dependsOn !== undefined) body.depends_on = opts.dependsOn;
95
+ return request('POST', `${queuesBase(orgId)}/${encodeURIComponent(name)}/jobs`, apiKey, body);
96
+ }
97
+
98
+ // listJobs lists a queue's jobs, newest first. `limit` is 1-200.
99
+ export async function listJobs(apiKey: string, orgId: string, name: string, opts: { status?: string; limit?: number } = {}): Promise<Job[]> {
100
+ const q = new URLSearchParams();
101
+ if (opts.status) q.set('status', opts.status);
102
+ if (opts.limit !== undefined) q.set('limit', String(opts.limit));
103
+ const qs = q.toString();
104
+ const res = await request<{ jobs?: Job[] }>('GET', `${queuesBase(orgId)}/${encodeURIComponent(name)}/jobs${qs ? `?${qs}` : ''}`, apiKey);
105
+ return res?.jobs ?? [];
106
+ }
107
+
108
+ export async function getJob(apiKey: string, orgId: string, jobId: string): Promise<Job> {
109
+ return request('GET', `${BASE_URL}/queue/orgs/${encodeURIComponent(orgId)}/jobs/${encodeURIComponent(jobId)}`, apiKey);
110
+ }