zitejs 0.10.0-start.10 → 0.10.0-start.12
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/auth/index.test.js +30 -0
- package/dist/cjs/start/entries.js +4 -2
- package/dist/esm/auth/index.test.js +30 -0
- package/dist/esm/start/entries.js +4 -2
- package/dist/esm/start/instance.d.ts +1 -0
- package/dist/esm/start/instance.js +12 -3
- package/dist/esm/start/quiet.d.ts +2 -0
- package/dist/esm/start/quiet.js +27 -0
- package/dist/esm/start/router.d.ts +5 -0
- package/dist/esm/start/router.js +32 -0
- package/dist/esm/start/server.d.ts +4 -0
- package/dist/esm/start/server.js +45 -6
- package/dist/esm/start/types.d.ts +1 -1
- package/dist/esm/start/version.d.ts +1 -1
- package/dist/esm/start/version.js +1 -1
- package/package.json +1 -1
|
@@ -187,3 +187,33 @@ function redirectParamOf(href) {
|
|
|
187
187
|
(0, vitest_1.expect)(params.get('usageToken')).toBeNull();
|
|
188
188
|
});
|
|
189
189
|
});
|
|
190
|
+
// AUTH-03: what the platform's auth routes receive from the client, on the app's own origin.
|
|
191
|
+
(0, vitest_1.describe)("the client's calls", () => {
|
|
192
|
+
const calls = () => {
|
|
193
|
+
const sent = [];
|
|
194
|
+
vitest_1.vi.stubGlobal('fetch', vitest_1.vi.fn(async (input, init) => {
|
|
195
|
+
const request = new Request(new URL(String(input instanceof Request ? input.url : input), 'https://app.zite.so'), init);
|
|
196
|
+
sent.push({
|
|
197
|
+
path: new URL(request.url).pathname,
|
|
198
|
+
method: request.method,
|
|
199
|
+
body: request.method === 'POST' ? await request.json().catch(() => null) : null,
|
|
200
|
+
});
|
|
201
|
+
return Response.json({});
|
|
202
|
+
}));
|
|
203
|
+
return sent;
|
|
204
|
+
};
|
|
205
|
+
(0, vitest_1.it)('sign in by link, sign out and edit the profile on /api/auth', async () => {
|
|
206
|
+
const sent = calls();
|
|
207
|
+
// The client takes its fetch when the module loads.
|
|
208
|
+
vitest_1.vi.resetModules();
|
|
209
|
+
const { signIn, signOut, updateProfile } = await Promise.resolve().then(() => __importStar(require('./index.js')));
|
|
210
|
+
await signIn.magicLink({ email: 'ada@x.co' });
|
|
211
|
+
await signOut();
|
|
212
|
+
await updateProfile({ firstName: 'Ada' });
|
|
213
|
+
(0, vitest_1.expect)(sent).toEqual([
|
|
214
|
+
{ path: '/api/auth/sign-in/magic-link', method: 'POST', body: vitest_1.expect.objectContaining({ email: 'ada@x.co' }) },
|
|
215
|
+
{ path: '/api/auth/sign-out', method: 'POST', body: vitest_1.expect.anything() },
|
|
216
|
+
{ path: '/api/auth/update-user', method: 'POST', body: { firstName: 'Ada' } },
|
|
217
|
+
]);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
@@ -17,15 +17,17 @@ const renderStartServerEntry = (target = "cloudflare") => target === "cloudflare
|
|
|
17
17
|
import handler from '@tanstack/react-start/server-entry';
|
|
18
18
|
import { createZiteWorker } from 'zitejs/start/worker';
|
|
19
19
|
import { getRouter } from '../src/router';
|
|
20
|
+
import { startInstance } from './start';
|
|
20
21
|
|
|
21
|
-
export default createZiteWorker({ handler, getRouter });
|
|
22
|
+
export default createZiteWorker({ handler, getRouter, startInstance });
|
|
22
23
|
`
|
|
23
24
|
: `// Generated by zitejs for TanStack Start apps. The platform owns this file.
|
|
24
25
|
import handler, { createServerEntry } from '@tanstack/react-start/server-entry';
|
|
25
26
|
import { createZiteFetch } from 'zitejs/start/server';
|
|
26
27
|
import { getRouter } from '../src/router';
|
|
28
|
+
import { startInstance } from './start';
|
|
27
29
|
|
|
28
|
-
export default createServerEntry({ fetch: createZiteFetch({ handler, getRouter }) });
|
|
30
|
+
export default createServerEntry({ fetch: createZiteFetch({ handler, getRouter, startInstance }) });
|
|
29
31
|
`;
|
|
30
32
|
exports.renderStartServerEntry = renderStartServerEntry;
|
|
31
33
|
/** The start instance: the platform's middleware, then the app's own `src/start.ts` when it has one. */
|
|
@@ -152,3 +152,33 @@ describe('loginWithRedirect', () => {
|
|
|
152
152
|
expect(params.get('usageToken')).toBeNull();
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
|
+
// AUTH-03: what the platform's auth routes receive from the client, on the app's own origin.
|
|
156
|
+
describe("the client's calls", () => {
|
|
157
|
+
const calls = () => {
|
|
158
|
+
const sent = [];
|
|
159
|
+
vi.stubGlobal('fetch', vi.fn(async (input, init) => {
|
|
160
|
+
const request = new Request(new URL(String(input instanceof Request ? input.url : input), 'https://app.zite.so'), init);
|
|
161
|
+
sent.push({
|
|
162
|
+
path: new URL(request.url).pathname,
|
|
163
|
+
method: request.method,
|
|
164
|
+
body: request.method === 'POST' ? await request.json().catch(() => null) : null,
|
|
165
|
+
});
|
|
166
|
+
return Response.json({});
|
|
167
|
+
}));
|
|
168
|
+
return sent;
|
|
169
|
+
};
|
|
170
|
+
it('sign in by link, sign out and edit the profile on /api/auth', async () => {
|
|
171
|
+
const sent = calls();
|
|
172
|
+
// The client takes its fetch when the module loads.
|
|
173
|
+
vi.resetModules();
|
|
174
|
+
const { signIn, signOut, updateProfile } = await import('./index.js');
|
|
175
|
+
await signIn.magicLink({ email: 'ada@x.co' });
|
|
176
|
+
await signOut();
|
|
177
|
+
await updateProfile({ firstName: 'Ada' });
|
|
178
|
+
expect(sent).toEqual([
|
|
179
|
+
{ path: '/api/auth/sign-in/magic-link', method: 'POST', body: expect.objectContaining({ email: 'ada@x.co' }) },
|
|
180
|
+
{ path: '/api/auth/sign-out', method: 'POST', body: expect.anything() },
|
|
181
|
+
{ path: '/api/auth/update-user', method: 'POST', body: { firstName: 'Ada' } },
|
|
182
|
+
]);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -12,15 +12,17 @@ export const renderStartServerEntry = (target = "cloudflare") => target === "clo
|
|
|
12
12
|
import handler from '@tanstack/react-start/server-entry';
|
|
13
13
|
import { createZiteWorker } from 'zitejs/start/worker';
|
|
14
14
|
import { getRouter } from '../src/router';
|
|
15
|
+
import { startInstance } from './start';
|
|
15
16
|
|
|
16
|
-
export default createZiteWorker({ handler, getRouter });
|
|
17
|
+
export default createZiteWorker({ handler, getRouter, startInstance });
|
|
17
18
|
`
|
|
18
19
|
: `// Generated by zitejs for TanStack Start apps. The platform owns this file.
|
|
19
20
|
import handler, { createServerEntry } from '@tanstack/react-start/server-entry';
|
|
20
21
|
import { createZiteFetch } from 'zitejs/start/server';
|
|
21
22
|
import { getRouter } from '../src/router';
|
|
23
|
+
import { startInstance } from './start';
|
|
22
24
|
|
|
23
|
-
export default createServerEntry({ fetch: createZiteFetch({ handler, getRouter }) });
|
|
25
|
+
export default createServerEntry({ fetch: createZiteFetch({ handler, getRouter, startInstance }) });
|
|
24
26
|
`;
|
|
25
27
|
/** The start instance: the platform's middleware, then the app's own `src/start.ts` when it has one. */
|
|
26
28
|
export const renderStartInstance = (hasAppStart) => hasAppStart
|
|
@@ -6,6 +6,7 @@ import type { AnyFunctionMiddleware, AnyRequestMiddleware, StartInstance } from
|
|
|
6
6
|
* adapters first, then whatever the app's own `src/start.ts` sets.
|
|
7
7
|
*/
|
|
8
8
|
export declare function createZiteStart<const TAdapters extends ReadonlyArray<AnySerializationAdapter> = [], TDefaultSsr extends SSROption = SSROption, const TRequest extends ReadonlyArray<AnyRequestMiddleware> = [], const TFunction extends ReadonlyArray<AnyFunctionMiddleware> = []>(app?: StartInstance<TAdapters, TDefaultSsr, TRequest, TFunction>): StartInstance<readonly [import("@tanstack/react-router").SerializationAdapter<Error, {
|
|
9
|
+
stack?: string | undefined;
|
|
9
10
|
code: "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "RATE_LIMITED" | "INTERNAL_ERROR" | "INVALID_INPUT";
|
|
10
11
|
message: string;
|
|
11
12
|
}, never>, ...TAdapters], TDefaultSsr, readonly [import("@tanstack/react-start").RequestMiddlewareAfterServer<{}, undefined, undefined>, ...TRequest], readonly [import("@tanstack/react-start").FunctionMiddlewareAfterClient<{}, unknown, undefined, undefined, undefined>, import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, undefined, undefined, undefined>, ...TFunction]>;
|
|
@@ -5,6 +5,7 @@ import { createSerializationAdapter, redirect } from "@tanstack/react-router";
|
|
|
5
5
|
import { toClientError, ZiteError } from "./errors.js";
|
|
6
6
|
import { isSignInRequired, loginHref } from "./index.js";
|
|
7
7
|
import { errorOf, preview } from "./runLog.js";
|
|
8
|
+
import { currentHost } from "./host.js";
|
|
8
9
|
import { getHost, inScope } from "./scope.js";
|
|
9
10
|
// TanStack drops its default CSRF check once an app has a start instance.
|
|
10
11
|
const csrf = createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === "serverFn" });
|
|
@@ -50,16 +51,24 @@ const runCapture = createMiddleware({ type: "function" }).server(async ({ next,
|
|
|
50
51
|
});
|
|
51
52
|
/**
|
|
52
53
|
* Every error a server function or a page's loader sends the browser arrives as a ZiteError, with its code and the
|
|
53
|
-
* message classic would show. Anything else on it,
|
|
54
|
+
* message classic would show. Anything else on it, an SDK's request, stays on the server; its stack goes only to the
|
|
55
|
+
* editor's preview, for "Fix it for me".
|
|
54
56
|
*/
|
|
55
57
|
const ziteErrorAdapter = createSerializationAdapter({
|
|
56
58
|
key: "zite-error",
|
|
57
59
|
test: (value) => value instanceof Error,
|
|
58
60
|
toSerializable: (error) => {
|
|
59
61
|
const { code, message } = toClientError(error);
|
|
60
|
-
|
|
62
|
+
// `currentHost`, not `getHost`: this adapter ships to the browser, which mustn't bundle the request scope.
|
|
63
|
+
const stack = currentHost()?.mode === "preview" ? error.stack : undefined;
|
|
64
|
+
return { code, message, ...(stack && { stack }) };
|
|
65
|
+
},
|
|
66
|
+
fromSerializable: ({ code, message, stack }) => {
|
|
67
|
+
const error = new ZiteError(code, message);
|
|
68
|
+
if (stack)
|
|
69
|
+
error.stack = stack;
|
|
70
|
+
return error;
|
|
61
71
|
},
|
|
62
|
-
fromSerializable: ({ code, message }) => new ZiteError(code, message),
|
|
63
72
|
});
|
|
64
73
|
/**
|
|
65
74
|
* The start instance every Start app builds with: the platform's middleware and
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Server-only. A trigger registration's console stays out of the platform's
|
|
2
|
+
// logs, as classic's does: the provider can answer it with the signing secret.
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
const LEVELS = ["debug", "dir", "error", "info", "log", "table", "trace", "warn"];
|
|
5
|
+
// Keyed on globalThis so two copies of zitejs in one bundle wrap console once.
|
|
6
|
+
const stores = globalThis;
|
|
7
|
+
const QUIET_KEY = Symbol.for("zitejs:quiet-console");
|
|
8
|
+
const quietStorage = () => {
|
|
9
|
+
const held = stores[QUIET_KEY];
|
|
10
|
+
if (held)
|
|
11
|
+
return held;
|
|
12
|
+
const storage = new AsyncLocalStorage();
|
|
13
|
+
stores[QUIET_KEY] = storage;
|
|
14
|
+
const methods = console;
|
|
15
|
+
for (const level of LEVELS) {
|
|
16
|
+
const original = methods[level];
|
|
17
|
+
if (typeof original !== "function")
|
|
18
|
+
continue;
|
|
19
|
+
methods[level] = (...args) => {
|
|
20
|
+
if (!storage.getStore())
|
|
21
|
+
original.apply(console, args);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return storage;
|
|
25
|
+
};
|
|
26
|
+
/** Runs `fn` with this request's console dropped; the isolate's other requests log as before. */
|
|
27
|
+
export const withoutConsole = (fn) => quietStorage().run(true, fn);
|
|
@@ -11,6 +11,11 @@ type Dehydrated = {
|
|
|
11
11
|
user: User | null;
|
|
12
12
|
};
|
|
13
13
|
type ZiteRouterOptions<TRouteTree extends AnyRoute> = Omit<RouterConstructorOptions<TRouteTree, "never", false, RouterHistory, Dehydrated>, "context" | "dehydrate" | "hydrate">;
|
|
14
|
+
/**
|
|
15
|
+
* @internal Tells the editor's preview the page crashed, as classic's runtime reports an emptied #root: a Start page
|
|
16
|
+
* has none, and an error a route's boundary catches is the crash. Being signed out isn't one.
|
|
17
|
+
*/
|
|
18
|
+
export declare const reportCrash: (error: unknown) => void;
|
|
14
19
|
/**
|
|
15
20
|
* The router for `src/router.tsx`. The signed-in user is in `context.user`: on the server from the platform, in the
|
|
16
21
|
* browser from the page it rendered, so no request asks for it again. `context.queryClient` is new for each request
|
package/dist/esm/start/router.js
CHANGED
|
@@ -9,12 +9,21 @@ import { currentHost } from "./host.js";
|
|
|
9
9
|
export const QUERY_STALE_TIME_MS = 30_000;
|
|
10
10
|
const ziteWindow = () => (typeof window === "undefined" ? undefined : window);
|
|
11
11
|
const box = { maxWidth: 480, margin: "15vh auto", padding: 24, fontFamily: "system-ui, sans-serif", textAlign: "center" };
|
|
12
|
+
/**
|
|
13
|
+
* @internal Tells the editor's preview the page crashed, as classic's runtime reports an emptied #root: a Start page
|
|
14
|
+
* has none, and an error a route's boundary catches is the crash. Being signed out isn't one.
|
|
15
|
+
*/
|
|
16
|
+
export const reportCrash = (error) => {
|
|
17
|
+
if (!isSignInError(error))
|
|
18
|
+
ziteWindow()?._ziteOnCrash?.(error);
|
|
19
|
+
};
|
|
12
20
|
// As classic's crash screen: the message, "Fix it for me" in the editor, and a reload. The server renders from the
|
|
13
21
|
// app's own error and the browser from the one that crossed, already mapped, so both show the same text.
|
|
14
22
|
function ZiteErrorComponent({ error }) {
|
|
15
23
|
const router = useRouter();
|
|
16
24
|
const [allowAiFix, setAllowAiFix] = useState(false);
|
|
17
25
|
useEffect(() => setAllowAiFix(ziteWindow()?.__ziteAllowAiFix === true), []);
|
|
26
|
+
useEffect(() => markReady("error"), []);
|
|
18
27
|
const message = typeof window === "undefined" ? toClientError(error).message : error instanceof Error ? error.message : String(error);
|
|
19
28
|
const reload = () => {
|
|
20
29
|
const onReload = ziteWindow()?._ziteOnReload;
|
|
@@ -27,6 +36,20 @@ function ZiteErrorComponent({ error }) {
|
|
|
27
36
|
!isSignInError(error) &&
|
|
28
37
|
h("button", { type: "button", onClick: () => ziteWindow()?._ziteOnFixError?.(error) }, "Fix it for me"), h("button", { type: "button", onClick: reload }, "Try again"));
|
|
29
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* `<html data-zite-ready>`: what the platform's screenshots wait for. `1` once
|
|
41
|
+
* the page has rendered with nothing loading, `error` when the error screen did.
|
|
42
|
+
*/
|
|
43
|
+
const markReady = (state) => {
|
|
44
|
+
if (typeof document !== "undefined")
|
|
45
|
+
document.documentElement.dataset.ziteReady = state;
|
|
46
|
+
};
|
|
47
|
+
const watchReady = (router) => () => {
|
|
48
|
+
const { status, isLoading, matches } = router.state;
|
|
49
|
+
if (status !== "idle" || isLoading || matches.some((match) => match.status === "pending"))
|
|
50
|
+
return;
|
|
51
|
+
markReady(matches.some((match) => match.status === "error") ? "error" : "1");
|
|
52
|
+
};
|
|
30
53
|
function ZiteNotFound() {
|
|
31
54
|
return h("div", { style: box }, h("p", { style: { fontWeight: 600 } }, "Page not found"), h(Link, { to: "/" }, "Go home"));
|
|
32
55
|
}
|
|
@@ -67,6 +90,12 @@ export function createZiteRouter(options) {
|
|
|
67
90
|
defaultPendingComponent: ZitePending,
|
|
68
91
|
...options,
|
|
69
92
|
...(claim && { rewrite: keepPreviewClaim(claim, options.rewrite) }),
|
|
93
|
+
// Whichever screen shows it: a route may have its own.
|
|
94
|
+
defaultOnCatch: (error, info) => {
|
|
95
|
+
markReady("error");
|
|
96
|
+
reportCrash(error);
|
|
97
|
+
options.defaultOnCatch?.(error, info);
|
|
98
|
+
},
|
|
70
99
|
context,
|
|
71
100
|
dehydrate: () => ({ user: context.user }),
|
|
72
101
|
hydrate: (dehydrated) => {
|
|
@@ -74,6 +103,9 @@ export function createZiteRouter(options) {
|
|
|
74
103
|
},
|
|
75
104
|
});
|
|
76
105
|
setupRouterSsrQueryIntegration({ router, queryClient });
|
|
106
|
+
const mark = watchReady(router);
|
|
107
|
+
router.subscribe("onResolved", mark);
|
|
108
|
+
router.subscribe("onRendered", mark);
|
|
77
109
|
const host = currentHost();
|
|
78
110
|
if (host)
|
|
79
111
|
host.router = router;
|
|
@@ -35,6 +35,10 @@ export type ZiteServerOptions = {
|
|
|
35
35
|
};
|
|
36
36
|
getRouter: () => unknown;
|
|
37
37
|
platform?: PlatformBinding;
|
|
38
|
+
/** The app's start instance, which a test run of a server function runs under. Entries before 0.10.0-start.11 don't pass it. */
|
|
39
|
+
startInstance?: {
|
|
40
|
+
getOptions: () => unknown;
|
|
41
|
+
};
|
|
38
42
|
};
|
|
39
43
|
type HostedContext = WorkerContext & {
|
|
40
44
|
props?: Partial<HostProps>;
|
package/dist/esm/start/server.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// For the generated server entry only. Apps never import this.
|
|
2
|
+
import { requestHandler } from "@tanstack/react-start/server";
|
|
3
|
+
import { createSsrRpc } from "@tanstack/react-start/ssr-rpc";
|
|
4
|
+
import { runWithStartContext } from "@tanstack/start-storage-context";
|
|
1
5
|
import { asZiteError, isZiteErrorCode, ZiteError, ZITE_ERROR_STATUS } from "./errors.js";
|
|
2
6
|
import { describeApp } from "./describe.js";
|
|
3
7
|
import { runRegistration } from "./registration.js";
|
|
@@ -5,6 +9,7 @@ import { isAuthHookName, loadAuthHooks } from "./authHooks.js";
|
|
|
5
9
|
import { errorOf, preview } from "./runLog.js";
|
|
6
10
|
import { DATA_INTEGRATION_ID, dataContextOf, runDataCall } from "./data/index.js";
|
|
7
11
|
import { airtableSettingsOf, runAirtableCall } from "./airtable/index.js";
|
|
12
|
+
import { withoutConsole } from "./quiet.js";
|
|
8
13
|
import { getHost, requireScope, runInScope, runWithHost } from "./scope.js";
|
|
9
14
|
import { ZITEJS_VERSION } from "./version.js";
|
|
10
15
|
import { loadWorkflows, loggedInput, runWorkflow } from "./workflowRun.js";
|
|
@@ -91,7 +96,7 @@ const watchOutboundFetches = () => {
|
|
|
91
96
|
};
|
|
92
97
|
};
|
|
93
98
|
const decodeUser = (value) => JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0))));
|
|
94
|
-
const INVOKE_KINDS = new Set(["webhook", "describe", "workflow", "register", "warm", "authHook"]);
|
|
99
|
+
const INVOKE_KINDS = new Set(["webhook", "describe", "workflow", "register", "warm", "authHook", "function"]);
|
|
95
100
|
// What a request without props may ask for: neither runs app code on anyone's behalf.
|
|
96
101
|
const UNHOSTED_INVOKE_KINDS = new Set(["warm", "describe"]);
|
|
97
102
|
/** What the host dispatched this request with. Headers are ignored: props are the only thing it alone can set. */
|
|
@@ -206,6 +211,38 @@ async function invokeWorkflow(request, host, workflows) {
|
|
|
206
211
|
});
|
|
207
212
|
return Response.json(result, { status: result.ok ? 200 : 500 });
|
|
208
213
|
}
|
|
214
|
+
// The host sends `{ input }`, an editor's test run of a server function. It runs
|
|
215
|
+
// as a call from a page would on the server: its own middleware decides access
|
|
216
|
+
// for the user the host dispatched with, validates the input and records the run.
|
|
217
|
+
async function invokeFunction(request, options) {
|
|
218
|
+
if (request.method !== "POST" || new URL(request.url).pathname !== INVOKE_PATH)
|
|
219
|
+
return new Response("Not found", { status: 404 });
|
|
220
|
+
const id = getHost()?.invoke?.name ?? "";
|
|
221
|
+
if (!builtFunctionIds().includes(id)) {
|
|
222
|
+
return Response.json({ ok: false, error: { code: "NOT_FOUND", message: `No server function ${id}` } }, { status: 404 });
|
|
223
|
+
}
|
|
224
|
+
const input = (await request.json().catch(() => ({})))?.input;
|
|
225
|
+
const startContext = {
|
|
226
|
+
request,
|
|
227
|
+
getRouter: options.getRouter,
|
|
228
|
+
startOptions: (await options.startInstance?.getOptions()) ?? {},
|
|
229
|
+
executedRequestMiddlewares: new Set(),
|
|
230
|
+
contextAfterGlobalMiddlewares: {},
|
|
231
|
+
handlerType: "serverFn",
|
|
232
|
+
};
|
|
233
|
+
// In TanStack's request event too, which the function's own status setting reads.
|
|
234
|
+
return requestHandler(async () => {
|
|
235
|
+
try {
|
|
236
|
+
const answer = (await runWithStartContext(startContext, () => createSsrRpc(id)({ data: input, context: {} })));
|
|
237
|
+
if (answer.error !== undefined)
|
|
238
|
+
throw answer.error;
|
|
239
|
+
return Response.json({ ok: true, output: answer.result ?? null });
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
return Response.json({ ok: false, error: errorOf(error) }, { status: 500 });
|
|
243
|
+
}
|
|
244
|
+
})(request, undefined);
|
|
245
|
+
}
|
|
209
246
|
// The host sends `{ op, input }`: `subscribe` with the platform's notification
|
|
210
247
|
// URL and secret, or `unsubscribe` with what `subscribe` returned.
|
|
211
248
|
async function invokeRegistration(request, host, workflows) {
|
|
@@ -283,11 +320,13 @@ export function createZiteHandlers(options) {
|
|
|
283
320
|
}
|
|
284
321
|
let response = await runWithHost(host, async () => host.invoke?.kind === "workflow"
|
|
285
322
|
? invokeWorkflow(request, host, await loadedWorkflows())
|
|
286
|
-
: host.invoke?.kind === "
|
|
287
|
-
?
|
|
288
|
-
: host.invoke?.kind === "
|
|
289
|
-
?
|
|
290
|
-
:
|
|
323
|
+
: host.invoke?.kind === "function"
|
|
324
|
+
? invokeFunction(request, options)
|
|
325
|
+
: host.invoke?.kind === "register"
|
|
326
|
+
? withoutConsole(async () => invokeRegistration(request, host, await loadedWorkflows()))
|
|
327
|
+
: host.invoke?.kind === "authHook"
|
|
328
|
+
? invokeAuthHook(request, host)
|
|
329
|
+
: options.handler.fetch(request));
|
|
291
330
|
const status = response.status === 500 ? pageStatus(host) : undefined;
|
|
292
331
|
if (status)
|
|
293
332
|
response = new Response(response.body, { status, headers: response.headers });
|
|
@@ -120,7 +120,7 @@ export type PlatformBinding = {
|
|
|
120
120
|
/** A demo is the published build serving a read-only visitor: as live, but every write is refused. */
|
|
121
121
|
export type HostMode = "live" | "preview" | "demo" | "validate";
|
|
122
122
|
export type HostInvoke = {
|
|
123
|
-
kind: "webhook" | "describe" | "workflow" | "register" | "warm" | "authHook";
|
|
123
|
+
kind: "webhook" | "describe" | "workflow" | "register" | "warm" | "authHook" | "function";
|
|
124
124
|
name: string;
|
|
125
125
|
};
|
|
126
126
|
/** The per-request props the host dispatches with. Only the host can set them. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ZITEJS_VERSION = "0.10.0-start.
|
|
1
|
+
export declare const ZITEJS_VERSION = "0.10.0-start.12";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Written by scripts/write-version.mjs from package.json.
|
|
2
|
-
export const ZITEJS_VERSION = "0.10.0-start.
|
|
2
|
+
export const ZITEJS_VERSION = "0.10.0-start.12";
|