zitejs 0.9.52 → 0.9.54
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/backend/index.d.ts +10 -4
- package/dist/cjs/backend/index.js +1 -1
- package/dist/cjs/caller/index.d.ts +6 -0
- package/dist/cjs/caller/index.js +120 -20
- package/dist/cjs/dev/index.js +6 -1
- package/dist/cjs/sync/index.js +7 -4
- package/dist/cjs/sync/lib.d.ts +5 -1
- package/dist/cjs/sync/lib.js +62 -17
- package/dist/esm/backend/index.d.ts +10 -4
- package/dist/esm/backend/index.js +1 -1
- package/dist/esm/caller/index.d.ts +6 -0
- package/dist/esm/caller/index.js +120 -21
- package/dist/esm/dev/index.js +6 -1
- package/dist/esm/sync/index.js +7 -4
- package/dist/esm/sync/lib.d.ts +5 -1
- package/dist/esm/sync/lib.js +62 -17
- package/package.json +1 -1
|
@@ -21,16 +21,22 @@ type SchemaLike<T> = {
|
|
|
21
21
|
_output: T;
|
|
22
22
|
parse: (data: unknown) => T;
|
|
23
23
|
};
|
|
24
|
-
export
|
|
24
|
+
export type ZiteStreamInterface = {
|
|
25
|
+
write: (data: unknown) => Promise<void>;
|
|
26
|
+
forward: (asyncIterable: AsyncIterable<string>) => Promise<string>;
|
|
27
|
+
};
|
|
28
|
+
export interface EndpointConfig<TInput = unknown, TOutput = unknown, TStream extends boolean = false> {
|
|
25
29
|
description?: string;
|
|
26
30
|
inputSchema?: SchemaLike<TInput>;
|
|
27
31
|
outputSchema?: SchemaLike<TOutput>;
|
|
28
|
-
stream?:
|
|
32
|
+
stream?: TStream;
|
|
29
33
|
authenticated?: boolean;
|
|
30
34
|
execute: (params: {
|
|
31
35
|
input: TInput;
|
|
32
36
|
context: ZiteRequestContext | ZiteScheduledContext;
|
|
33
|
-
}
|
|
37
|
+
} & (TStream extends true ? {
|
|
38
|
+
stream: ZiteStreamInterface;
|
|
39
|
+
} : {})) => Promise<TOutput> | TOutput;
|
|
34
40
|
}
|
|
35
|
-
export declare function createEndpoint<TInput = unknown, TOutput = unknown>(config: EndpointConfig<TInput, TOutput>): EndpointConfig<TInput, TOutput>;
|
|
41
|
+
export declare function createEndpoint<TInput = unknown, TOutput = unknown, TStream extends boolean = false>(config: EndpointConfig<TInput, TOutput, TStream>): EndpointConfig<TInput, TOutput, TStream>;
|
|
36
42
|
export {};
|
|
@@ -4,4 +4,10 @@ export interface EndpointConfig<TInput = unknown, TOutput = unknown> {
|
|
|
4
4
|
context: unknown;
|
|
5
5
|
}) => Promise<TOutput> | TOutput;
|
|
6
6
|
}
|
|
7
|
+
export declare function createCaller<TInput, TOutput>(name: string, flowId?: string): (input: TInput) => Promise<TOutput>;
|
|
7
8
|
export declare function createCaller<TInput, TOutput>(endpoint: EndpointConfig<TInput, TOutput>, name: string, flowId?: string): (input: TInput) => Promise<TOutput>;
|
|
9
|
+
export type StreamingResponse<T> = {
|
|
10
|
+
[Symbol.asyncIterator](): AsyncIterator<string>;
|
|
11
|
+
result: Promise<T>;
|
|
12
|
+
};
|
|
13
|
+
export declare function createStreamingCaller<TInput, TOutput>(name: string): (input: TInput) => StreamingResponse<TOutput>;
|
package/dist/cjs/caller/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCaller = createCaller;
|
|
4
|
+
exports.createStreamingCaller = createStreamingCaller;
|
|
4
5
|
const env_js_1 = require("../internal/env.js");
|
|
5
6
|
const ENVIRONMENTS = {
|
|
6
|
-
production:
|
|
7
|
-
staging:
|
|
8
|
-
local:
|
|
7
|
+
production: "https://workflows.zite.com",
|
|
8
|
+
staging: "https://workflows.zitestaging.com",
|
|
9
|
+
local: "http://localhost:2506",
|
|
9
10
|
};
|
|
10
11
|
function getRunnerUrl() {
|
|
11
|
-
const env = (0, env_js_1.getEnv)(
|
|
12
|
-
return (0, env_js_1.getEnv)(
|
|
12
|
+
const env = (0, env_js_1.getEnv)("ZITE_ENV", "VITE_ZITE_ENV") ?? "production";
|
|
13
|
+
return ((0, env_js_1.getEnv)("ZITE_RUNNER_URL", "VITE_ZITE_RUNNER_URL") ??
|
|
14
|
+
ENVIRONMENTS[env] ??
|
|
15
|
+
ENVIRONMENTS.production);
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* Get the user's usage token for endpoint auth.
|
|
@@ -17,35 +20,132 @@ function getRunnerUrl() {
|
|
|
17
20
|
* In external mode: stored in localStorage by the auth flow
|
|
18
21
|
*/
|
|
19
22
|
function getUsageToken() {
|
|
20
|
-
if (typeof window !==
|
|
23
|
+
if (typeof window !== "undefined") {
|
|
21
24
|
const win = window;
|
|
22
|
-
if (typeof win._ziteUsageToken ===
|
|
25
|
+
if (typeof win._ziteUsageToken === "string")
|
|
23
26
|
return win._ziteUsageToken;
|
|
24
27
|
}
|
|
25
28
|
// Fallback to stored auth token (external mode)
|
|
26
|
-
if (typeof localStorage !==
|
|
27
|
-
const stored = localStorage.getItem(
|
|
29
|
+
if (typeof localStorage !== "undefined") {
|
|
30
|
+
const stored = localStorage.getItem("zite.auth.token");
|
|
28
31
|
if (stored)
|
|
29
32
|
return stored;
|
|
30
33
|
}
|
|
31
|
-
return
|
|
34
|
+
return "";
|
|
32
35
|
}
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
function buildFetchOptions(name, input, extra) {
|
|
37
|
+
const appId = (0, env_js_1.getEnv)("ZITE_FLOW_ID", "VITE_ZITE_FLOW_ID") ?? "";
|
|
38
|
+
const token = getUsageToken();
|
|
39
|
+
const ziteAuthToken = typeof localStorage !== "undefined"
|
|
40
|
+
? localStorage.getItem("zite.auth.token")
|
|
41
|
+
: null;
|
|
42
|
+
return {
|
|
43
|
+
url: getRunnerUrl() + "/public/" + appId + "/api/" + name,
|
|
44
|
+
init: {
|
|
45
|
+
method: "POST",
|
|
39
46
|
headers: {
|
|
40
47
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
41
|
-
|
|
48
|
+
"Content-Type": "application/json",
|
|
42
49
|
},
|
|
43
|
-
body: JSON.stringify({
|
|
44
|
-
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
inputs: input,
|
|
52
|
+
mode: "preview",
|
|
53
|
+
usageToken: token,
|
|
54
|
+
...(ziteAuthToken ? { ziteAuthToken } : {}),
|
|
55
|
+
...extra,
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function createCaller(endpointOrName, nameOrFlowId, flowId) {
|
|
61
|
+
const name = typeof endpointOrName === "string" ? endpointOrName : nameOrFlowId;
|
|
62
|
+
return async (input) => {
|
|
63
|
+
const { url, init } = buildFetchOptions(name, input);
|
|
64
|
+
const res = await fetch(url, init);
|
|
45
65
|
if (!res.ok) {
|
|
46
|
-
const text = await res.text().catch(() =>
|
|
66
|
+
const text = await res.text().catch(() => "");
|
|
47
67
|
throw new Error(`API call failed (${res.status}): ${text}`);
|
|
48
68
|
}
|
|
49
69
|
return res.json();
|
|
50
70
|
};
|
|
51
71
|
}
|
|
72
|
+
function createStreamingCaller(name) {
|
|
73
|
+
return (input) => {
|
|
74
|
+
let resultResolve;
|
|
75
|
+
let resultReject;
|
|
76
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
77
|
+
resultResolve = resolve;
|
|
78
|
+
resultReject = reject;
|
|
79
|
+
});
|
|
80
|
+
const { url, init } = buildFetchOptions(name, input, { stream: true });
|
|
81
|
+
const fetchPromise = fetch(url, init);
|
|
82
|
+
return {
|
|
83
|
+
async *[Symbol.asyncIterator]() {
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetchPromise;
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const errorData = await response.json().catch(() => ({}));
|
|
88
|
+
const error = new Error(errorData.message ||
|
|
89
|
+
`Error with endpoint ${name}: ${response.status}`);
|
|
90
|
+
resultReject(error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
if (!response.body) {
|
|
94
|
+
const error = new Error("No response body for streaming endpoint");
|
|
95
|
+
resultReject(error);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
const reader = response.body
|
|
99
|
+
.pipeThrough(new TextDecoderStream())
|
|
100
|
+
.getReader();
|
|
101
|
+
let buffer = "";
|
|
102
|
+
while (true) {
|
|
103
|
+
const { value, done } = await reader.read();
|
|
104
|
+
if (done)
|
|
105
|
+
break;
|
|
106
|
+
buffer += value;
|
|
107
|
+
while (buffer.includes("\n\n")) {
|
|
108
|
+
const eventEnd = buffer.indexOf("\n\n");
|
|
109
|
+
const eventBlock = buffer.substring(0, eventEnd);
|
|
110
|
+
buffer = buffer.substring(eventEnd + 2);
|
|
111
|
+
const eventTypeMatch = eventBlock.match(/^event: (.+)$/m);
|
|
112
|
+
const dataMatch = eventBlock.match(/^data: (.+)$/m);
|
|
113
|
+
const eventType = eventTypeMatch?.[1];
|
|
114
|
+
const dataStr = dataMatch?.[1];
|
|
115
|
+
if (eventType === "data" && dataStr) {
|
|
116
|
+
try {
|
|
117
|
+
yield JSON.parse(dataStr);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
yield dataStr;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (eventType === "result" && dataStr) {
|
|
124
|
+
try {
|
|
125
|
+
resultResolve(JSON.parse(dataStr));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
resultResolve(dataStr);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (eventType === "error" && dataStr) {
|
|
132
|
+
try {
|
|
133
|
+
const errorData = JSON.parse(dataStr);
|
|
134
|
+
resultReject(new Error(errorData.message || "Streaming error"));
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
resultReject(new Error(dataStr || "Streaming error"));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
resultReject(error);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
result: resultPromise,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
}
|
package/dist/cjs/dev/index.js
CHANGED
|
@@ -44,7 +44,12 @@ function regenerateAppApiTs(appDir) {
|
|
|
44
44
|
const apiDir = (0, path_1.join)("apps", appDir, "src", "api");
|
|
45
45
|
if (!(0, fs_2.existsSync)(apiDir))
|
|
46
46
|
return;
|
|
47
|
-
const endpointFiles = (0, fs_2.readdirSync)(apiDir)
|
|
47
|
+
const endpointFiles = (0, fs_2.readdirSync)(apiDir)
|
|
48
|
+
.filter((f) => f.endsWith(".ts") || f.endsWith(".js"))
|
|
49
|
+
.map((f) => ({
|
|
50
|
+
fileName: f,
|
|
51
|
+
content: (0, fs_2.readFileSync)((0, path_1.join)(apiDir, f), "utf-8"),
|
|
52
|
+
}));
|
|
48
53
|
const content = (0, lib_js_1.generateApiTs)(endpointFiles);
|
|
49
54
|
if (content) {
|
|
50
55
|
const outDir = (0, path_1.join)("apps", appDir, ".zite");
|
package/dist/cjs/sync/index.js
CHANGED
|
@@ -27,9 +27,7 @@ const DB_ENVIRONMENTS = {
|
|
|
27
27
|
local: "http://localhost:2507/api/v1",
|
|
28
28
|
};
|
|
29
29
|
const env = process.env.ZITE_ENV ?? "production";
|
|
30
|
-
const BASE_URL = process.env.ZITE_DB_URL ??
|
|
31
|
-
DB_ENVIRONMENTS[env] ??
|
|
32
|
-
DB_ENVIRONMENTS.production;
|
|
30
|
+
const BASE_URL = process.env.ZITE_DB_URL ?? DB_ENVIRONMENTS[env] ?? DB_ENVIRONMENTS.production;
|
|
33
31
|
const TOKEN = process.env.ZITE_DB_TOKEN ?? "";
|
|
34
32
|
async function fetchDatabase(baseId) {
|
|
35
33
|
const url = `${BASE_URL}/bases/${encodeURIComponent(baseId)}`;
|
|
@@ -88,7 +86,12 @@ function regenerateApiTs() {
|
|
|
88
86
|
const apiDir = (0, path_1.join)("src", "api");
|
|
89
87
|
if (!(0, fs_1.existsSync)(apiDir))
|
|
90
88
|
return;
|
|
91
|
-
const endpointFiles = (0, fs_1.readdirSync)(apiDir)
|
|
89
|
+
const endpointFiles = (0, fs_1.readdirSync)(apiDir)
|
|
90
|
+
.filter((f) => f.endsWith(".ts") || f.endsWith(".js"))
|
|
91
|
+
.map((f) => ({
|
|
92
|
+
fileName: f,
|
|
93
|
+
content: (0, fs_1.readFileSync)((0, path_1.join)(apiDir, f), "utf-8"),
|
|
94
|
+
}));
|
|
92
95
|
const apiTs = (0, lib_js_1.generateApiTs)(endpointFiles);
|
|
93
96
|
if (apiTs) {
|
|
94
97
|
(0, fs_1.mkdirSync)(".zite", { recursive: true });
|
package/dist/cjs/sync/lib.d.ts
CHANGED
|
@@ -30,7 +30,11 @@ export declare function generateSchema(database: Database, existingSchema?: Zite
|
|
|
30
30
|
* Pure function — no external data needed beyond what's in the schema file.
|
|
31
31
|
*/
|
|
32
32
|
export declare function generateDbTs(schema: ZiteSchema): string;
|
|
33
|
-
export
|
|
33
|
+
export type EndpointFileInfo = {
|
|
34
|
+
fileName: string;
|
|
35
|
+
content?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function generateApiTs(endpointFiles: (string | EndpointFileInfo)[]): string | null;
|
|
34
38
|
export declare function generateUserTs(usersTableFields?: Array<{
|
|
35
39
|
name: string;
|
|
36
40
|
type: 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
|
+
const parser_1 = require("@babel/parser");
|
|
12
13
|
const FIELD_TYPE_MAP = {
|
|
13
14
|
single_line_text: "string",
|
|
14
15
|
long_text: "string",
|
|
@@ -269,36 +270,80 @@ function generateDbTs(schema) {
|
|
|
269
270
|
lines.push("");
|
|
270
271
|
return lines.join("\n");
|
|
271
272
|
}
|
|
273
|
+
function detectStreamEnabled(source) {
|
|
274
|
+
try {
|
|
275
|
+
const ast = (0, parser_1.parse)(source, {
|
|
276
|
+
sourceType: "module",
|
|
277
|
+
plugins: ["typescript"],
|
|
278
|
+
});
|
|
279
|
+
const defaultExport = ast.program.body.find((n) => n.type === "ExportDefaultDeclaration" &&
|
|
280
|
+
n.declaration.type === "CallExpression");
|
|
281
|
+
if (!defaultExport || defaultExport.type !== "ExportDefaultDeclaration")
|
|
282
|
+
return false;
|
|
283
|
+
const call = defaultExport.declaration;
|
|
284
|
+
if (call.type !== "CallExpression" || call.arguments.length === 0)
|
|
285
|
+
return false;
|
|
286
|
+
const arg = call.arguments[0];
|
|
287
|
+
if (arg.type !== "ObjectExpression")
|
|
288
|
+
return false;
|
|
289
|
+
const streamProp = arg.properties.find((p) => p.type === "ObjectProperty" &&
|
|
290
|
+
((p.key.type === "Identifier" && p.key.name === "stream") ||
|
|
291
|
+
(p.key.type === "StringLiteral" && p.key.value === "stream")));
|
|
292
|
+
if (!streamProp || streamProp.type !== "ObjectProperty")
|
|
293
|
+
return false;
|
|
294
|
+
return (streamProp.value.type === "BooleanLiteral" &&
|
|
295
|
+
streamProp.value.value === true);
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
272
301
|
function generateApiTs(endpointFiles) {
|
|
273
302
|
if (!endpointFiles || endpointFiles.length === 0)
|
|
274
303
|
return null;
|
|
304
|
+
const endpoints = [];
|
|
305
|
+
for (const file of endpointFiles) {
|
|
306
|
+
const fileName = typeof file === "string" ? file : file.fileName;
|
|
307
|
+
const content = typeof file === "string" ? undefined : file.content;
|
|
308
|
+
const name = fileName.replace(/\.(ts|js)$/, "");
|
|
309
|
+
const camelName = toCamelCase(name);
|
|
310
|
+
const pascal = toPascalCase(camelName);
|
|
311
|
+
const stream = content ? detectStreamEnabled(content) : false;
|
|
312
|
+
endpoints.push({ camelName, pascal, stream });
|
|
313
|
+
}
|
|
314
|
+
const hasStreaming = endpoints.some((e) => e.stream);
|
|
275
315
|
const lines = [
|
|
276
316
|
"// Auto-generated by zitejs sync. Do not edit manually.",
|
|
277
317
|
"",
|
|
278
|
-
|
|
318
|
+
hasStreaming
|
|
319
|
+
? "import { createCaller, createStreamingCaller } from 'zitejs/caller';"
|
|
320
|
+
: "import { createCaller } from 'zitejs/caller';",
|
|
279
321
|
"",
|
|
280
322
|
];
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
lines.push("");
|
|
289
|
-
for (const name of endpointNames) {
|
|
290
|
-
lines.push(`export const ${name} = createCaller(${name}Endpoint, '${name}');`);
|
|
323
|
+
for (const { pascal, camelName } of endpoints) {
|
|
324
|
+
const name = camelName.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
325
|
+
const rawName = endpointFiles[endpoints.findIndex((e) => e.camelName === camelName)];
|
|
326
|
+
const fileName = typeof rawName === "string" ? rawName : rawName.fileName;
|
|
327
|
+
const baseName = fileName.replace(/\.(ts|js)$/, "");
|
|
328
|
+
lines.push(`import type { default as _${pascal}Ep } from '../src/api/${baseName}';`);
|
|
291
329
|
}
|
|
292
330
|
lines.push("");
|
|
293
|
-
for (const
|
|
294
|
-
|
|
295
|
-
lines.push(`export type ${pascal}InputType = Parameters<
|
|
296
|
-
lines.push(`export type ${pascal}OutputType = Awaited<ReturnType<
|
|
331
|
+
for (const { camelName, pascal, stream } of endpoints) {
|
|
332
|
+
lines.push(`type _${pascal}Cfg = typeof _${pascal}Ep;`);
|
|
333
|
+
lines.push(`export type ${pascal}InputType = Parameters<_${pascal}Cfg['execute']>[0]['input'];`);
|
|
334
|
+
lines.push(`export type ${pascal}OutputType = Awaited<ReturnType<_${pascal}Cfg['execute']>>;`);
|
|
335
|
+
if (stream) {
|
|
336
|
+
lines.push(`export const ${camelName} = createStreamingCaller<${pascal}InputType, ${pascal}OutputType>('${camelName}');`);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
lines.push(`export const ${camelName} = createCaller<${pascal}InputType, ${pascal}OutputType>('${camelName}');`);
|
|
340
|
+
}
|
|
341
|
+
lines.push("");
|
|
297
342
|
}
|
|
298
343
|
lines.push("");
|
|
299
344
|
lines.push("export const api = {");
|
|
300
|
-
for (const
|
|
301
|
-
lines.push(` ${
|
|
345
|
+
for (const { camelName } of endpoints) {
|
|
346
|
+
lines.push(` ${camelName},`);
|
|
302
347
|
}
|
|
303
348
|
lines.push("};");
|
|
304
349
|
lines.push("");
|
|
@@ -21,16 +21,22 @@ type SchemaLike<T> = {
|
|
|
21
21
|
_output: T;
|
|
22
22
|
parse: (data: unknown) => T;
|
|
23
23
|
};
|
|
24
|
-
export
|
|
24
|
+
export type ZiteStreamInterface = {
|
|
25
|
+
write: (data: unknown) => Promise<void>;
|
|
26
|
+
forward: (asyncIterable: AsyncIterable<string>) => Promise<string>;
|
|
27
|
+
};
|
|
28
|
+
export interface EndpointConfig<TInput = unknown, TOutput = unknown, TStream extends boolean = false> {
|
|
25
29
|
description?: string;
|
|
26
30
|
inputSchema?: SchemaLike<TInput>;
|
|
27
31
|
outputSchema?: SchemaLike<TOutput>;
|
|
28
|
-
stream?:
|
|
32
|
+
stream?: TStream;
|
|
29
33
|
authenticated?: boolean;
|
|
30
34
|
execute: (params: {
|
|
31
35
|
input: TInput;
|
|
32
36
|
context: ZiteRequestContext | ZiteScheduledContext;
|
|
33
|
-
}
|
|
37
|
+
} & (TStream extends true ? {
|
|
38
|
+
stream: ZiteStreamInterface;
|
|
39
|
+
} : {})) => Promise<TOutput> | TOutput;
|
|
34
40
|
}
|
|
35
|
-
export declare function createEndpoint<TInput = unknown, TOutput = unknown>(config: EndpointConfig<TInput, TOutput>): EndpointConfig<TInput, TOutput>;
|
|
41
|
+
export declare function createEndpoint<TInput = unknown, TOutput = unknown, TStream extends boolean = false>(config: EndpointConfig<TInput, TOutput, TStream>): EndpointConfig<TInput, TOutput, TStream>;
|
|
36
42
|
export {};
|
|
@@ -4,4 +4,10 @@ export interface EndpointConfig<TInput = unknown, TOutput = unknown> {
|
|
|
4
4
|
context: unknown;
|
|
5
5
|
}) => Promise<TOutput> | TOutput;
|
|
6
6
|
}
|
|
7
|
+
export declare function createCaller<TInput, TOutput>(name: string, flowId?: string): (input: TInput) => Promise<TOutput>;
|
|
7
8
|
export declare function createCaller<TInput, TOutput>(endpoint: EndpointConfig<TInput, TOutput>, name: string, flowId?: string): (input: TInput) => Promise<TOutput>;
|
|
9
|
+
export type StreamingResponse<T> = {
|
|
10
|
+
[Symbol.asyncIterator](): AsyncIterator<string>;
|
|
11
|
+
result: Promise<T>;
|
|
12
|
+
};
|
|
13
|
+
export declare function createStreamingCaller<TInput, TOutput>(name: string): (input: TInput) => StreamingResponse<TOutput>;
|
package/dist/esm/caller/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { getEnv } from
|
|
1
|
+
import { getEnv } from "../internal/env.js";
|
|
2
2
|
const ENVIRONMENTS = {
|
|
3
|
-
production:
|
|
4
|
-
staging:
|
|
5
|
-
local:
|
|
3
|
+
production: "https://workflows.zite.com",
|
|
4
|
+
staging: "https://workflows.zitestaging.com",
|
|
5
|
+
local: "http://localhost:2506",
|
|
6
6
|
};
|
|
7
7
|
function getRunnerUrl() {
|
|
8
|
-
const env = getEnv(
|
|
9
|
-
return getEnv(
|
|
8
|
+
const env = getEnv("ZITE_ENV", "VITE_ZITE_ENV") ?? "production";
|
|
9
|
+
return (getEnv("ZITE_RUNNER_URL", "VITE_ZITE_RUNNER_URL") ??
|
|
10
|
+
ENVIRONMENTS[env] ??
|
|
11
|
+
ENVIRONMENTS.production);
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Get the user's usage token for endpoint auth.
|
|
@@ -14,35 +16,132 @@ function getRunnerUrl() {
|
|
|
14
16
|
* In external mode: stored in localStorage by the auth flow
|
|
15
17
|
*/
|
|
16
18
|
function getUsageToken() {
|
|
17
|
-
if (typeof window !==
|
|
19
|
+
if (typeof window !== "undefined") {
|
|
18
20
|
const win = window;
|
|
19
|
-
if (typeof win._ziteUsageToken ===
|
|
21
|
+
if (typeof win._ziteUsageToken === "string")
|
|
20
22
|
return win._ziteUsageToken;
|
|
21
23
|
}
|
|
22
24
|
// Fallback to stored auth token (external mode)
|
|
23
|
-
if (typeof localStorage !==
|
|
24
|
-
const stored = localStorage.getItem(
|
|
25
|
+
if (typeof localStorage !== "undefined") {
|
|
26
|
+
const stored = localStorage.getItem("zite.auth.token");
|
|
25
27
|
if (stored)
|
|
26
28
|
return stored;
|
|
27
29
|
}
|
|
28
|
-
return
|
|
30
|
+
return "";
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
function buildFetchOptions(name, input, extra) {
|
|
33
|
+
const appId = getEnv("ZITE_FLOW_ID", "VITE_ZITE_FLOW_ID") ?? "";
|
|
34
|
+
const token = getUsageToken();
|
|
35
|
+
const ziteAuthToken = typeof localStorage !== "undefined"
|
|
36
|
+
? localStorage.getItem("zite.auth.token")
|
|
37
|
+
: null;
|
|
38
|
+
return {
|
|
39
|
+
url: getRunnerUrl() + "/public/" + appId + "/api/" + name,
|
|
40
|
+
init: {
|
|
41
|
+
method: "POST",
|
|
36
42
|
headers: {
|
|
37
43
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
38
|
-
|
|
44
|
+
"Content-Type": "application/json",
|
|
39
45
|
},
|
|
40
|
-
body: JSON.stringify({
|
|
41
|
-
|
|
46
|
+
body: JSON.stringify({
|
|
47
|
+
inputs: input,
|
|
48
|
+
mode: "preview",
|
|
49
|
+
usageToken: token,
|
|
50
|
+
...(ziteAuthToken ? { ziteAuthToken } : {}),
|
|
51
|
+
...extra,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function createCaller(endpointOrName, nameOrFlowId, flowId) {
|
|
57
|
+
const name = typeof endpointOrName === "string" ? endpointOrName : nameOrFlowId;
|
|
58
|
+
return async (input) => {
|
|
59
|
+
const { url, init } = buildFetchOptions(name, input);
|
|
60
|
+
const res = await fetch(url, init);
|
|
42
61
|
if (!res.ok) {
|
|
43
|
-
const text = await res.text().catch(() =>
|
|
62
|
+
const text = await res.text().catch(() => "");
|
|
44
63
|
throw new Error(`API call failed (${res.status}): ${text}`);
|
|
45
64
|
}
|
|
46
65
|
return res.json();
|
|
47
66
|
};
|
|
48
67
|
}
|
|
68
|
+
export function createStreamingCaller(name) {
|
|
69
|
+
return (input) => {
|
|
70
|
+
let resultResolve;
|
|
71
|
+
let resultReject;
|
|
72
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
73
|
+
resultResolve = resolve;
|
|
74
|
+
resultReject = reject;
|
|
75
|
+
});
|
|
76
|
+
const { url, init } = buildFetchOptions(name, input, { stream: true });
|
|
77
|
+
const fetchPromise = fetch(url, init);
|
|
78
|
+
return {
|
|
79
|
+
async *[Symbol.asyncIterator]() {
|
|
80
|
+
try {
|
|
81
|
+
const response = await fetchPromise;
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const errorData = await response.json().catch(() => ({}));
|
|
84
|
+
const error = new Error(errorData.message ||
|
|
85
|
+
`Error with endpoint ${name}: ${response.status}`);
|
|
86
|
+
resultReject(error);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
if (!response.body) {
|
|
90
|
+
const error = new Error("No response body for streaming endpoint");
|
|
91
|
+
resultReject(error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
const reader = response.body
|
|
95
|
+
.pipeThrough(new TextDecoderStream())
|
|
96
|
+
.getReader();
|
|
97
|
+
let buffer = "";
|
|
98
|
+
while (true) {
|
|
99
|
+
const { value, done } = await reader.read();
|
|
100
|
+
if (done)
|
|
101
|
+
break;
|
|
102
|
+
buffer += value;
|
|
103
|
+
while (buffer.includes("\n\n")) {
|
|
104
|
+
const eventEnd = buffer.indexOf("\n\n");
|
|
105
|
+
const eventBlock = buffer.substring(0, eventEnd);
|
|
106
|
+
buffer = buffer.substring(eventEnd + 2);
|
|
107
|
+
const eventTypeMatch = eventBlock.match(/^event: (.+)$/m);
|
|
108
|
+
const dataMatch = eventBlock.match(/^data: (.+)$/m);
|
|
109
|
+
const eventType = eventTypeMatch?.[1];
|
|
110
|
+
const dataStr = dataMatch?.[1];
|
|
111
|
+
if (eventType === "data" && dataStr) {
|
|
112
|
+
try {
|
|
113
|
+
yield JSON.parse(dataStr);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
yield dataStr;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (eventType === "result" && dataStr) {
|
|
120
|
+
try {
|
|
121
|
+
resultResolve(JSON.parse(dataStr));
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
resultResolve(dataStr);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (eventType === "error" && dataStr) {
|
|
128
|
+
try {
|
|
129
|
+
const errorData = JSON.parse(dataStr);
|
|
130
|
+
resultReject(new Error(errorData.message || "Streaming error"));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
resultReject(new Error(dataStr || "Streaming error"));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
resultReject(error);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
result: resultPromise,
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
}
|
package/dist/esm/dev/index.js
CHANGED
|
@@ -40,7 +40,12 @@ function regenerateAppApiTs(appDir) {
|
|
|
40
40
|
const apiDir = join("apps", appDir, "src", "api");
|
|
41
41
|
if (!existsSync(apiDir))
|
|
42
42
|
return;
|
|
43
|
-
const endpointFiles = readdirSync(apiDir)
|
|
43
|
+
const endpointFiles = readdirSync(apiDir)
|
|
44
|
+
.filter((f) => f.endsWith(".ts") || f.endsWith(".js"))
|
|
45
|
+
.map((f) => ({
|
|
46
|
+
fileName: f,
|
|
47
|
+
content: readFileSync(join(apiDir, f), "utf-8"),
|
|
48
|
+
}));
|
|
44
49
|
const content = generateApiTs(endpointFiles);
|
|
45
50
|
if (content) {
|
|
46
51
|
const outDir = join("apps", appDir, ".zite");
|
package/dist/esm/sync/index.js
CHANGED
|
@@ -9,9 +9,7 @@ const DB_ENVIRONMENTS = {
|
|
|
9
9
|
local: "http://localhost:2507/api/v1",
|
|
10
10
|
};
|
|
11
11
|
const env = process.env.ZITE_ENV ?? "production";
|
|
12
|
-
const BASE_URL = process.env.ZITE_DB_URL ??
|
|
13
|
-
DB_ENVIRONMENTS[env] ??
|
|
14
|
-
DB_ENVIRONMENTS.production;
|
|
12
|
+
const BASE_URL = process.env.ZITE_DB_URL ?? DB_ENVIRONMENTS[env] ?? DB_ENVIRONMENTS.production;
|
|
15
13
|
const TOKEN = process.env.ZITE_DB_TOKEN ?? "";
|
|
16
14
|
async function fetchDatabase(baseId) {
|
|
17
15
|
const url = `${BASE_URL}/bases/${encodeURIComponent(baseId)}`;
|
|
@@ -70,7 +68,12 @@ export function regenerateApiTs() {
|
|
|
70
68
|
const apiDir = join("src", "api");
|
|
71
69
|
if (!existsSync(apiDir))
|
|
72
70
|
return;
|
|
73
|
-
const endpointFiles = readdirSync(apiDir)
|
|
71
|
+
const endpointFiles = readdirSync(apiDir)
|
|
72
|
+
.filter((f) => f.endsWith(".ts") || f.endsWith(".js"))
|
|
73
|
+
.map((f) => ({
|
|
74
|
+
fileName: f,
|
|
75
|
+
content: readFileSync(join(apiDir, f), "utf-8"),
|
|
76
|
+
}));
|
|
74
77
|
const apiTs = generateApiTs(endpointFiles);
|
|
75
78
|
if (apiTs) {
|
|
76
79
|
mkdirSync(".zite", { recursive: true });
|
package/dist/esm/sync/lib.d.ts
CHANGED
|
@@ -30,7 +30,11 @@ export declare function generateSchema(database: Database, existingSchema?: Zite
|
|
|
30
30
|
* Pure function — no external data needed beyond what's in the schema file.
|
|
31
31
|
*/
|
|
32
32
|
export declare function generateDbTs(schema: ZiteSchema): string;
|
|
33
|
-
export
|
|
33
|
+
export type EndpointFileInfo = {
|
|
34
|
+
fileName: string;
|
|
35
|
+
content?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function generateApiTs(endpointFiles: (string | EndpointFileInfo)[]): string | null;
|
|
34
38
|
export declare function generateUserTs(usersTableFields?: Array<{
|
|
35
39
|
name: string;
|
|
36
40
|
type: string;
|
package/dist/esm/sync/lib.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parse } from "@babel/parser";
|
|
1
2
|
const FIELD_TYPE_MAP = {
|
|
2
3
|
single_line_text: "string",
|
|
3
4
|
long_text: "string",
|
|
@@ -258,36 +259,80 @@ export function generateDbTs(schema) {
|
|
|
258
259
|
lines.push("");
|
|
259
260
|
return lines.join("\n");
|
|
260
261
|
}
|
|
262
|
+
function detectStreamEnabled(source) {
|
|
263
|
+
try {
|
|
264
|
+
const ast = parse(source, {
|
|
265
|
+
sourceType: "module",
|
|
266
|
+
plugins: ["typescript"],
|
|
267
|
+
});
|
|
268
|
+
const defaultExport = ast.program.body.find((n) => n.type === "ExportDefaultDeclaration" &&
|
|
269
|
+
n.declaration.type === "CallExpression");
|
|
270
|
+
if (!defaultExport || defaultExport.type !== "ExportDefaultDeclaration")
|
|
271
|
+
return false;
|
|
272
|
+
const call = defaultExport.declaration;
|
|
273
|
+
if (call.type !== "CallExpression" || call.arguments.length === 0)
|
|
274
|
+
return false;
|
|
275
|
+
const arg = call.arguments[0];
|
|
276
|
+
if (arg.type !== "ObjectExpression")
|
|
277
|
+
return false;
|
|
278
|
+
const streamProp = arg.properties.find((p) => p.type === "ObjectProperty" &&
|
|
279
|
+
((p.key.type === "Identifier" && p.key.name === "stream") ||
|
|
280
|
+
(p.key.type === "StringLiteral" && p.key.value === "stream")));
|
|
281
|
+
if (!streamProp || streamProp.type !== "ObjectProperty")
|
|
282
|
+
return false;
|
|
283
|
+
return (streamProp.value.type === "BooleanLiteral" &&
|
|
284
|
+
streamProp.value.value === true);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
261
290
|
export function generateApiTs(endpointFiles) {
|
|
262
291
|
if (!endpointFiles || endpointFiles.length === 0)
|
|
263
292
|
return null;
|
|
293
|
+
const endpoints = [];
|
|
294
|
+
for (const file of endpointFiles) {
|
|
295
|
+
const fileName = typeof file === "string" ? file : file.fileName;
|
|
296
|
+
const content = typeof file === "string" ? undefined : file.content;
|
|
297
|
+
const name = fileName.replace(/\.(ts|js)$/, "");
|
|
298
|
+
const camelName = toCamelCase(name);
|
|
299
|
+
const pascal = toPascalCase(camelName);
|
|
300
|
+
const stream = content ? detectStreamEnabled(content) : false;
|
|
301
|
+
endpoints.push({ camelName, pascal, stream });
|
|
302
|
+
}
|
|
303
|
+
const hasStreaming = endpoints.some((e) => e.stream);
|
|
264
304
|
const lines = [
|
|
265
305
|
"// Auto-generated by zitejs sync. Do not edit manually.",
|
|
266
306
|
"",
|
|
267
|
-
|
|
307
|
+
hasStreaming
|
|
308
|
+
? "import { createCaller, createStreamingCaller } from 'zitejs/caller';"
|
|
309
|
+
: "import { createCaller } from 'zitejs/caller';",
|
|
268
310
|
"",
|
|
269
311
|
];
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
lines.push("");
|
|
278
|
-
for (const name of endpointNames) {
|
|
279
|
-
lines.push(`export const ${name} = createCaller(${name}Endpoint, '${name}');`);
|
|
312
|
+
for (const { pascal, camelName } of endpoints) {
|
|
313
|
+
const name = camelName.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
314
|
+
const rawName = endpointFiles[endpoints.findIndex((e) => e.camelName === camelName)];
|
|
315
|
+
const fileName = typeof rawName === "string" ? rawName : rawName.fileName;
|
|
316
|
+
const baseName = fileName.replace(/\.(ts|js)$/, "");
|
|
317
|
+
lines.push(`import type { default as _${pascal}Ep } from '../src/api/${baseName}';`);
|
|
280
318
|
}
|
|
281
319
|
lines.push("");
|
|
282
|
-
for (const
|
|
283
|
-
|
|
284
|
-
lines.push(`export type ${pascal}InputType = Parameters<
|
|
285
|
-
lines.push(`export type ${pascal}OutputType = Awaited<ReturnType<
|
|
320
|
+
for (const { camelName, pascal, stream } of endpoints) {
|
|
321
|
+
lines.push(`type _${pascal}Cfg = typeof _${pascal}Ep;`);
|
|
322
|
+
lines.push(`export type ${pascal}InputType = Parameters<_${pascal}Cfg['execute']>[0]['input'];`);
|
|
323
|
+
lines.push(`export type ${pascal}OutputType = Awaited<ReturnType<_${pascal}Cfg['execute']>>;`);
|
|
324
|
+
if (stream) {
|
|
325
|
+
lines.push(`export const ${camelName} = createStreamingCaller<${pascal}InputType, ${pascal}OutputType>('${camelName}');`);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
lines.push(`export const ${camelName} = createCaller<${pascal}InputType, ${pascal}OutputType>('${camelName}');`);
|
|
329
|
+
}
|
|
330
|
+
lines.push("");
|
|
286
331
|
}
|
|
287
332
|
lines.push("");
|
|
288
333
|
lines.push("export const api = {");
|
|
289
|
-
for (const
|
|
290
|
-
lines.push(` ${
|
|
334
|
+
for (const { camelName } of endpoints) {
|
|
335
|
+
lines.push(` ${camelName},`);
|
|
291
336
|
}
|
|
292
337
|
lines.push("};");
|
|
293
338
|
lines.push("");
|