zitejs 0.10.0-start.7 → 0.10.0-start.8

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.
Files changed (32) hide show
  1. package/dist/cjs/sync/lib.js +4 -7
  2. package/dist/cjs/vite/index.js +8 -3
  3. package/dist/cjs/vite/index.test.js +10 -2
  4. package/dist/esm/start/airtable/arrayFields.d.ts +10 -0
  5. package/dist/esm/start/airtable/arrayFields.js +30 -0
  6. package/dist/esm/start/airtable/dispatch.d.ts +54 -0
  7. package/dist/esm/start/airtable/dispatch.js +465 -0
  8. package/dist/esm/start/airtable/formulas.d.ts +69 -0
  9. package/dist/esm/start/airtable/formulas.js +235 -0
  10. package/dist/esm/start/airtable/index.d.ts +11 -0
  11. package/dist/esm/start/airtable/index.js +70 -0
  12. package/dist/esm/start/data/baseRunner.d.ts +92 -0
  13. package/dist/esm/start/data/baseRunner.js +83 -0
  14. package/dist/esm/start/data/dispatch.d.ts +16 -0
  15. package/dist/esm/start/data/dispatch.js +198 -0
  16. package/dist/esm/start/data/index.d.ts +18 -0
  17. package/dist/esm/start/data/index.js +76 -0
  18. package/dist/esm/start/data/sqlNameMappings.d.ts +58 -0
  19. package/dist/esm/start/data/sqlNameMappings.js +92 -0
  20. package/dist/esm/start/data/transformations.d.ts +128 -0
  21. package/dist/esm/start/data/transformations.js +318 -0
  22. package/dist/esm/start/data/types.d.ts +91 -0
  23. package/dist/esm/start/data/types.js +14 -0
  24. package/dist/esm/start/server.js +54 -5
  25. package/dist/esm/start/types.d.ts +40 -0
  26. package/dist/esm/start/version.d.ts +1 -1
  27. package/dist/esm/start/version.js +1 -1
  28. package/dist/esm/start/vite.js +2 -1
  29. package/dist/esm/sync/lib.js +4 -7
  30. package/dist/esm/vite/index.js +8 -3
  31. package/dist/esm/vite/index.test.js +10 -2
  32. package/package.json +1 -1
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+ import type { AirtableFieldShape } from './arrayFields.js';
3
+ /**
4
+ * Supported filter operators for Airtable queries
5
+ */
6
+ export declare const WhereConditionOperators: z.ZodEnum<{
7
+ in: "in";
8
+ not: "not";
9
+ contains: "contains";
10
+ gt: "gt";
11
+ gte: "gte";
12
+ lt: "lt";
13
+ lte: "lte";
14
+ notIn: "notIn";
15
+ ilike: "ilike";
16
+ }>;
17
+ export type WhereConditionOperatorType = z.infer<typeof WhereConditionOperators>;
18
+ /**
19
+ * Check if a key is a condition operator
20
+ */
21
+ export declare const isConditionOperator: (key: string) => key is WhereConditionOperatorType;
22
+ /**
23
+ * Check if a value is a nested condition object (e.g., { contains: 'value' })
24
+ */
25
+ export declare const isNestedCondition: (value: unknown) => value is Partial<Record<WhereConditionOperatorType, unknown>>;
26
+ /**
27
+ * Check if a string is a valid Airtable record ID
28
+ */
29
+ export declare const isValidRecordId: (value: string) => boolean;
30
+ export type FiltersToFormulaOptions = {
31
+ /**
32
+ * Filters object with field names as keys.
33
+ * Values can be direct values (equality) or operator objects like { contains: 'value' }
34
+ */
35
+ filters: Record<string, unknown> | undefined;
36
+ /**
37
+ * Table schema for field lookups (optional).
38
+ * If provided, field IDs will be resolved to field names.
39
+ */
40
+ tableSchema?: {
41
+ fields: Array<AirtableFieldShape & {
42
+ id: string;
43
+ name: string;
44
+ }>;
45
+ };
46
+ /**
47
+ * Callback to resolve a linked record ID to its primary field value.
48
+ * Required for filtering on multipleRecordLinks fields by record ID.
49
+ */
50
+ getPrimaryFieldForRecord?: (tableId: string, recordId: string) => Promise<string | undefined>;
51
+ };
52
+ /**
53
+ * Convert filters to Airtable filterByFormula string.
54
+ *
55
+ * Supports operators: contains, not, in, notIn, lt, lte, gt, gte, ilike
56
+ *
57
+ * @example
58
+ * // Equality
59
+ * { name: 'John' } -> {Name}="John"
60
+ *
61
+ * @example
62
+ * // Contains
63
+ * { name: { contains: 'john' } } -> SEARCH("john", {Name}) != ""
64
+ *
65
+ * @example
66
+ * // Multiple conditions
67
+ * { status: 'active', age: { gte: 18 } } -> AND({Status}="active", {Age}>=18)
68
+ */
69
+ export declare const filtersToFormula: ({ filters, tableSchema, getPrimaryFieldForRecord, }: FiltersToFormulaOptions) => Promise<string | undefined>;
@@ -0,0 +1,235 @@
1
+ import { z } from 'zod';
2
+ import { airtableEqualsFormula } from './arrayFields.js';
3
+ // =============================================================================
4
+ // Condition Operators
5
+ // =============================================================================
6
+ /**
7
+ * Supported filter operators for Airtable queries
8
+ */
9
+ export const WhereConditionOperators = z.enum([
10
+ 'contains',
11
+ 'not',
12
+ 'in',
13
+ 'notIn',
14
+ 'lt',
15
+ 'lte',
16
+ 'gt',
17
+ 'gte',
18
+ 'ilike',
19
+ ]);
20
+ const WHERE_CONDITION_OPERATORS = WhereConditionOperators.options;
21
+ /**
22
+ * Check if a key is a condition operator
23
+ */
24
+ export const isConditionOperator = (key) => WHERE_CONDITION_OPERATORS.includes(key);
25
+ /**
26
+ * Check if a value is a nested condition object (e.g., { contains: 'value' })
27
+ */
28
+ export const isNestedCondition = (value) => {
29
+ if (value === null || typeof value !== 'object')
30
+ return false;
31
+ if (Array.isArray(value))
32
+ return false;
33
+ // Check if any keys are condition operators
34
+ return Object.keys(value).some(key => isConditionOperator(key));
35
+ };
36
+ // =============================================================================
37
+ // Formula Helpers
38
+ // =============================================================================
39
+ /** Regex to validate Airtable record IDs */
40
+ const AIRTABLE_RECORD_ID_REGEX = /^rec[a-zA-Z0-9]{14}$/;
41
+ /** SDK field name for record ID */
42
+ const SDK_ID_FIELD = 'id';
43
+ /**
44
+ * Check if a string is a valid Airtable record ID
45
+ */
46
+ export const isValidRecordId = (value) => {
47
+ return !!value.match(AIRTABLE_RECORD_ID_REGEX);
48
+ };
49
+ /**
50
+ * Escape quotes in string values for Airtable formulas
51
+ */
52
+ const escapeFormulaString = (value) => value.replace(/"/g, '\\"');
53
+ /**
54
+ * Format a value for use in Airtable formulas
55
+ */
56
+ const getAirtableFilterValue = (value) => {
57
+ if (value instanceof Date) {
58
+ if (!Number.isFinite(value.getTime())) {
59
+ throw new Error('Invalid Date passed to Airtable filter formula. Use a valid Date or ISO date string.');
60
+ }
61
+ return `"${value.toISOString()}"`;
62
+ }
63
+ if (typeof value === 'string') {
64
+ return `"${escapeFormulaString(value)}"`;
65
+ }
66
+ if (typeof value === 'boolean') {
67
+ return value ? 'TRUE()' : 'FALSE()';
68
+ }
69
+ if (value === undefined || value === null) {
70
+ return 'BLANK()';
71
+ }
72
+ // For numbers and other types, use as is
73
+ return String(value);
74
+ };
75
+ /**
76
+ * Convert filters to Airtable filterByFormula string.
77
+ *
78
+ * Supports operators: contains, not, in, notIn, lt, lte, gt, gte, ilike
79
+ *
80
+ * @example
81
+ * // Equality
82
+ * { name: 'John' } -> {Name}="John"
83
+ *
84
+ * @example
85
+ * // Contains
86
+ * { name: { contains: 'john' } } -> SEARCH("john", {Name}) != ""
87
+ *
88
+ * @example
89
+ * // Multiple conditions
90
+ * { status: 'active', age: { gte: 18 } } -> AND({Status}="active", {Age}>=18)
91
+ */
92
+ export const filtersToFormula = async ({ filters, tableSchema, getPrimaryFieldForRecord, }) => {
93
+ if (!filters || Object.keys(filters).length === 0)
94
+ return undefined;
95
+ const conditions = [];
96
+ for (const [field, condition] of Object.entries(filters)) {
97
+ let value = condition;
98
+ let operator = 'equals';
99
+ if (isNestedCondition(condition)) {
100
+ operator = Object.keys(condition)[0];
101
+ value = condition[operator];
102
+ }
103
+ // Special case for id field - use RECORD_ID()
104
+ if (field === SDK_ID_FIELD || field === 'id') {
105
+ const recordIds = Array.isArray(value) ? value : [value];
106
+ if (operator === 'equals') {
107
+ conditions.push(`RECORD_ID() = '${recordIds[0]}'`);
108
+ }
109
+ else {
110
+ const recordIdClause = `OR(${recordIds
111
+ .map(recordId => `RECORD_ID() = '${recordId}'`)
112
+ .join(', ')})`;
113
+ if (operator === 'notIn' || operator === 'not') {
114
+ conditions.push(`NOT(${recordIdClause})`);
115
+ continue;
116
+ }
117
+ conditions.push(recordIdClause);
118
+ }
119
+ continue;
120
+ }
121
+ // Find the actual field in the schema
122
+ const fieldInfo = tableSchema?.fields.find(f => f.id === field || f.name === field);
123
+ // Skip undefined conditions
124
+ if (condition === undefined)
125
+ continue;
126
+ // Use field name from schema if available, otherwise use the key as-is
127
+ const fieldName = `{${fieldInfo?.name || field}}`;
128
+ // Pre-process linked record values
129
+ if (fieldInfo?.type === 'multipleRecordLinks' && getPrimaryFieldForRecord) {
130
+ const linkedRecordOptions = fieldInfo.options;
131
+ let linkedRecords = [];
132
+ if (value !== undefined) {
133
+ if (!Array.isArray(value)) {
134
+ if (value !== '') {
135
+ linkedRecords = [String(value)];
136
+ }
137
+ }
138
+ else {
139
+ linkedRecords = value;
140
+ }
141
+ }
142
+ // Resolve record IDs to primary field values
143
+ if (linkedRecordOptions?.linkedTableId) {
144
+ value = (await Promise.all(linkedRecords.map(async (recordValue) => {
145
+ if (isValidRecordId(recordValue)) {
146
+ const primaryColumn = await getPrimaryFieldForRecord(linkedRecordOptions.linkedTableId, recordValue);
147
+ if (primaryColumn) {
148
+ return primaryColumn;
149
+ }
150
+ }
151
+ return recordValue;
152
+ }))).flat();
153
+ }
154
+ }
155
+ // Handle checkbox fields with string values
156
+ if (fieldInfo?.type === 'checkbox' &&
157
+ (operator === 'equals' || operator === 'not') &&
158
+ typeof value === 'string') {
159
+ const TRUE_VALUES = ['true', 'yes', 'y', 'TRUE'];
160
+ value = TRUE_VALUES.includes(value.toLowerCase()) ? true : false;
161
+ }
162
+ // Skip undefined values
163
+ if (value === undefined)
164
+ continue;
165
+ const textFieldRef = `ARRAYJOIN(${fieldName})`;
166
+ const equalsClause = (v) => fieldInfo
167
+ ? airtableEqualsFormula({
168
+ field: fieldInfo,
169
+ fieldName,
170
+ value: getAirtableFilterValue(v),
171
+ })
172
+ : `${fieldName}=${getAirtableFilterValue(v)}`;
173
+ // Build condition based on operator
174
+ switch (operator) {
175
+ case 'equals':
176
+ if (Array.isArray(value)) {
177
+ const andClauses = value.map(equalsClause);
178
+ conditions.push(`AND(${andClauses.join(',')})`);
179
+ }
180
+ else {
181
+ conditions.push(equalsClause(value));
182
+ }
183
+ break;
184
+ case 'contains':
185
+ if (Array.isArray(value)) {
186
+ const andClauses = value.map(v => `SEARCH(${getAirtableFilterValue(v)}, ${textFieldRef}) != ""`);
187
+ conditions.push(`AND(${andClauses.join(',')})`);
188
+ }
189
+ else {
190
+ conditions.push(`SEARCH(${getAirtableFilterValue(value)}, ${textFieldRef}) != ""`);
191
+ }
192
+ break;
193
+ case 'not':
194
+ if (Array.isArray(value) && value.length === 0) {
195
+ break;
196
+ }
197
+ conditions.push(`NOT(${Array.isArray(value)
198
+ ? `OR(${value.map(equalsClause).join(',')})`
199
+ : equalsClause(value)})`);
200
+ break;
201
+ case 'in':
202
+ if (Array.isArray(value)) {
203
+ const orClauses = value.map(equalsClause);
204
+ conditions.push(`OR(${orClauses.join(',')})`);
205
+ }
206
+ break;
207
+ case 'notIn':
208
+ if (Array.isArray(value) && value.length > 0) {
209
+ const orClauses = value.map(equalsClause);
210
+ conditions.push(`NOT(OR(${orClauses.join(',')}))`);
211
+ }
212
+ break;
213
+ case 'lt':
214
+ conditions.push(`${fieldName}<${getAirtableFilterValue(value)}`);
215
+ break;
216
+ case 'lte':
217
+ conditions.push(`${fieldName}<=${getAirtableFilterValue(value)}`);
218
+ break;
219
+ case 'gt':
220
+ conditions.push(`${fieldName}>${getAirtableFilterValue(value)}`);
221
+ break;
222
+ case 'gte':
223
+ conditions.push(`${fieldName}>=${getAirtableFilterValue(value)}`);
224
+ break;
225
+ case 'ilike':
226
+ conditions.push(`LOWER(${textFieldRef}) = LOWER(${getAirtableFilterValue(value)})`);
227
+ break;
228
+ }
229
+ }
230
+ if (conditions.length === 0)
231
+ return undefined;
232
+ if (conditions.length === 1)
233
+ return conditions[0];
234
+ return `AND(${conditions.join(',')})`;
235
+ };
@@ -0,0 +1,11 @@
1
+ import { type AirtableSettings } from "./dispatch.js";
2
+ import type { PlatformSession, ZiteRequestContext } from "../types.js";
3
+ /** The build's Airtable integration `integrationId`, or undefined when it isn't one, or the host can't say. */
4
+ export declare const airtableSettingsOf: (session: PlatformSession, integrationId: string) => Promise<AirtableSettings | undefined>;
5
+ /**
6
+ * One generated Airtable table call, run here with the connection's placeholder
7
+ * token; egress swaps the real one in for Airtable alone, and refreshes it.
8
+ */
9
+ export declare function runAirtableCall(host: ZiteRequestContext, session: PlatformSession, integrationId: string, settings: AirtableSettings, methodName: string, params: unknown, access: "signedIn" | "anyone" | "webhook" | "workflow"): Promise<unknown>;
10
+ /** For tests: forget what this isolate learned. */
11
+ export declare const resetAirtableSettings: () => void;
@@ -0,0 +1,70 @@
1
+ import { executeAirtableCall } from "./dispatch.js";
2
+ import { ZiteError, isZiteErrorCode } from "../errors.js";
3
+ const AIRTABLE_API = "https://api.airtable.com";
4
+ // The platform id `integrations.get` is answered under (`INTEGRATIONS_SDK_INTEGRATION_ID`).
5
+ const CONNECTIONS = "__connections__";
6
+ // A build's integrations don't change, so per isolate: only answers, never a pending call.
7
+ const settingsHeld = new Map();
8
+ let unsupported = false;
9
+ const NOT_IMPLEMENTED = /does not implement (?:the )?method/i;
10
+ /** The build's Airtable integration `integrationId`, or undefined when it isn't one, or the host can't say. */
11
+ export const airtableSettingsOf = async (session, integrationId) => {
12
+ if (unsupported || !session.integrationSettings)
13
+ return undefined;
14
+ if (settingsHeld.has(integrationId))
15
+ return settingsHeld.get(integrationId) ?? undefined;
16
+ try {
17
+ const answer = await session.integrationSettings(integrationId);
18
+ const settings = answer?.serviceType === "airtable" && typeof answer.baseId === "string"
19
+ ? { baseId: answer.baseId, nameMappings: answer.nameMappings ?? null }
20
+ : null;
21
+ settingsHeld.set(integrationId, settings);
22
+ return settings ?? undefined;
23
+ }
24
+ catch (error) {
25
+ if (error instanceof Error && NOT_IMPLEMENTED.test(error.message)) {
26
+ unsupported = true;
27
+ return undefined;
28
+ }
29
+ throw error;
30
+ }
31
+ };
32
+ /**
33
+ * One generated Airtable table call, run here with the connection's placeholder
34
+ * token; egress swaps the real one in for Airtable alone, and refreshes it.
35
+ */
36
+ export async function runAirtableCall(host, session, integrationId, settings, methodName, params, access) {
37
+ // As classic: a demo reaches no connected account.
38
+ if (host.mode === "demo")
39
+ throw new ZiteError("FORBIDDEN", "This action is not available in demo mode");
40
+ const connection = await session.call({
41
+ integrationId: CONNECTIONS,
42
+ className: "Connections",
43
+ methodName: "get",
44
+ params: { name: integrationId },
45
+ access,
46
+ });
47
+ if ("error" in connection) {
48
+ const { code, message, userFacingMessage } = connection.error;
49
+ throw new ZiteError({ code: isZiteErrorCode(code) ? code : "INTERNAL_ERROR", message, userFacingMessage });
50
+ }
51
+ const token = connection.value?.accessToken;
52
+ if (typeof token !== "string") {
53
+ throw new ZiteError("INTERNAL_ERROR", `The ${integrationId} connection has no token`);
54
+ }
55
+ host.airtableReads ??= new Map();
56
+ return executeAirtableCall({
57
+ settings,
58
+ reads: host.airtableReads,
59
+ fetch: (path, init) => fetch(`${AIRTABLE_API}${path}`, {
60
+ method: init.method,
61
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
62
+ body: init.body === undefined ? undefined : JSON.stringify(init.body),
63
+ }),
64
+ }, methodName, params);
65
+ }
66
+ /** For tests: forget what this isolate learned. */
67
+ export const resetAirtableSettings = () => {
68
+ settingsHeld.clear();
69
+ unsupported = false;
70
+ };
@@ -0,0 +1,92 @@
1
+ import { type BulkCreateResponseType, type FindAllResponseType, type FindOneResponseType, type GetBaseResponseType, type LegacyRecordsFilterClauseType, type NameMappings } from "./types.js";
2
+ /** One base-runner request, `path` from `/api/v1`; the platform sends it and answers with base-runner's response. */
3
+ export type DataTransport = (request: {
4
+ method: string;
5
+ path: string;
6
+ body?: string;
7
+ }) => Promise<Response>;
8
+ type Sort = string | Array<{
9
+ field: string;
10
+ direction: "asc" | "desc";
11
+ }>;
12
+ /** An id as one path segment: an unencoded `/` or a `..` would move the request to another base's URL. */
13
+ export declare const segment: (id: string | number) => string;
14
+ export declare const createBaseRunner: (transport: DataTransport) => {
15
+ bases: {
16
+ get: ({ baseId }: {
17
+ baseId: string;
18
+ }) => Promise<GetBaseResponseType>;
19
+ };
20
+ records: {
21
+ get: ({ baseId, tableId, recordId, fields }: {
22
+ baseId: string;
23
+ tableId: string;
24
+ recordId: string;
25
+ fields?: string[];
26
+ }) => Promise<FindOneResponseType>;
27
+ findAll: ({ baseId, tableId, filters, offset, sort, limit, fields, }: {
28
+ baseId: string;
29
+ tableId: string;
30
+ filters?: LegacyRecordsFilterClauseType;
31
+ offset?: number;
32
+ sort?: Sort;
33
+ limit?: number;
34
+ fields?: string[];
35
+ }) => Promise<FindAllResponseType>;
36
+ create: ({ baseId, tableId, record }: {
37
+ baseId: string;
38
+ tableId: string;
39
+ record: Record<string, unknown>;
40
+ }) => Promise<FindOneResponseType>;
41
+ update: ({ baseId, tableId, recordId, record, }: {
42
+ baseId: string;
43
+ tableId: string;
44
+ recordId: string;
45
+ record: Record<string, unknown>;
46
+ }) => Promise<FindOneResponseType>;
47
+ delete: ({ baseId, tableId, recordId }: {
48
+ baseId: string;
49
+ tableId: string;
50
+ recordId: string;
51
+ }) => Promise<{
52
+ id: string;
53
+ }>;
54
+ bulkCreate: ({ baseId, tableId, records, matchOn, }: {
55
+ baseId: string;
56
+ tableId: string;
57
+ records: Record<string, unknown>[];
58
+ matchOn?: string[];
59
+ }) => Promise<BulkCreateResponseType>;
60
+ };
61
+ sql: {
62
+ execute: ({ baseId, sql, params, statementTimeoutMs, nameMappings, }: {
63
+ baseId: string;
64
+ sql: string;
65
+ params?: unknown[];
66
+ statementTimeoutMs?: number;
67
+ nameMappings?: NameMappings;
68
+ }) => Promise<unknown>;
69
+ };
70
+ auth: {
71
+ findAll: ({ baseId, appIds, filters, filter, offset, sort, limit, }: {
72
+ baseId: string;
73
+ appIds?: string[];
74
+ filters?: LegacyRecordsFilterClauseType;
75
+ filter?: unknown;
76
+ offset?: number;
77
+ sort?: Sort;
78
+ limit?: number;
79
+ }) => Promise<unknown>;
80
+ update: ({ baseId, userId, profile, }: {
81
+ baseId: string;
82
+ userId: string;
83
+ profile: {
84
+ firstName?: string | null;
85
+ lastName?: string | null;
86
+ image?: string | null;
87
+ };
88
+ }) => Promise<unknown>;
89
+ };
90
+ };
91
+ export type BaseRunner = ReturnType<typeof createBaseRunner>;
92
+ export {};
@@ -0,0 +1,83 @@
1
+ // Ported from restly's packages/workflow-edge/src/databases (client, records, sql, authUsers, bases):
2
+ // the requests are the same bytes classic's DatabasesSdk sends; the host adds the key and the acting user.
3
+ import { DatabasesApiError, } from "./types.js";
4
+ /** An id as one path segment: an unencoded `/` or a `..` would move the request to another base's URL. */
5
+ export const segment = (id) => {
6
+ const value = String(id);
7
+ const invalid = new DatabasesApiError(`Invalid id: "${value}"`, 400, "Bad Request");
8
+ if (value === "" || value === "." || value === "..")
9
+ throw invalid;
10
+ try {
11
+ return encodeURIComponent(value);
12
+ }
13
+ catch {
14
+ // A lone surrogate, which a visitor can send as JSON.
15
+ throw invalid;
16
+ }
17
+ };
18
+ /** Every path, however it was built: none may climb out of where it starts. */
19
+ const apiPath = (path) => {
20
+ const full = `/api/v1${path}`;
21
+ const pathname = full.split("?")[0];
22
+ if (!new URL(full, "https://base-runner.invalid").pathname.endsWith(pathname)) {
23
+ throw new DatabasesApiError(`Invalid path: ${pathname}`, 400, "Bad Request");
24
+ }
25
+ return full;
26
+ };
27
+ export const createBaseRunner = (transport) => {
28
+ const send = async (method, path, body) => {
29
+ const response = await transport({ method, path: apiPath(path), body: body ? JSON.stringify(body) : undefined });
30
+ if (!response.ok) {
31
+ let errorMessage = response.statusText;
32
+ try {
33
+ const errorBody = (await response.json());
34
+ errorMessage = errorBody?.error?.message || errorBody?.message || errorMessage;
35
+ }
36
+ catch {
37
+ // If we can't parse the error body, fall back to statusText
38
+ }
39
+ throw new DatabasesApiError(errorMessage, response.status, response.statusText);
40
+ }
41
+ return response;
42
+ };
43
+ const json = async (method, path, body) => (await send(method, path, body)).json();
44
+ return {
45
+ bases: {
46
+ get: ({ baseId }) => json("GET", `/bases/${segment(baseId)}`),
47
+ },
48
+ records: {
49
+ get: ({ baseId, tableId, recordId, fields }) => json("GET", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records/${segment(recordId)}${fields?.length ? `?fields=${encodeURIComponent(fields.join(","))}` : ""}`),
50
+ findAll: ({ baseId, tableId, filters, offset, sort, limit = 500, fields, }) => json("POST", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records/list`, {
51
+ filters,
52
+ offset,
53
+ sort,
54
+ limit,
55
+ fields,
56
+ }),
57
+ create: ({ baseId, tableId, record }) => json("POST", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records`, { record }),
58
+ update: ({ baseId, tableId, recordId, record, }) => json("PATCH", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records/${segment(recordId)}`, { record }),
59
+ delete: async ({ baseId, tableId, recordId }) => {
60
+ await send("DELETE", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records/${segment(recordId)}`);
61
+ return { id: recordId };
62
+ },
63
+ bulkCreate: ({ baseId, tableId, records, matchOn, }) => json("POST", `/bases/${segment(baseId)}/tables/${segment(tableId)}/records/bulk`, {
64
+ records,
65
+ matchOn,
66
+ }),
67
+ },
68
+ sql: {
69
+ execute: ({ baseId, sql, params, statementTimeoutMs, nameMappings, }) => json("POST", `/bases/${segment(baseId)}/sql`, { sql, params, statementTimeoutMs, nameMappings }),
70
+ },
71
+ auth: {
72
+ findAll: ({ baseId, appIds, filters, filter, offset, sort, limit = 500, }) => json("POST", `/bases/${segment(baseId)}/auth/users/list`, {
73
+ appIds,
74
+ filters,
75
+ filter,
76
+ offset,
77
+ sort,
78
+ limit,
79
+ }),
80
+ update: ({ baseId, userId, profile, }) => json("PATCH", `/bases/${segment(baseId)}/auth/users/${segment(userId)}`, profile),
81
+ },
82
+ };
83
+ };
@@ -0,0 +1,16 @@
1
+ import type { BaseRunner } from "./baseRunner.js";
2
+ import { type BaseTable, type DataNameMappings } from "./types.js";
3
+ export type DataContext = {
4
+ baseRunner: BaseRunner;
5
+ /** The build's base, from the platform; a base id the app sends is ignored. */
6
+ baseId: string;
7
+ nameMappings: DataNameMappings | null;
8
+ /** The base's tables, for field names and SQL names. */
9
+ tables: BaseTable[] | undefined;
10
+ /** A demo: only reads reach the database. */
11
+ readOnly: boolean;
12
+ };
13
+ export declare const DEMO_UNAVAILABLE_MESSAGE = "This action is not available in demo mode";
14
+ export declare function asZiteClientError(error: unknown): unknown;
15
+ /** One `zite.*` data call, as classic's dispatch runs it. */
16
+ export declare function executeDatabasesCall(context: DataContext, methodName: string, params: any): Promise<any>;