@sovaria/sdk 0.0.0-stage → 0.4.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.
@@ -0,0 +1,1054 @@
1
+ function dropUndefined(obj) {
2
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined && v !== null));
3
+ }
4
+ function need(name, value) {
5
+ const text = String(value ?? '').trim();
6
+ if (!text)
7
+ throw new Error(`${name} is required`);
8
+ return text;
9
+ }
10
+ /** Every Sovaria API operation, grouped by module. */
11
+ export function createGeneratedApi(request, scope) {
12
+ return {
13
+ attestation: {
14
+ /** App attestation settings, credentials (metadata only), debug tokens and the last 7 days. `GET /api/v1/projects/{project_id}/attestation` */
15
+ getConfig: (args = {}) => {
16
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
17
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation`);
18
+ },
19
+ /** Set mode (off | monitor | enforce), tokenTtlSeconds, providers, playIntegrity, appAttest. `PUT /api/v1/projects/{project_id}/attestation` */
20
+ updateConfig: (args) => {
21
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
22
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation`, { body: args.body });
23
+ },
24
+ /** Google service account for Play Integrity (encrypted, write-only). `PUT /api/v1/projects/{project_id}/attestation/credentials/google` */
25
+ setGoogleCredentials: (args) => {
26
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
27
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation/credentials/google`, { body: dropUndefined({ "service_account": args.serviceAccount }) });
28
+ },
29
+ /** Apple key with DeviceCheck enabled (encrypted, write-only). `PUT /api/v1/projects/{project_id}/attestation/credentials/apple` */
30
+ setAppleCredentials: (args) => {
31
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
32
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation/credentials/apple`, { body: dropUndefined({ "p8": args.p8, "key_id": args.keyId, "team_id": args.teamId }) });
33
+ },
34
+ /** Remove the google or apple attestation credentials. `DELETE /api/v1/projects/{project_id}/attestation/credentials/{which}` */
35
+ deleteCredentials: (args) => {
36
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
37
+ const which = need('which', args.which);
38
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation/credentials/${encodeURIComponent(which)}`);
39
+ },
40
+ /** Create a debug token for simulators and CI (shown once). `POST /api/v1/projects/{project_id}/attestation/debug-tokens` */
41
+ createDebugToken: (args = {}) => {
42
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
43
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation/debug-tokens`, { body: dropUndefined({ "name": args.name }) });
44
+ },
45
+ /** Delete a debug token. `DELETE /api/v1/projects/{project_id}/attestation/debug-tokens/{token_id}` */
46
+ deleteDebugToken: (args) => {
47
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
48
+ const tokenId = need('token_id', args.tokenId);
49
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/attestation/debug-tokens/${encodeURIComponent(tokenId)}`);
50
+ },
51
+ /** One-time challenge to bind attestation evidence to (anon key). `POST /api/v1/attest/challenge` */
52
+ challenge: () => request('POST', `/api/v1/attest/challenge`, { body: {} }),
53
+ /** Exchange Play Integrity / App Attest / DeviceCheck / debug evidence for an attestation token. `POST /api/v1/attest/exchange` */
54
+ exchange: (args) => request('POST', `/api/v1/attest/exchange`, { body: dropUndefined({ "provider": args.provider, "app_id": args.appId, "challenge": args.challenge, "token": args.token, "key_id": args.keyId, "attestation": args.attestation, "assertion": args.assertion, "development": args.development }) }),
55
+ },
56
+ auth: {
57
+ /** Confirm an email verification token. `POST /api/v1/auth/verify-email/confirm` */
58
+ confirmVerificationEmail: (args) => request('POST', `/api/v1/auth/verify-email/confirm`, { body: dropUndefined({ "token": args.token }), requiresAuth: false }),
59
+ /** `DELETE /api/v1/auth/mfa` */
60
+ disableMfa: (args) => request('DELETE', `/api/v1/auth/mfa`, { body: dropUndefined({ "totp_code": args.totpCode }) }),
61
+ /** `POST /api/v1/auth/mfa/enroll` */
62
+ enrollMfa: () => request('POST', `/api/v1/auth/mfa/enroll`, { body: {} }),
63
+ /** `GET /api/v1/auth/mfa/status` */
64
+ getMfaStatus: () => request('GET', `/api/v1/auth/mfa/status`),
65
+ /** `GET /api/v1/auth/providers/config` */
66
+ getProvidersConfig: () => request('GET', `/api/v1/auth/providers/config`),
67
+ /** `GET /api/v1/auth/sessions/config` */
68
+ getSessionsConfig: () => request('GET', `/api/v1/auth/sessions/config`),
69
+ /** `GET /api/v1/auth/product-users` */
70
+ listConsoleProductUsers: () => request('GET', `/api/v1/auth/product-users`),
71
+ /** `GET /api/v1/auth/sessions` */
72
+ listSessions: () => request('GET', `/api/v1/auth/sessions`),
73
+ /** `POST /api/v1/auth/sessions/revoke-others` */
74
+ revokeOtherSessions: () => request('POST', `/api/v1/auth/sessions/revoke-others`, { body: {} }),
75
+ /** `DELETE /api/v1/auth/sessions/{session_id}` */
76
+ revokeSession: (args) => {
77
+ const sessionId = need('session_id', args.sessionId);
78
+ return request('DELETE', `/api/v1/auth/sessions/${encodeURIComponent(sessionId)}`);
79
+ },
80
+ /** Trigger a verification email for the authenticated user. `POST /api/v1/auth/verify-email/send` */
81
+ sendVerificationEmail: () => request('POST', `/api/v1/auth/verify-email/send`, { body: {} }),
82
+ /** `PUT /api/v1/auth/providers/config` */
83
+ updateProvidersConfig: (args) => request('PUT', `/api/v1/auth/providers/config`, { body: args.body }),
84
+ /** `PUT /api/v1/auth/sessions/config` */
85
+ updateSessionsConfig: (args) => request('PUT', `/api/v1/auth/sessions/config`, { body: args.body }),
86
+ /** Devices the signed-in user is signed in on (current = this one). `GET /api/v1/auth/devices` */
87
+ listDevices: () => request('GET', `/api/v1/auth/devices`),
88
+ /** Sign one device out: its sessions end and push tokens are removed. `DELETE /api/v1/auth/devices/{device_id}` */
89
+ signOutDevice: (args) => {
90
+ const deviceId = need('device_id', args.deviceId);
91
+ return request('DELETE', `/api/v1/auth/devices/${encodeURIComponent(deviceId)}`);
92
+ },
93
+ },
94
+ billing: {
95
+ /** `POST /api/v1/invoices/{org_id}/build` */
96
+ buildInvoice: (args = {}) => {
97
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
98
+ return request('POST', `/api/v1/invoices/${encodeURIComponent(orgId)}/build`, { query: dropUndefined({ "period": args.period }) });
99
+ },
100
+ /** `POST /api/v1/accounts/{account_id}/cancel` */
101
+ cancelAccount: (args) => {
102
+ const accountId = need('account_id', args.accountId);
103
+ return request('POST', `/api/v1/accounts/${encodeURIComponent(accountId)}/cancel`);
104
+ },
105
+ /** `POST /api/v1/billing/checkout` */
106
+ checkout: (args) => request('POST', `/api/v1/billing/checkout`, { body: args.body }),
107
+ /** `GET /api/v1/accounts/{account_id}` */
108
+ getAccount: (args) => {
109
+ const accountId = need('account_id', args.accountId);
110
+ return request('GET', `/api/v1/accounts/${encodeURIComponent(accountId)}`);
111
+ },
112
+ /** `GET /api/v1/billing/accounts/{account_id}/overage` */
113
+ getAccountOverage: (args) => {
114
+ const accountId = need('account_id', args.accountId);
115
+ return request('GET', `/api/v1/billing/accounts/${encodeURIComponent(accountId)}/overage`);
116
+ },
117
+ /** `GET /api/v1/billing/accounts/{account_id}/overage-prefs` */
118
+ getAccountOveragePrefs: (args) => {
119
+ const accountId = need('account_id', args.accountId);
120
+ return request('GET', `/api/v1/billing/accounts/${encodeURIComponent(accountId)}/overage-prefs`);
121
+ },
122
+ /** The org's overage switches (one setting for the whole org) `GET /api/v1/billing/orgs/{org_id}/overage-prefs` */
123
+ getOrgOveragePrefs: (args = {}) => {
124
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
125
+ return request('GET', `/api/v1/billing/orgs/${encodeURIComponent(orgId)}/overage-prefs`);
126
+ },
127
+ /** `GET /api/v1/compute/{org_id}` */
128
+ getCompute: (args = {}) => {
129
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
130
+ return request('GET', `/api/v1/compute/${encodeURIComponent(orgId)}`, { query: dropUndefined({ "period": args.period }) });
131
+ },
132
+ /** `GET /api/v1/billing/fx` */
133
+ getFx: () => request('GET', `/api/v1/billing/fx`),
134
+ /** `GET /api/v1/billing/invoices/open` */
135
+ getOpenInvoice: () => request('GET', `/api/v1/billing/invoices/open`),
136
+ /** `GET /api/v1/billing/overage/{org_id}` */
137
+ getOverage: (args = {}) => {
138
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
139
+ return request('GET', `/api/v1/billing/overage/${encodeURIComponent(orgId)}`);
140
+ },
141
+ /** Fetch a billing plan by name. `GET /api/v1/plans/{name}` */
142
+ getPlan: (args) => {
143
+ const name = need('name', args.name);
144
+ return request('GET', `/api/v1/plans/${encodeURIComponent(name)}`, { requiresAuth: false });
145
+ },
146
+ /** `GET /api/v1/billing/provider` */
147
+ getProvider: () => request('GET', `/api/v1/billing/provider`),
148
+ /** Fetch the active subscription for an organisation. `GET /api/v1/subscriptions/{org_id}` */
149
+ getSubscription: (args = {}) => {
150
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
151
+ return request('GET', `/api/v1/subscriptions/${encodeURIComponent(orgId)}`);
152
+ },
153
+ /** Fetch usage counters for an organisation. `GET /api/v1/usage/{org_id}` */
154
+ getUsage: (args = {}) => {
155
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
156
+ return request('GET', `/api/v1/usage/${encodeURIComponent(orgId)}`, { query: dropUndefined({ "period": args.period }) });
157
+ },
158
+ /** Fetch historical usage for an organisation. `GET /api/v1/usage/{org_id}/history` */
159
+ getUsageHistory: (args = {}) => {
160
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
161
+ return request('GET', `/api/v1/usage/${encodeURIComponent(orgId)}/history`, { query: dropUndefined({ "months": args.months }) });
162
+ },
163
+ /** `GET /api/v1/invoices/{org_id}` */
164
+ listInvoices: (args = {}) => {
165
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
166
+ return request('GET', `/api/v1/invoices/${encodeURIComponent(orgId)}`);
167
+ },
168
+ /** List public billing plans. `GET /api/v1/plans` */
169
+ listPlans: () => request('GET', `/api/v1/plans`, { requiresAuth: false }),
170
+ /** List subscriptions visible to the authenticated caller. `GET /api/v1/subscriptions` */
171
+ listSubscriptions: () => request('GET', `/api/v1/subscriptions`),
172
+ /** `POST /api/v1/billing/invoices/{org_id}/{period}/pay` */
173
+ payInvoice: (args) => {
174
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
175
+ const period = need('period', args.period);
176
+ return request('POST', `/api/v1/billing/invoices/${encodeURIComponent(orgId)}/${encodeURIComponent(period)}/pay`);
177
+ },
178
+ /** `POST /api/v1/billing/razorpay/create-order` */
179
+ razorpayCreateOrder: (args) => request('POST', `/api/v1/billing/razorpay/create-order`, { body: args.body }),
180
+ /** `POST /api/v1/billing/razorpay/verify-payment` */
181
+ razorpayVerifyPayment: (args) => request('POST', `/api/v1/billing/razorpay/verify-payment`, { body: args.body }),
182
+ /** `POST /api/v1/accounts/{account_id}/resume` */
183
+ resumeAccount: (args) => {
184
+ const accountId = need('account_id', args.accountId);
185
+ return request('POST', `/api/v1/accounts/${encodeURIComponent(accountId)}/resume`);
186
+ },
187
+ /** `PUT /api/v1/billing/accounts/{account_id}/overage-prefs` */
188
+ setAccountOveragePrefs: (args) => {
189
+ const accountId = need('account_id', args.accountId);
190
+ return request('PUT', `/api/v1/billing/accounts/${encodeURIComponent(accountId)}/overage-prefs`, { body: dropUndefined({ "services": args.services }) });
191
+ },
192
+ /** Change the org's overage switches (org owners and admins) `PUT /api/v1/billing/orgs/{org_id}/overage-prefs` */
193
+ setOrgOveragePrefs: (args) => {
194
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
195
+ return request('PUT', `/api/v1/billing/orgs/${encodeURIComponent(orgId)}/overage-prefs`, { body: dropUndefined({ "services": args.services }) });
196
+ },
197
+ },
198
+ builds: {
199
+ /** Check an app build Sovariq wrote (title, description, migration {name, up_sql, down_sql}, policies [{id, spl}], functions [{name, runtime, files}], tests [rules test cases]) against the project — nothing changes: the migration is dry-run up, down and up again, rules are simulated, rules tests run with the build's rules. Returns the build id and the report. `POST /api/v1/fn/builds/check` */
200
+ check: (args) => request('POST', `/api/v1/fn/builds/check`, { body: dropUndefined({ "build": args.build }) }),
201
+ /** Recent app builds of the project: title, status (checked, failed, pr_opened), each check's result and the pull request. `GET /api/v1/fn/builds` */
202
+ list: (args = {}) => request('GET', `/api/v1/fn/builds`, { query: dropUndefined({ "limit": args.limit }) }),
203
+ /** One app build: its files (the bundle), the check report and the pull request. `GET /api/v1/fn/builds/{build_id}` */
204
+ get: (args) => {
205
+ const buildId = need('build_id', args.buildId);
206
+ return request('GET', `/api/v1/fn/builds/${encodeURIComponent(buildId)}`);
207
+ },
208
+ /** Check the build again and open it as a pull request on the project's linked GitHub repository (one commit on a new branch; dev.app_build_prs_month). GitHub needs repository access: connect it with repository access or pass a token with repo scope. `POST /api/v1/fn/builds/{build_id}/pull-request` */
209
+ pullRequest: (args) => {
210
+ const buildId = need('build_id', args.buildId);
211
+ return request('POST', `/api/v1/fn/builds/${encodeURIComponent(buildId)}/pull-request`, { body: dropUndefined({ "token": args.token }) });
212
+ },
213
+ /** Forget an app build (its pull request, if opened, stays on GitHub). `DELETE /api/v1/fn/builds/{build_id}` */
214
+ delete: (args) => {
215
+ const buildId = need('build_id', args.buildId);
216
+ return request('DELETE', `/api/v1/fn/builds/${encodeURIComponent(buildId)}`);
217
+ },
218
+ },
219
+ byok: {
220
+ /** Your organization's own encryption key (Enterprise): whether it's on, the key, its data key version, whether it is usable now, what it covers, and setup (Sovaria's AWS principal and the key policy statement). `GET /api/v1/byok` */
221
+ get: () => request('GET', `/api/v1/byok`),
222
+ /** Use your AWS KMS key (its ARN) for the organization's storage files and backups. Checked end to end first (wrap, unwrap, a file written and read with it). Organization owners. `PUT /api/v1/byok` */
223
+ set: (args) => request('PUT', `/api/v1/byok`, { body: dropUndefined({ "provider": args.provider, "key_ref": args.keyRef }) }),
224
+ /** A new data key version under the same KMS key; older versions stay to decrypt what they encrypted. Organization owners. `POST /api/v1/byok/rotate` */
225
+ rotate: () => request('POST', `/api/v1/byok/rotate`),
226
+ /** Ask your KMS now whether Sovaria can still use the key. `POST /api/v1/byok/check` */
227
+ check: () => request('POST', `/api/v1/byok/check`),
228
+ /** Rewrite the organization's existing storage files under its key (in the background; progress in byok.get). Organization owners. `POST /api/v1/byok/reencrypt-storage` */
229
+ reencryptStorage: () => request('POST', `/api/v1/byok/reencrypt-storage`),
230
+ },
231
+ crashes: {
232
+ /** App crash issues of the project (grouped reports from sov.crashes), newest first, with the plan's limits. `GET /api/v1/crashes/issues` */
233
+ listIssues: (args = {}) => request('GET', `/api/v1/crashes/issues`, { query: dropUndefined({ "status": args.status, "limit": args.limit }) }),
234
+ /** One crash issue: sample report (stack, breadcrumbs, device, release) and its last 50 reports. `GET /api/v1/crashes/issues/{fingerprint}` */
235
+ getIssue: (args) => {
236
+ const fingerprint = need('fingerprint', args.fingerprint);
237
+ return request('GET', `/api/v1/crashes/issues/${encodeURIComponent(fingerprint)}`);
238
+ },
239
+ /** Mark a crash issue open, resolved (reopens if it happens again) or ignored. `POST /api/v1/crashes/issues/{fingerprint}/status` */
240
+ setIssueStatus: (args) => {
241
+ const fingerprint = need('fingerprint', args.fingerprint);
242
+ return request('POST', `/api/v1/crashes/issues/${encodeURIComponent(fingerprint)}/status`, { body: dropUndefined({ "status": args.status }) });
243
+ },
244
+ /** Crash reports accepted and dropped this month, and the plan's limits. `GET /api/v1/crashes/usage` */
245
+ usage: () => request('GET', `/api/v1/crashes/usage`),
246
+ },
247
+ data: {
248
+ /** Add a column to an existing table. `POST /api/v1/data/rel/column/add` */
249
+ addColumn: (args) => request('POST', `/api/v1/data/rel/column/add`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName, "data_type": args.dataType, "is_nullable": args.isNullable, "is_unique": args.isUnique, "default_value": args.defaultValue }) }),
250
+ /** Add a foreign-key relation. `POST /api/v1/data/rel/foreign-key/add` */
251
+ addForeignKey: (args) => request('POST', `/api/v1/data/rel/foreign-key/add`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName, "referenced_table": args.referencedTable, "referenced_column": args.referencedColumn }) }),
252
+ /** Start a table transaction and receive tx/snapshot IDs. `POST /api/v1/data/rel/transaction/begin` */
253
+ beginTransaction: () => request('POST', `/api/v1/data/rel/transaction/begin`),
254
+ /** Commit a previously opened table transaction. `POST /api/v1/data/rel/transaction/commit` */
255
+ commitTransaction: (args) => request('POST', `/api/v1/data/rel/transaction/commit`, { body: dropUndefined({ "txid": args.txid }) }),
256
+ /** Drop a column from a table. `POST /api/v1/data/rel/column/drop` */
257
+ dropColumn: (args) => request('POST', `/api/v1/data/rel/column/drop`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName }) }),
258
+ /** Drop a foreign-key relation. `POST /api/v1/data/rel/foreign-key/drop` */
259
+ dropForeignKey: (args) => request('POST', `/api/v1/data/rel/foreign-key/drop`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName, "referenced_table": args.referencedTable, "referenced_column": args.referencedColumn }) }),
260
+ /** Drop a relational table. `POST /api/v1/data/rel/drop` */
261
+ dropTable: (args) => request('POST', `/api/v1/data/rel/drop`, { body: dropUndefined({ "table_name": args.tableName }) }),
262
+ /** `POST /api/v1/data/rel/transaction/rollback` */
263
+ rollbackTransaction: (args) => request('POST', `/api/v1/data/rel/transaction/rollback`, { body: dropUndefined({ "txid": args.txid }) }),
264
+ /** Tables that keep history (versions, oldest, retention) and the plan's db.history_* limits. `GET /api/v1/data/rel/history` */
265
+ tableHistory: () => request('GET', `/api/v1/data/rel/history`),
266
+ /** Turn a table's history on (every row version kept; read with sov_as_of(NULL::table, time)) or off (versions dropped). `POST /api/v1/data/rel/history` */
267
+ setTableHistory: (args) => request('POST', `/api/v1/data/rel/history`, { body: dropUndefined({ "table_name": args.tableName, "enabled": args.enabled, "keep_days": args.keepDays }) }),
268
+ /** The schema as one short line per table: columns with types, keys, →references, allowed values, indexes and owner-only rows. tables (comma-separated) expands only those in a big schema; since=<version> answers unchanged when nothing changed. `GET /api/v1/data/rel/schema/digest` */
269
+ schemaDigest: (args = {}) => request('GET', `/api/v1/data/rel/schema/digest`, { query: dropUndefined({ "tables": args.tables, "max_chars": args.maxChars, "since": args.since }) }),
270
+ /** Create or extend tables from one declarative plan ([{name, columns, patterns, unique, indexes}]; columns as objects or short form like "status text!='draft' in(draft|live)" or "customer_id →customers cascade"). Checked first (422 lists every problem, nothing changes), then applied as one reversible migration and verified. dry_run returns the SQL without applying. `POST /api/v1/data/rel/schema/plan` */
271
+ applySchemaPlan: (args) => request('POST', `/api/v1/data/rel/schema/plan`, { body: dropUndefined({ "tables": args.tables, "dry_run": args.dryRun, "name": args.name }) }),
272
+ /** Apply a migration and record it in the project's history, in one transaction (all or nothing). down_sql makes it reversible; the same version with the same SQL again does nothing, with different SQL it is refused (409). `POST /api/v1/data/rel/migrations/apply` */
273
+ applyMigration: (args) => request('POST', `/api/v1/data/rel/migrations/apply`, { body: dropUndefined({ "name": args.name, "up_sql": args.upSql, "down_sql": args.downSql, "version": args.version }) }),
274
+ /** Run a migration inside a transaction and roll it back: whether it would apply. Nothing is kept. `POST /api/v1/data/rel/migrations/dry-run` */
275
+ dryRunMigration: (args) => request('POST', `/api/v1/data/rel/migrations/dry-run`, { body: dropUndefined({ "name": args.name, "up_sql": args.upSql, "down_sql": args.downSql }) }),
276
+ /** Check several migrations ([{name, up_sql}], up to 500 and 5 MB of SQL) in order inside one transaction that is rolled back, so later ones see what earlier ones create. Returns status dry_run_ok, or failed with failed.index, name and error for the first that fails. `POST /api/v1/data/rel/migrations/dry-run-sequence` */
277
+ dryRunMigrations: (args) => request('POST', `/api/v1/data/rel/migrations/dry-run-sequence`, { body: dropUndefined({ "migrations": args.migrations }) }),
278
+ /** Undo the most recent migration with its down SQL (or version, with force when it isn't the latest). `POST /api/v1/data/rel/migrations/rollback` */
279
+ rollbackMigration: (args = {}) => request('POST', `/api/v1/data/rel/migrations/rollback`, { query: dropUndefined({ "version": args.version, "force": args.force }) }),
280
+ },
281
+ e2ee: {
282
+ /** Create (or fetch) the active e2ee channel key. `POST /api/v1/rt/e2ee/keys/bootstrap` */
283
+ bootstrapKey: (args) => request('POST', `/api/v1/rt/e2ee/keys/bootstrap`, { body: dropUndefined({ "channel": args.channel, "ttl_seconds": args.ttlSeconds, "force_new": args.forceNew }) }),
284
+ /** Get the active e2ee key for a channel, wrapped for ``client_public_key``. `GET /api/v1/rt/e2ee/keys/active/{channel}` */
285
+ getActiveKey: (args) => {
286
+ const channel = need('channel', args.channel);
287
+ return request('GET', `/api/v1/rt/e2ee/keys/active/${encodeURIComponent(channel)}`, { query: dropUndefined({ "client_public_key_pem": args.clientPublicKey }) });
288
+ },
289
+ /** Get key material by channel/key_id, wrapped for ``client_public_key``. `GET /api/v1/rt/e2ee/keys/{channel}/{key_id}` */
290
+ getKey: (args) => {
291
+ const channel = need('channel', args.channel);
292
+ const keyId = need('key_id', args.keyId);
293
+ return request('GET', `/api/v1/rt/e2ee/keys/${encodeURIComponent(channel)}/${encodeURIComponent(keyId)}`, { query: dropUndefined({ "client_public_key_pem": args.clientPublicKey }) });
294
+ },
295
+ /** List key metadata for a channel. `GET /api/v1/rt/e2ee/keys/{channel}` */
296
+ listKeys: (args) => {
297
+ const channel = need('channel', args.channel);
298
+ return request('GET', `/api/v1/rt/e2ee/keys/${encodeURIComponent(channel)}`);
299
+ },
300
+ /** Revoke an active or historical channel key. `POST /api/v1/rt/e2ee/keys/revoke` */
301
+ revokeKey: (args) => request('POST', `/api/v1/rt/e2ee/keys/revoke`, { body: dropUndefined({ "channel": args.channel, "key_id": args.keyId, "reason": args.reason }) }),
302
+ /** Rotate e2ee key material for a channel. `POST /api/v1/rt/e2ee/keys/rotate` */
303
+ rotateKey: (args) => request('POST', `/api/v1/rt/e2ee/keys/rotate`, { body: dropUndefined({ "channel": args.channel, "ttl_seconds": args.ttlSeconds }) }),
304
+ },
305
+ functions: {
306
+ /** `DELETE /api/v1/fn/functions/{function_name}` */
307
+ delete: (args) => {
308
+ const functionName = need('function_name', args.functionName);
309
+ return request('DELETE', `/api/v1/fn/functions/${encodeURIComponent(functionName)}`);
310
+ },
311
+ /** `GET /api/v1/fn/functions/{function_name}` */
312
+ get: (args) => {
313
+ const functionName = need('function_name', args.functionName);
314
+ return request('GET', `/api/v1/fn/functions/${encodeURIComponent(functionName)}`, { query: dropUndefined({ "project_id": args.projectId }) });
315
+ },
316
+ /** `GET /api/v1/fn/functions/{function_name}/bindings` */
317
+ getBindings: (args) => {
318
+ const functionName = need('function_name', args.functionName);
319
+ return request('GET', `/api/v1/fn/functions/${encodeURIComponent(functionName)}/bindings`);
320
+ },
321
+ /** `GET /api/v1/fn/functions/{function_name}/policy` */
322
+ getPolicy: (args) => {
323
+ const functionName = need('function_name', args.functionName);
324
+ return request('GET', `/api/v1/fn/functions/${encodeURIComponent(functionName)}/policy`);
325
+ },
326
+ /** `GET /api/v1/fn/functions/{function_name}/source` */
327
+ getSource: (args) => {
328
+ const functionName = need('function_name', args.functionName);
329
+ return request('GET', `/api/v1/fn/functions/${encodeURIComponent(functionName)}/source`, { query: dropUndefined({ "project_id": args.projectId }) });
330
+ },
331
+ /** `POST /api/v1/fn/github/commit` */
332
+ githubCommit: (args) => request('POST', `/api/v1/fn/github/commit`, { body: args.body }),
333
+ /** `POST /api/v1/fn/github/import` */
334
+ githubImport: (args) => request('POST', `/api/v1/fn/github/import`, { body: args.body }),
335
+ /** Get status for an async Forge invocation id. `GET /api/v1/fn/invocations/{invocation_id}` */
336
+ invocationStatus: (args) => {
337
+ const invocationId = need('invocation_id', args.invocationId);
338
+ return request('GET', `/api/v1/fn/invocations/${encodeURIComponent(invocationId)}`, { query: dropUndefined({ "project_id": args.projectId }) });
339
+ },
340
+ /** List Forge functions with active version and queue summary. `GET /api/v1/fn/functions` */
341
+ list: (args = {}) => request('GET', `/api/v1/fn/functions`, { query: dropUndefined({ "project_id": args.projectId, "limit": args.limit, "offset": args.offset }) }),
342
+ /** Diff two simulation invocation outputs. `GET /api/v1/fn/{function_name}/history/simulation-diff` */
343
+ simulationDiff: (args) => {
344
+ const functionName = need('function_name', args.functionName);
345
+ return request('GET', `/api/v1/fn/${encodeURIComponent(functionName)}/history/simulation-diff`, { query: dropUndefined({ "project_id": args.projectId, "left_invocation_id": args.leftInvocationId, "right_invocation_id": args.rightInvocationId }) });
346
+ },
347
+ /** Get forge deployment status by deploy id. `GET /api/v1/fn/{deploy_id}/status` */
348
+ status: (args) => {
349
+ const deployId = need('deploy_id', args.deployId);
350
+ return request('GET', `/api/v1/fn/${encodeURIComponent(deployId)}/status`, { query: dropUndefined({ "project_id": args.projectId }) });
351
+ },
352
+ /** `PATCH /api/v1/fn/functions/{function_name}` */
353
+ update: (args) => {
354
+ const functionName = need('function_name', args.functionName);
355
+ return request('PATCH', `/api/v1/fn/functions/${encodeURIComponent(functionName)}`, { body: args.body, query: dropUndefined({ "project_id": args.projectId }) });
356
+ },
357
+ /** `PUT /api/v1/fn/functions/{function_name}/bindings` */
358
+ updateBindings: (args) => {
359
+ const functionName = need('function_name', args.functionName);
360
+ return request('PUT', `/api/v1/fn/functions/${encodeURIComponent(functionName)}/bindings`, { body: dropUndefined({ "bindings": args.bindings }) });
361
+ },
362
+ /** `PUT /api/v1/fn/functions/{function_name}/policy` */
363
+ updatePolicy: (args) => {
364
+ const functionName = need('function_name', args.functionName);
365
+ return request('PUT', `/api/v1/fn/functions/${encodeURIComponent(functionName)}/policy`, { body: args.policy });
366
+ },
367
+ /** List deployment versions for a Forge function. `GET /api/v1/fn/{function_name}/versions` */
368
+ versions: (args) => {
369
+ const functionName = need('function_name', args.functionName);
370
+ return request('GET', `/api/v1/fn/${encodeURIComponent(functionName)}/versions`, { query: dropUndefined({ "project_id": args.projectId, "limit": args.limit, "offset": args.offset }) });
371
+ },
372
+ },
373
+ governance: {
374
+ /** `GET /api/v1/governance/admin/databases` */
375
+ adminDatabases: () => request('GET', `/api/v1/governance/admin/databases`),
376
+ /** `GET /api/v1/governance/tenants/{org_id}` */
377
+ getTenant: (args = {}) => {
378
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
379
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}`);
380
+ },
381
+ /** `GET /api/v1/governance/tenants/{org_id}/databases/{project_id}/connection` */
382
+ getTenantDatabaseConnection: (args = {}) => {
383
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
384
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
385
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/connection`);
386
+ },
387
+ /** `GET /api/v1/governance/hosts` */
388
+ listHosts: (args = {}) => request('GET', `/api/v1/governance/hosts`, { query: dropUndefined({ "region_id": args.regionId }) }),
389
+ /** `GET /api/v1/governance/regions` */
390
+ listRegions: () => request('GET', `/api/v1/governance/regions`),
391
+ /** `GET /api/v1/governance/tenants/{org_id}/databases/{project_id}/backups` */
392
+ listTenantDatabaseBackups: (args = {}) => {
393
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
394
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
395
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/backups`, { query: dropUndefined({ "limit": args.limit }) });
396
+ },
397
+ /** `GET /api/v1/governance/tenants/{org_id}/databases` */
398
+ listTenantDatabases: (args = {}) => {
399
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
400
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases`);
401
+ },
402
+ /** `GET /api/v1/governance/tenants` */
403
+ listTenants: () => request('GET', `/api/v1/governance/tenants`),
404
+ /** `GET /api/v1/governance/metrics/overview` */
405
+ metricsOverview: () => request('GET', `/api/v1/governance/metrics/overview`),
406
+ /** `PATCH /api/v1/governance/hosts/{host_id}` */
407
+ patchHost: (args) => {
408
+ const hostId = need('host_id', args.hostId);
409
+ return request('PATCH', `/api/v1/governance/hosts/${encodeURIComponent(hostId)}`, { body: args.body });
410
+ },
411
+ /** `PATCH /api/v1/governance/regions/{region_id}` */
412
+ patchRegion: (args) => {
413
+ const regionId = need('region_id', args.regionId);
414
+ return request('PATCH', `/api/v1/governance/regions/${encodeURIComponent(regionId)}`, { body: args.body });
415
+ },
416
+ /** `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/pause` */
417
+ pauseTenantDatabase: (args = {}) => {
418
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
419
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
420
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/pause`);
421
+ },
422
+ /** `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/resize` */
423
+ resizeTenantDatabase: (args) => {
424
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
425
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
426
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/resize`, { body: dropUndefined({ "compute_size": args.computeSize }) });
427
+ },
428
+ /** `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/resume` */
429
+ resumeTenantDatabase: (args = {}) => {
430
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
431
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
432
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/resume`);
433
+ },
434
+ /** Reveal a database connection string (staff, with an active access grant). `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/connection/reveal` */
435
+ revealTenantDatabaseConnection: (args) => {
436
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
437
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
438
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/connection/reveal`, { body: dropUndefined({ "grant_id": args.grantId }) });
439
+ },
440
+ /** `POST /api/v1/governance/tenants/{org_id}/status` */
441
+ setTenantStatus: (args) => {
442
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
443
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/status`, { body: dropUndefined({ "status": args.status }) });
444
+ },
445
+ /** `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/backups` */
446
+ triggerTenantDatabaseBackup: (args = {}) => {
447
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
448
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
449
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/backups`);
450
+ },
451
+ /** Read replicas of the project's dedicated database: status, connection string, lag behind the primary, plan limit. `GET /api/v1/governance/tenants/{org_id}/databases/{project_id}/replicas` */
452
+ listDatabaseReplicas: (args = {}) => {
453
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
454
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
455
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/replicas`);
456
+ },
457
+ /** Start a streaming read replica (status provisioning until its base backup is done, then ready). `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/replicas` */
458
+ createDatabaseReplica: (args = {}) => {
459
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
460
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
461
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/replicas`, { body: {} });
462
+ },
463
+ /** Remove a read replica and its copy of the data. `DELETE /api/v1/governance/tenants/{org_id}/databases/{project_id}/replicas/{replica_id}` */
464
+ deleteDatabaseReplica: (args) => {
465
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
466
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
467
+ const replicaId = need('replica_id', args.replicaId);
468
+ return request('DELETE', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/replicas/${encodeURIComponent(replicaId)}`);
469
+ },
470
+ /** What changed between two moments of the database — a backup id or "now" on each side: schema objects added, removed or changed (with a diff) and rows per table. `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/compare` */
471
+ compareDatabaseMoments: (args) => {
472
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
473
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
474
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/compare`, { body: dropUndefined({ "from": args.fromMoment, "to": args.toMoment, "include_platform": args.includePlatform }) });
475
+ },
476
+ /** Replace the project's database with a backup (dedicated databases): a safety backup is taken first, the backup loads beside production in one transaction and is swapped in; undo within 7 days. Org owners and admins. `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/backups/{backup_id}/restore` */
477
+ restoreDatabaseBackup: (args) => {
478
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
479
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
480
+ const backupId = need('backup_id', args.backupId);
481
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/backups/${encodeURIComponent(backupId)}/restore`, { body: dropUndefined({ "confirm": args.confirm }) });
482
+ },
483
+ /** Database restores of the project: status, the backup used, the safety backup and until when it can be undone. `GET /api/v1/governance/tenants/{org_id}/databases/{project_id}/restores` */
484
+ listDatabaseRestores: (args = {}) => {
485
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
486
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
487
+ return request('GET', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/restores`);
488
+ },
489
+ /** Put back the database exactly as it was right before a restore (within the undo window). `POST /api/v1/governance/tenants/{org_id}/databases/{project_id}/restores/{restore_id}/undo` */
490
+ undoDatabaseRestore: (args) => {
491
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
492
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
493
+ const restoreId = need('restore_id', args.restoreId);
494
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/databases/${encodeURIComponent(projectId)}/restores/${encodeURIComponent(restoreId)}/undo`, { body: {} });
495
+ },
496
+ },
497
+ history: {
498
+ /** Create a Chrono commit. `POST /api/v1/chrono/commit` */
499
+ commit: (args) => request('POST', `/api/v1/chrono/commit`, { body: dropUndefined({ "timeline": args.timeline, "message": args.message, "author": args.author, "event_type": args.eventType }) }),
500
+ /** Converge source timeline into target timeline. `POST /api/v1/chrono/timelines/converge` */
501
+ converge: (args) => request('POST', `/api/v1/chrono/timelines/converge`, { body: dropUndefined({ "target": args.target, "source": args.source, "author": args.author, "message": args.message }) }),
502
+ /** Create a system snapshot. `POST /api/v1/chrono/snapshots/create` */
503
+ createSnapshot: (args) => request('POST', `/api/v1/chrono/snapshots/create`, { body: dropUndefined({ "message": args.message }) }),
504
+ /** Delete a timeline. `DELETE /api/v1/chrono/timelines/{name}` */
505
+ deleteTimeline: (args) => {
506
+ const name = need('name', args.name);
507
+ return request('DELETE', `/api/v1/chrono/timelines/${encodeURIComponent(name)}`);
508
+ },
509
+ /** Force-jump a timeline head. `POST /api/v1/chrono/timelines/{name}/jump` */
510
+ jumpTimeline: (args) => {
511
+ const name = need('name', args.name);
512
+ return request('POST', `/api/v1/chrono/timelines/${encodeURIComponent(name)}/jump`, { body: dropUndefined({ "target_hex": args.targetHex }) });
513
+ },
514
+ /** List known snapshots. `GET /api/v1/chrono/snapshots` */
515
+ listSnapshots: () => request('GET', `/api/v1/chrono/snapshots`),
516
+ /** List available timelines. `GET /api/v1/chrono/timelines` */
517
+ listTimelines: () => request('GET', `/api/v1/chrono/timelines`),
518
+ /** Restore a snapshot by id. `POST /api/v1/chrono/snapshots/{snapshot_id}/restore` */
519
+ restoreSnapshot: (args) => {
520
+ const snapshotId = need('snapshot_id', args.snapshotId);
521
+ return request('POST', `/api/v1/chrono/snapshots/${encodeURIComponent(snapshotId)}/restore`);
522
+ },
523
+ /** Spawn a new timeline from a source chronon. `POST /api/v1/chrono/timelines/spawn` */
524
+ spawnTimeline: (args) => request('POST', `/api/v1/chrono/timelines/spawn`, { body: dropUndefined({ "name": args.name, "source_hex_id": args.sourceHexId }) }),
525
+ /** Fetch timeline history chronons. `GET /api/v1/chrono/timelines/{name}/history` */
526
+ timelineHistory: (args) => {
527
+ const name = need('name', args.name);
528
+ return request('GET', `/api/v1/chrono/timelines/${encodeURIComponent(name)}/history`, { query: dropUndefined({ "limit": args.limit, "offset": args.offset }) });
529
+ },
530
+ /** Return timeline graph topology. `GET /api/v1/chrono/timelines/topology` */
531
+ topology: (args = {}) => request('GET', `/api/v1/chrono/timelines/topology`, { query: dropUndefined({ "timeline": args.timeline, "limit": args.limit }) }),
532
+ /** Calculate variance between two chronons. `POST /api/v1/chrono/variance` */
533
+ variance: (args) => request('POST', `/api/v1/chrono/variance`, { body: dropUndefined({ "old_chronon_hex": args.oldChrononHex, "new_chronon_hex": args.newChrononHex, "domain_filter": args.domainFilter }) }),
534
+ },
535
+ mcp: {
536
+ /** AI assistants you connected over Sovaria's MCP server: the app, its organization and project, read-only or not, when it was connected and last used. `GET /api/v1/auth/mcp/connections` */
537
+ listConnections: () => request('GET', `/api/v1/auth/mcp/connections`),
538
+ /** Disconnect one of your AI assistants: its tokens stop working at once. `DELETE /api/v1/auth/mcp/connections/{grant_id}` */
539
+ disconnect: (args) => {
540
+ const grantId = need('grant_id', args.grantId);
541
+ return request('DELETE', `/api/v1/auth/mcp/connections/${encodeURIComponent(grantId)}`);
542
+ },
543
+ /** Whether members may connect AI assistants to this organization, the MCP server URL, and (owners and admins) every member's connection. `GET /api/v1/org/{org_id}/mcp` */
544
+ orgSettings: (args = {}) => {
545
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
546
+ return request('GET', `/api/v1/org/${encodeURIComponent(orgId)}/mcp`);
547
+ },
548
+ /** Allow or stop AI assistants for the organization (owners and admins). Turning it off ends every member's connection. `PUT /api/v1/org/{org_id}/mcp` */
549
+ setOrgAllowed: (args) => {
550
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
551
+ return request('PUT', `/api/v1/org/${encodeURIComponent(orgId)}/mcp`, { body: dropUndefined({ "allowed": args.allowed }) });
552
+ },
553
+ /** Disconnect a member's AI assistant from the organization (owners and admins). `DELETE /api/v1/org/{org_id}/mcp/connections/{grant_id}` */
554
+ orgDisconnect: (args) => {
555
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
556
+ const grantId = need('grant_id', args.grantId);
557
+ return request('DELETE', `/api/v1/org/${encodeURIComponent(orgId)}/mcp/connections/${encodeURIComponent(grantId)}`);
558
+ },
559
+ },
560
+ messaging: {
561
+ /** Message templates of the project (push and/or email content with {{ variables }}). `GET /api/v1/projects/{project_id}/messaging/templates` */
562
+ listTemplates: (args = {}) => {
563
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
564
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/templates`);
565
+ },
566
+ /** One message template. `GET /api/v1/projects/{project_id}/messaging/templates/{name}` */
567
+ getTemplate: (args) => {
568
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
569
+ const name = need('name', args.name);
570
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/templates/${encodeURIComponent(name)}`);
571
+ },
572
+ /** Create or replace a template: push {title, body, image?, data?}, email {subject, html?, text?}; category transactional or marketing (marketing skips opted-out users and adds an unsubscribe link). `PUT /api/v1/projects/{project_id}/messaging/templates/{name}` */
573
+ putTemplate: (args) => {
574
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
575
+ const name = need('name', args.name);
576
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/templates/${encodeURIComponent(name)}`, { body: dropUndefined({ "description": args.description, "category": args.category, "push": args.push, "email": args.email }) });
577
+ },
578
+ /** Delete a message template. `DELETE /api/v1/projects/{project_id}/messaging/templates/{name}` */
579
+ deleteTemplate: (args) => {
580
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
581
+ const name = need('name', args.name);
582
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/templates/${encodeURIComponent(name)}`);
583
+ },
584
+ /** Saved audiences: read-only SQL queries returning user_id (other columns become per-user variables). `GET /api/v1/projects/{project_id}/messaging/audiences` */
585
+ listAudiences: (args = {}) => {
586
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
587
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences`);
588
+ },
589
+ /** One audience and its last count. `GET /api/v1/projects/{project_id}/messaging/audiences/{name}` */
590
+ getAudience: (args) => {
591
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
592
+ const name = need('name', args.name);
593
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences/${encodeURIComponent(name)}`);
594
+ },
595
+ /** Create or replace an audience: a SELECT on the project database returning user_id (e.g. select user_id, first_name from profiles where plan = 'pro'). `PUT /api/v1/projects/{project_id}/messaging/audiences/{name}` */
596
+ putAudience: (args) => {
597
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
598
+ const name = need('name', args.name);
599
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences/${encodeURIComponent(name)}`, { body: dropUndefined({ "sql": args.sql, "description": args.description }) });
600
+ },
601
+ /** Delete an audience. `DELETE /api/v1/projects/{project_id}/messaging/audiences/{name}` */
602
+ deleteAudience: (args) => {
603
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
604
+ const name = need('name', args.name);
605
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences/${encodeURIComponent(name)}`);
606
+ },
607
+ /** Run a saved audience: how many app users it reaches, columns and a sample of 10. `POST /api/v1/projects/{project_id}/messaging/audiences/{name}/preview` */
608
+ previewAudience: (args) => {
609
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
610
+ const name = need('name', args.name);
611
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences/${encodeURIComponent(name)}/preview`, { body: {} });
612
+ },
613
+ /** Try an audience query before saving it: app users reached, columns and a sample. `POST /api/v1/projects/{project_id}/messaging/audiences/preview` */
614
+ previewSql: (args) => {
615
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
616
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/audiences/preview`, { body: dropUndefined({ "sql": args.sql }) });
617
+ },
618
+ /** Send a template (or content {push, email}) to {user_ids | audience | sql | topic | all_users} on push and/or email, with variables; dry_run reports who would get it and renders a preview. Runs in the background; poll getSend. `POST /api/v1/projects/{project_id}/messaging/send` */
619
+ send: (args) => {
620
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
621
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/send`, { body: dropUndefined({ "template": args.template, "content": args.content, "to": args.to, "channels": args.channels, "variables": args.variables, "category": args.category, "dry_run": args.dryRun }) });
622
+ },
623
+ /** Recent sends with status and per-channel counts. `GET /api/v1/projects/{project_id}/messaging/sends` */
624
+ listSends: (args = {}) => {
625
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
626
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/sends`, { query: dropUndefined({ "limit": args.limit }) });
627
+ },
628
+ /** One send: status (sending, done, failed) and counts per channel and outcome. `GET /api/v1/projects/{project_id}/messaging/sends/{send_id}` */
629
+ getSend: (args) => {
630
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
631
+ const sendId = need('send_id', args.sendId);
632
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/sends/${encodeURIComponent(sendId)}`);
633
+ },
634
+ /** Delivery log: per recipient and channel, sent / failed / no_device / no_email / opted_out with an error code (never content). `GET /api/v1/projects/{project_id}/messaging/deliveries` */
635
+ listDeliveries: (args = {}) => {
636
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
637
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/deliveries`, { query: dropUndefined({ "send_id": args.sendId, "user_id": args.userId, "status": args.status, "limit": args.limit, "offset": args.offset }) });
638
+ },
639
+ /** Messages sent this month per channel and the plan's messaging limits. `GET /api/v1/projects/{project_id}/messaging/usage` */
640
+ usage: (args = {}) => {
641
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
642
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/usage`);
643
+ },
644
+ /** Record an app user's marketing choice (channel push, email or all) from your own UI. `PUT /api/v1/projects/{project_id}/messaging/users/{user_id}/optouts` */
645
+ setUserOptout: (args) => {
646
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
647
+ const userId = need('user_id', args.userId);
648
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/messaging/users/${encodeURIComponent(userId)}/optouts`, { body: dropUndefined({ "channel": args.channel, "opted_out": args.optedOut }) });
649
+ },
650
+ /** The signed-in app user's marketing preferences per channel. `GET /api/v1/messaging/preferences` */
651
+ getPreferences: () => request('GET', `/api/v1/messaging/preferences`),
652
+ /** The signed-in app user turns marketing push/email on or off: { marketing: { email: false } }. `PUT /api/v1/messaging/preferences` */
653
+ setPreferences: (args) => request('PUT', `/api/v1/messaging/preferences`, { body: dropUndefined({ "marketing": args.marketing }) }),
654
+ },
655
+ mobile: {
656
+ /** Registered iOS/Android apps (bundle/package ids, redirect URIs). `GET /api/v1/projects/{project_id}/mobile/apps` */
657
+ listApps: (args = {}) => {
658
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
659
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/mobile/apps`);
660
+ },
661
+ /** Register an app: platform, bundle_id+team_id (iOS) or package_name+sha256_cert_fingerprints (Android), redirect_uris. `POST /api/v1/projects/{project_id}/mobile/apps` */
662
+ createApp: (args) => {
663
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
664
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/mobile/apps`, { body: args.body });
665
+ },
666
+ /** Change a registered app (name, ids, fingerprints, redirect URIs). `PATCH /api/v1/projects/{project_id}/mobile/apps/{app_id}` */
667
+ updateApp: (args) => {
668
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
669
+ const appId = need('app_id', args.appId);
670
+ return request('PATCH', `/api/v1/projects/${encodeURIComponent(projectId)}/mobile/apps/${encodeURIComponent(appId)}`, { body: args.body });
671
+ },
672
+ /** Remove a registered app. `DELETE /api/v1/projects/{project_id}/mobile/apps/{app_id}` */
673
+ deleteApp: (args) => {
674
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
675
+ const appId = need('app_id', args.appId);
676
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/mobile/apps/${encodeURIComponent(appId)}`);
677
+ },
678
+ /** An app user's signed-in devices and push tokens. `GET /api/v1/projects/{project_id}/users/{user_id}/devices` */
679
+ listUserDevices: (args) => {
680
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
681
+ const userId = need('user_id', args.userId);
682
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(userId)}/devices`);
683
+ },
684
+ /** Sign one of an app user's devices out (sessions and push tokens). `DELETE /api/v1/projects/{project_id}/users/{user_id}/devices/{device_id}` */
685
+ revokeUserDevice: (args) => {
686
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
687
+ const userId = need('user_id', args.userId);
688
+ const deviceId = need('device_id', args.deviceId);
689
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(userId)}/devices/${encodeURIComponent(deviceId)}`);
690
+ },
691
+ },
692
+ org: {
693
+ /** `POST /api/v1/org/invites/accept` */
694
+ acceptOrgInvite: (args) => request('POST', `/api/v1/org/invites/accept`, { body: dropUndefined({ "token": args.token }) }),
695
+ /** Add a user as a member of an org/project node. `POST /api/v1/org/{org_id}/member` */
696
+ addMember: (args) => {
697
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
698
+ return request('POST', `/api/v1/org/${encodeURIComponent(orgId)}/member`, { body: dropUndefined({ "user_id": args.userId, "role": args.role }) });
699
+ },
700
+ /** Connect two DAPG nodes with a typed relationship. `POST /api/v1/edge` */
701
+ createEdge: (args) => request('POST', `/api/v1/edge`, { body: dropUndefined({ "source_id": args.sourceNodeId, "target_id": args.targetNodeId, "relation_type": args.relationType, "role": args.role }) }),
702
+ /** `POST /api/v1/org/{org_id}/invites` */
703
+ createOrgInvite: (args) => {
704
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
705
+ return request('POST', `/api/v1/org/${encodeURIComponent(orgId)}/invites`, { body: dropUndefined({ "email": args.email, "role": args.role }) });
706
+ },
707
+ /** `DELETE /api/v1/org/{org_id}` */
708
+ deleteOrg: (args = {}) => {
709
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
710
+ return request('DELETE', `/api/v1/org/${encodeURIComponent(orgId)}`);
711
+ },
712
+ /** `POST /api/v1/apikeys/ensure-defaults` */
713
+ ensureDefaultApiKeys: () => request('POST', `/api/v1/apikeys/ensure-defaults`, { body: {} }),
714
+ /** List child nodes attached by a relation (e.g. OWNS, HAS_ENV). `GET /api/v1/org/{parent_id}/children` */
715
+ getChildren: (args) => {
716
+ const parentId = need('parent_id', args.parentId);
717
+ return request('GET', `/api/v1/org/${encodeURIComponent(parentId)}/children`, { query: dropUndefined({ "relation": args.relation }) });
718
+ },
719
+ /** Resolve a user's roles on a resource by walking the DAPG. `GET /api/v1/context/{user_id}/{resource_id}` */
720
+ getContext: (args) => {
721
+ const userId = need('user_id', args.userId);
722
+ const resourceId = need('resource_id', args.resourceId);
723
+ return request('GET', `/api/v1/context/${encodeURIComponent(userId)}/${encodeURIComponent(resourceId)}`);
724
+ },
725
+ /** Fetch a single graph node by ID. `GET /api/v1/org/{node_id}` */
726
+ getNode: (args) => {
727
+ const nodeId = need('node_id', args.nodeId);
728
+ return request('GET', `/api/v1/org/${encodeURIComponent(nodeId)}`);
729
+ },
730
+ /** `GET /api/v1/org/{project_id}/ref` */
731
+ getProjectRef: (args = {}) => {
732
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
733
+ return request('GET', `/api/v1/org/${encodeURIComponent(projectId)}/ref`);
734
+ },
735
+ /** `GET /api/v1/project-settings` */
736
+ getProjectSettings: () => request('GET', `/api/v1/project-settings`),
737
+ /** `GET /api/v1/roles/catalog` */
738
+ getRoleCatalog: () => request('GET', `/api/v1/roles/catalog`),
739
+ /** `GET /api/v1/roles/matrix` */
740
+ getRoleMatrix: () => request('GET', `/api/v1/roles/matrix`),
741
+ /** `GET /api/v1/apikeys` */
742
+ listApiKeys: () => request('GET', `/api/v1/apikeys`),
743
+ /** List graph nodes; when provided, ``node_type`` filters by type. `GET /api/v1/org` */
744
+ listNodes: (args = {}) => request('GET', `/api/v1/org`, { query: dropUndefined({ "type": args.nodeType }) }),
745
+ /** `GET /api/v1/org/{org_id}/members` */
746
+ listOrgMembers: (args = {}) => {
747
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
748
+ return request('GET', `/api/v1/org/${encodeURIComponent(orgId)}/members`);
749
+ },
750
+ /** `DELETE /api/v1/org/{org_id}/member/{user_id}` */
751
+ removeOrgMember: (args) => {
752
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
753
+ const userId = need('user_id', args.userId);
754
+ return request('DELETE', `/api/v1/org/${encodeURIComponent(orgId)}/member/${encodeURIComponent(userId)}`);
755
+ },
756
+ /** `DELETE /api/v1/apikeys/{key_id}` */
757
+ revokeApiKey: (args) => {
758
+ const keyId = need('key_id', args.keyId);
759
+ return request('DELETE', `/api/v1/apikeys/${encodeURIComponent(keyId)}`);
760
+ },
761
+ /** `PUT /api/v1/org/{org_id}/plan` */
762
+ setOrgPlan: (args) => {
763
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
764
+ return request('PUT', `/api/v1/org/${encodeURIComponent(orgId)}/plan`, { body: dropUndefined({ "plan": args.plan }) });
765
+ },
766
+ /** `PUT /api/v1/org/{org_id}/member/{user_id}` */
767
+ updateMemberRole: (args) => {
768
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
769
+ const userId = need('user_id', args.userId);
770
+ return request('PUT', `/api/v1/org/${encodeURIComponent(orgId)}/member/${encodeURIComponent(userId)}`, { body: dropUndefined({ "role": args.role }) });
771
+ },
772
+ /** `PUT /api/v1/org/{org_id}` */
773
+ updateOrg: (args) => {
774
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
775
+ return request('PUT', `/api/v1/org/${encodeURIComponent(orgId)}`, { body: args.body });
776
+ },
777
+ /** `PUT /api/v1/project-settings` */
778
+ updateProjectSettings: (args) => request('PUT', `/api/v1/project-settings`, { body: dropUndefined({ "settings": args.settings }) }),
779
+ /** `PUT /api/v1/roles/matrix` */
780
+ updateRoleMatrix: (args) => request('PUT', `/api/v1/roles/matrix`, { body: dropUndefined({ "matrix": args.matrix }) }),
781
+ },
782
+ platform: {
783
+ /** `POST /api/v1/auth/event-hooks` */
784
+ createEventHook: (args) => request('POST', `/api/v1/auth/event-hooks`, { body: args.body }),
785
+ /** `DELETE /api/v1/auth/event-hooks/{hook_id}` */
786
+ deleteEventHook: (args) => {
787
+ const hookId = need('hook_id', args.hookId);
788
+ return request('DELETE', `/api/v1/auth/event-hooks/${encodeURIComponent(hookId)}`);
789
+ },
790
+ /** `DELETE /api/v1/auth/github/connection-state` */
791
+ disconnectGithub: (args = {}) => request('DELETE', `/api/v1/auth/github/connection-state`, { query: dropUndefined({ "project_id": args.projectId }) }),
792
+ /** `GET /healthz` */
793
+ gatewayHealth: () => request('GET', `/healthz`, { requiresAuth: false }),
794
+ /** Return aggregate gateway health for downstream engines. `GET /api/v1/system/engines/health` */
795
+ getEnginesHealth: () => request('GET', `/api/v1/system/engines/health`, { requiresAuth: false }),
796
+ /** `GET /api/v1/error-traces/{trace_id}` */
797
+ getErrorTrace: (args) => {
798
+ const traceId = need('trace_id', args.traceId);
799
+ return request('GET', `/api/v1/error-traces/${encodeURIComponent(traceId)}`);
800
+ },
801
+ /** `GET /api/v1/auth/github/connection-state` */
802
+ getGithubConnectionState: (args = {}) => request('GET', `/api/v1/auth/github/connection-state`, { query: dropUndefined({ "project_id": args.projectId }) }),
803
+ /** `GET /api/v1/auth/event-hooks` */
804
+ listEventHooks: () => request('GET', `/api/v1/auth/event-hooks`),
805
+ /** `PATCH /api/v1/error-traces/{trace_id}/resolved` */
806
+ resolveErrorTrace: (args) => {
807
+ const traceId = need('trace_id', args.traceId);
808
+ return request('PATCH', `/api/v1/error-traces/${encodeURIComponent(traceId)}/resolved`, { body: dropUndefined({ "resolved": args.resolved }) });
809
+ },
810
+ },
811
+ policy: {
812
+ /** Return current audit-entry count. `GET /api/v1/audit/count` */
813
+ auditCount: () => request('GET', `/api/v1/audit/count`),
814
+ /** Verify audit hash-chain integrity. `GET /api/v1/audit/verify` */
815
+ auditVerify: () => request('GET', `/api/v1/audit/verify`),
816
+ /** Create and compile a policy. `POST /api/v1/policies/` */
817
+ policyCreate: (args) => request('POST', `/api/v1/policies/`, { body: dropUndefined({ "policy_id": args.policyId, "name": args.name, "spl_source": args.splSource, "org_id": args.orgId }) }),
818
+ /** Delete (deactivate) a policy. `DELETE /api/v1/policies/{policy_id}` */
819
+ policyDelete: (args) => {
820
+ const policyId = need('policy_id', args.policyId);
821
+ return request('DELETE', `/api/v1/policies/${encodeURIComponent(policyId)}`);
822
+ },
823
+ /** Evaluate a policy against an explicit debug context. `POST /api/v1/policies/{policy_id}/evaluate` */
824
+ policyEvaluate: (args) => {
825
+ const policyId = need('policy_id', args.policyId);
826
+ return request('POST', `/api/v1/policies/${encodeURIComponent(policyId)}/evaluate`, { body: dropUndefined({ "context": args.context }) });
827
+ },
828
+ /** Get a single policy by ID. `GET /api/v1/policies/{policy_id}` */
829
+ policyGet: (args) => {
830
+ const policyId = need('policy_id', args.policyId);
831
+ return request('GET', `/api/v1/policies/${encodeURIComponent(policyId)}`);
832
+ },
833
+ /** Return version history for a policy. `GET /api/v1/policies/{policy_id}/history` */
834
+ policyHistory: (args) => {
835
+ const policyId = need('policy_id', args.policyId);
836
+ return request('GET', `/api/v1/policies/${encodeURIComponent(policyId)}/history`);
837
+ },
838
+ /** List active policies visible in current tenant scope. `GET /api/v1/policies/` */
839
+ policyList: () => request('GET', `/api/v1/policies/`),
840
+ /** Rollback a policy to a historical version. `POST /api/v1/policies/{policy_id}/rollback` */
841
+ policyRollback: (args) => {
842
+ const policyId = need('policy_id', args.policyId);
843
+ return request('POST', `/api/v1/policies/${encodeURIComponent(policyId)}/rollback`, { body: dropUndefined({ "version": args.version }) });
844
+ },
845
+ /** List server-authoritative SPL templates. `GET /api/v1/policies/templates` */
846
+ policyTemplates: () => request('GET', `/api/v1/policies/templates`),
847
+ },
848
+ push: {
849
+ /** Which push providers are set up (never the keys). `GET /api/v1/projects/{project_id}/push/credentials` */
850
+ getCredentials: (args = {}) => {
851
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
852
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/push/credentials`);
853
+ },
854
+ /** Upload the Firebase service account JSON (encrypted, write-only). `PUT /api/v1/projects/{project_id}/push/credentials/fcm` */
855
+ setFcmCredentials: (args) => {
856
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
857
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/push/credentials/fcm`, { body: dropUndefined({ "service_account": args.serviceAccount }) });
858
+ },
859
+ /** Upload the APNs .p8 key (encrypted, write-only). `PUT /api/v1/projects/{project_id}/push/credentials/apns` */
860
+ setApnsCredentials: (args) => {
861
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
862
+ return request('PUT', `/api/v1/projects/${encodeURIComponent(projectId)}/push/credentials/apns`, { body: dropUndefined({ "p8": args.p8, "key_id": args.keyId, "team_id": args.teamId, "bundle_id": args.bundleId, "environment": args.environment }) });
863
+ },
864
+ /** Remove FCM or APNs credentials. `DELETE /api/v1/projects/{project_id}/push/credentials/{provider}` */
865
+ deleteCredentials: (args) => {
866
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
867
+ const provider = need('provider', args.provider);
868
+ return request('DELETE', `/api/v1/projects/${encodeURIComponent(projectId)}/push/credentials/${encodeURIComponent(provider)}`);
869
+ },
870
+ /** Push devices registered in the project (tokens are never returned). `GET /api/v1/projects/{project_id}/push/devices` */
871
+ listDevices: (args = {}) => {
872
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
873
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/push/devices`, { query: dropUndefined({ "user_id": args.userId, "limit": args.limit, "before": args.before }) });
874
+ },
875
+ /** Send a push: to {user_ids|device_ids|topic}, notification {title, body, image}, data, badge, priority, ttl_seconds, dry_run. `POST /api/v1/projects/{project_id}/push/send` */
876
+ send: (args) => {
877
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
878
+ return request('POST', `/api/v1/projects/${encodeURIComponent(projectId)}/push/send`, { body: args.message });
879
+ },
880
+ /** Recent sends (counts and error codes) and this month's total. `GET /api/v1/projects/{project_id}/push/sends` */
881
+ listSends: (args = {}) => {
882
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
883
+ return request('GET', `/api/v1/projects/${encodeURIComponent(projectId)}/push/sends`, { query: dropUndefined({ "limit": args.limit }) });
884
+ },
885
+ /** Register the signed-in app user's push token (FCM or APNs). `POST /api/v1/push/devices` */
886
+ registerDevice: (args) => request('POST', `/api/v1/push/devices`, { body: dropUndefined({ "token": args.token, "platform": args.platform, "provider": args.provider, "device_id": args.deviceId, "app_id": args.appId, "topics": args.topics, "locale": args.locale }) }),
887
+ /** The signed-in app user's push tokens. `GET /api/v1/push/devices` */
888
+ myDevices: () => request('GET', `/api/v1/push/devices`),
889
+ /** Subscribe a device to topics or unsubscribe it. `PATCH /api/v1/push/devices/{device_row_id}/topics` */
890
+ updateTopics: (args) => {
891
+ const deviceRowId = need('device_row_id', args.deviceRowId);
892
+ return request('PATCH', `/api/v1/push/devices/${encodeURIComponent(deviceRowId)}/topics`, { body: dropUndefined({ "subscribe": args.subscribe, "unsubscribe": args.unsubscribe, "replace": args.replace }) });
893
+ },
894
+ /** Remove one of the signed-in user's push devices. `DELETE /api/v1/push/devices/{device_row_id}` */
895
+ deleteDevice: (args) => {
896
+ const deviceRowId = need('device_row_id', args.deviceRowId);
897
+ return request('DELETE', `/api/v1/push/devices/${encodeURIComponent(deviceRowId)}`);
898
+ },
899
+ /** Drop a push token (sign-out, notifications turned off). `POST /api/v1/push/devices/unregister` */
900
+ unregisterToken: (args) => request('POST', `/api/v1/push/devices/unregister`, { body: dropUndefined({ "token": args.token }) }),
901
+ },
902
+ realtime: {
903
+ /** List active realtime channels. `GET /api/v1/rt/stream/channels` */
904
+ channels: () => request('GET', `/api/v1/rt/stream/channels`),
905
+ /** Fetch presence for a realtime channel. `GET /api/v1/rt/stream/presence/{channel}` */
906
+ presence: (args) => {
907
+ const channel = need('channel', args.channel);
908
+ return request('GET', `/api/v1/rt/stream/presence/${encodeURIComponent(channel)}`);
909
+ },
910
+ /** Replay events for a realtime channel. `GET /api/v1/rt/stream/replay/{channel}` */
911
+ replay: (args) => {
912
+ const channel = need('channel', args.channel);
913
+ return request('GET', `/api/v1/rt/stream/replay/${encodeURIComponent(channel)}`, { query: dropUndefined({ "after": args.after, "limit": args.limit }) });
914
+ },
915
+ /** Subscribe a client ID to a realtime channel. `POST /api/v1/rt/stream/subscribe` */
916
+ subscribe: (args) => request('POST', `/api/v1/rt/stream/subscribe`, { body: dropUndefined({ "channel": args.channel, "client_id": args.clientId }) }),
917
+ /** Unsubscribe a client ID from a realtime channel. `POST /api/v1/rt/stream/unsubscribe` */
918
+ unsubscribe: (args) => request('POST', `/api/v1/rt/stream/unsubscribe`, { body: dropUndefined({ "channel": args.channel, "client_id": args.clientId }) }),
919
+ },
920
+ simulation: {
921
+ /** `GET /api/v1/sim/runs/{target_run_id}/compare/{baseline_run_id}` */
922
+ compareRuns: (args) => {
923
+ const targetRunId = need('target_run_id', args.targetRunId);
924
+ const baselineRunId = need('baseline_run_id', args.baselineRunId);
925
+ return request('GET', `/api/v1/sim/runs/${encodeURIComponent(targetRunId)}/compare/${encodeURIComponent(baselineRunId)}`);
926
+ },
927
+ /** `POST /api/v1/sim/discover` */
928
+ discover: () => request('POST', `/api/v1/sim/discover`, { body: {} }),
929
+ /** `GET /api/v1/sim/runs/{run_id}` */
930
+ getRun: (args) => {
931
+ const runId = need('run_id', args.runId);
932
+ return request('GET', `/api/v1/sim/runs/${encodeURIComponent(runId)}`);
933
+ },
934
+ /** `GET /api/v1/sim/runs` */
935
+ listRuns: (args = {}) => request('GET', `/api/v1/sim/runs`, { query: dropUndefined({ "limit": args.limit, "offset": args.offset }) }),
936
+ },
937
+ storage: {
938
+ /** `POST /api/v1/store/buckets` */
939
+ createBucket: (args) => request('POST', `/api/v1/store/buckets`, { body: args.body }),
940
+ /** `DELETE /api/v1/store/buckets/{name}` */
941
+ deleteBucket: (args) => {
942
+ const name = need('name', args.name);
943
+ return request('DELETE', `/api/v1/store/buckets/${encodeURIComponent(name)}`);
944
+ },
945
+ /** `GET /api/v1/store/buckets/{name}` */
946
+ getBucket: (args) => {
947
+ const name = need('name', args.name);
948
+ return request('GET', `/api/v1/store/buckets/${encodeURIComponent(name)}`);
949
+ },
950
+ /** `GET /api/v1/store/buckets` */
951
+ listBuckets: () => request('GET', `/api/v1/store/buckets`),
952
+ /** `POST /api/v1/store/objects/move` */
953
+ moveObject: (args) => request('POST', `/api/v1/store/objects/move`, { body: dropUndefined({ "from_path": args.fromPath, "to_path": args.toPath }) }),
954
+ /** `PATCH /api/v1/store/buckets/{name}` */
955
+ updateBucket: (args) => {
956
+ const name = need('name', args.name);
957
+ return request('PATCH', `/api/v1/store/buckets/${encodeURIComponent(name)}`, { body: args.body });
958
+ },
959
+ },
960
+ templates: {
961
+ /** App templates (SaaS, marketplace, chat): what each creates, the tables it adds and its steps. Project team only. `GET /api/v1/templates` */
962
+ list: () => request('GET', `/api/v1/templates`),
963
+ /** One app template, including the SQL its migration runs. `GET /api/v1/templates/{name}` */
964
+ get: (args) => {
965
+ const name = need('name', args.name);
966
+ return request('GET', `/api/v1/templates/${encodeURIComponent(name)}`);
967
+ },
968
+ /** Apply a template to the project: its migration (tables + row-level security), buckets and their rules, realtime — each step with your own permissions, stopping at the first refusal. dry_run checks for tables that already exist and changes nothing. Needs database.admin. `POST /api/v1/governance/tenants/{org_id}/projects/{project_id}/templates/{name}/apply` */
969
+ apply: (args) => {
970
+ const orgId = need('org_id', args.orgId ?? scope()?.orgId);
971
+ const projectId = need('project_id', args.projectId ?? scope()?.projectId);
972
+ const name = need('name', args.name);
973
+ return request('POST', `/api/v1/governance/tenants/${encodeURIComponent(orgId)}/projects/${encodeURIComponent(projectId)}/templates/${encodeURIComponent(name)}/apply`, { body: dropUndefined({ "dry_run": args.dryRun }) });
974
+ },
975
+ },
976
+ traces: {
977
+ /** The project's recent refused (4xx) and failed (5xx) requests, each with who refused it, why and what to do (kind: denied, failed or all). Project team only. `GET /api/v1/request-traces` */
978
+ list: (args = {}) => request('GET', `/api/v1/request-traces`, { query: dropUndefined({ "kind": args.kind, "before": args.before, "limit": args.limit }) }),
979
+ /** One request by its trace id (SovariaError.traceId, the X-Request-ID header): every hop — gateway checks, engine, SQL — and the explanation. `GET /api/v1/request-traces/{trace_id}` */
980
+ get: (args) => {
981
+ const traceId = need('trace_id', args.traceId);
982
+ return request('GET', `/api/v1/request-traces/${encodeURIComponent(traceId)}`);
983
+ },
984
+ },
985
+ vector: {
986
+ /** Delete an entire vector collection. `DELETE /api/v1/collections/{collection}` */
987
+ deleteCollection: (args) => {
988
+ const collection = need('collection', args.collection);
989
+ return request('DELETE', `/api/v1/collections/${encodeURIComponent(collection)}`);
990
+ },
991
+ /** Delete a record from a vector collection. `DELETE /api/v1/collections/{collection}/records/{record_id}` */
992
+ deleteRecord: (args) => {
993
+ const collection = need('collection', args.collection);
994
+ const recordId = need('record_id', args.recordId);
995
+ return request('DELETE', `/api/v1/collections/${encodeURIComponent(collection)}/records/${encodeURIComponent(recordId)}`);
996
+ },
997
+ /** Generate embeddings for one or more texts. `POST /api/v1/embed` */
998
+ embed: (args) => request('POST', `/api/v1/embed`, { body: dropUndefined({ "texts": args.texts }) }),
999
+ /** List vector collections in the current project scope. `GET /api/v1/collections` */
1000
+ listCollections: () => request('GET', `/api/v1/collections`),
1001
+ /** Embed and upsert documents into a vector collection. `POST /api/v1/vectors/upsert` */
1002
+ upsert: (args) => request('POST', `/api/v1/vectors/upsert`, { body: dropUndefined({ "collection": args.collection, "docs": args.docs }) }),
1003
+ /** Collection settings. app_search: true lets the project's apps (anon key, signed-in users) search it; they can never write or list it. `PATCH /api/v1/collections/{collection}` */
1004
+ setCollection: (args) => {
1005
+ const collection = need('collection', args.collection);
1006
+ return request('PATCH', `/api/v1/collections/${encodeURIComponent(collection)}`, { body: dropUndefined({ "app_search": args.appSearch }) });
1007
+ },
1008
+ /** Embed every stored text again with the project's current model (large collections need this after a model change). `POST /api/v1/collections/{collection}/reembed` */
1009
+ reembedCollection: (args) => {
1010
+ const collection = need('collection', args.collection);
1011
+ return request('POST', `/api/v1/collections/${encodeURIComponent(collection)}/reembed`, { query: dropUndefined({ "force": args.force }) });
1012
+ },
1013
+ /** Search a SQL table: mode vector (nearest embeddings), keyword (full text) or hybrid (both, reciprocal rank fusion). text is embedded with the project's model when no vector is given. Only rows the caller may read. `POST /api/v1/data/rel/vector/search` */
1014
+ sqlSearch: (args) => request('POST', `/api/v1/data/rel/vector/search`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName, "vector": args.vector, "text": args.text, "mode": args.mode, "text_columns": args.textColumns, "language": args.language, "k": args.k, "metric": args.metric, "select": args.select, "filter": args.filter, "max_distance": args.maxDistance }) }),
1015
+ /** Tables whose vector column Sovaria keeps embedded, rows embedded and waiting, last error, and the project's model. `GET /api/v1/data/rel/vector/auto` */
1016
+ sqlAutoStatus: () => request('GET', `/api/v1/data/rel/vector/auto`),
1017
+ /** Keep a vector column (created if missing) filled with embeddings of the source columns; edited rows are embedded again automatically. rebuild re-embeds the whole table. `POST /api/v1/data/rel/vector/auto` */
1018
+ sqlAutoEnable: (args) => request('POST', `/api/v1/data/rel/vector/auto`, { body: dropUndefined({ "table_name": args.tableName, "column_name": args.columnName, "source_columns": args.sourceColumns, "rebuild": args.rebuild }) }),
1019
+ /** Stop keeping a table's vectors up to date (the column and its vectors stay). `DELETE /api/v1/data/rel/vector/auto/{table_name}` */
1020
+ sqlAutoDisable: (args) => {
1021
+ const tableName = need('table_name', args.tableName);
1022
+ return request('DELETE', `/api/v1/data/rel/vector/auto/${encodeURIComponent(tableName)}`);
1023
+ },
1024
+ /** Embed waiting rows now instead of on the next background pass (up to limit per table). `POST /api/v1/data/rel/vector/auto/sync` */
1025
+ sqlAutoSync: (args = {}) => request('POST', `/api/v1/data/rel/vector/auto/sync`, { body: dropUndefined({ "table_name": args.tableName, "limit": args.limit }) }),
1026
+ },
1027
+ workflows: {
1028
+ /** Start a durable workflow run of a function that uses context.step; key makes the start idempotent. `POST /api/v1/fn/workflows` */
1029
+ start: (args) => request('POST', `/api/v1/fn/workflows`, { body: dropUndefined({ "function_name": args.functionName, "input": args.input, "key": args.key }) }),
1030
+ /** Workflow runs, newest first, with the plan's workflow limits. `GET /api/v1/fn/workflows` */
1031
+ list: (args = {}) => request('GET', `/api/v1/fn/workflows`, { query: dropUndefined({ "function": args.functionName, "status": args.status, "before": args.before, "limit": args.limit }) }),
1032
+ /** One run: status, input, output or error, and every finished step with its result. `GET /api/v1/fn/workflows/{run_id}` */
1033
+ get: (args) => {
1034
+ const runId = need('run_id', args.runId);
1035
+ return request('GET', `/api/v1/fn/workflows/${encodeURIComponent(runId)}`);
1036
+ },
1037
+ /** Wake step.waitForSignal(name) with data (kept until the run waits for it). `POST /api/v1/fn/workflows/{run_id}/signal` */
1038
+ signal: (args) => {
1039
+ const runId = need('run_id', args.runId);
1040
+ return request('POST', `/api/v1/fn/workflows/${encodeURIComponent(runId)}/signal`, { body: dropUndefined({ "name": args.name, "data": args.data }) });
1041
+ },
1042
+ /** Stop an unfinished run for good. `POST /api/v1/fn/workflows/{run_id}/cancel` */
1043
+ cancel: (args) => {
1044
+ const runId = need('run_id', args.runId);
1045
+ return request('POST', `/api/v1/fn/workflows/${encodeURIComponent(runId)}/cancel`);
1046
+ },
1047
+ /** Resume a failed run from its failed step; latest moves it to the live function version. `POST /api/v1/fn/workflows/{run_id}/retry` */
1048
+ retry: (args) => {
1049
+ const runId = need('run_id', args.runId);
1050
+ return request('POST', `/api/v1/fn/workflows/${encodeURIComponent(runId)}/retry`, { body: dropUndefined({ "latest": args.latest }) });
1051
+ },
1052
+ },
1053
+ };
1054
+ }