zitejs 0.9.40 → 0.9.42
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/sync/index.js +18 -6
- package/dist/cjs/sync/lib.js +182 -33
- package/dist/esm/client/index.d.ts +236 -236
- package/dist/esm/sync/index.js +19 -7
- package/dist/esm/sync/lib.d.ts +27 -18
- package/dist/esm/sync/lib.js +182 -33
- package/dist/esm/types/fields.d.ts +329 -894
- package/dist/esm/types/tables.d.ts +659 -4125
- package/package.json +2 -2
package/dist/cjs/sync/index.js
CHANGED
|
@@ -12,9 +12,11 @@ const DB_ENVIRONMENTS = {
|
|
|
12
12
|
local: "http://localhost:2507/api/v1",
|
|
13
13
|
};
|
|
14
14
|
const env = process.env.ZITE_ENV ?? "production";
|
|
15
|
-
const BASE_URL = process.env.ZITE_DB_URL ??
|
|
15
|
+
const BASE_URL = process.env.ZITE_DB_URL ??
|
|
16
|
+
DB_ENVIRONMENTS[env] ??
|
|
17
|
+
DB_ENVIRONMENTS.production;
|
|
16
18
|
const TOKEN = process.env.ZITE_DB_TOKEN ?? "";
|
|
17
|
-
async function
|
|
19
|
+
async function fetchDatabase(baseId) {
|
|
18
20
|
const url = `${BASE_URL}/bases/${encodeURIComponent(baseId)}`;
|
|
19
21
|
const res = await fetch(url, {
|
|
20
22
|
headers: { Authorization: `Bearer ${TOKEN}` },
|
|
@@ -35,6 +37,15 @@ function resolveBaseId() {
|
|
|
35
37
|
return undefined;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
40
|
+
function readExistingSchema() {
|
|
41
|
+
try {
|
|
42
|
+
if ((0, fs_1.existsSync)("zite.schema.json")) {
|
|
43
|
+
return JSON.parse((0, fs_1.readFileSync)("zite.schema.json", "utf-8"));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
38
49
|
async function runSync() {
|
|
39
50
|
if (!TOKEN) {
|
|
40
51
|
throw new Error("ZITE_DB_TOKEN is required.");
|
|
@@ -44,12 +55,13 @@ async function runSync() {
|
|
|
44
55
|
throw new Error("Could not determine base ID.");
|
|
45
56
|
}
|
|
46
57
|
console.log(`Syncing database ${baseId}...`);
|
|
47
|
-
const
|
|
48
|
-
console.log(`Found ${
|
|
49
|
-
const
|
|
58
|
+
const database = await fetchDatabase(baseId);
|
|
59
|
+
console.log(`Found ${database.tables?.length ?? 0} tables`);
|
|
60
|
+
const existingSchema = readExistingSchema();
|
|
61
|
+
const schema = (0, lib_js_1.generateSchema)(database, existingSchema);
|
|
50
62
|
(0, fs_1.writeFileSync)("zite.schema.json", JSON.stringify(schema, null, 2));
|
|
51
63
|
console.log("Wrote zite.schema.json");
|
|
52
|
-
const dbTs = (0, lib_js_1.generateDbTs)(
|
|
64
|
+
const dbTs = (0, lib_js_1.generateDbTs)(schema);
|
|
53
65
|
const dotZite = ".zite";
|
|
54
66
|
(0, fs_1.mkdirSync)(dotZite, { recursive: true });
|
|
55
67
|
(0, fs_1.writeFileSync)((0, path_1.join)(dotZite, "db.ts"), dbTs);
|
package/dist/cjs/sync/lib.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.generateBackendWrapperTs = generateBackendWrapperTs;
|
|
|
11
11
|
const FIELD_TYPE_MAP = {
|
|
12
12
|
single_line_text: "string",
|
|
13
13
|
long_text: "string",
|
|
14
|
+
rich_text: "string",
|
|
14
15
|
email: "string",
|
|
15
16
|
url: "string",
|
|
16
17
|
phone_number: "string",
|
|
@@ -29,6 +30,25 @@ const FIELD_TYPE_MAP = {
|
|
|
29
30
|
lookup: "unknown",
|
|
30
31
|
autonumber: "number",
|
|
31
32
|
source: "string",
|
|
33
|
+
formula: "unknown",
|
|
34
|
+
created_at: "string",
|
|
35
|
+
updated_at: "string",
|
|
36
|
+
};
|
|
37
|
+
const MAX_SELECT_OPTIONS = 100;
|
|
38
|
+
const NUMBER_FORMAT_EXAMPLES = {
|
|
39
|
+
local: "1,000,000.50",
|
|
40
|
+
comma_period: "1,000,000.50",
|
|
41
|
+
period_comma: "1.000.000,50",
|
|
42
|
+
space_comma: "1 000 000,50",
|
|
43
|
+
space_period: "1 000 000.50",
|
|
44
|
+
no_separator: "1000000.50",
|
|
45
|
+
};
|
|
46
|
+
const DURATION_FORMAT_EXAMPLES = {
|
|
47
|
+
"h:mm": "1:23",
|
|
48
|
+
"h:mm:ss": "1:23:03",
|
|
49
|
+
"h:mm:ss.s": "1:23:03.0",
|
|
50
|
+
"h:mm:ss.ss": "1:23:03.00",
|
|
51
|
+
"h:mm:ss.sss": "1:23:03.000",
|
|
32
52
|
};
|
|
33
53
|
function toPascalCase(name) {
|
|
34
54
|
return name
|
|
@@ -39,33 +59,157 @@ function toCamelCase(name) {
|
|
|
39
59
|
const pascal = toPascalCase(name);
|
|
40
60
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
41
61
|
}
|
|
42
|
-
function
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
function tsTypeForSchemaField(def) {
|
|
63
|
+
if (def.type === "single_select" || def.type === "multiple_select") {
|
|
64
|
+
const options = def.template
|
|
65
|
+
?.options;
|
|
66
|
+
if (options && options.length > 0) {
|
|
67
|
+
const literals = options
|
|
68
|
+
.slice(0, MAX_SELECT_OPTIONS)
|
|
69
|
+
.map((o) => `"${o.label.replace(/"/g, '\\"')}"`)
|
|
70
|
+
.join(" | ");
|
|
71
|
+
const union = `${literals} | string`;
|
|
72
|
+
if (def.type === "multiple_select")
|
|
73
|
+
return `(${union})[]`;
|
|
74
|
+
return union;
|
|
75
|
+
}
|
|
51
76
|
}
|
|
77
|
+
if (FIELD_TYPE_MAP[def.type])
|
|
78
|
+
return FIELD_TYPE_MAP[def.type];
|
|
52
79
|
return "string";
|
|
53
80
|
}
|
|
54
|
-
function
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
function fieldJsdoc(schemaField, table) {
|
|
82
|
+
const def = schemaField.definition;
|
|
83
|
+
const parts = [];
|
|
84
|
+
if (table.primaryFieldId === schemaField.id)
|
|
85
|
+
parts.push("Primary field");
|
|
86
|
+
if (def.type === "created_at" ||
|
|
87
|
+
def.type === "updated_at" ||
|
|
88
|
+
def.type === "lookup" ||
|
|
89
|
+
def.type === "formula" ||
|
|
90
|
+
def.type === "autonumber") {
|
|
91
|
+
parts.push("Read-only");
|
|
92
|
+
}
|
|
93
|
+
if (def.type === "linked_record") {
|
|
94
|
+
const tpl = def.template;
|
|
95
|
+
if (tpl.tableId)
|
|
96
|
+
parts.push(`Links to table ${tpl.tableId}`);
|
|
97
|
+
if (tpl.allowMultiple === false)
|
|
98
|
+
parts.push("Single record only");
|
|
99
|
+
}
|
|
100
|
+
parts.push(`"${def.name}"`);
|
|
101
|
+
if (def.type === "date") {
|
|
102
|
+
const tpl = def.template;
|
|
103
|
+
if (tpl.dateFormat)
|
|
104
|
+
parts.push(`Date-only field (YYYY-MM-DD string), display as "${tpl.dateFormat}" format`);
|
|
105
|
+
}
|
|
106
|
+
if (def.type === "datetime") {
|
|
107
|
+
const tpl = def.template;
|
|
108
|
+
const timeParts = [
|
|
109
|
+
"Date+time field (ISO 8601 timestamp)",
|
|
110
|
+
];
|
|
111
|
+
if (tpl.dateFormat)
|
|
112
|
+
timeParts.push(`date: ${tpl.dateFormat}`);
|
|
113
|
+
if (tpl.timeFormat)
|
|
114
|
+
timeParts.push(`time: ${tpl.timeFormat}`);
|
|
115
|
+
if (tpl.timezone)
|
|
116
|
+
timeParts.push(`tz: ${tpl.timezone}`);
|
|
117
|
+
if (tpl.displayTimeZone)
|
|
118
|
+
timeParts.push("timezone displayed to user");
|
|
119
|
+
parts.push(timeParts.join(", "));
|
|
120
|
+
}
|
|
121
|
+
if (def.type === "currency") {
|
|
122
|
+
const tpl = def.template;
|
|
123
|
+
if (tpl.currencySymbol) {
|
|
124
|
+
const formatHint = NUMBER_FORMAT_EXAMPLES[tpl.numberFormat ?? "local"] ?? "";
|
|
125
|
+
parts.push(`Value is a raw number; display as currency with symbol "${tpl.currencySymbol}", ${tpl.decimalPlaces ?? 2} decimal places, format: ${tpl.numberFormat ?? "local"} (e.g. ${formatHint})`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (def.type === "number") {
|
|
129
|
+
const tpl = def.template;
|
|
130
|
+
const formatHint = NUMBER_FORMAT_EXAMPLES[tpl.numberFormat ?? "local"] ?? "";
|
|
131
|
+
parts.push(`${tpl.decimalPlaces ?? 0} decimal places, format: ${tpl.numberFormat ?? "local"} (e.g. ${formatHint})`);
|
|
132
|
+
}
|
|
133
|
+
if (def.type === "percent") {
|
|
134
|
+
const tpl = def.template;
|
|
135
|
+
if (tpl.decimalPlaces !== undefined)
|
|
136
|
+
parts.push(`${tpl.decimalPlaces} decimal places`);
|
|
137
|
+
}
|
|
138
|
+
if (def.type === "duration") {
|
|
139
|
+
const tpl = def.template;
|
|
140
|
+
if (tpl.format) {
|
|
141
|
+
const example = DURATION_FORMAT_EXAMPLES[tpl.format] ?? "";
|
|
142
|
+
parts.push(`Value is in seconds; display in "${tpl.format}" format (${example})`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (def.type === "rating") {
|
|
146
|
+
const tpl = def.template;
|
|
147
|
+
if (tpl.maxRating)
|
|
148
|
+
parts.push(`Max rating: ${tpl.maxRating}`);
|
|
149
|
+
}
|
|
150
|
+
if (def.type === "created_at") {
|
|
151
|
+
parts.push("Auto-set when record was created (ISO 8601)");
|
|
152
|
+
}
|
|
153
|
+
if (def.type === "updated_at") {
|
|
154
|
+
parts.push("Auto-set when record was last modified (ISO 8601)");
|
|
155
|
+
}
|
|
156
|
+
if ((def.type === "single_select" || def.type === "multiple_select") &&
|
|
157
|
+
def.template?.options) {
|
|
158
|
+
const count = (def.template.options ?? []).length;
|
|
159
|
+
if (count > MAX_SELECT_OPTIONS) {
|
|
160
|
+
parts.push(`${count - MAX_SELECT_OPTIONS} more options omitted`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (parts.length <= 1)
|
|
164
|
+
return undefined;
|
|
165
|
+
return parts.join(". ");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Build a ZiteSchema from a Database API response.
|
|
169
|
+
*
|
|
170
|
+
* If `existingSchema` is provided, locked SDK names are preserved for
|
|
171
|
+
* tables/fields that already exist (matched by ID). New tables/fields
|
|
172
|
+
* get fresh camelCase SDK names. This is how `zitejs sync` preserves
|
|
173
|
+
* name stability across schema changes.
|
|
174
|
+
*/
|
|
175
|
+
function generateSchema(database, existingSchema) {
|
|
176
|
+
const existingTableById = new Map();
|
|
177
|
+
for (const t of existingSchema?.tables ?? []) {
|
|
178
|
+
existingTableById.set(t.id, t);
|
|
179
|
+
}
|
|
180
|
+
const tables = [];
|
|
181
|
+
for (const table of database.tables) {
|
|
182
|
+
const existingTable = existingTableById.get(table.id);
|
|
183
|
+
const existingFieldById = new Map();
|
|
184
|
+
for (const f of existingTable?.fields ?? []) {
|
|
185
|
+
existingFieldById.set(f.id, f);
|
|
186
|
+
}
|
|
187
|
+
const fields = [];
|
|
188
|
+
for (const field of table.fields) {
|
|
189
|
+
const existing = existingFieldById.get(field.id);
|
|
190
|
+
const { id: _id, order: _order, ...definition } = field;
|
|
191
|
+
fields.push({
|
|
192
|
+
id: field.id,
|
|
193
|
+
sdkName: existing?.sdkName ?? toCamelCase(field.name),
|
|
194
|
+
definition,
|
|
195
|
+
});
|
|
61
196
|
}
|
|
62
|
-
|
|
197
|
+
tables.push({
|
|
198
|
+
id: table.id,
|
|
199
|
+
sdkName: existingTable?.sdkName ?? toCamelCase(table.name),
|
|
200
|
+
primaryFieldId: table.primaryFieldId,
|
|
201
|
+
fields,
|
|
202
|
+
});
|
|
63
203
|
}
|
|
64
|
-
return
|
|
204
|
+
return { tables };
|
|
65
205
|
}
|
|
66
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Generate .zite/db.ts purely from ZiteSchema.
|
|
208
|
+
* Pure function — no external data needed beyond what's in the schema file.
|
|
209
|
+
*/
|
|
210
|
+
function generateDbTs(schema) {
|
|
67
211
|
const lines = [];
|
|
68
|
-
lines.push("// Auto-generated by zitejs
|
|
212
|
+
lines.push("// Auto-generated by zitejs generate. Do not edit manually.");
|
|
69
213
|
lines.push("//");
|
|
70
214
|
lines.push("// Usage in endpoint files (src/api/*.ts):");
|
|
71
215
|
lines.push('// import { zite } from "zitejs/db";');
|
|
@@ -97,26 +241,28 @@ function generateDbTs(base, schema) {
|
|
|
97
241
|
lines.push('// - Load the "zite:sql" skill for full SQL reference (formulas, lookups, etc.)');
|
|
98
242
|
lines.push("import { createTableClient, createSqlClient } from 'zitejs/runtime';");
|
|
99
243
|
lines.push("");
|
|
100
|
-
for (const table of
|
|
101
|
-
const className = toPascalCase(table.
|
|
244
|
+
for (const table of schema.tables) {
|
|
245
|
+
const className = toPascalCase(table.sdkName);
|
|
102
246
|
const recordType = `${className}RecordType`;
|
|
103
247
|
lines.push(`export type ${recordType} = {`);
|
|
104
248
|
lines.push(" id: string;");
|
|
105
|
-
for (const field of table.fields
|
|
106
|
-
|
|
107
|
-
if (fieldName === "id")
|
|
249
|
+
for (const field of table.fields) {
|
|
250
|
+
if (field.sdkName === "id")
|
|
108
251
|
continue;
|
|
109
|
-
const tsType =
|
|
110
|
-
|
|
252
|
+
const tsType = tsTypeForSchemaField(field.definition);
|
|
253
|
+
const jsdoc = fieldJsdoc(field, table);
|
|
254
|
+
if (jsdoc) {
|
|
255
|
+
lines.push(` /** ${jsdoc} */`);
|
|
256
|
+
}
|
|
257
|
+
lines.push(` ${field.sdkName}: ${tsType};`);
|
|
111
258
|
}
|
|
112
259
|
lines.push("};");
|
|
113
260
|
lines.push("");
|
|
114
261
|
}
|
|
115
262
|
lines.push("export const zite = {");
|
|
116
|
-
for (const table of
|
|
117
|
-
const className = toPascalCase(table.
|
|
118
|
-
|
|
119
|
-
lines.push(` ${propName}: createTableClient<${className}RecordType>('${className}'),`);
|
|
263
|
+
for (const table of schema.tables) {
|
|
264
|
+
const className = toPascalCase(table.sdkName);
|
|
265
|
+
lines.push(` ${table.sdkName}: createTableClient<${className}RecordType>('${className}'),`);
|
|
120
266
|
}
|
|
121
267
|
lines.push(` sql: createSqlClient(),`);
|
|
122
268
|
lines.push("};");
|
|
@@ -144,14 +290,12 @@ function generateApiTs(endpointFiles) {
|
|
|
144
290
|
lines.push(`export const ${name} = createCaller(${name}Endpoint, '${name}');`);
|
|
145
291
|
}
|
|
146
292
|
lines.push("");
|
|
147
|
-
// Inferred input/output types per endpoint (e.g. GetDashboardInputType, GetDashboardOutputType)
|
|
148
293
|
for (const name of endpointNames) {
|
|
149
294
|
const pascal = toPascalCase(name);
|
|
150
295
|
lines.push(`export type ${pascal}InputType = Parameters<typeof ${name}Endpoint.execute>[0]['input'];`);
|
|
151
296
|
lines.push(`export type ${pascal}OutputType = Awaited<ReturnType<typeof ${name}Endpoint.execute>>;`);
|
|
152
297
|
}
|
|
153
298
|
lines.push("");
|
|
154
|
-
// Also export as a single api object
|
|
155
299
|
lines.push("export const api = {");
|
|
156
300
|
for (const name of endpointNames) {
|
|
157
301
|
lines.push(` ${name},`);
|
|
@@ -160,6 +304,11 @@ function generateApiTs(endpointFiles) {
|
|
|
160
304
|
lines.push("");
|
|
161
305
|
return lines.join("\n");
|
|
162
306
|
}
|
|
307
|
+
function tsTypeForField(field) {
|
|
308
|
+
if (FIELD_TYPE_MAP[field.type])
|
|
309
|
+
return FIELD_TYPE_MAP[field.type];
|
|
310
|
+
return "string";
|
|
311
|
+
}
|
|
163
312
|
function generateUserTs(usersTableFields) {
|
|
164
313
|
const lines = [
|
|
165
314
|
"// Auto-generated by zitejs sync. Do not edit manually.",
|