totalum-sdk 0.1.0-dev.3 → 0.1.0-dev.5
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 +7 -3
- package/dist/_types/billing.d-Cj9gNbAW.d.ts +38 -0
- package/dist/_types/coerce.d-C1KWvgPp.d.ts +6 -0
- package/dist/_types/errors.d-ZrZKjL3U.d.ts +2991 -0
- package/dist/_types/integrations.d-Cii20Vl4.d.ts +793 -0
- package/dist/_types/ops.d-BIgDkhpR.d.ts +117 -0
- package/dist/ai/index.d.ts +424 -0
- package/dist/ai/index.js +185 -0
- package/dist/analytics/index.d.ts +35 -0
- package/dist/analytics/index.js +15 -0
- package/dist/browser/index.d.ts +1442 -0
- package/dist/browser/index.js +168 -0
- package/dist/cron/index.d.ts +180 -0
- package/dist/cron/index.js +61 -0
- package/dist/d1/errors.js +5 -13
- package/dist/d1/index.d.ts +90 -5
- package/dist/d1/index.js +6 -10
- package/dist/email/index.d.ts +31 -0
- package/dist/email/index.js +30 -0
- package/dist/errors.js +35 -0
- package/dist/files/index.d.ts +119 -0
- package/dist/files/index.js +63 -0
- package/dist/http.js +85 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +68 -0
- package/dist/logs/index.d.ts +51 -0
- package/dist/logs/index.js +18 -0
- package/dist/payments/index.d.ts +47 -0
- package/dist/payments/index.js +20 -0
- package/dist/pdf/index.d.ts +42 -0
- package/dist/pdf/index.js +17 -0
- package/dist/realtime/index.d.ts +68 -0
- package/dist/realtime/index.js +20 -0
- package/dist/scan/index.d.ts +46 -0
- package/dist/scan/index.js +12 -0
- package/dist/seo/index.d.ts +23 -0
- package/dist/seo/index.js +12 -0
- package/dist/speech/index.d.ts +41 -0
- package/dist/speech/index.js +22 -0
- package/dist/web/index.d.ts +170 -0
- package/dist/web/index.js +31 -0
- package/dist/webhooks/index.d.ts +48 -0
- package/dist/webhooks/index.js +61 -0
- package/package.json +78 -9
- package/totalum-sdk.md +1040 -0
- package/dist/d1/errors.d.ts +0 -27
- package/dist/d1/https.d.ts +0 -10
- package/dist/d1/lazy.d.ts +0 -7
- package/dist/d1/libsql.d.ts +0 -23
- package/dist/d1/sql.d.ts +0 -9
- package/dist/d1/types.d.ts +0 -72
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { TotalumError } from '../errors.js';
|
|
2
|
+
import { jsonClient } from '../http.js';
|
|
3
|
+
export { TotalumError, isTotalumError } from '../errors.js';
|
|
4
|
+
/** The frozen 67 (contracts `BROWSER_COMMANDS`, plan 11 §3.4) as a literal, so nothing is imported at runtime. */
|
|
5
|
+
const BROWSER_COMMANDS = [
|
|
6
|
+
...[
|
|
7
|
+
'goto',
|
|
8
|
+
'back',
|
|
9
|
+
'forward',
|
|
10
|
+
'reload',
|
|
11
|
+
'pageInfo',
|
|
12
|
+
'click',
|
|
13
|
+
'dblclick',
|
|
14
|
+
'type',
|
|
15
|
+
'press',
|
|
16
|
+
'hover',
|
|
17
|
+
],
|
|
18
|
+
...[
|
|
19
|
+
'scroll',
|
|
20
|
+
'dragAndDrop',
|
|
21
|
+
'select',
|
|
22
|
+
'upload',
|
|
23
|
+
'frames.list',
|
|
24
|
+
'frames.use',
|
|
25
|
+
'tabs.list',
|
|
26
|
+
'tabs.new',
|
|
27
|
+
],
|
|
28
|
+
...['tabs.use', 'tabs.close', 'waitFor', 'evaluate', 'content', 'screenshot', 'pdf', 'extract'],
|
|
29
|
+
...[
|
|
30
|
+
'cookies.get',
|
|
31
|
+
'cookies.set',
|
|
32
|
+
'cookies.clear',
|
|
33
|
+
'storage.get',
|
|
34
|
+
'storage.set',
|
|
35
|
+
'storage.clear',
|
|
36
|
+
],
|
|
37
|
+
...[
|
|
38
|
+
'context.save',
|
|
39
|
+
'downloads.list',
|
|
40
|
+
'downloads.get',
|
|
41
|
+
'network.capture',
|
|
42
|
+
'network.log',
|
|
43
|
+
'network.har',
|
|
44
|
+
],
|
|
45
|
+
...[
|
|
46
|
+
'network.intercept',
|
|
47
|
+
'network.setHeaders',
|
|
48
|
+
'emulate.viewport',
|
|
49
|
+
'emulate.device',
|
|
50
|
+
'emulate.geolocation',
|
|
51
|
+
],
|
|
52
|
+
...[
|
|
53
|
+
'emulate.timezone',
|
|
54
|
+
'emulate.locale',
|
|
55
|
+
'emulate.userAgent',
|
|
56
|
+
'captcha.solve',
|
|
57
|
+
'captcha.events',
|
|
58
|
+
],
|
|
59
|
+
...[
|
|
60
|
+
'proxy.usage',
|
|
61
|
+
'stealth.get',
|
|
62
|
+
'session.status',
|
|
63
|
+
'session.liveView',
|
|
64
|
+
'session.recording',
|
|
65
|
+
'dialog.handle',
|
|
66
|
+
],
|
|
67
|
+
...[
|
|
68
|
+
'page.addInitScript',
|
|
69
|
+
'page.exposeFunction',
|
|
70
|
+
'emulate.media',
|
|
71
|
+
'emulate.network',
|
|
72
|
+
'emulate.cpu',
|
|
73
|
+
],
|
|
74
|
+
...[
|
|
75
|
+
'permissions.grant',
|
|
76
|
+
'clipboard.read',
|
|
77
|
+
'clipboard.write',
|
|
78
|
+
'act',
|
|
79
|
+
'observe',
|
|
80
|
+
'session.release',
|
|
81
|
+
],
|
|
82
|
+
...['network.subscribe', 'accessibility.snapshot'],
|
|
83
|
+
];
|
|
84
|
+
/** The leading positional arguments of a command method; the last argument is always the rest of its parameters. */
|
|
85
|
+
const POSITIONAL = {
|
|
86
|
+
goto: ['url'],
|
|
87
|
+
click: ['target'],
|
|
88
|
+
dblclick: ['target'],
|
|
89
|
+
type: ['target', 'text'],
|
|
90
|
+
press: ['key'],
|
|
91
|
+
hover: ['target'],
|
|
92
|
+
select: ['target', 'value'],
|
|
93
|
+
upload: ['target', 'files'],
|
|
94
|
+
dragAndDrop: ['from', 'to'],
|
|
95
|
+
evaluate: ['expression'],
|
|
96
|
+
'cookies.set': ['cookies'],
|
|
97
|
+
act: ['instruction'],
|
|
98
|
+
observe: ['instruction'],
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* `totalum.browser` (plan 05 §6.3) over SDK-API `/v1/browser/*` (scope `browser`): Browserbase sessions driven entirely
|
|
102
|
+
* over HTTPS, so every command works from a Worker (A6.29). A command's refusal throws `TotalumError` with its frozen
|
|
103
|
+
* code (`ACTION_TIMEOUT`, `ACTION_FAILED`, …); `actions()` returns every result instead.
|
|
104
|
+
*/
|
|
105
|
+
export function totalumBrowser(options = {}) {
|
|
106
|
+
const call = jsonClient(options);
|
|
107
|
+
const path = (id) => `/v1/browser/sessions/${encodeURIComponent(id)}`;
|
|
108
|
+
function handle(created) {
|
|
109
|
+
const run = async (command) => {
|
|
110
|
+
const { results } = await call('POST', `${path(created.id)}/actions`, {
|
|
111
|
+
action: command,
|
|
112
|
+
});
|
|
113
|
+
const r = results[0];
|
|
114
|
+
if (!r?.ok)
|
|
115
|
+
throw new TotalumError(r?.error?.code ?? 'ACTION_FAILED', r?.error?.message ?? 'Browser command failed', 400);
|
|
116
|
+
return r.data;
|
|
117
|
+
};
|
|
118
|
+
const methods = {};
|
|
119
|
+
for (const type of BROWSER_COMMANDS) {
|
|
120
|
+
const names = POSITIONAL[type] ?? [];
|
|
121
|
+
const method = (...args) => {
|
|
122
|
+
const params = Object.fromEntries(names.map((n, i) => [n, args[i]]));
|
|
123
|
+
return run({ ...args[names.length], ...params, type });
|
|
124
|
+
};
|
|
125
|
+
const [group, name] = type.split('.');
|
|
126
|
+
if (name && group)
|
|
127
|
+
(methods[group] ??= {})[name] = method;
|
|
128
|
+
else
|
|
129
|
+
methods[type] = method;
|
|
130
|
+
}
|
|
131
|
+
return Object.assign(methods, {
|
|
132
|
+
id: created.id,
|
|
133
|
+
liveViewUrl: created.liveViewUrl ?? '',
|
|
134
|
+
expiresAt: created.expiresAt ?? '',
|
|
135
|
+
actions: async (batch, opts = {}) => (await call('POST', `${path(created.id)}/actions`, { actions: batch, ...opts }))
|
|
136
|
+
.results,
|
|
137
|
+
program: (program) => call('POST', `${path(created.id)}/program`, program),
|
|
138
|
+
status: () => call('GET', path(created.id)),
|
|
139
|
+
close: () => call('DELETE', path(created.id)),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
/** Opens a session with the vendor options and the Totalum-synthesised ones. */
|
|
144
|
+
session: async (opts = {}) => handle(await call('POST', '/v1/browser/sessions', opts)),
|
|
145
|
+
sessions: {
|
|
146
|
+
/** The project's sessions, filtered by `status` or `metadata`. */
|
|
147
|
+
list: (q = {}) => call('GET', `/v1/browser/sessions?${Object.entries(q)
|
|
148
|
+
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
|
|
149
|
+
.join('&')}`),
|
|
150
|
+
/** A handle on an existing session (no call is made). */
|
|
151
|
+
get: (id) => handle({ id }),
|
|
152
|
+
},
|
|
153
|
+
programs: {
|
|
154
|
+
/** A program's status and, once finished, its results. */
|
|
155
|
+
get: (programId) => call('GET', `/v1/browser/programs/${encodeURIComponent(programId)}`),
|
|
156
|
+
/** Polls until the program leaves `pending`/`running` (the `browser.program.completed` webhook is the push twin). */
|
|
157
|
+
wait: async (programId, opts = {}) => {
|
|
158
|
+
const until = Date.now() + (opts.timeoutMs ?? 960_000);
|
|
159
|
+
for (;;) {
|
|
160
|
+
const s = await call('GET', `/v1/browser/programs/${encodeURIComponent(programId)}`);
|
|
161
|
+
if ((s.status !== 'pending' && s.status !== 'running') || Date.now() > until)
|
|
162
|
+
return s;
|
|
163
|
+
await new Promise((r) => setTimeout(r, opts.intervalMs ?? 2000));
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { c as CronJobInput, b as CronJob, d as CronJobPatch } from '../_types/integrations.d-Cii20Vl4.js';
|
|
2
|
+
export { e as CronRun, f as CronRunsPage } from '../_types/integrations.d-Cii20Vl4.js';
|
|
3
|
+
import { T as TotalumClientOptions } from '../_types/errors.d-ZrZKjL3U.js';
|
|
4
|
+
export { a as TotalumError, i as isTotalumError } from '../_types/errors.d-ZrZKjL3U.js';
|
|
5
|
+
import '../_types/coerce.d-C1KWvgPp.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `totalum.cron` (plan 05 §6.9) over SDK-API `/v1/cron/*` (scope `cron`): HTTP jobs against the project's own host,
|
|
9
|
+
* fired by Totalum's Scheduler; limits per plan (`429 CRON_LIMIT_REACHED {limit, plan}`, `400 INVALID_SCHEDULE
|
|
10
|
+
* {minIntervalSeconds}`). Executions cost nothing.
|
|
11
|
+
*/
|
|
12
|
+
declare function totalumCron(options?: TotalumClientOptions): {
|
|
13
|
+
/**
|
|
14
|
+
* A job that calls a URL of the project's own host on a cron `schedule` (or `{ everyMinutes }`).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* await cron.create({
|
|
18
|
+
* name: 'daily-report',
|
|
19
|
+
* schedule: '0 8 * * *',
|
|
20
|
+
* request: { method: 'POST', url: 'https://my-app.totalum-project.com/api/cron/report' },
|
|
21
|
+
* });
|
|
22
|
+
*/
|
|
23
|
+
create: (input: CronJobInput) => Promise<{
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
schedule: string | {
|
|
27
|
+
everyMinutes: number;
|
|
28
|
+
};
|
|
29
|
+
request: {
|
|
30
|
+
method: "GET" | "POST";
|
|
31
|
+
url: string;
|
|
32
|
+
headers?: Record<string, string> | undefined;
|
|
33
|
+
body?: string | undefined;
|
|
34
|
+
timeoutMs?: number | undefined;
|
|
35
|
+
};
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
status: "active" | "paused" | "paused_failures";
|
|
38
|
+
nextRunAt: string | null;
|
|
39
|
+
createdAt: string;
|
|
40
|
+
env: "dev" | "live";
|
|
41
|
+
lastRun?: {
|
|
42
|
+
at: string;
|
|
43
|
+
status: number | "error" | "timeout" | "skipped";
|
|
44
|
+
latencyMs: number;
|
|
45
|
+
} | undefined;
|
|
46
|
+
description?: string | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
/** Every job of the project. */
|
|
49
|
+
list: () => Promise<{
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
schedule: string | {
|
|
53
|
+
everyMinutes: number;
|
|
54
|
+
};
|
|
55
|
+
request: {
|
|
56
|
+
method: "GET" | "POST";
|
|
57
|
+
url: string;
|
|
58
|
+
headers?: Record<string, string> | undefined;
|
|
59
|
+
body?: string | undefined;
|
|
60
|
+
timeoutMs?: number | undefined;
|
|
61
|
+
};
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
status: "active" | "paused" | "paused_failures";
|
|
64
|
+
nextRunAt: string | null;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
env: "dev" | "live";
|
|
67
|
+
lastRun?: {
|
|
68
|
+
at: string;
|
|
69
|
+
status: number | "error" | "timeout" | "skipped";
|
|
70
|
+
latencyMs: number;
|
|
71
|
+
} | undefined;
|
|
72
|
+
description?: string | undefined;
|
|
73
|
+
}[]>;
|
|
74
|
+
/** `null` when the job is not this project's. */
|
|
75
|
+
get: (id: string) => Promise<CronJob | null>;
|
|
76
|
+
/** Changes any field of a job (`schedule`, `request`, `enabled`, …). */
|
|
77
|
+
update: (id: string, patch: CronJobPatch) => Promise<{
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
schedule: string | {
|
|
81
|
+
everyMinutes: number;
|
|
82
|
+
};
|
|
83
|
+
request: {
|
|
84
|
+
method: "GET" | "POST";
|
|
85
|
+
url: string;
|
|
86
|
+
headers?: Record<string, string> | undefined;
|
|
87
|
+
body?: string | undefined;
|
|
88
|
+
timeoutMs?: number | undefined;
|
|
89
|
+
};
|
|
90
|
+
enabled: boolean;
|
|
91
|
+
status: "active" | "paused" | "paused_failures";
|
|
92
|
+
nextRunAt: string | null;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
env: "dev" | "live";
|
|
95
|
+
lastRun?: {
|
|
96
|
+
at: string;
|
|
97
|
+
status: number | "error" | "timeout" | "skipped";
|
|
98
|
+
latencyMs: number;
|
|
99
|
+
} | undefined;
|
|
100
|
+
description?: string | undefined;
|
|
101
|
+
}>;
|
|
102
|
+
/** Deletes a job. */
|
|
103
|
+
delete: (id: string) => Promise<void>;
|
|
104
|
+
/** Stops a job from firing until `resume`. */
|
|
105
|
+
pause: (id: string) => Promise<{
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
schedule: string | {
|
|
109
|
+
everyMinutes: number;
|
|
110
|
+
};
|
|
111
|
+
request: {
|
|
112
|
+
method: "GET" | "POST";
|
|
113
|
+
url: string;
|
|
114
|
+
headers?: Record<string, string> | undefined;
|
|
115
|
+
body?: string | undefined;
|
|
116
|
+
timeoutMs?: number | undefined;
|
|
117
|
+
};
|
|
118
|
+
enabled: boolean;
|
|
119
|
+
status: "active" | "paused" | "paused_failures";
|
|
120
|
+
nextRunAt: string | null;
|
|
121
|
+
createdAt: string;
|
|
122
|
+
env: "dev" | "live";
|
|
123
|
+
lastRun?: {
|
|
124
|
+
at: string;
|
|
125
|
+
status: number | "error" | "timeout" | "skipped";
|
|
126
|
+
latencyMs: number;
|
|
127
|
+
} | undefined;
|
|
128
|
+
description?: string | undefined;
|
|
129
|
+
}>;
|
|
130
|
+
/** Lets a paused job fire again. */
|
|
131
|
+
resume: (id: string) => Promise<{
|
|
132
|
+
id: string;
|
|
133
|
+
name: string;
|
|
134
|
+
schedule: string | {
|
|
135
|
+
everyMinutes: number;
|
|
136
|
+
};
|
|
137
|
+
request: {
|
|
138
|
+
method: "GET" | "POST";
|
|
139
|
+
url: string;
|
|
140
|
+
headers?: Record<string, string> | undefined;
|
|
141
|
+
body?: string | undefined;
|
|
142
|
+
timeoutMs?: number | undefined;
|
|
143
|
+
};
|
|
144
|
+
enabled: boolean;
|
|
145
|
+
status: "active" | "paused" | "paused_failures";
|
|
146
|
+
nextRunAt: string | null;
|
|
147
|
+
createdAt: string;
|
|
148
|
+
env: "dev" | "live";
|
|
149
|
+
lastRun?: {
|
|
150
|
+
at: string;
|
|
151
|
+
status: number | "error" | "timeout" | "skipped";
|
|
152
|
+
latencyMs: number;
|
|
153
|
+
} | undefined;
|
|
154
|
+
description?: string | undefined;
|
|
155
|
+
}>;
|
|
156
|
+
/** A job's executions, newest first (30 days). */
|
|
157
|
+
runs: (id: string, opts?: {
|
|
158
|
+
limit?: number;
|
|
159
|
+
cursor?: string;
|
|
160
|
+
}) => Promise<{
|
|
161
|
+
items: {
|
|
162
|
+
id: string;
|
|
163
|
+
scheduledFor: string;
|
|
164
|
+
startedAt: string | null;
|
|
165
|
+
status: number | "error" | "timeout" | "skipped";
|
|
166
|
+
latencyMs: number | null;
|
|
167
|
+
error?: string | undefined;
|
|
168
|
+
responseSnippet?: string | undefined;
|
|
169
|
+
}[];
|
|
170
|
+
nextCursor: string | null;
|
|
171
|
+
}>;
|
|
172
|
+
/** Fires a job now, outside its schedule. */
|
|
173
|
+
trigger: (id: string) => Promise<{
|
|
174
|
+
runId: string;
|
|
175
|
+
}>;
|
|
176
|
+
};
|
|
177
|
+
type TotalumCron = ReturnType<typeof totalumCron>;
|
|
178
|
+
|
|
179
|
+
export { CronJob, CronJobInput, CronJobPatch, TotalumClientOptions, totalumCron };
|
|
180
|
+
export type { TotalumCron };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isTotalumError } from '../errors.js';
|
|
2
|
+
import { jsonClient } from '../http.js';
|
|
3
|
+
export { TotalumError, isTotalumError } from '../errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* `totalum.cron` (plan 05 §6.9) over SDK-API `/v1/cron/*` (scope `cron`): HTTP jobs against the project's own host,
|
|
6
|
+
* fired by Totalum's Scheduler; limits per plan (`429 CRON_LIMIT_REACHED {limit, plan}`, `400 INVALID_SCHEDULE
|
|
7
|
+
* {minIntervalSeconds}`). Executions cost nothing.
|
|
8
|
+
*/
|
|
9
|
+
export function totalumCron(options = {}) {
|
|
10
|
+
const call = jsonClient(options);
|
|
11
|
+
const job = (id) => `/v1/cron/jobs/${encodeURIComponent(id)}`;
|
|
12
|
+
const update = (id, patch) => call('PATCH', job(id), patch);
|
|
13
|
+
return {
|
|
14
|
+
/**
|
|
15
|
+
* A job that calls a URL of the project's own host on a cron `schedule` (or `{ everyMinutes }`).
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* await cron.create({
|
|
19
|
+
* name: 'daily-report',
|
|
20
|
+
* schedule: '0 8 * * *',
|
|
21
|
+
* request: { method: 'POST', url: 'https://my-app.totalum-project.com/api/cron/report' },
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
create: (input) => call('POST', '/v1/cron/jobs', input),
|
|
25
|
+
/** Every job of the project. */
|
|
26
|
+
list: async () => (await call('GET', '/v1/cron/jobs')).items,
|
|
27
|
+
/** `null` when the job is not this project's. */
|
|
28
|
+
get: async (id) => {
|
|
29
|
+
try {
|
|
30
|
+
return await call('GET', job(id));
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
if (isTotalumError(e) && e.errorCode === 'CRON_JOB_NOT_FOUND')
|
|
34
|
+
return null;
|
|
35
|
+
throw e;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
/** Changes any field of a job (`schedule`, `request`, `enabled`, …). */
|
|
39
|
+
update,
|
|
40
|
+
/** Deletes a job. */
|
|
41
|
+
delete: async (id) => {
|
|
42
|
+
await call('DELETE', job(id));
|
|
43
|
+
},
|
|
44
|
+
/** Stops a job from firing until `resume`. */
|
|
45
|
+
pause: (id) => update(id, { enabled: false }),
|
|
46
|
+
/** Lets a paused job fire again. */
|
|
47
|
+
resume: (id) => update(id, { enabled: true }),
|
|
48
|
+
/** A job's executions, newest first (30 days). */
|
|
49
|
+
runs: (id, opts = {}) => {
|
|
50
|
+
const q = new URLSearchParams();
|
|
51
|
+
if (opts.limit !== undefined)
|
|
52
|
+
q.set('limit', String(opts.limit));
|
|
53
|
+
if (opts.cursor !== undefined)
|
|
54
|
+
q.set('cursor', opts.cursor);
|
|
55
|
+
const qs = q.toString();
|
|
56
|
+
return call('GET', `${job(id)}/runs${qs ? `?${qs}` : ''}`);
|
|
57
|
+
},
|
|
58
|
+
/** Fires a job now, outside its schedule. */
|
|
59
|
+
trigger: (id) => call('POST', `${job(id)}/trigger`),
|
|
60
|
+
};
|
|
61
|
+
}
|
package/dist/d1/errors.js
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
|
+
import { TotalumError } from '../errors.js';
|
|
1
2
|
/**
|
|
2
|
-
* The database
|
|
3
|
-
*
|
|
3
|
+
* The database `TotalumError` (plan 05 §3.5): `message` is `D1_ERROR: …`-shaped so it reads like a native failure —
|
|
4
|
+
* byte-identical to the binding's message when the failure is SQLite's.
|
|
4
5
|
*/
|
|
5
|
-
export class TotalumD1Error extends
|
|
6
|
+
export class TotalumD1Error extends TotalumError {
|
|
6
7
|
name = 'TotalumD1Error';
|
|
7
|
-
errorCode;
|
|
8
|
-
/** HTTP status; 0 for network errors, 500 for client-side refusals. */
|
|
9
|
-
status;
|
|
10
|
-
details;
|
|
11
|
-
requestId;
|
|
12
8
|
constructor(errorCode, message, options = {}) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.errorCode = errorCode;
|
|
15
|
-
this.status = options.status ?? 500;
|
|
16
|
-
this.details = options.details;
|
|
17
|
-
this.requestId = options.requestId;
|
|
9
|
+
super(errorCode, message, options.status ?? 500, options.details, options.requestId);
|
|
18
10
|
}
|
|
19
11
|
/** A client-side refusal (`D1_ERROR: <code>: <message>`). */
|
|
20
12
|
static client(errorCode, message) {
|
package/dist/d1/index.d.ts
CHANGED
|
@@ -1,10 +1,95 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
1
|
+
import { S as SdkClientErrorCode, a as TotalumError, b as TotalumErrorCode, E as ErrorBody } from '../_types/errors.d-ZrZKjL3U.js';
|
|
2
|
+
import { TotalumClientOptions } from '../ai/index.js';
|
|
3
|
+
export { i as isTotalumError } from '../_types/errors.d-ZrZKjL3U.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cloudflare's `D1Database` surface, re-declared structurally so an app needs no Cloudflare types to compile
|
|
7
|
+
* and `drizzle-orm/d1` accepts the object (plan 05 §1, §3.1). `D1Meta` is Cloudflare's own interface
|
|
8
|
+
* (`size_after` required); the contracts wire shape is looser and every value here satisfies it (type-tested).
|
|
9
|
+
*/
|
|
10
|
+
type D1Meta = {
|
|
11
|
+
duration: number;
|
|
12
|
+
size_after: number;
|
|
13
|
+
rows_read: number;
|
|
14
|
+
rows_written: number;
|
|
15
|
+
last_row_id: number;
|
|
16
|
+
changed_db: boolean;
|
|
17
|
+
changes: number;
|
|
18
|
+
served_by_region?: string;
|
|
19
|
+
served_by_primary?: boolean;
|
|
20
|
+
};
|
|
21
|
+
interface D1Result<T = Record<string, unknown>> {
|
|
22
|
+
results: T[];
|
|
23
|
+
success: true;
|
|
24
|
+
meta: D1Meta;
|
|
25
|
+
}
|
|
26
|
+
interface D1ExecResult {
|
|
27
|
+
count: number;
|
|
28
|
+
duration: number;
|
|
29
|
+
}
|
|
30
|
+
interface D1PreparedStatement {
|
|
31
|
+
bind(...values: unknown[]): D1PreparedStatement;
|
|
32
|
+
first<T = Record<string, unknown>>(colName?: string): Promise<T | null>;
|
|
33
|
+
run<T = Record<string, unknown>>(): Promise<D1Result<T>>;
|
|
34
|
+
all<T = Record<string, unknown>>(): Promise<D1Result<T>>;
|
|
35
|
+
raw<T = unknown[]>(options: {
|
|
36
|
+
columnNames: true;
|
|
37
|
+
}): Promise<[string[], ...T[]]>;
|
|
38
|
+
raw<T = unknown[]>(options?: {
|
|
39
|
+
columnNames?: false;
|
|
40
|
+
}): Promise<T[]>;
|
|
41
|
+
}
|
|
42
|
+
interface D1DatabaseSession {
|
|
43
|
+
prepare(sql: string): D1PreparedStatement;
|
|
44
|
+
batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
|
|
45
|
+
getBookmark(): string | null;
|
|
46
|
+
}
|
|
47
|
+
interface D1Database {
|
|
48
|
+
prepare(sql: string): D1PreparedStatement;
|
|
49
|
+
batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
|
|
50
|
+
exec(sql: string): Promise<D1ExecResult>;
|
|
51
|
+
dump(): Promise<ArrayBuffer>;
|
|
52
|
+
withSession(constraintOrBookmark?: string): D1DatabaseSession;
|
|
53
|
+
}
|
|
54
|
+
/** `key`, `apiUrl` and `env` (HTTPS path only) resolve exactly as in every other namespace. */
|
|
55
|
+
interface TotalumD1Options extends TotalumClientOptions {
|
|
56
|
+
/** `'migrate'` (scripts/migrate.ts only) sends `x-totalum-migrate: 1` and enables `exec()`; default `'query'`. */
|
|
57
|
+
mode?: 'query' | 'migrate';
|
|
58
|
+
/** Migrate mode only: sends `x-totalum-migrate-destructive: 1` (A10.4). */
|
|
59
|
+
destructive?: boolean;
|
|
60
|
+
/** An explicit binding wins over detection (plain Workers: `env.TOTALUM_DB`; tests: a Miniflare D1). */
|
|
61
|
+
binding?: D1Database;
|
|
62
|
+
/** `'https'` forces the HTTPS path even inside a Worker (the conformance corpus); default `'auto'`. */
|
|
63
|
+
transport?: 'auto' | 'https';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The client-side codes the driver throws (plan 05 §7.2), from contracts' `SDK_CLIENT_ERROR_CODES`. */
|
|
67
|
+
type TotalumD1ClientCode = Extract<SdkClientErrorCode, 'SDK_NOT_CONFIGURED' | 'NOT_SUPPORTED' | 'BATCH_FOREIGN_STATEMENT' | 'NETWORK_ERROR' | 'RESPONSE_PARSE_ERROR'>;
|
|
68
|
+
type TotalumD1ErrorCode = TotalumErrorCode;
|
|
69
|
+
/**
|
|
70
|
+
* The database `TotalumError` (plan 05 §3.5): `message` is `D1_ERROR: …`-shaped so it reads like a native failure —
|
|
71
|
+
* byte-identical to the binding's message when the failure is SQLite's.
|
|
72
|
+
*/
|
|
73
|
+
declare class TotalumD1Error extends TotalumError {
|
|
74
|
+
name: string;
|
|
75
|
+
constructor(errorCode: TotalumD1ErrorCode, message: string, options?: {
|
|
76
|
+
status?: number;
|
|
77
|
+
details?: Record<string, unknown>;
|
|
78
|
+
requestId?: string;
|
|
79
|
+
});
|
|
80
|
+
/** A client-side refusal (`D1_ERROR: <code>: <message>`). */
|
|
81
|
+
static client(errorCode: TotalumD1ClientCode | 'EXEC_REQUIRES_MIGRATE_MODE', message: string): TotalumD1Error;
|
|
82
|
+
/** The SDK-API error envelope → typed error; `SQL_ERROR` rebuilds the native message from `sqliteMessage`. */
|
|
83
|
+
static fromWire(errors: ErrorBody, status: number, requestId: string | undefined): TotalumD1Error;
|
|
84
|
+
}
|
|
85
|
+
declare function isTotalumD1Error(e: unknown): e is TotalumD1Error;
|
|
86
|
+
|
|
5
87
|
/**
|
|
6
88
|
* A `D1Database` for the project's own database wherever the code runs (A3.4, plan 05 §3): the bound
|
|
7
89
|
* `TOTALUM_DB` inside a Worker, the libsql adapter when the environment moved to Turso, and an HTTPS client to
|
|
8
90
|
* SDK-API everywhere else. Detection happens on the first statement, never at call time (§3.1).
|
|
9
91
|
*/
|
|
10
|
-
|
|
92
|
+
declare function totalumD1(options?: TotalumD1Options): D1Database;
|
|
93
|
+
|
|
94
|
+
export { TotalumD1Error, TotalumError, TotalumErrorCode, isTotalumD1Error, totalumD1 };
|
|
95
|
+
export type { D1Database, D1DatabaseSession, D1ExecResult, D1PreparedStatement, D1Result, TotalumD1ClientCode, TotalumD1ErrorCode, TotalumD1Options };
|
package/dist/d1/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { inWorker } from '../errors.js';
|
|
2
|
+
import { apiUrlOf, envOf, readEnv } from '../http.js';
|
|
1
3
|
import { TotalumD1Error } from './errors.js';
|
|
2
4
|
import { httpsExecutor } from './https.js';
|
|
3
5
|
import { lazyD1 } from './lazy.js';
|
|
4
6
|
import { libsqlExecutor } from './libsql.js';
|
|
7
|
+
export { TotalumError, isTotalumError } from '../errors.js';
|
|
5
8
|
export { TotalumD1Error, isTotalumD1Error } from './errors.js';
|
|
6
|
-
const DEFAULT_API_URL = 'https://sdk-api.totalum.app';
|
|
7
9
|
/**
|
|
8
10
|
* A `D1Database` for the project's own database wherever the code runs (A3.4, plan 05 §3): the bound
|
|
9
11
|
* `TOTALUM_DB` inside a Worker, the libsql adapter when the environment moved to Turso, and an HTTPS client to
|
|
@@ -15,8 +17,7 @@ export function totalumD1(options = {}) {
|
|
|
15
17
|
async function resolveTarget(options) {
|
|
16
18
|
if (options.binding)
|
|
17
19
|
return options.binding;
|
|
18
|
-
|
|
19
|
-
if (inWorker && options.transport !== 'https') {
|
|
20
|
+
if (inWorker() && options.transport !== 'https') {
|
|
20
21
|
if (readEnv('TOTALUM_DB_PROVIDER') === 'turso')
|
|
21
22
|
return await tursoTarget();
|
|
22
23
|
const binding = await openNextBinding();
|
|
@@ -28,18 +29,13 @@ async function resolveTarget(options) {
|
|
|
28
29
|
throw TotalumD1Error.client('SDK_NOT_CONFIGURED', 'Set TOTALUM_PROJECT_KEY (server-side) or pass { binding } to totalumD1().');
|
|
29
30
|
}
|
|
30
31
|
return httpsExecutor({
|
|
31
|
-
apiUrl: options
|
|
32
|
+
apiUrl: apiUrlOf(options),
|
|
32
33
|
key,
|
|
33
|
-
env: options
|
|
34
|
+
env: envOf(options),
|
|
34
35
|
migrate: options.mode === 'migrate',
|
|
35
36
|
destructive: options.destructive === true,
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
|
-
/** Env is `process.env` (Node; workerd with `nodejs_compat`, where OpenNext and Miniflare populate it from bindings). */
|
|
39
|
-
function readEnv(name) {
|
|
40
|
-
const value = typeof process === 'undefined' ? undefined : process.env[name];
|
|
41
|
-
return value === '' ? undefined : value;
|
|
42
|
-
}
|
|
43
39
|
/** OpenNext exposes the request's bindings; absent (a laptop) or outside a request, there is no binding. */
|
|
44
40
|
async function openNextBinding() {
|
|
45
41
|
try {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { E as EmailSendInput, j as EmailView } from '../_types/integrations.d-Cii20Vl4.js';
|
|
2
|
+
export { i as EmailSendOutput } from '../_types/integrations.d-Cii20Vl4.js';
|
|
3
|
+
import { T as TotalumClientOptions } from '../_types/errors.d-ZrZKjL3U.js';
|
|
4
|
+
export { a as TotalumError, i as isTotalumError } from '../_types/errors.d-ZrZKjL3U.js';
|
|
5
|
+
import '../_types/coerce.d-C1KWvgPp.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `totalum.email` (plan 05 §6.4) over SDK-API `/v1/email/*` (scope `email`): Resend, HTML sent byte for byte, charged
|
|
9
|
+
* per recipient. On dev only allow-listed recipients are accepted (`DEV_RECIPIENT_NOT_ALLOWED`).
|
|
10
|
+
*/
|
|
11
|
+
declare function totalumEmail(options?: TotalumClientOptions): {
|
|
12
|
+
/**
|
|
13
|
+
* Sends one e-mail (HTML byte for byte); charged per recipient.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* await email.send({ to: 'ana@example.com', subject: 'Welcome', html: '<p>Hi Ana</p>' });
|
|
17
|
+
*/
|
|
18
|
+
send: (msg: EmailSendInput) => Promise<{
|
|
19
|
+
success: true;
|
|
20
|
+
message: "Email sent successfully";
|
|
21
|
+
messageId: string;
|
|
22
|
+
id: string;
|
|
23
|
+
status: "queued" | "sent";
|
|
24
|
+
}>;
|
|
25
|
+
/** `null` when the e-mail is not this project's. */
|
|
26
|
+
get: (id: string) => Promise<EmailView | null>;
|
|
27
|
+
};
|
|
28
|
+
type TotalumEmail = ReturnType<typeof totalumEmail>;
|
|
29
|
+
|
|
30
|
+
export { EmailSendInput, EmailView, TotalumClientOptions, totalumEmail };
|
|
31
|
+
export type { TotalumEmail };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isTotalumError } from '../errors.js';
|
|
2
|
+
import { jsonClient } from '../http.js';
|
|
3
|
+
export { TotalumError, isTotalumError } from '../errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* `totalum.email` (plan 05 §6.4) over SDK-API `/v1/email/*` (scope `email`): Resend, HTML sent byte for byte, charged
|
|
6
|
+
* per recipient. On dev only allow-listed recipients are accepted (`DEV_RECIPIENT_NOT_ALLOWED`).
|
|
7
|
+
*/
|
|
8
|
+
export function totalumEmail(options = {}) {
|
|
9
|
+
const call = jsonClient(options);
|
|
10
|
+
return {
|
|
11
|
+
/**
|
|
12
|
+
* Sends one e-mail (HTML byte for byte); charged per recipient.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* await email.send({ to: 'ana@example.com', subject: 'Welcome', html: '<p>Hi Ana</p>' });
|
|
16
|
+
*/
|
|
17
|
+
send: (msg) => call('POST', '/v1/email/send', msg),
|
|
18
|
+
/** `null` when the e-mail is not this project's. */
|
|
19
|
+
get: async (id) => {
|
|
20
|
+
try {
|
|
21
|
+
return await call('GET', `/v1/email/${encodeURIComponent(id)}`);
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
if (isTotalumError(e) && e.status === 404)
|
|
25
|
+
return null;
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|