zitejs 0.9.68 → 0.9.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/bundle/index.js +9 -0
- package/dist/cjs/dev/index.js +28 -0
- package/dist/cjs/runtime/index.d.ts +65 -3
- package/dist/cjs/runtime/index.js +13 -0
- package/dist/cjs/sync/lib.d.ts +8 -0
- package/dist/cjs/sync/lib.js +53 -8
- package/dist/esm/bundle/index.js +9 -0
- package/dist/esm/cli.js +0 -0
- package/dist/esm/dev/index.js +29 -1
- package/dist/esm/runtime/index.d.ts +65 -3
- package/dist/esm/runtime/index.js +12 -0
- package/dist/esm/sync/lib.d.ts +8 -0
- package/dist/esm/sync/lib.js +52 -8
- package/package.json +1 -1
- package/dist/cjs/api/index.js +0 -5
- package/dist/cjs/db/index.js +0 -5
- package/dist/esm/api/index.d.ts +0 -2
- package/dist/esm/api/index.js +0 -1
- package/dist/esm/db/index.d.ts +0 -2
- package/dist/esm/db/index.js +0 -1
package/dist/cjs/bundle/index.js
CHANGED
|
@@ -259,6 +259,15 @@ function createAliasPlugin(opts) {
|
|
|
259
259
|
}
|
|
260
260
|
return { path: 'zitejs/integrations', external: true };
|
|
261
261
|
});
|
|
262
|
+
// Resolve zitejs/email to .zite/integrations/email.ts
|
|
263
|
+
build.onResolve({ filter: /^zitejs\/email$/ }, () => {
|
|
264
|
+
if (opts.baseDir) {
|
|
265
|
+
const intPath = path.resolve(opts.baseDir, '.zite/integrations/email.ts');
|
|
266
|
+
if (fs.existsSync(intPath))
|
|
267
|
+
return { path: intPath };
|
|
268
|
+
}
|
|
269
|
+
return { path: 'zitejs/email', external: true };
|
|
270
|
+
});
|
|
262
271
|
// zitejs/runtime is NOT in PREBUNDLED_LIBS — it's a thin fetch()
|
|
263
272
|
// wrapper that gets bundled inline by esbuild (no special handling).
|
|
264
273
|
for (const [pkgName, modulePath] of Object.entries(PREBUNDLED_LIBS)) {
|
package/dist/cjs/dev/index.js
CHANGED
|
@@ -33,11 +33,39 @@ function getFlowId(appDir) {
|
|
|
33
33
|
catch { }
|
|
34
34
|
return undefined;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Find the connected email integration's key in an app's zite.config.json,
|
|
38
|
+
* if any. The key is the integrationId used by the runtime SDK bridge.
|
|
39
|
+
*/
|
|
40
|
+
function getEmailIntegrationId(appDir) {
|
|
41
|
+
try {
|
|
42
|
+
const configPath = (0, path_1.join)("apps", appDir, "zite.config.json");
|
|
43
|
+
if (!(0, fs_2.existsSync)(configPath))
|
|
44
|
+
return undefined;
|
|
45
|
+
const config = JSON.parse((0, fs_2.readFileSync)(configPath, "utf-8"));
|
|
46
|
+
const integrations = config.integrations ?? {};
|
|
47
|
+
for (const [id, int] of Object.entries(integrations)) {
|
|
48
|
+
if (int?.type === "email")
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch { }
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
36
55
|
function regenerateAppTypedWrappers(appDir) {
|
|
37
56
|
const outDir = (0, path_1.join)("apps", appDir, ".zite");
|
|
38
57
|
(0, fs_2.mkdirSync)(outDir, { recursive: true });
|
|
39
58
|
(0, fs_2.writeFileSync)((0, path_1.join)(outDir, "user.ts"), (0, lib_js_1.generateUserTs)());
|
|
40
59
|
(0, fs_2.writeFileSync)((0, path_1.join)(outDir, "auth.ts"), (0, lib_js_1.generateAuthWrapperTs)());
|
|
60
|
+
// Email integration: generate the Email client at .zite/integrations/email.ts.
|
|
61
|
+
// Resolved by the `zitejs/email` bundler/tsconfig alias (mirrors airtable's
|
|
62
|
+
// `zitejs/integrations`), so endpoint code uses `import { Email } from 'zitejs/email'`.
|
|
63
|
+
const emailIntegrationId = getEmailIntegrationId(appDir);
|
|
64
|
+
if (emailIntegrationId) {
|
|
65
|
+
const intDir = (0, path_1.join)(outDir, "integrations");
|
|
66
|
+
(0, fs_2.mkdirSync)(intDir, { recursive: true });
|
|
67
|
+
(0, fs_2.writeFileSync)((0, path_1.join)(intDir, "email.ts"), (0, lib_js_1.generateEmailSdk)(emailIntegrationId));
|
|
68
|
+
}
|
|
41
69
|
(0, fs_2.writeFileSync)((0, path_1.join)(outDir, "backend.ts"), (0, lib_js_1.generateBackendWrapperTs)());
|
|
42
70
|
}
|
|
43
71
|
function regenerateAppApiTs(appDir) {
|
|
@@ -73,7 +73,7 @@ export interface AirtableTableClient<T> {
|
|
|
73
73
|
}): Promise<T | undefined>;
|
|
74
74
|
create(params: {
|
|
75
75
|
record: Partial<T>;
|
|
76
|
-
}): Promise<T>;
|
|
76
|
+
}): Promise<T | undefined>;
|
|
77
77
|
bulkCreate(params: {
|
|
78
78
|
records: Partial<T>[];
|
|
79
79
|
}): Promise<T[]>;
|
|
@@ -82,13 +82,75 @@ export interface AirtableTableClient<T> {
|
|
|
82
82
|
record: Partial<T>;
|
|
83
83
|
}): Promise<{
|
|
84
84
|
id: string;
|
|
85
|
-
fields:
|
|
86
|
-
}>;
|
|
85
|
+
fields: T;
|
|
86
|
+
} | undefined>;
|
|
87
87
|
delete(params: {
|
|
88
88
|
id: string;
|
|
89
89
|
}): Promise<DeleteResult>;
|
|
90
90
|
}
|
|
91
91
|
export declare function createAirtableClient<T>(integrationId: string, className: string, implicitParams: Record<string, unknown>): AirtableTableClient<T>;
|
|
92
|
+
/** A block of content in an email body. */
|
|
93
|
+
export type EmailBlock = {
|
|
94
|
+
type: "text";
|
|
95
|
+
content: string;
|
|
96
|
+
} | {
|
|
97
|
+
type: "button";
|
|
98
|
+
label: string;
|
|
99
|
+
href: string;
|
|
100
|
+
alignment?: "left" | "center" | "right";
|
|
101
|
+
} | {
|
|
102
|
+
type: "image";
|
|
103
|
+
src: string;
|
|
104
|
+
alt?: string;
|
|
105
|
+
alignment?: "left" | "center" | "right";
|
|
106
|
+
width: number;
|
|
107
|
+
height: number;
|
|
108
|
+
} | {
|
|
109
|
+
type: "spacer";
|
|
110
|
+
height: number;
|
|
111
|
+
} | {
|
|
112
|
+
type: "divider";
|
|
113
|
+
borderColor?: string;
|
|
114
|
+
};
|
|
115
|
+
export interface SendEmailParams {
|
|
116
|
+
/** Recipient address(es). Must be valid emails — never placeholders like "me". */
|
|
117
|
+
to: string | string[];
|
|
118
|
+
subject: string;
|
|
119
|
+
/** Email body as an array of content blocks. */
|
|
120
|
+
body: EmailBlock[];
|
|
121
|
+
cc?: string[];
|
|
122
|
+
bcc?: string[];
|
|
123
|
+
replyTo?: string;
|
|
124
|
+
/** 'formatted' (default) for styled HTML, 'plain' for text-only. */
|
|
125
|
+
layout?: "formatted" | "plain";
|
|
126
|
+
/** Custom logo shown above the email content (header area), for branding. */
|
|
127
|
+
logo?: {
|
|
128
|
+
url: string;
|
|
129
|
+
width?: number;
|
|
130
|
+
height?: number;
|
|
131
|
+
};
|
|
132
|
+
/** File attachments, each fetched from its URL at send time. */
|
|
133
|
+
attachments?: {
|
|
134
|
+
filename: string;
|
|
135
|
+
url: string;
|
|
136
|
+
contentType?: string;
|
|
137
|
+
}[];
|
|
138
|
+
}
|
|
139
|
+
export interface SendEmailResult {
|
|
140
|
+
success: boolean;
|
|
141
|
+
messageId: string;
|
|
142
|
+
}
|
|
143
|
+
export interface EmailClient {
|
|
144
|
+
send(params: SendEmailParams): Promise<SendEmailResult>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Email client — sends through the Zite email gateway via the runtime SDK
|
|
148
|
+
* bridge. Email cannot run in-worker (provider auth, image processing, HTML
|
|
149
|
+
* inlining all live in the gateway), so every call dispatches through
|
|
150
|
+
* getSdkCall(), which routes to the email handler. The integrationId is the
|
|
151
|
+
* app's connected email integration key.
|
|
152
|
+
*/
|
|
153
|
+
export declare function createEmailClient(integrationId: string): EmailClient;
|
|
92
154
|
export declare function createNotificationsClient(): {
|
|
93
155
|
create(params: NotificationsCreateParams): Promise<NotificationsCreateResult>;
|
|
94
156
|
};
|
|
@@ -4,6 +4,7 @@ exports.createCaller = void 0;
|
|
|
4
4
|
exports.createTableClient = createTableClient;
|
|
5
5
|
exports.createSqlClient = createSqlClient;
|
|
6
6
|
exports.createAirtableClient = createAirtableClient;
|
|
7
|
+
exports.createEmailClient = createEmailClient;
|
|
7
8
|
exports.createNotificationsClient = createNotificationsClient;
|
|
8
9
|
exports.createMetaClient = createMetaClient;
|
|
9
10
|
const sdkCall_js_1 = require("../internal/sdkCall.js");
|
|
@@ -100,6 +101,18 @@ function createAirtableClient(integrationId, className, implicitParams) {
|
|
|
100
101
|
}),
|
|
101
102
|
};
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Email client — sends through the Zite email gateway via the runtime SDK
|
|
106
|
+
* bridge. Email cannot run in-worker (provider auth, image processing, HTML
|
|
107
|
+
* inlining all live in the gateway), so every call dispatches through
|
|
108
|
+
* getSdkCall(), which routes to the email handler. The integrationId is the
|
|
109
|
+
* app's connected email integration key.
|
|
110
|
+
*/
|
|
111
|
+
function createEmailClient(integrationId) {
|
|
112
|
+
return {
|
|
113
|
+
send: (params) => (0, sdkCall_js_1.getSdkCall)()(integrationId, "Email", "send", params),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
103
116
|
const NOTIFICATIONS_SDK_INTEGRATION_ID = "__notifications__";
|
|
104
117
|
const META_SDK_INTEGRATION_ID = "__meta__";
|
|
105
118
|
function createNotificationsClient() {
|
package/dist/cjs/sync/lib.d.ts
CHANGED
|
@@ -59,3 +59,11 @@ export type AirtableLock = {
|
|
|
59
59
|
};
|
|
60
60
|
export declare function generateAirtableTs(lock: AirtableLock): string | null;
|
|
61
61
|
export declare function generateBackendWrapperTs(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Generate `.zite/integrations/email.ts` — the `Email` client for an app with
|
|
64
|
+
* an email integration connected. Mirrors the airtable SDK generation: a thin
|
|
65
|
+
* wrapper over a `zitejs/runtime` factory that dispatches through the runtime
|
|
66
|
+
* SDK bridge, resolved via the `zitejs/email` alias. `integrationId` is the
|
|
67
|
+
* connected integration's key.
|
|
68
|
+
*/
|
|
69
|
+
export declare function generateEmailSdk(integrationId: string): string;
|
package/dist/cjs/sync/lib.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.generateUserTs = generateUserTs;
|
|
|
9
9
|
exports.generateAuthWrapperTs = generateAuthWrapperTs;
|
|
10
10
|
exports.generateAirtableTs = generateAirtableTs;
|
|
11
11
|
exports.generateBackendWrapperTs = generateBackendWrapperTs;
|
|
12
|
+
exports.generateEmailSdk = generateEmailSdk;
|
|
12
13
|
const parser_1 = require("@babel/parser");
|
|
13
14
|
const FIELD_TYPE_MAP = {
|
|
14
15
|
single_line_text: "string",
|
|
@@ -25,8 +26,8 @@ const FIELD_TYPE_MAP = {
|
|
|
25
26
|
single_select: "string",
|
|
26
27
|
multiple_select: "string[]",
|
|
27
28
|
checkbox: "boolean",
|
|
28
|
-
date: "string",
|
|
29
|
-
datetime: "string",
|
|
29
|
+
date: "string | null",
|
|
30
|
+
datetime: "string | null",
|
|
30
31
|
attachments: "Array<{ url: string; name?: string }>",
|
|
31
32
|
linked_record: "string | string[]",
|
|
32
33
|
lookup: "unknown",
|
|
@@ -53,14 +54,31 @@ const DURATION_FORMAT_EXAMPLES = {
|
|
|
53
54
|
"h:mm:ss.sss": "1:23:03.000",
|
|
54
55
|
};
|
|
55
56
|
function toPascalCase(name) {
|
|
56
|
-
|
|
57
|
+
const pascal = name
|
|
57
58
|
.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase())
|
|
58
|
-
.replace(/^(.)/, (_, c) => c.toUpperCase())
|
|
59
|
+
.replace(/^(.)/, (_, c) => c.toUpperCase())
|
|
60
|
+
// Drop leftover non-alphanumerics (e.g. a trailing ">" from "</p>") so the
|
|
61
|
+
// sdkName is always a valid identifier in .zite/db.ts.
|
|
62
|
+
.replace(/[^a-zA-Z0-9]+/g, "");
|
|
63
|
+
if (!pascal)
|
|
64
|
+
return "_";
|
|
65
|
+
return /^[0-9]/.test(pascal) ? `_${pascal}` : pascal; // can't start with a digit
|
|
59
66
|
}
|
|
60
67
|
function toCamelCase(name) {
|
|
61
68
|
const pascal = toPascalCase(name);
|
|
62
69
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
63
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Existing sdkNames are preserved across syncs so user code keeps compiling,
|
|
73
|
+
* but schemas written before the sanitizer stripped trailing symbols can carry
|
|
74
|
+
* invalid identifiers (e.g. "timeSeconds)"). Keep an existing name only when
|
|
75
|
+
* it's a valid identifier; otherwise fall through to recomputing it.
|
|
76
|
+
*/
|
|
77
|
+
function keepValidSdkName(sdkName) {
|
|
78
|
+
if (!sdkName)
|
|
79
|
+
return undefined;
|
|
80
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(sdkName) ? sdkName : undefined;
|
|
81
|
+
}
|
|
64
82
|
function tsTypeForSchemaField(def) {
|
|
65
83
|
if (def.type === "single_select" || def.type === "multiple_select") {
|
|
66
84
|
const options = def.template
|
|
@@ -103,11 +121,11 @@ function fieldJsdoc(schemaField, table) {
|
|
|
103
121
|
if (def.type === "date") {
|
|
104
122
|
const tpl = def.template;
|
|
105
123
|
if (tpl.dateFormat)
|
|
106
|
-
parts.push(`Date-only field (YYYY-MM-DD string), display as "${tpl.dateFormat}" format`);
|
|
124
|
+
parts.push(`Date-only field (YYYY-MM-DD string), null when unset, display as "${tpl.dateFormat}" format`);
|
|
107
125
|
}
|
|
108
126
|
if (def.type === "datetime") {
|
|
109
127
|
const tpl = def.template;
|
|
110
|
-
const timeParts = ["Date+time field (ISO 8601 timestamp)"];
|
|
128
|
+
const timeParts = ["Date+time field (ISO 8601 timestamp), null when unset"];
|
|
111
129
|
if (tpl.dateFormat)
|
|
112
130
|
timeParts.push(`date: ${tpl.dateFormat}`);
|
|
113
131
|
if (tpl.timeFormat)
|
|
@@ -191,13 +209,13 @@ function generateSchema(database, existingSchema) {
|
|
|
191
209
|
const { id: _id, order: _order, ...definition } = field;
|
|
192
210
|
fields.push({
|
|
193
211
|
id: field.id,
|
|
194
|
-
sdkName: existing?.sdkName ?? toCamelCase(field.name),
|
|
212
|
+
sdkName: keepValidSdkName(existing?.sdkName) ?? toCamelCase(field.name),
|
|
195
213
|
definition,
|
|
196
214
|
});
|
|
197
215
|
}
|
|
198
216
|
tables.push({
|
|
199
217
|
id: table.id,
|
|
200
|
-
sdkName: existingTable?.sdkName ?? toCamelCase(table.name),
|
|
218
|
+
sdkName: keepValidSdkName(existingTable?.sdkName) ?? toCamelCase(table.name),
|
|
201
219
|
primaryFieldId: table.primaryFieldId,
|
|
202
220
|
fields,
|
|
203
221
|
});
|
|
@@ -725,3 +743,30 @@ function generateBackendWrapperTs() {
|
|
|
725
743
|
"",
|
|
726
744
|
].join("\n");
|
|
727
745
|
}
|
|
746
|
+
/**
|
|
747
|
+
* Generate `.zite/integrations/email.ts` — the `Email` client for an app with
|
|
748
|
+
* an email integration connected. Mirrors the airtable SDK generation: a thin
|
|
749
|
+
* wrapper over a `zitejs/runtime` factory that dispatches through the runtime
|
|
750
|
+
* SDK bridge, resolved via the `zitejs/email` alias. `integrationId` is the
|
|
751
|
+
* connected integration's key.
|
|
752
|
+
*/
|
|
753
|
+
function generateEmailSdk(integrationId) {
|
|
754
|
+
return [
|
|
755
|
+
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.",
|
|
756
|
+
"// Email SDK — sends through the Zite email gateway via the runtime bridge.",
|
|
757
|
+
"//",
|
|
758
|
+
"// await Email.send({ to, subject, body: [{ type: 'text', content: '...' }] })",
|
|
759
|
+
"// => { success: boolean; messageId: string }",
|
|
760
|
+
"",
|
|
761
|
+
"import { createEmailClient } from 'zitejs/runtime';",
|
|
762
|
+
"",
|
|
763
|
+
"export type {",
|
|
764
|
+
" EmailBlock,",
|
|
765
|
+
" SendEmailParams,",
|
|
766
|
+
" SendEmailResult,",
|
|
767
|
+
"} from 'zitejs/runtime';",
|
|
768
|
+
"",
|
|
769
|
+
`export const Email = createEmailClient('${integrationId}');`,
|
|
770
|
+
"",
|
|
771
|
+
].join("\n");
|
|
772
|
+
}
|
package/dist/esm/bundle/index.js
CHANGED
|
@@ -223,6 +223,15 @@ function createAliasPlugin(opts) {
|
|
|
223
223
|
}
|
|
224
224
|
return { path: 'zitejs/integrations', external: true };
|
|
225
225
|
});
|
|
226
|
+
// Resolve zitejs/email to .zite/integrations/email.ts
|
|
227
|
+
build.onResolve({ filter: /^zitejs\/email$/ }, () => {
|
|
228
|
+
if (opts.baseDir) {
|
|
229
|
+
const intPath = path.resolve(opts.baseDir, '.zite/integrations/email.ts');
|
|
230
|
+
if (fs.existsSync(intPath))
|
|
231
|
+
return { path: intPath };
|
|
232
|
+
}
|
|
233
|
+
return { path: 'zitejs/email', external: true };
|
|
234
|
+
});
|
|
226
235
|
// zitejs/runtime is NOT in PREBUNDLED_LIBS — it's a thin fetch()
|
|
227
236
|
// wrapper that gets bundled inline by esbuild (no special handling).
|
|
228
237
|
for (const [pkgName, modulePath] of Object.entries(PREBUNDLED_LIBS)) {
|
package/dist/esm/cli.js
CHANGED
|
File without changes
|
package/dist/esm/dev/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { watch } from "fs";
|
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { runSync } from "../sync/index.js";
|
|
5
|
-
import { generateDbTs, generateApiTs, generateUserTs, generateAuthWrapperTs, generateBackendWrapperTs, generateAirtableTs, } from "../sync/lib.js";
|
|
5
|
+
import { generateDbTs, generateApiTs, generateUserTs, generateAuthWrapperTs, generateBackendWrapperTs, generateAirtableTs, generateEmailSdk, } from "../sync/lib.js";
|
|
6
6
|
const debounceTimers = new Map();
|
|
7
7
|
function debounce(key, fn, ms) {
|
|
8
8
|
const existing = debounceTimers.get(key);
|
|
@@ -29,11 +29,39 @@ function getFlowId(appDir) {
|
|
|
29
29
|
catch { }
|
|
30
30
|
return undefined;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Find the connected email integration's key in an app's zite.config.json,
|
|
34
|
+
* if any. The key is the integrationId used by the runtime SDK bridge.
|
|
35
|
+
*/
|
|
36
|
+
function getEmailIntegrationId(appDir) {
|
|
37
|
+
try {
|
|
38
|
+
const configPath = join("apps", appDir, "zite.config.json");
|
|
39
|
+
if (!existsSync(configPath))
|
|
40
|
+
return undefined;
|
|
41
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
42
|
+
const integrations = config.integrations ?? {};
|
|
43
|
+
for (const [id, int] of Object.entries(integrations)) {
|
|
44
|
+
if (int?.type === "email")
|
|
45
|
+
return id;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
32
51
|
function regenerateAppTypedWrappers(appDir) {
|
|
33
52
|
const outDir = join("apps", appDir, ".zite");
|
|
34
53
|
mkdirSync(outDir, { recursive: true });
|
|
35
54
|
writeFileSync(join(outDir, "user.ts"), generateUserTs());
|
|
36
55
|
writeFileSync(join(outDir, "auth.ts"), generateAuthWrapperTs());
|
|
56
|
+
// Email integration: generate the Email client at .zite/integrations/email.ts.
|
|
57
|
+
// Resolved by the `zitejs/email` bundler/tsconfig alias (mirrors airtable's
|
|
58
|
+
// `zitejs/integrations`), so endpoint code uses `import { Email } from 'zitejs/email'`.
|
|
59
|
+
const emailIntegrationId = getEmailIntegrationId(appDir);
|
|
60
|
+
if (emailIntegrationId) {
|
|
61
|
+
const intDir = join(outDir, "integrations");
|
|
62
|
+
mkdirSync(intDir, { recursive: true });
|
|
63
|
+
writeFileSync(join(intDir, "email.ts"), generateEmailSdk(emailIntegrationId));
|
|
64
|
+
}
|
|
37
65
|
writeFileSync(join(outDir, "backend.ts"), generateBackendWrapperTs());
|
|
38
66
|
}
|
|
39
67
|
function regenerateAppApiTs(appDir) {
|
|
@@ -73,7 +73,7 @@ export interface AirtableTableClient<T> {
|
|
|
73
73
|
}): Promise<T | undefined>;
|
|
74
74
|
create(params: {
|
|
75
75
|
record: Partial<T>;
|
|
76
|
-
}): Promise<T>;
|
|
76
|
+
}): Promise<T | undefined>;
|
|
77
77
|
bulkCreate(params: {
|
|
78
78
|
records: Partial<T>[];
|
|
79
79
|
}): Promise<T[]>;
|
|
@@ -82,13 +82,75 @@ export interface AirtableTableClient<T> {
|
|
|
82
82
|
record: Partial<T>;
|
|
83
83
|
}): Promise<{
|
|
84
84
|
id: string;
|
|
85
|
-
fields:
|
|
86
|
-
}>;
|
|
85
|
+
fields: T;
|
|
86
|
+
} | undefined>;
|
|
87
87
|
delete(params: {
|
|
88
88
|
id: string;
|
|
89
89
|
}): Promise<DeleteResult>;
|
|
90
90
|
}
|
|
91
91
|
export declare function createAirtableClient<T>(integrationId: string, className: string, implicitParams: Record<string, unknown>): AirtableTableClient<T>;
|
|
92
|
+
/** A block of content in an email body. */
|
|
93
|
+
export type EmailBlock = {
|
|
94
|
+
type: "text";
|
|
95
|
+
content: string;
|
|
96
|
+
} | {
|
|
97
|
+
type: "button";
|
|
98
|
+
label: string;
|
|
99
|
+
href: string;
|
|
100
|
+
alignment?: "left" | "center" | "right";
|
|
101
|
+
} | {
|
|
102
|
+
type: "image";
|
|
103
|
+
src: string;
|
|
104
|
+
alt?: string;
|
|
105
|
+
alignment?: "left" | "center" | "right";
|
|
106
|
+
width: number;
|
|
107
|
+
height: number;
|
|
108
|
+
} | {
|
|
109
|
+
type: "spacer";
|
|
110
|
+
height: number;
|
|
111
|
+
} | {
|
|
112
|
+
type: "divider";
|
|
113
|
+
borderColor?: string;
|
|
114
|
+
};
|
|
115
|
+
export interface SendEmailParams {
|
|
116
|
+
/** Recipient address(es). Must be valid emails — never placeholders like "me". */
|
|
117
|
+
to: string | string[];
|
|
118
|
+
subject: string;
|
|
119
|
+
/** Email body as an array of content blocks. */
|
|
120
|
+
body: EmailBlock[];
|
|
121
|
+
cc?: string[];
|
|
122
|
+
bcc?: string[];
|
|
123
|
+
replyTo?: string;
|
|
124
|
+
/** 'formatted' (default) for styled HTML, 'plain' for text-only. */
|
|
125
|
+
layout?: "formatted" | "plain";
|
|
126
|
+
/** Custom logo shown above the email content (header area), for branding. */
|
|
127
|
+
logo?: {
|
|
128
|
+
url: string;
|
|
129
|
+
width?: number;
|
|
130
|
+
height?: number;
|
|
131
|
+
};
|
|
132
|
+
/** File attachments, each fetched from its URL at send time. */
|
|
133
|
+
attachments?: {
|
|
134
|
+
filename: string;
|
|
135
|
+
url: string;
|
|
136
|
+
contentType?: string;
|
|
137
|
+
}[];
|
|
138
|
+
}
|
|
139
|
+
export interface SendEmailResult {
|
|
140
|
+
success: boolean;
|
|
141
|
+
messageId: string;
|
|
142
|
+
}
|
|
143
|
+
export interface EmailClient {
|
|
144
|
+
send(params: SendEmailParams): Promise<SendEmailResult>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Email client — sends through the Zite email gateway via the runtime SDK
|
|
148
|
+
* bridge. Email cannot run in-worker (provider auth, image processing, HTML
|
|
149
|
+
* inlining all live in the gateway), so every call dispatches through
|
|
150
|
+
* getSdkCall(), which routes to the email handler. The integrationId is the
|
|
151
|
+
* app's connected email integration key.
|
|
152
|
+
*/
|
|
153
|
+
export declare function createEmailClient(integrationId: string): EmailClient;
|
|
92
154
|
export declare function createNotificationsClient(): {
|
|
93
155
|
create(params: NotificationsCreateParams): Promise<NotificationsCreateResult>;
|
|
94
156
|
};
|
|
@@ -92,6 +92,18 @@ export function createAirtableClient(integrationId, className, implicitParams) {
|
|
|
92
92
|
}),
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Email client — sends through the Zite email gateway via the runtime SDK
|
|
97
|
+
* bridge. Email cannot run in-worker (provider auth, image processing, HTML
|
|
98
|
+
* inlining all live in the gateway), so every call dispatches through
|
|
99
|
+
* getSdkCall(), which routes to the email handler. The integrationId is the
|
|
100
|
+
* app's connected email integration key.
|
|
101
|
+
*/
|
|
102
|
+
export function createEmailClient(integrationId) {
|
|
103
|
+
return {
|
|
104
|
+
send: (params) => getSdkCall()(integrationId, "Email", "send", params),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
95
107
|
const NOTIFICATIONS_SDK_INTEGRATION_ID = "__notifications__";
|
|
96
108
|
const META_SDK_INTEGRATION_ID = "__meta__";
|
|
97
109
|
export function createNotificationsClient() {
|
package/dist/esm/sync/lib.d.ts
CHANGED
|
@@ -59,3 +59,11 @@ export type AirtableLock = {
|
|
|
59
59
|
};
|
|
60
60
|
export declare function generateAirtableTs(lock: AirtableLock): string | null;
|
|
61
61
|
export declare function generateBackendWrapperTs(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Generate `.zite/integrations/email.ts` — the `Email` client for an app with
|
|
64
|
+
* an email integration connected. Mirrors the airtable SDK generation: a thin
|
|
65
|
+
* wrapper over a `zitejs/runtime` factory that dispatches through the runtime
|
|
66
|
+
* SDK bridge, resolved via the `zitejs/email` alias. `integrationId` is the
|
|
67
|
+
* connected integration's key.
|
|
68
|
+
*/
|
|
69
|
+
export declare function generateEmailSdk(integrationId: string): string;
|
package/dist/esm/sync/lib.js
CHANGED
|
@@ -14,8 +14,8 @@ const FIELD_TYPE_MAP = {
|
|
|
14
14
|
single_select: "string",
|
|
15
15
|
multiple_select: "string[]",
|
|
16
16
|
checkbox: "boolean",
|
|
17
|
-
date: "string",
|
|
18
|
-
datetime: "string",
|
|
17
|
+
date: "string | null",
|
|
18
|
+
datetime: "string | null",
|
|
19
19
|
attachments: "Array<{ url: string; name?: string }>",
|
|
20
20
|
linked_record: "string | string[]",
|
|
21
21
|
lookup: "unknown",
|
|
@@ -42,14 +42,31 @@ const DURATION_FORMAT_EXAMPLES = {
|
|
|
42
42
|
"h:mm:ss.sss": "1:23:03.000",
|
|
43
43
|
};
|
|
44
44
|
export function toPascalCase(name) {
|
|
45
|
-
|
|
45
|
+
const pascal = name
|
|
46
46
|
.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase())
|
|
47
|
-
.replace(/^(.)/, (_, c) => c.toUpperCase())
|
|
47
|
+
.replace(/^(.)/, (_, c) => c.toUpperCase())
|
|
48
|
+
// Drop leftover non-alphanumerics (e.g. a trailing ">" from "</p>") so the
|
|
49
|
+
// sdkName is always a valid identifier in .zite/db.ts.
|
|
50
|
+
.replace(/[^a-zA-Z0-9]+/g, "");
|
|
51
|
+
if (!pascal)
|
|
52
|
+
return "_";
|
|
53
|
+
return /^[0-9]/.test(pascal) ? `_${pascal}` : pascal; // can't start with a digit
|
|
48
54
|
}
|
|
49
55
|
export function toCamelCase(name) {
|
|
50
56
|
const pascal = toPascalCase(name);
|
|
51
57
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
52
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Existing sdkNames are preserved across syncs so user code keeps compiling,
|
|
61
|
+
* but schemas written before the sanitizer stripped trailing symbols can carry
|
|
62
|
+
* invalid identifiers (e.g. "timeSeconds)"). Keep an existing name only when
|
|
63
|
+
* it's a valid identifier; otherwise fall through to recomputing it.
|
|
64
|
+
*/
|
|
65
|
+
function keepValidSdkName(sdkName) {
|
|
66
|
+
if (!sdkName)
|
|
67
|
+
return undefined;
|
|
68
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(sdkName) ? sdkName : undefined;
|
|
69
|
+
}
|
|
53
70
|
function tsTypeForSchemaField(def) {
|
|
54
71
|
if (def.type === "single_select" || def.type === "multiple_select") {
|
|
55
72
|
const options = def.template
|
|
@@ -92,11 +109,11 @@ function fieldJsdoc(schemaField, table) {
|
|
|
92
109
|
if (def.type === "date") {
|
|
93
110
|
const tpl = def.template;
|
|
94
111
|
if (tpl.dateFormat)
|
|
95
|
-
parts.push(`Date-only field (YYYY-MM-DD string), display as "${tpl.dateFormat}" format`);
|
|
112
|
+
parts.push(`Date-only field (YYYY-MM-DD string), null when unset, display as "${tpl.dateFormat}" format`);
|
|
96
113
|
}
|
|
97
114
|
if (def.type === "datetime") {
|
|
98
115
|
const tpl = def.template;
|
|
99
|
-
const timeParts = ["Date+time field (ISO 8601 timestamp)"];
|
|
116
|
+
const timeParts = ["Date+time field (ISO 8601 timestamp), null when unset"];
|
|
100
117
|
if (tpl.dateFormat)
|
|
101
118
|
timeParts.push(`date: ${tpl.dateFormat}`);
|
|
102
119
|
if (tpl.timeFormat)
|
|
@@ -180,13 +197,13 @@ export function generateSchema(database, existingSchema) {
|
|
|
180
197
|
const { id: _id, order: _order, ...definition } = field;
|
|
181
198
|
fields.push({
|
|
182
199
|
id: field.id,
|
|
183
|
-
sdkName: existing?.sdkName ?? toCamelCase(field.name),
|
|
200
|
+
sdkName: keepValidSdkName(existing?.sdkName) ?? toCamelCase(field.name),
|
|
184
201
|
definition,
|
|
185
202
|
});
|
|
186
203
|
}
|
|
187
204
|
tables.push({
|
|
188
205
|
id: table.id,
|
|
189
|
-
sdkName: existingTable?.sdkName ?? toCamelCase(table.name),
|
|
206
|
+
sdkName: keepValidSdkName(existingTable?.sdkName) ?? toCamelCase(table.name),
|
|
190
207
|
primaryFieldId: table.primaryFieldId,
|
|
191
208
|
fields,
|
|
192
209
|
});
|
|
@@ -714,3 +731,30 @@ export function generateBackendWrapperTs() {
|
|
|
714
731
|
"",
|
|
715
732
|
].join("\n");
|
|
716
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* Generate `.zite/integrations/email.ts` — the `Email` client for an app with
|
|
736
|
+
* an email integration connected. Mirrors the airtable SDK generation: a thin
|
|
737
|
+
* wrapper over a `zitejs/runtime` factory that dispatches through the runtime
|
|
738
|
+
* SDK bridge, resolved via the `zitejs/email` alias. `integrationId` is the
|
|
739
|
+
* connected integration's key.
|
|
740
|
+
*/
|
|
741
|
+
export function generateEmailSdk(integrationId) {
|
|
742
|
+
return [
|
|
743
|
+
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.",
|
|
744
|
+
"// Email SDK — sends through the Zite email gateway via the runtime bridge.",
|
|
745
|
+
"//",
|
|
746
|
+
"// await Email.send({ to, subject, body: [{ type: 'text', content: '...' }] })",
|
|
747
|
+
"// => { success: boolean; messageId: string }",
|
|
748
|
+
"",
|
|
749
|
+
"import { createEmailClient } from 'zitejs/runtime';",
|
|
750
|
+
"",
|
|
751
|
+
"export type {",
|
|
752
|
+
" EmailBlock,",
|
|
753
|
+
" SendEmailParams,",
|
|
754
|
+
" SendEmailResult,",
|
|
755
|
+
"} from 'zitejs/runtime';",
|
|
756
|
+
"",
|
|
757
|
+
`export const Email = createEmailClient('${integrationId}');`,
|
|
758
|
+
"",
|
|
759
|
+
].join("\n");
|
|
760
|
+
}
|
package/package.json
CHANGED
package/dist/cjs/api/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createCaller = void 0;
|
|
4
|
-
var index_js_1 = require("../caller/index.js");
|
|
5
|
-
Object.defineProperty(exports, "createCaller", { enumerable: true, get: function () { return index_js_1.createCaller; } });
|
package/dist/cjs/db/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createTableClient = void 0;
|
|
4
|
-
var index_js_1 = require("../runtime/index.js");
|
|
5
|
-
Object.defineProperty(exports, "createTableClient", { enumerable: true, get: function () { return index_js_1.createTableClient; } });
|
package/dist/esm/api/index.d.ts
DELETED
package/dist/esm/api/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createCaller } from '../caller/index.js';
|
package/dist/esm/db/index.d.ts
DELETED
package/dist/esm/db/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createTableClient } from '../runtime/index.js';
|