var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/compose.js var compose; var init_compose = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/compose.js"() { compose = (middleware, onError, onNotFound) => { return (context, next) => { let index = -1; return dispatch(0); async function dispatch(i) { if (i <= index) { throw new Error("next() called multiple times"); } index = i; let res; let isError = false; let handler; if (middleware[i]) { handler = middleware[i][0][0]; context.req.routeIndex = i; } else { handler = i === middleware.length && next || void 0; } if (handler) { try { res = await handler(context, () => dispatch(i + 1)); } catch (err) { if (err instanceof Error && onError) { context.error = err; res = await onError(err, context); isError = true; } else { throw err; } } } else { if (context.finalized === false && onNotFound) { res = await onNotFound(context); } } if (res && (context.finalized === false || isError)) { context.res = res; } return context; } }; }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/http-exception.js var init_http_exception = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/http-exception.js"() { } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/request/constants.js var GET_MATCH_RESULT; var init_constants = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/request/constants.js"() { GET_MATCH_RESULT = /* @__PURE__ */ Symbol(); } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/body.js async function parseFormData(request, options) { const formData = await request.formData(); if (formData) { return convertFormDataToBodyData(formData, options); } return {}; } function convertFormDataToBodyData(formData, options) { const form = /* @__PURE__ */ Object.create(null); formData.forEach((value, key) => { const shouldParseAllValues = options.all || key.endsWith("[]"); if (!shouldParseAllValues) { form[key] = value; } else { handleParsingAllValues(form, key, value); } }); if (options.dot) { Object.entries(form).forEach(([key, value]) => { const shouldParseDotValues = key.includes("."); if (shouldParseDotValues) { handleParsingNestedValues(form, key, value); delete form[key]; } }); } return form; } var parseBody, handleParsingAllValues, handleParsingNestedValues; var init_body = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/body.js"() { init_request(); parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => { const { all = false, dot = false } = options; const headers = request instanceof HonoRequest ? request.raw.headers : request.headers; const contentType = headers.get("Content-Type"); if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) { return parseFormData(request, { all, dot }); } return {}; }; handleParsingAllValues = (form, key, value) => { if (form[key] !== void 0) { if (Array.isArray(form[key])) { ; form[key].push(value); } else { form[key] = [form[key], value]; } } else { if (!key.endsWith("[]")) { form[key] = value; } else { form[key] = [value]; } } }; handleParsingNestedValues = (form, key, value) => { if (/(?:^|\.)__proto__\./.test(key)) { return; } let nestedForm = form; const keys = key.split("."); keys.forEach((key2, index) => { if (index === keys.length - 1) { nestedForm[key2] = value; } else { if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) { nestedForm[key2] = /* @__PURE__ */ Object.create(null); } nestedForm = nestedForm[key2]; } }); }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/url.js var splitPath, splitRoutingPath, extractGroupsFromPath, replaceGroupMarks, patternCache, getPattern, tryDecode, tryDecodeURI, getPath, getPathNoStrict, mergePath, checkOptionalParameter, _decodeURI, _getQueryParam, getQueryParam, getQueryParams, decodeURIComponent_; var init_url = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/url.js"() { splitPath = (path) => { const paths = path.split("/"); if (paths[0] === "") { paths.shift(); } return paths; }; splitRoutingPath = (routePath) => { const { groups, path } = extractGroupsFromPath(routePath); const paths = splitPath(path); return replaceGroupMarks(paths, groups); }; extractGroupsFromPath = (path) => { const groups = []; path = path.replace(/\{[^}]+\}/g, (match2, index) => { const mark = `@${index}`; groups.push([mark, match2]); return mark; }); return { groups, path }; }; replaceGroupMarks = (paths, groups) => { for (let i = groups.length - 1; i >= 0; i--) { const [mark] = groups[i]; for (let j = paths.length - 1; j >= 0; j--) { if (paths[j].includes(mark)) { paths[j] = paths[j].replace(mark, groups[i][1]); break; } } } return paths; }; patternCache = {}; getPattern = (label, next) => { if (label === "*") { return "*"; } const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); if (match2) { const cacheKey = `${label}#${next}`; if (!patternCache[cacheKey]) { if (match2[2]) { patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match2[1], new RegExp(`^${match2[2]}(?=/${next})`)] : [label, match2[1], new RegExp(`^${match2[2]}$`)]; } else { patternCache[cacheKey] = [label, match2[1], true]; } } return patternCache[cacheKey]; } return null; }; tryDecode = (str2, decoder) => { try { return decoder(str2); } catch { return str2.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => { try { return decoder(match2); } catch { return match2; } }); } }; tryDecodeURI = (str2) => tryDecode(str2, decodeURI); getPath = (request) => { const url = request.url; const start = url.indexOf("/", url.indexOf(":") + 4); let i = start; for (; i < url.length; i++) { const charCode = url.charCodeAt(i); if (charCode === 37) { const queryIndex = url.indexOf("?", i); const hashIndex = url.indexOf("#", i); const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex); const path = url.slice(start, end); return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path); } else if (charCode === 63 || charCode === 35) { break; } } return url.slice(start, i); }; getPathNoStrict = (request) => { const result = getPath(request); return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result; }; mergePath = (base, sub, ...rest) => { if (rest.length) { sub = mergePath(sub, ...rest); } return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`; }; checkOptionalParameter = (path) => { if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) { return null; } const segments = path.split("/"); const results = []; let basePath = ""; segments.forEach((segment) => { if (segment !== "" && !/\:/.test(segment)) { basePath += "/" + segment; } else if (/\:/.test(segment)) { if (/\?/.test(segment)) { if (results.length === 0 && basePath === "") { results.push("/"); } else { results.push(basePath); } const optionalSegment = segment.replace("?", ""); basePath += "/" + optionalSegment; results.push(basePath); } else { basePath += "/" + segment; } } }); return results.filter((v, i, a) => a.indexOf(v) === i); }; _decodeURI = (value) => { if (!/[%+]/.test(value)) { return value; } if (value.indexOf("+") !== -1) { value = value.replace(/\+/g, " "); } return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value; }; _getQueryParam = (url, key, multiple) => { let encoded; if (!multiple && key && !/[%+]/.test(key)) { let keyIndex2 = url.indexOf("?", 8); if (keyIndex2 === -1) { return void 0; } if (!url.startsWith(key, keyIndex2 + 1)) { keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1); } while (keyIndex2 !== -1) { const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1); if (trailingKeyCode === 61) { const valueIndex = keyIndex2 + key.length + 2; const endIndex = url.indexOf("&", valueIndex); return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex)); } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) { return ""; } keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1); } encoded = /[%+]/.test(url); if (!encoded) { return void 0; } } const results = {}; encoded ??= /[%+]/.test(url); let keyIndex = url.indexOf("?", 8); while (keyIndex !== -1) { const nextKeyIndex = url.indexOf("&", keyIndex + 1); let valueIndex = url.indexOf("=", keyIndex); if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) { valueIndex = -1; } let name = url.slice( keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex ); if (encoded) { name = _decodeURI(name); } keyIndex = nextKeyIndex; if (name === "") { continue; } let value; if (valueIndex === -1) { value = ""; } else { value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex); if (encoded) { value = _decodeURI(value); } } if (multiple) { if (!(results[name] && Array.isArray(results[name]))) { results[name] = []; } ; results[name].push(value); } else { results[name] ??= value; } } return key ? results[key] : results; }; getQueryParam = _getQueryParam; getQueryParams = (url, key) => { return _getQueryParam(url, key, true); }; decodeURIComponent_ = decodeURIComponent; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/request.js var tryDecodeURIComponent, HonoRequest; var init_request = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/request.js"() { init_http_exception(); init_constants(); init_body(); init_url(); tryDecodeURIComponent = (str2) => tryDecode(str2, decodeURIComponent_); HonoRequest = class { /** * `.raw` can get the raw Request object. * * @see {@link https://hono.dev/docs/api/request#raw} * * @example * ```ts * // For Cloudflare Workers * app.post('/', async (c) => { * const metadata = c.req.raw.cf?.hostMetadata? * ... * }) * ``` */ raw; #validatedData; // Short name of validatedData #matchResult; routeIndex = 0; /** * `.path` can get the pathname of the request. * * @see {@link https://hono.dev/docs/api/request#path} * * @example * ```ts * app.get('/about/me', (c) => { * const pathname = c.req.path // `/about/me` * }) * ``` */ path; bodyCache = {}; constructor(request, path = "/", matchResult = [[]]) { this.raw = request; this.path = path; this.#matchResult = matchResult; this.#validatedData = {}; } param(key) { return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams(); } #getDecodedParam(key) { const paramKey = this.#matchResult[0][this.routeIndex][1][key]; const param = this.#getParamValue(paramKey); return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param; } #getAllDecodedParams() { const decoded = {}; const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]); for (const key of keys) { const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]); if (value !== void 0) { decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value; } } return decoded; } #getParamValue(paramKey) { return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey; } query(key) { return getQueryParam(this.url, key); } queries(key) { return getQueryParams(this.url, key); } header(name) { if (name) { return this.raw.headers.get(name) ?? void 0; } const headerData = {}; this.raw.headers.forEach((value, key) => { headerData[key] = value; }); return headerData; } async parseBody(options) { return parseBody(this, options); } #cachedBody = (key) => { const { bodyCache, raw: raw2 } = this; const cachedBody = bodyCache[key]; if (cachedBody) { return cachedBody; } const anyCachedKey = Object.keys(bodyCache)[0]; if (anyCachedKey) { return bodyCache[anyCachedKey].then((body) => { if (anyCachedKey === "json") { body = JSON.stringify(body); } return new Response(body)[key](); }); } return bodyCache[key] = raw2[key](); }; /** * `.json()` can parse Request body of type `application/json` * * @see {@link https://hono.dev/docs/api/request#json} * * @example * ```ts * app.post('/entry', async (c) => { * const body = await c.req.json() * }) * ``` */ json() { return this.#cachedBody("text").then((text) => JSON.parse(text)); } /** * `.text()` can parse Request body of type `text/plain` * * @see {@link https://hono.dev/docs/api/request#text} * * @example * ```ts * app.post('/entry', async (c) => { * const body = await c.req.text() * }) * ``` */ text() { return this.#cachedBody("text"); } /** * `.arrayBuffer()` parse Request body as an `ArrayBuffer` * * @see {@link https://hono.dev/docs/api/request#arraybuffer} * * @example * ```ts * app.post('/entry', async (c) => { * const body = await c.req.arrayBuffer() * }) * ``` */ arrayBuffer() { return this.#cachedBody("arrayBuffer"); } /** * Parses the request body as a `Blob`. * @example * ```ts * app.post('/entry', async (c) => { * const body = await c.req.blob(); * }); * ``` * @see https://hono.dev/docs/api/request#blob */ blob() { return this.#cachedBody("blob"); } /** * Parses the request body as `FormData`. * @example * ```ts * app.post('/entry', async (c) => { * const body = await c.req.formData(); * }); * ``` * @see https://hono.dev/docs/api/request#formdata */ formData() { return this.#cachedBody("formData"); } /** * Adds validated data to the request. * * @param target - The target of the validation. * @param data - The validated data to add. */ addValidatedData(target, data) { this.#validatedData[target] = data; } valid(target) { return this.#validatedData[target]; } /** * `.url()` can get the request url strings. * * @see {@link https://hono.dev/docs/api/request#url} * * @example * ```ts * app.get('/about/me', (c) => { * const url = c.req.url // `http://localhost:8787/about/me` * ... * }) * ``` */ get url() { return this.raw.url; } /** * `.method()` can get the method name of the request. * * @see {@link https://hono.dev/docs/api/request#method} * * @example * ```ts * app.get('/about/me', (c) => { * const method = c.req.method // `GET` * }) * ``` */ get method() { return this.raw.method; } get [GET_MATCH_RESULT]() { return this.#matchResult; } /** * `.matchedRoutes()` can return a matched route in the handler * * @deprecated * * Use matchedRoutes helper defined in "hono/route" instead. * * @see {@link https://hono.dev/docs/api/request#matchedroutes} * * @example * ```ts * app.use('*', async function logger(c, next) { * await next() * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => { * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]') * console.log( * method, * ' ', * path, * ' '.repeat(Math.max(10 - path.length, 0)), * name, * i === c.req.routeIndex ? '<- respond from here' : '' * ) * }) * }) * ``` */ get matchedRoutes() { return this.#matchResult[0].map(([[, route]]) => route); } /** * `routePath()` can retrieve the path registered within the handler * * @deprecated * * Use routePath helper defined in "hono/route" instead. * * @see {@link https://hono.dev/docs/api/request#routepath} * * @example * ```ts * app.get('/posts/:id', (c) => { * return c.json({ path: c.req.routePath }) * }) * ``` */ get routePath() { return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/html.js var HtmlEscapedCallbackPhase, raw, resolveCallback; var init_html = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/html.js"() { HtmlEscapedCallbackPhase = { Stringify: 1, BeforeStream: 2, Stream: 3 }; raw = (value, callbacks) => { const escapedString = new String(value); escapedString.isEscaped = true; escapedString.callbacks = callbacks; return escapedString; }; resolveCallback = async (str2, phase, preserveCallbacks, context, buffer) => { if (typeof str2 === "object" && !(str2 instanceof String)) { if (!(str2 instanceof Promise)) { str2 = str2.toString(); } if (str2 instanceof Promise) { str2 = await str2; } } const callbacks = str2.callbacks; if (!callbacks?.length) { return Promise.resolve(str2); } if (buffer) { buffer[0] += str2; } else { buffer = [str2]; } const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then( (res) => Promise.all( res.filter(Boolean).map((str22) => resolveCallback(str22, phase, false, context, buffer)) ).then(() => buffer[0]) ); if (preserveCallbacks) { return raw(await resStr, callbacks); } else { return resStr; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/context.js var TEXT_PLAIN, setDefaultContentType, createResponseInstance, Context; var init_context = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/context.js"() { init_request(); init_html(); TEXT_PLAIN = "text/plain; charset=UTF-8"; setDefaultContentType = (contentType, headers) => { return { "Content-Type": contentType, ...headers }; }; createResponseInstance = (body, init) => new Response(body, init); Context = class { #rawRequest; #req; /** * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers. * * @see {@link https://hono.dev/docs/api/context#env} * * @example * ```ts * // Environment object for Cloudflare Workers * app.get('*', async c => { * const counter = c.env.COUNTER * }) * ``` */ env = {}; #var; finalized = false; /** * `.error` can get the error object from the middleware if the Handler throws an error. * * @see {@link https://hono.dev/docs/api/context#error} * * @example * ```ts * app.use('*', async (c, next) => { * await next() * if (c.error) { * // do something... * } * }) * ``` */ error; #status; #executionCtx; #res; #layout; #renderer; #notFoundHandler; #preparedHeaders; #matchResult; #path; /** * Creates an instance of the Context class. * * @param req - The Request object. * @param options - Optional configuration options for the context. */ constructor(req, options) { this.#rawRequest = req; if (options) { this.#executionCtx = options.executionCtx; this.env = options.env; this.#notFoundHandler = options.notFoundHandler; this.#path = options.path; this.#matchResult = options.matchResult; } } /** * `.req` is the instance of {@link HonoRequest}. */ get req() { this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult); return this.#req; } /** * @see {@link https://hono.dev/docs/api/context#event} * The FetchEvent associated with the current request. * * @throws Will throw an error if the context does not have a FetchEvent. */ get event() { if (this.#executionCtx && "respondWith" in this.#executionCtx) { return this.#executionCtx; } else { throw Error("This context has no FetchEvent"); } } /** * @see {@link https://hono.dev/docs/api/context#executionctx} * The ExecutionContext associated with the current request. * * @throws Will throw an error if the context does not have an ExecutionContext. */ get executionCtx() { if (this.#executionCtx) { return this.#executionCtx; } else { throw Error("This context has no ExecutionContext"); } } /** * @see {@link https://hono.dev/docs/api/context#res} * The Response object for the current request. */ get res() { return this.#res ||= createResponseInstance(null, { headers: this.#preparedHeaders ??= new Headers() }); } /** * Sets the Response object for the current request. * * @param _res - The Response object to set. */ set res(_res) { if (this.#res && _res) { _res = createResponseInstance(_res.body, _res); for (const [k, v] of this.#res.headers.entries()) { if (k === "content-type") { continue; } if (k === "set-cookie") { const cookies = this.#res.headers.getSetCookie(); _res.headers.delete("set-cookie"); for (const cookie of cookies) { _res.headers.append("set-cookie", cookie); } } else { _res.headers.set(k, v); } } } this.#res = _res; this.finalized = true; } /** * `.render()` can create a response within a layout. * * @see {@link https://hono.dev/docs/api/context#render-setrenderer} * * @example * ```ts * app.get('/', (c) => { * return c.render('Hello!') * }) * ``` */ render = (...args) => { this.#renderer ??= (content) => this.html(content); return this.#renderer(...args); }; /** * Sets the layout for the response. * * @param layout - The layout to set. * @returns The layout function. */ setLayout = (layout) => this.#layout = layout; /** * Gets the current layout for the response. * * @returns The current layout function. */ getLayout = () => this.#layout; /** * `.setRenderer()` can set the layout in the custom middleware. * * @see {@link https://hono.dev/docs/api/context#render-setrenderer} * * @example * ```tsx * app.use('*', async (c, next) => { * c.setRenderer((content) => { * return c.html( * * *

{content}

* * * ) * }) * await next() * }) * ``` */ setRenderer = (renderer) => { this.#renderer = renderer; }; /** * `.header()` can set headers. * * @see {@link https://hono.dev/docs/api/context#header} * * @example * ```ts * app.get('/welcome', (c) => { * // Set headers * c.header('X-Message', 'Hello!') * c.header('Content-Type', 'text/plain') * * return c.body('Thank you for coming') * }) * ``` */ header = (name, value, options) => { if (this.finalized) { this.#res = createResponseInstance(this.#res.body, this.#res); } const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers(); if (value === void 0) { headers.delete(name); } else if (options?.append) { headers.append(name, value); } else { headers.set(name, value); } }; status = (status) => { this.#status = status; }; /** * `.set()` can set the value specified by the key. * * @see {@link https://hono.dev/docs/api/context#set-get} * * @example * ```ts * app.use('*', async (c, next) => { * c.set('message', 'Hono is hot!!') * await next() * }) * ``` */ set = (key, value) => { this.#var ??= /* @__PURE__ */ new Map(); this.#var.set(key, value); }; /** * `.get()` can use the value specified by the key. * * @see {@link https://hono.dev/docs/api/context#set-get} * * @example * ```ts * app.get('/', (c) => { * const message = c.get('message') * return c.text(`The message is "${message}"`) * }) * ``` */ get = (key) => { return this.#var ? this.#var.get(key) : void 0; }; /** * `.var` can access the value of a variable. * * @see {@link https://hono.dev/docs/api/context#var} * * @example * ```ts * const result = c.var.client.oneMethod() * ``` */ // c.var.propName is a read-only get var() { if (!this.#var) { return {}; } return Object.fromEntries(this.#var); } #newResponse(data, arg, headers) { const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers(); if (typeof arg === "object" && "headers" in arg) { const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers); for (const [key, value] of argHeaders) { if (key.toLowerCase() === "set-cookie") { responseHeaders.append(key, value); } else { responseHeaders.set(key, value); } } } if (headers) { for (const [k, v] of Object.entries(headers)) { if (typeof v === "string") { responseHeaders.set(k, v); } else { responseHeaders.delete(k); for (const v2 of v) { responseHeaders.append(k, v2); } } } } const status = typeof arg === "number" ? arg : arg?.status ?? this.#status; return createResponseInstance(data, { status, headers: responseHeaders }); } newResponse = (...args) => this.#newResponse(...args); /** * `.body()` can return the HTTP response. * You can set headers with `.header()` and set HTTP status code with `.status`. * This can also be set in `.text()`, `.json()` and so on. * * @see {@link https://hono.dev/docs/api/context#body} * * @example * ```ts * app.get('/welcome', (c) => { * // Set headers * c.header('X-Message', 'Hello!') * c.header('Content-Type', 'text/plain') * // Set HTTP status code * c.status(201) * * // Return the response body * return c.body('Thank you for coming') * }) * ``` */ body = (data, arg, headers) => this.#newResponse(data, arg, headers); /** * `.text()` can render text as `Content-Type:text/plain`. * * @see {@link https://hono.dev/docs/api/context#text} * * @example * ```ts * app.get('/say', (c) => { * return c.text('Hello!') * }) * ``` */ text = (text, arg, headers) => { return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse( text, arg, setDefaultContentType(TEXT_PLAIN, headers) ); }; /** * `.json()` can render JSON as `Content-Type:application/json`. * * @see {@link https://hono.dev/docs/api/context#json} * * @example * ```ts * app.get('/api', (c) => { * return c.json({ message: 'Hello!' }) * }) * ``` */ json = (object, arg, headers) => { return this.#newResponse( JSON.stringify(object), arg, setDefaultContentType("application/json", headers) ); }; html = (html, arg, headers) => { const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers)); return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html); }; /** * `.redirect()` can Redirect, default status code is 302. * * @see {@link https://hono.dev/docs/api/context#redirect} * * @example * ```ts * app.get('/redirect', (c) => { * return c.redirect('/') * }) * app.get('/redirect-permanently', (c) => { * return c.redirect('/', 301) * }) * ``` */ redirect = (location, status) => { const locationString = String(location); this.header( "Location", // Multibyes should be encoded // eslint-disable-next-line no-control-regex !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString) ); return this.newResponse(null, status ?? 302); }; /** * `.notFound()` can return the Not Found Response. * * @see {@link https://hono.dev/docs/api/context#notfound} * * @example * ```ts * app.get('/notfound', (c) => { * return c.notFound() * }) * ``` */ notFound = () => { this.#notFoundHandler ??= () => createResponseInstance(); return this.#notFoundHandler(this); }; }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router.js var METHOD_NAME_ALL, METHOD_NAME_ALL_LOWERCASE, METHODS, MESSAGE_MATCHER_IS_ALREADY_BUILT, UnsupportedPathError; var init_router = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router.js"() { METHOD_NAME_ALL = "ALL"; METHOD_NAME_ALL_LOWERCASE = "all"; METHODS = ["get", "post", "put", "delete", "options", "patch"]; MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built."; UnsupportedPathError = class extends Error { }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/constants.js var COMPOSED_HANDLER; var init_constants2 = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/utils/constants.js"() { COMPOSED_HANDLER = "__COMPOSED_HANDLER"; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/hono-base.js var notFoundHandler, errorHandler, Hono; var init_hono_base = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/hono-base.js"() { init_compose(); init_context(); init_router(); init_constants2(); init_url(); notFoundHandler = (c) => { return c.text("404 Not Found", 404); }; errorHandler = (err, c) => { if ("getResponse" in err) { const res = err.getResponse(); return c.newResponse(res.body, res); } console.error(err); return c.text("Internal Server Error", 500); }; Hono = class _Hono { get; post; put; delete; options; patch; all; on; use; /* This class is like an abstract class and does not have a router. To use it, inherit the class and implement router in the constructor. */ router; getPath; // Cannot use `#` because it requires visibility at JavaScript runtime. _basePath = "/"; #path = "/"; routes = []; constructor(options = {}) { const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE]; allMethods.forEach((method) => { this[method] = (args1, ...args) => { if (typeof args1 === "string") { this.#path = args1; } else { this.#addRoute(method, this.#path, args1); } args.forEach((handler) => { this.#addRoute(method, this.#path, handler); }); return this; }; }); this.on = (method, path, ...handlers) => { for (const p of [path].flat()) { this.#path = p; for (const m of [method].flat()) { handlers.map((handler) => { this.#addRoute(m.toUpperCase(), this.#path, handler); }); } } return this; }; this.use = (arg1, ...handlers) => { if (typeof arg1 === "string") { this.#path = arg1; } else { this.#path = "*"; handlers.unshift(arg1); } handlers.forEach((handler) => { this.#addRoute(METHOD_NAME_ALL, this.#path, handler); }); return this; }; const { strict, ...optionsWithoutStrict } = options; Object.assign(this, optionsWithoutStrict); this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict; } #clone() { const clone = new _Hono({ router: this.router, getPath: this.getPath }); clone.errorHandler = this.errorHandler; clone.#notFoundHandler = this.#notFoundHandler; clone.routes = this.routes; return clone; } #notFoundHandler = notFoundHandler; // Cannot use `#` because it requires visibility at JavaScript runtime. errorHandler = errorHandler; /** * `.route()` allows grouping other Hono instance in routes. * * @see {@link https://hono.dev/docs/api/routing#grouping} * * @param {string} path - base Path * @param {Hono} app - other Hono instance * @returns {Hono} routed Hono instance * * @example * ```ts * const app = new Hono() * const app2 = new Hono() * * app2.get("/user", (c) => c.text("user")) * app.route("/api", app2) // GET /api/user * ``` */ route(path, app2) { const subApp = this.basePath(path); app2.routes.map((r) => { let handler; if (app2.errorHandler === errorHandler) { handler = r.handler; } else { handler = async (c, next) => (await compose([], app2.errorHandler)(c, () => r.handler(c, next))).res; handler[COMPOSED_HANDLER] = r.handler; } subApp.#addRoute(r.method, r.path, handler); }); return this; } /** * `.basePath()` allows base paths to be specified. * * @see {@link https://hono.dev/docs/api/routing#base-path} * * @param {string} path - base Path * @returns {Hono} changed Hono instance * * @example * ```ts * const api = new Hono().basePath('/api') * ``` */ basePath(path) { const subApp = this.#clone(); subApp._basePath = mergePath(this._basePath, path); return subApp; } /** * `.onError()` handles an error and returns a customized Response. * * @see {@link https://hono.dev/docs/api/hono#error-handling} * * @param {ErrorHandler} handler - request Handler for error * @returns {Hono} changed Hono instance * * @example * ```ts * app.onError((err, c) => { * console.error(`${err}`) * return c.text('Custom Error Message', 500) * }) * ``` */ onError = (handler) => { this.errorHandler = handler; return this; }; /** * `.notFound()` allows you to customize a Not Found Response. * * @see {@link https://hono.dev/docs/api/hono#not-found} * * @param {NotFoundHandler} handler - request handler for not-found * @returns {Hono} changed Hono instance * * @example * ```ts * app.notFound((c) => { * return c.text('Custom 404 Message', 404) * }) * ``` */ notFound = (handler) => { this.#notFoundHandler = handler; return this; }; /** * `.mount()` allows you to mount applications built with other frameworks into your Hono application. * * @see {@link https://hono.dev/docs/api/hono#mount} * * @param {string} path - base Path * @param {Function} applicationHandler - other Request Handler * @param {MountOptions} [options] - options of `.mount()` * @returns {Hono} mounted Hono instance * * @example * ```ts * import { Router as IttyRouter } from 'itty-router' * import { Hono } from 'hono' * // Create itty-router application * const ittyRouter = IttyRouter() * // GET /itty-router/hello * ittyRouter.get('/hello', () => new Response('Hello from itty-router')) * * const app = new Hono() * app.mount('/itty-router', ittyRouter.handle) * ``` * * @example * ```ts * const app = new Hono() * // Send the request to another application without modification. * app.mount('/app', anotherApp, { * replaceRequest: (req) => req, * }) * ``` */ mount(path, applicationHandler, options) { let replaceRequest; let optionHandler; if (options) { if (typeof options === "function") { optionHandler = options; } else { optionHandler = options.optionHandler; if (options.replaceRequest === false) { replaceRequest = (request) => request; } else { replaceRequest = options.replaceRequest; } } } const getOptions = optionHandler ? (c) => { const options2 = optionHandler(c); return Array.isArray(options2) ? options2 : [options2]; } : (c) => { let executionContext = void 0; try { executionContext = c.executionCtx; } catch { } return [c.env, executionContext]; }; replaceRequest ||= (() => { const mergedPath = mergePath(this._basePath, path); const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length; return (request) => { const url = new URL(request.url); url.pathname = url.pathname.slice(pathPrefixLength) || "/"; return new Request(url, request); }; })(); const handler = async (c, next) => { const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c)); if (res) { return res; } await next(); }; this.#addRoute(METHOD_NAME_ALL, mergePath(path, "*"), handler); return this; } #addRoute(method, path, handler) { method = method.toUpperCase(); path = mergePath(this._basePath, path); const r = { basePath: this._basePath, path, method, handler }; this.router.add(method, path, [handler, r]); this.routes.push(r); } #handleError(err, c) { if (err instanceof Error) { return this.errorHandler(err, c); } throw err; } #dispatch(request, executionCtx, env, method) { if (method === "HEAD") { return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))(); } const path = this.getPath(request, { env }); const matchResult = this.router.match(method, path); const c = new Context(request, { path, matchResult, env, executionCtx, notFoundHandler: this.#notFoundHandler }); if (matchResult[0].length === 1) { let res; try { res = matchResult[0][0][0][0](c, async () => { c.res = await this.#notFoundHandler(c); }); } catch (err) { return this.#handleError(err, c); } return res instanceof Promise ? res.then( (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c)) ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c); } const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler); return (async () => { try { const context = await composed(c); if (!context.finalized) { throw new Error( "Context is not finalized. Did you forget to return a Response object or `await next()`?" ); } return context.res; } catch (err) { return this.#handleError(err, c); } })(); } /** * `.fetch()` will be entry point of your app. * * @see {@link https://hono.dev/docs/api/hono#fetch} * * @param {Request} request - request Object of request * @param {Env} Env - env Object * @param {ExecutionContext} - context of execution * @returns {Response | Promise} response of request * */ fetch = (request, ...rest) => { return this.#dispatch(request, rest[1], rest[0], request.method); }; /** * `.request()` is a useful method for testing. * You can pass a URL or pathname to send a GET request. * app will return a Response object. * ```ts * test('GET /hello is ok', async () => { * const res = await app.request('/hello') * expect(res.status).toBe(200) * }) * ``` * @see https://hono.dev/docs/api/hono#request */ request = (input, requestInit, Env, executionCtx) => { if (input instanceof Request) { return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx); } input = input.toString(); return this.fetch( new Request( /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit ), Env, executionCtx ); }; /** * `.fire()` automatically adds a global fetch event listener. * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers. * @deprecated * Use `fire` from `hono/service-worker` instead. * ```ts * import { Hono } from 'hono' * import { fire } from 'hono/service-worker' * * const app = new Hono() * // ... * fire(app) * ``` * @see https://hono.dev/docs/api/hono#fire * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/ */ fire = () => { addEventListener("fetch", (event) => { event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method)); }); }; }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/matcher.js function match(method, path) { const matchers = this.buildAllMatchers(); const match2 = (method2, path2) => { const matcher = matchers[method2] || matchers[METHOD_NAME_ALL]; const staticMatch = matcher[2][path2]; if (staticMatch) { return staticMatch; } const match3 = path2.match(matcher[0]); if (!match3) { return [[], emptyParam]; } const index = match3.indexOf("", 1); return [matcher[1][index], match3]; }; this.match = match2; return match2(method, path); } var emptyParam; var init_matcher = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/matcher.js"() { init_router(); emptyParam = []; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/node.js function compareKey(a, b) { if (a.length === 1) { return b.length === 1 ? a < b ? -1 : 1 : -1; } if (b.length === 1) { return 1; } if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) { return 1; } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) { return -1; } if (a === LABEL_REG_EXP_STR) { return 1; } else if (b === LABEL_REG_EXP_STR) { return -1; } return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length; } var LABEL_REG_EXP_STR, ONLY_WILDCARD_REG_EXP_STR, TAIL_WILDCARD_REG_EXP_STR, PATH_ERROR, regExpMetaChars, Node; var init_node = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/node.js"() { LABEL_REG_EXP_STR = "[^/]+"; ONLY_WILDCARD_REG_EXP_STR = ".*"; TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)"; PATH_ERROR = /* @__PURE__ */ Symbol(); regExpMetaChars = new Set(".\\+*[^]$()"); Node = class _Node { #index; #varIndex; #children = /* @__PURE__ */ Object.create(null); insert(tokens, index, paramMap, context, pathErrorCheckOnly) { if (tokens.length === 0) { if (this.#index !== void 0) { throw PATH_ERROR; } if (pathErrorCheckOnly) { return; } this.#index = index; return; } const [token, ...restTokens] = tokens; const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); let node; if (pattern) { const name = pattern[1]; let regexpStr = pattern[2] || LABEL_REG_EXP_STR; if (name && pattern[2]) { if (regexpStr === ".*") { throw PATH_ERROR; } regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:"); if (/\((?!\?:)/.test(regexpStr)) { throw PATH_ERROR; } } node = this.#children[regexpStr]; if (!node) { if (Object.keys(this.#children).some( (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR )) { throw PATH_ERROR; } if (pathErrorCheckOnly) { return; } node = this.#children[regexpStr] = new _Node(); if (name !== "") { node.#varIndex = context.varIndex++; } } if (!pathErrorCheckOnly && name !== "") { paramMap.push([name, node.#varIndex]); } } else { node = this.#children[token]; if (!node) { if (Object.keys(this.#children).some( (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR )) { throw PATH_ERROR; } if (pathErrorCheckOnly) { return; } node = this.#children[token] = new _Node(); } } node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly); } buildRegExpStr() { const childKeys = Object.keys(this.#children).sort(compareKey); const strList = childKeys.map((k) => { const c = this.#children[k]; return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr(); }); if (typeof this.#index === "number") { strList.unshift(`#${this.#index}`); } if (strList.length === 0) { return ""; } if (strList.length === 1) { return strList[0]; } return "(?:" + strList.join("|") + ")"; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/trie.js var Trie; var init_trie = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/trie.js"() { init_node(); Trie = class { #context = { varIndex: 0 }; #root = new Node(); insert(path, index, pathErrorCheckOnly) { const paramAssoc = []; const groups = []; for (let i = 0; ; ) { let replaced = false; path = path.replace(/\{[^}]+\}/g, (m) => { const mark = `@\\${i}`; groups[i] = [mark, m]; i++; replaced = true; return mark; }); if (!replaced) { break; } } const tokens = path.match(/(?::[^\/]+)|(?:\/\*$)|./g) || []; for (let i = groups.length - 1; i >= 0; i--) { const [mark] = groups[i]; for (let j = tokens.length - 1; j >= 0; j--) { if (tokens[j].indexOf(mark) !== -1) { tokens[j] = tokens[j].replace(mark, groups[i][1]); break; } } } this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly); return paramAssoc; } buildRegExp() { let regexp = this.#root.buildRegExpStr(); if (regexp === "") { return [/^$/, [], []]; } let captureIndex = 0; const indexReplacementMap = []; const paramReplacementMap = []; regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => { if (handlerIndex !== void 0) { indexReplacementMap[++captureIndex] = Number(handlerIndex); return "$()"; } if (paramIndex !== void 0) { paramReplacementMap[Number(paramIndex)] = ++captureIndex; return ""; } return ""; }); return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap]; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/router.js function buildWildcardRegExp(path) { return wildcardRegExpCache[path] ??= new RegExp( path === "*" ? "" : `^${path.replace( /\/\*$|([.\\+*[^\]$()])/g, (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)" )}$` ); } function clearWildcardRegExpCache() { wildcardRegExpCache = /* @__PURE__ */ Object.create(null); } function buildMatcherFromPreprocessedRoutes(routes) { const trie = new Trie(); const handlerData = []; if (routes.length === 0) { return nullMatcher; } const routesWithStaticPathFlag = routes.map( (route) => [!/\*|\/:/.test(route[0]), ...route] ).sort( ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length ); const staticMap = /* @__PURE__ */ Object.create(null); for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) { const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i]; if (pathErrorCheckOnly) { staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam]; } else { j++; } let paramAssoc; try { paramAssoc = trie.insert(path, j, pathErrorCheckOnly); } catch (e) { throw e === PATH_ERROR ? new UnsupportedPathError(path) : e; } if (pathErrorCheckOnly) { continue; } handlerData[j] = handlers.map(([h, paramCount]) => { const paramIndexMap = /* @__PURE__ */ Object.create(null); paramCount -= 1; for (; paramCount >= 0; paramCount--) { const [key, value] = paramAssoc[paramCount]; paramIndexMap[key] = value; } return [h, paramIndexMap]; }); } const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp(); for (let i = 0, len = handlerData.length; i < len; i++) { for (let j = 0, len2 = handlerData[i].length; j < len2; j++) { const map = handlerData[i][j]?.[1]; if (!map) { continue; } const keys = Object.keys(map); for (let k = 0, len3 = keys.length; k < len3; k++) { map[keys[k]] = paramReplacementMap[map[keys[k]]]; } } } const handlerMap = []; for (const i in indexReplacementMap) { handlerMap[i] = handlerData[indexReplacementMap[i]]; } return [regexp, handlerMap, staticMap]; } function findMiddleware(middleware, path) { if (!middleware) { return void 0; } for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) { if (buildWildcardRegExp(k).test(path)) { return [...middleware[k]]; } } return void 0; } var nullMatcher, wildcardRegExpCache, RegExpRouter; var init_router2 = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/router.js"() { init_router(); init_url(); init_matcher(); init_node(); init_trie(); nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)]; wildcardRegExpCache = /* @__PURE__ */ Object.create(null); RegExpRouter = class { name = "RegExpRouter"; #middleware; #routes; constructor() { this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; } add(method, path, handler) { const middleware = this.#middleware; const routes = this.#routes; if (!middleware || !routes) { throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); } if (!middleware[method]) { ; [middleware, routes].forEach((handlerMap) => { handlerMap[method] = /* @__PURE__ */ Object.create(null); Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => { handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]]; }); }); } if (path === "/*") { path = "*"; } const paramCount = (path.match(/\/:/g) || []).length; if (/\*$/.test(path)) { const re = buildWildcardRegExp(path); if (method === METHOD_NAME_ALL) { Object.keys(middleware).forEach((m) => { middleware[m][path] ||= findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || []; }); } else { middleware[method][path] ||= findMiddleware(middleware[method], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || []; } Object.keys(middleware).forEach((m) => { if (method === METHOD_NAME_ALL || method === m) { Object.keys(middleware[m]).forEach((p) => { re.test(p) && middleware[m][p].push([handler, paramCount]); }); } }); Object.keys(routes).forEach((m) => { if (method === METHOD_NAME_ALL || method === m) { Object.keys(routes[m]).forEach( (p) => re.test(p) && routes[m][p].push([handler, paramCount]) ); } }); return; } const paths = checkOptionalParameter(path) || [path]; for (let i = 0, len = paths.length; i < len; i++) { const path2 = paths[i]; Object.keys(routes).forEach((m) => { if (method === METHOD_NAME_ALL || method === m) { routes[m][path2] ||= [ ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || [] ]; routes[m][path2].push([handler, paramCount - len + i + 1]); } }); } } match = match; buildAllMatchers() { const matchers = /* @__PURE__ */ Object.create(null); Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => { matchers[method] ||= this.#buildMatcher(method); }); this.#middleware = this.#routes = void 0; clearWildcardRegExpCache(); return matchers; } #buildMatcher(method) { const routes = []; let hasOwnRoute = method === METHOD_NAME_ALL; [this.#middleware, this.#routes].forEach((r) => { const ownRoute = r[method] ? Object.keys(r[method]).map((path) => [path, r[method][path]]) : []; if (ownRoute.length !== 0) { hasOwnRoute ||= true; routes.push(...ownRoute); } else if (method !== METHOD_NAME_ALL) { routes.push( ...Object.keys(r[METHOD_NAME_ALL]).map((path) => [path, r[METHOD_NAME_ALL][path]]) ); } }); if (!hasOwnRoute) { return null; } else { return buildMatcherFromPreprocessedRoutes(routes); } } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/prepared-router.js var init_prepared_router = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/prepared-router.js"() { init_router(); init_matcher(); init_router2(); } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/index.js var init_reg_exp_router = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/reg-exp-router/index.js"() { init_router2(); init_prepared_router(); } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/smart-router/router.js var SmartRouter; var init_router3 = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/smart-router/router.js"() { init_router(); SmartRouter = class { name = "SmartRouter"; #routers = []; #routes = []; constructor(init) { this.#routers = init.routers; } add(method, path, handler) { if (!this.#routes) { throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); } this.#routes.push([method, path, handler]); } match(method, path) { if (!this.#routes) { throw new Error("Fatal error"); } const routers = this.#routers; const routes = this.#routes; const len = routers.length; let i = 0; let res; for (; i < len; i++) { const router = routers[i]; try { for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) { router.add(...routes[i2]); } res = router.match(method, path); } catch (e) { if (e instanceof UnsupportedPathError) { continue; } throw e; } this.match = router.match.bind(router); this.#routers = [router]; this.#routes = void 0; break; } if (i === len) { throw new Error("Fatal error"); } this.name = `SmartRouter + ${this.activeRouter.name}`; return res; } get activeRouter() { if (this.#routes || this.#routers.length !== 1) { throw new Error("No active router has been determined yet."); } return this.#routers[0]; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/smart-router/index.js var init_smart_router = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/smart-router/index.js"() { init_router3(); } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/node.js var emptyParams, hasChildren, Node2; var init_node2 = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/node.js"() { init_router(); init_url(); emptyParams = /* @__PURE__ */ Object.create(null); hasChildren = (children) => { for (const _ in children) { return true; } return false; }; Node2 = class _Node2 { #methods; #children; #patterns; #order = 0; #params = emptyParams; constructor(method, handler, children) { this.#children = children || /* @__PURE__ */ Object.create(null); this.#methods = []; if (method && handler) { const m = /* @__PURE__ */ Object.create(null); m[method] = { handler, possibleKeys: [], score: 0 }; this.#methods = [m]; } this.#patterns = []; } insert(method, path, handler) { this.#order = ++this.#order; let curNode = this; const parts = splitRoutingPath(path); const possibleKeys = []; for (let i = 0, len = parts.length; i < len; i++) { const p = parts[i]; const nextP = parts[i + 1]; const pattern = getPattern(p, nextP); const key = Array.isArray(pattern) ? pattern[0] : p; if (key in curNode.#children) { curNode = curNode.#children[key]; if (pattern) { possibleKeys.push(pattern[1]); } continue; } curNode.#children[key] = new _Node2(); if (pattern) { curNode.#patterns.push(pattern); possibleKeys.push(pattern[1]); } curNode = curNode.#children[key]; } curNode.#methods.push({ [method]: { handler, possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i), score: this.#order } }); return curNode; } #pushHandlerSets(handlerSets, node, method, nodeParams, params) { for (let i = 0, len = node.#methods.length; i < len; i++) { const m = node.#methods[i]; const handlerSet = m[method] || m[METHOD_NAME_ALL]; const processedSet = {}; if (handlerSet !== void 0) { handlerSet.params = /* @__PURE__ */ Object.create(null); handlerSets.push(handlerSet); if (nodeParams !== emptyParams || params && params !== emptyParams) { for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) { const key = handlerSet.possibleKeys[i2]; const processed = processedSet[handlerSet.score]; handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]; processedSet[handlerSet.score] = true; } } } } } search(method, path) { const handlerSets = []; this.#params = emptyParams; const curNode = this; let curNodes = [curNode]; const parts = splitPath(path); const curNodesQueue = []; const len = parts.length; let partOffsets = null; for (let i = 0; i < len; i++) { const part = parts[i]; const isLast = i === len - 1; const tempNodes = []; for (let j = 0, len2 = curNodes.length; j < len2; j++) { const node = curNodes[j]; const nextNode = node.#children[part]; if (nextNode) { nextNode.#params = node.#params; if (isLast) { if (nextNode.#children["*"]) { this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params); } this.#pushHandlerSets(handlerSets, nextNode, method, node.#params); } else { tempNodes.push(nextNode); } } for (let k = 0, len3 = node.#patterns.length; k < len3; k++) { const pattern = node.#patterns[k]; const params = node.#params === emptyParams ? {} : { ...node.#params }; if (pattern === "*") { const astNode = node.#children["*"]; if (astNode) { this.#pushHandlerSets(handlerSets, astNode, method, node.#params); astNode.#params = params; tempNodes.push(astNode); } continue; } const [key, name, matcher] = pattern; if (!part && !(matcher instanceof RegExp)) { continue; } const child = node.#children[key]; if (matcher instanceof RegExp) { if (partOffsets === null) { partOffsets = new Array(len); let offset = path[0] === "/" ? 1 : 0; for (let p = 0; p < len; p++) { partOffsets[p] = offset; offset += parts[p].length + 1; } } const restPathString = path.substring(partOffsets[i]); const m = matcher.exec(restPathString); if (m) { params[name] = m[0]; this.#pushHandlerSets(handlerSets, child, method, node.#params, params); if (hasChildren(child.#children)) { child.#params = params; const componentCount = m[0].match(/\//)?.length ?? 0; const targetCurNodes = curNodesQueue[componentCount] ||= []; targetCurNodes.push(child); } continue; } } if (matcher === true || matcher.test(part)) { params[name] = part; if (isLast) { this.#pushHandlerSets(handlerSets, child, method, params, node.#params); if (child.#children["*"]) { this.#pushHandlerSets( handlerSets, child.#children["*"], method, params, node.#params ); } } else { child.#params = params; tempNodes.push(child); } } } } const shifted = curNodesQueue.shift(); curNodes = shifted ? tempNodes.concat(shifted) : tempNodes; } if (handlerSets.length > 1) { handlerSets.sort((a, b) => { return a.score - b.score; }); } return [handlerSets.map(({ handler, params }) => [handler, params])]; } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/router.js var TrieRouter; var init_router4 = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/router.js"() { init_url(); init_node2(); TrieRouter = class { name = "TrieRouter"; #node; constructor() { this.#node = new Node2(); } add(method, path, handler) { const results = checkOptionalParameter(path); if (results) { for (let i = 0, len = results.length; i < len; i++) { this.#node.insert(method, results[i], handler); } return; } this.#node.insert(method, path, handler); } match(method, path) { return this.#node.search(method, path); } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/index.js var init_trie_router = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/router/trie-router/index.js"() { init_router4(); } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/hono.js var Hono2; var init_hono = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/hono.js"() { init_hono_base(); init_reg_exp_router(); init_smart_router(); init_trie_router(); Hono2 = class extends Hono { /** * Creates an instance of the Hono class. * * @param options - Optional configuration options for the Hono instance. */ constructor(options = {}) { super(options); this.router = options.router ?? new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }); } }; } }); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/index.js var init_dist = __esm({ "cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/index.js"() { init_hono(); } }); // cypher-executor/src/types.ts async function kvGetNodeOutput(store, nodeId) { try { const val = await store.kv.get(`${store.runId}:node:${nodeId}`, "json"); return val; } catch { return void 0; } } async function kvSetNodeOutput(store, nodeId, output) { try { await store.kv.put( `${store.runId}:node:${nodeId}`, JSON.stringify(output), { expirationTtl: 3600 } ); } catch { } } var WorkflowPaused, ExecutionError; var init_types = __esm({ "cypher-executor/src/types.ts"() { "use strict"; WorkflowPaused = class extends Error { task_id; run_id; paused_node_id; trace_so_far; constructor(task_id, run_id, paused_node_id, trace_so_far) { super(`workflow paused at node ${paused_node_id} waiting for task ${task_id}`); this.name = "WorkflowPaused"; this.task_id = task_id; this.run_id = run_id; this.paused_node_id = paused_node_id; this.trace_so_far = trace_so_far; } }; ExecutionError = class extends Error { failed_node; failed_input; trace; constructor(message, failed_node, failed_input, trace) { super(message); this.name = "ExecutionError"; this.failed_node = failed_node; this.failed_input = failed_input; this.trace = trace; } }; } }); // cypher-executor/src/lib/hash.ts async function deriveRecipeHash(canonicalId) { return "rec_" + await sha256Prefix(canonicalId); } function isComponentHash(id) { return /^cmp_[0-9a-f]{8}$/.test(id); } function isRecipeHash(id) { return /^rec_[0-9a-f]{8}$/.test(id); } async function sha256Prefix(input) { const data = new TextEncoder().encode(input); const buf = await crypto.subtle.digest("SHA-256", data); return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8); } var init_hash = __esm({ "cypher-executor/src/lib/hash.ts"() { "use strict"; } }); // cypher-executor/src/routes/recipes.ts async function installRecipeRecord(kv, recipe) { const uuid = recipe.uuid; const { canonical_id, hash_id } = recipe; const listRaw = await kv.get(kIdxCanonical(canonical_id)); const uuids = listRaw ? JSON.parse(listRaw) : []; if (!uuids.includes(uuid)) uuids.push(uuid); await Promise.all([ kv.put(`recipe:${uuid}`, JSON.stringify(recipe)), kv.put(kIdxCanonical(canonical_id), JSON.stringify(uuids)), kv.put(kIdxInstalled(canonical_id), uuid), kv.put(`idx:${hash_id}`, canonical_id) ]); } async function fetchMarketStat(env, canonicalId) { try { const base = (env.KBDB_BASE_URL ?? "https://kbdb.finally.click").replace(/\/$/, ""); const headers = {}; if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`; const res = await fetch(`${base}/recipe-stats/${encodeURIComponent(canonicalId)}`, { headers }); if (!res.ok) return null; const json = await res.json(); if (!json.stat) return null; return { success_count: json.stat.success_count ?? 0, failure_count: json.stat.failure_count ?? 0 }; } catch { return null; } } async function listAllRecipes(kv) { const list = await kv.list({ prefix: "recipe:" }); const all = (await Promise.all( list.keys.map((k) => kv.get(k.name, "json")) )).filter(Boolean); const hasUuid = new Set(all.filter((r) => r.uuid).map((r) => r.canonical_id)); return all.filter((r) => r.uuid || !hasUuid.has(r.canonical_id)); } async function resolveRecipe(id, kv) { const direct = await kv.get(`recipe:${id}`, "json"); if (direct && direct.uuid) return direct; let canonicalId = id; if (id.startsWith("rec_")) { const looked = await kv.get(`idx:${id}`); if (!looked) return direct; canonicalId = looked; } const installedUuid = await kv.get(kIdxInstalled(canonicalId)); if (installedUuid) { const byUuid = await kv.get(`recipe:${installedUuid}`, "json"); if (byUuid) return byUuid; } return direct ?? await kv.get(`recipe:${canonicalId}`, "json"); } async function resolveAuthRecipe(service, kv) { return kv.get(`auth_recipe:${service}`, "json"); } var recipesRouter, kIdxCanonical, kIdxInstalled; var init_recipes = __esm({ "cypher-executor/src/routes/recipes.ts"() { "use strict"; init_dist(); init_hash(); recipesRouter = new Hono2(); kIdxCanonical = (canonicalId) => `idx:canonical:${canonicalId}`; kIdxInstalled = (canonicalId) => `idx:installed:${canonicalId}`; recipesRouter.post("/recipes", async (c) => { let body; try { body = await c.req.json(); } catch { return c.json({ success: false, error: "request body \u5FC5\u9808\u70BA JSON" }, 400); } const canonicalId = (body.canonical_id ?? "").trim().toLowerCase(); if (!canonicalId) return c.json({ success: false, error: "canonical_id \u5FC5\u586B" }, 400); if (!body.endpoint) return c.json({ success: false, error: "endpoint \u5FC5\u586B" }, 400); const hashId = await deriveRecipeHash(canonicalId); const now2 = Date.now(); const existing = await resolveRecipe(canonicalId, c.env.RECIPES); const recipe = { uuid: existing?.uuid ?? crypto.randomUUID(), author: body.author ?? existing?.author ?? "local", derived_from: body.derived_from ?? existing?.derived_from, canonical_id: canonicalId, hash_id: hashId, display_name: body.display_name, description: body.description, endpoint: body.endpoint, method: (body.method ?? "POST").toUpperCase(), headers: body.headers, body: body.body, // ③ payload/回應/binding 三層(3.12):全選填,沒給就是 undefined=既有行為 body_template: body.body_template, response_map: body.response_map, auth: body.auth, binding_name: body.binding_name, auth_service: body.auth_service, credentials_required: body.credentials_required, created_at: existing?.created_at ?? now2, updated_at: now2 }; await installRecipeRecord(c.env.RECIPES, recipe); return c.json({ success: true, recipe }); }); recipesRouter.post("/recipes/submit", async (c) => { let body; try { body = await c.req.json(); } catch { return c.json({ success: false, error: "request body \u5FC5\u9808\u70BA JSON" }, 400); } const canonicalId = (body.canonical_id ?? "").trim().toLowerCase(); if (!canonicalId) return c.json({ success: false, error: "canonical_id \u5FC5\u586B" }, 400); if (!body.endpoint) return c.json({ success: false, error: "endpoint \u5FC5\u586B" }, 400); const hashId = await deriveRecipeHash(canonicalId); const now2 = Date.now(); const recipe = { uuid: crypto.randomUUID(), author: body.author ?? body.submitter ?? "anonymous", derived_from: body.derived_from, canonical_id: canonicalId, hash_id: hashId, display_name: body.display_name, description: body.description, endpoint: body.endpoint, method: (body.method ?? "POST").toUpperCase(), headers: body.headers, body: body.body, auth_service: body.auth_service, credentials_required: body.credentials_required, created_at: now2, updated_at: now2 }; await installRecipeRecord(c.env.RECIPES, recipe); const kbdbBase2 = (c.env.KBDB_BASE_URL ?? "https://kbdb.finally.click").replace(/\/$/, ""); const evidence = { content: canonicalId, entry_type: "recipe_submission", metadata_json: JSON.stringify({ uuid: recipe.uuid, canonical_id: canonicalId, author: recipe.author, submitter: body.submitter ?? "unknown", claimed_stat: body.stat ?? null, submitted_at: now2 }) }; const kbdbHeaders = { "Content-Type": "application/json" }; if (c.env.KBDB_INTERNAL_TOKEN) kbdbHeaders["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`; c.executionCtx.waitUntil( fetch(`${kbdbBase2}/entries`, { method: "POST", headers: kbdbHeaders, body: JSON.stringify(evidence) }).catch(() => void 0) ); return c.json({ success: true, recipe, evidence_recorded: true }); }); recipesRouter.post("/recipes/migrate-uuid", async (c) => { const list = await c.env.RECIPES.list({ prefix: "recipe:" }); let migrated = 0, skipped = 0; const errors = []; for (const k of list.keys) { try { const rec = await c.env.RECIPES.get(k.name, "json"); if (!rec || !rec.canonical_id) { skipped++; continue; } if (rec.uuid) { skipped++; continue; } const migrated_recipe = { ...rec, uuid: crypto.randomUUID(), author: rec.author ?? "system" // 舊種子歸 system }; await installRecipeRecord(c.env.RECIPES, migrated_recipe); migrated++; } catch (e) { errors.push(`${k.name}: ${e instanceof Error ? e.message : String(e)}`); } } return c.json({ success: errors.length === 0, migrated, skipped, errors }); }); recipesRouter.get("/recipes/:id", async (c) => { const id = c.req.param("id"); const recipe = await resolveRecipe(id, c.env.RECIPES); if (!recipe) return c.json({ success: false, error: `\u627E\u4E0D\u5230 recipe: ${id}` }, 404); return c.json({ success: true, recipe }); }); recipesRouter.get("/recipes", async (c) => { const list = await c.env.RECIPES.list({ prefix: "recipe:" }); const all = (await Promise.all( list.keys.map((k) => c.env.RECIPES.get(k.name, "json")) )).filter(Boolean); const hasUuidVersion = new Set(all.filter((r) => r.uuid).map((r) => r.canonical_id)); const recipes = all.filter((r) => r.uuid || !hasUuidVersion.has(r.canonical_id)); return c.json({ success: true, recipes, count: recipes.length }); }); recipesRouter.get("/public-recipes", async (c) => { const q = (c.req.query("q") ?? "").trim().toLowerCase(); const limit = Math.min(Number(c.req.query("limit") ?? 50), 200); const offset = Number(c.req.query("offset") ?? 0); const all = await listAllRecipes(c.env.RECIPES); const matched = q ? all.filter((r) => r.canonical_id.toLowerCase().includes(q) || (r.display_name ?? "").toLowerCase().includes(q) || (r.description ?? "").toLowerCase().includes(q)) : all; if (q && matched.length === 0) { return c.json({ found: false, query: q, hint: `\u516C\u5EAB\u7121\u7B26\u5408\u300C${q}\u300D\u7684 recipe\u3002\u53EF\u81EA\u884C\u5EFA\u7ACB\u4E26 submit-p \u6295\u7A3F\u6210\u70BA\u4F5C\u8005\uFF08app-store \u6A21\u578B\uFF09\u3002` }); } const page = matched.slice(offset, offset + limit); const withStats = await Promise.all( page.map(async (r) => ({ uuid: r.uuid, canonical_id: r.canonical_id, author: r.author, display_name: r.display_name, description: r.description, market_stat: await fetchMarketStat(c.env, r.uuid ?? r.canonical_id) // §7.5.h per-uuid })) ); return c.json({ found: true, recipes: withStats, count: matched.length }); }); recipesRouter.get("/public-recipes/:canonical_id", async (c) => { const canonicalId = c.req.param("canonical_id").trim().toLowerCase(); const author = c.req.query("author"); const all = await listAllRecipes(c.env.RECIPES); let versions = all.filter((r) => r.canonical_id === canonicalId); if (author) versions = versions.filter((r) => r.author === author); if (versions.length === 0) { return c.json({ found: false, canonical_id: canonicalId, hint: `\u516C\u5EAB\u7121 recipe\u300C${canonicalId}\u300D${author ? `\uFF08author=${author}\uFF09` : ""}\u3002\u53EF\u81EA\u884C\u5EFA\u7ACB\u4E26 submit-p \u6295\u7A3F\u6210\u70BA\u4F5C\u8005\uFF08app-store \u6A21\u578B\uFF09\u3002` }); } let best = versions[0]; let bestStat = null; let bestScore = -1; for (const v of versions) { const stat = await fetchMarketStat(c.env, v.uuid ?? v.canonical_id); const score = stat?.success_count ?? 0; if (score > bestScore) { bestScore = score; best = v; bestStat = stat; } } return c.json({ found: true, recipe: best, market_stat: bestStat }); }); recipesRouter.delete("/recipes/:id", async (c) => { const id = c.req.param("id"); const recipe = await resolveRecipe(id, c.env.RECIPES); if (!recipe) return c.json({ success: false, error: `\u627E\u4E0D\u5230 recipe: ${id}` }, 404); const canonicalId = recipe.canonical_id; const ops = [ c.env.RECIPES.delete(`idx:${recipe.hash_id}`), c.env.RECIPES.delete(`recipe:${canonicalId}`) // 舊 key(若存在) ]; if (recipe.uuid) { ops.push(c.env.RECIPES.delete(`recipe:${recipe.uuid}`)); const listRaw = await c.env.RECIPES.get(kIdxCanonical(canonicalId)); const uuids = listRaw ? JSON.parse(listRaw) : []; const left = uuids.filter((u) => u !== recipe.uuid); if (left.length > 0) { ops.push(c.env.RECIPES.put(kIdxCanonical(canonicalId), JSON.stringify(left))); const installed = await c.env.RECIPES.get(kIdxInstalled(canonicalId)); if (installed === recipe.uuid) ops.push(c.env.RECIPES.put(kIdxInstalled(canonicalId), left[0])); } else { ops.push(c.env.RECIPES.delete(kIdxCanonical(canonicalId))); ops.push(c.env.RECIPES.delete(kIdxInstalled(canonicalId))); } } await Promise.all(ops); return c.json({ success: true, deleted: recipe.uuid ?? canonicalId }); }); recipesRouter.post("/auth-recipes", async (c) => { let body; try { body = await c.req.json(); } catch { return c.json({ success: false, error: "request body \u5FC5\u9808\u70BA JSON" }, 400); } const service = (body.service ?? "").trim().toLowerCase(); if (!service) return c.json({ success: false, error: "service \u5FC5\u586B" }, 400); if (!body.primitive) return c.json({ success: false, error: "primitive \u5FC5\u586B" }, 400); if (!body.base_url) return c.json({ success: false, error: "base_url \u5FC5\u586B" }, 400); if (!body.required_secrets?.length) return c.json({ success: false, error: "required_secrets \u5FC5\u586B" }, 400); if (!body.inject) return c.json({ success: false, error: "inject \u5FC5\u586B" }, 400); const missingHelp = body.required_secrets.filter((s) => !s.help_url || !/^https?:\/\//.test(s.help_url)); if (missingHelp.length > 0) { return c.json({ success: false, error: `\u6BCF\u500B required_secret \u5FC5\u9808\u6709 help_url\uFF08\u5B98\u65B9\u6587\u4EF6\u9023\u7D50\uFF0Chttp(s)://\uFF09\u3002\u7F3A\uFF1A${missingHelp.map((s) => s.key).join(", ")}`, requires: "help_url" }, 400); } const now2 = Date.now(); const existing = await c.env.RECIPES.get(`auth_recipe:${service}`, "json"); const recipe = { kind: "auth_recipe", service, version: body.version ?? 1, primitive: body.primitive, base_url: body.base_url, display_name: body.display_name, description: body.description, service_account_kind: body.service_account_kind, token_exchange: body.token_exchange, required_secrets: body.required_secrets, inject: body.inject, created_at: existing?.created_at ?? now2, updated_at: now2 }; await c.env.RECIPES.put(`auth_recipe:${service}`, JSON.stringify(recipe)); return c.json({ success: true, recipe }); }); recipesRouter.get("/auth-recipes", async (c) => { const list = await c.env.RECIPES.list({ prefix: "auth_recipe:" }); const recipes = await Promise.all( list.keys.map((k) => c.env.RECIPES.get(k.name, "json")) ); return c.json({ success: true, recipes: recipes.filter(Boolean), count: recipes.length }); }); recipesRouter.get("/auth-recipes/:service", async (c) => { const service = c.req.param("service"); const recipe = await resolveAuthRecipe(service, c.env.RECIPES); if (!recipe) return c.json({ success: false, error: `\u627E\u4E0D\u5230 auth recipe: ${service}` }, 404); return c.json({ success: true, recipe }); }); recipesRouter.delete("/auth-recipes/:service", async (c) => { const service = c.req.param("service"); const recipe = await resolveAuthRecipe(service, c.env.RECIPES); if (!recipe) return c.json({ success: false, error: `\u627E\u4E0D\u5230 auth recipe: ${service}` }, 404); await c.env.RECIPES.delete(`auth_recipe:${service}`); return c.json({ success: true, deleted: service }); }); } }); // cypher-executor/src/lib/constants.ts var VALID_EDGE_TYPES, SEMANTIC_EDGE_MAP, BUILTIN_COMPONENTS; var init_constants3 = __esm({ "cypher-executor/src/lib/constants.ts"() { "use strict"; VALID_EDGE_TYPES = /* @__PURE__ */ new Set([ // 現有 "PIPE", "IF", "FOREACH", "CONTINUE", // 新增:執行語意 "IS_A", "ON_SUCCESS", "ON_FAIL", // 新增:條件語意(SDD workflow-discovery 3.11)—— 讀上游 if_control/switch 的 branch "ON_TRUE", "ON_FALSE", "ON_BRANCH", // 新增:觸發語意 "ON_CLICK", "CALLS_SUBFLOW", // 新增:結構語意(記錄圖結構,不執行) "CONTAINS", "HAS_STYLE", "HAS_BEHAVIOR" ]); SEMANTIC_EDGE_MAP = { // 中文語意詞 "\u5B8C\u6210\u5F8C": "PIPE", "\u5931\u6557\u6642": "ON_FAIL", "\u5C0D\u6BCF\u500B": "FOREACH", "\u689D\u4EF6\u6EFF\u8DB3\u6642": "IF", // 條件分支語意(SDD workflow-discovery 3.11):讓意圖工作流寫得出兩條路 "\u6210\u7ACB\u6642": "ON_TRUE", "\u70BA\u771F\u6642": "ON_TRUE", "\u4E0D\u6210\u7ACB\u6642": "ON_FALSE", "\u70BA\u5047\u6642": "ON_FALSE", "\u5426\u5247": "ON_FALSE", // 英文別名 "SUCCESS": "ON_SUCCESS", "FAIL": "ON_FAIL", "TRUE": "ON_TRUE", "FALSE": "ON_FALSE", "ELSE": "ON_FALSE", "BRANCH": "ON_BRANCH", "CLICK": "ON_CLICK", "SUBFLOW": "CALLS_SUBFLOW" }; BUILTIN_COMPONENTS = /* @__PURE__ */ new Map([ ["comp_passthrough", (ctx) => ctx], ["comp_uppercase", (ctx) => { const c = ctx; return { ...c, text: String(c.text || "").toUpperCase() }; }], ["comp_counter", (ctx) => { const c = ctx; return { ...c, count: (Number(c.count) || 0) + 1 }; }] ]); } }); // cypher-executor/src/lib/recipe-payload.ts function getPath2(obj, path) { let cur = obj; for (const part of path.split(".")) { if (cur === null || cur === void 0) return void 0; if (typeof cur !== "object") return void 0; cur = cur[part]; } return cur; } function renderBodyTemplate(template, ctx) { if (template === void 0 || template === null) return void 0; return renderValue(template, ctx); } function renderValue(v, ctx) { if (typeof v === "string") return renderString(v, ctx); if (Array.isArray(v)) return v.map((item) => renderValue(item, ctx)); if (v !== null && typeof v === "object") { const out = {}; for (const [k, val] of Object.entries(v)) { out[k] = renderValue(val, ctx); } return out; } return v; } function renderString(s, ctx) { const single = s.match(/^\s*\{\{([\w.]+)\}\}\s*$/); if (single) { const val = getPath2(ctx, single[1]); return val === void 0 ? s : val; } return s.replace(/\{\{([\w.]+)\}\}/g, (_, key) => { const val = getPath2(ctx, key); if (val === void 0) return `{{${key}}}`; return typeof val === "string" ? val : JSON.stringify(val); }); } function applyResponseMap(body, map) { if (!map) return { raw: body }; let picked = map.text_path ? getPath2(body, map.text_path) : body; if (map.thinking_model && Array.isArray(picked)) { const real = picked.filter( (p) => !(p && typeof p === "object" && p.thought === true) ); const last = real[real.length - 1]; picked = last && typeof last === "object" ? last.text : last; } if (typeof picked !== "string") return { text: void 0, raw: body }; return { text: sanitize(picked, map), raw: body }; } function sanitize(input, map) { let s = input.trim(); if (map.answer_marker) { const idx = s.lastIndexOf(map.answer_marker); if (idx >= 0) s = s.slice(idx + map.answer_marker.length); } const prefixes = map.strip_prefixes ?? []; if (prefixes.length > 0) { let changed = true; while (changed) { changed = false; s = s.trimStart(); for (const p of prefixes) { if (p && s.startsWith(p)) { s = s.slice(p.length); changed = true; } } } } return s.trim(); } var init_recipe_payload = __esm({ "cypher-executor/src/lib/recipe-payload.ts"() { "use strict"; } }); // cypher-executor/src/lib/component-loader.ts function wasmWorkerUrl(canonicalId, subdomain) { const kebab = canonicalId.replace(/_/g, "-"); return `https://arcrun-${kebab}.${subdomain}.workers.dev`; } function createComponentLoader(env) { return async (componentId) => { if (componentId === "trigger_workflow") { return makeTriggerWorkflowRunner(env); } const builtin = BUILTIN_COMPONENTS.get(componentId); if (builtin) return builtin; if (componentId.startsWith("http://") || componentId.startsWith("https://")) { return makeHttpRunner(componentId); } if (isComponentHash(componentId)) { const canonicalId = await env.WEBHOOKS.get(`idx:${componentId}`); if (canonicalId) { const runner = makeLogicRunner(canonicalId, env); if (runner) return runner; } throw new Error(`\u627E\u4E0D\u5230\u96F6\u4EF6 hash "${componentId}"\uFF0C\u8ACB\u78BA\u8A8D\u5DF2\u900F\u904E acr push \u4E0A\u50B3`); } if (isRecipeHash(componentId)) { const recipe = await resolveRecipe(componentId, env.RECIPES); if (recipe) return pickRecipeRunner(recipe, env); throw new Error(`\u627E\u4E0D\u5230 recipe hash "${componentId}"\uFF0C\u8ACB\u78BA\u8A8D\u5DF2\u900F\u904E acr push \u4E0A\u50B3`); } const logicRunner = makeLogicRunner(componentId, env); if (logicRunner) return logicRunner; const authRecipe = await resolveAuthRecipe(componentId, env.RECIPES); if (authRecipe) return makeAuthRecipeRunner(authRecipe); const kvRecipe = await resolveRecipe(componentId, env.RECIPES); if (kvRecipe) return pickRecipeRunner(kvRecipe, env); if (WASM_HTTP_RUNNER_IDS.has(componentId)) { return makeHttpRunner(wasmWorkerUrl(componentId, env.WORKER_SUBDOMAIN)); } throw new Error( `\u627E\u4E0D\u5230\u96F6\u4EF6 "${componentId}"\u3002 \u908F\u8F2F\u96F6\u4EF6\uFF1A${Object.keys(LOGIC_BINDING_MAP).join(", ")} \u6216\u50B3\u5165\u5916\u90E8 URL\uFF08https://...\uFF09\u3001recipe hash\uFF08rec_xxxxxxxx\uFF09\u3001\u96F6\u4EF6 hash\uFF08cmp_xxxxxxxx\uFF09` ); }; } function makeTriggerWorkflowRunner(env) { return async (ctx) => { const c = ctx && typeof ctx === "object" ? ctx : {}; const workflowName = String(c.workflow_name ?? ""); const apiKey = String(c.api_key ?? ""); const input = c.input && typeof c.input === "object" ? c.input : {}; const wait = c.wait !== false; if (!workflowName) return { success: false, error: "trigger_workflow \u7F3A workflow_name" }; if (!apiKey) return { success: false, error: "trigger_workflow \u7F3A api_key" }; const wfKey = `${apiKey}:wf:${workflowName}`; const wfRaw = await env.WEBHOOKS.get(wfKey, "text"); if (!wfRaw) return { success: false, error: `\u627E\u4E0D\u5230 workflow "${workflowName}" (key=${wfKey})` }; let record; try { record = JSON.parse(wfRaw); } catch { return { success: false, error: `workflow "${workflowName}" KV \u5167\u5BB9\u975E JSON` }; } if (!record.graph) return { success: false, error: `workflow "${workflowName}" \u7F3A graph \u6B04\u4F4D` }; const { executeWebhookGraph: executeWebhookGraph2 } = await Promise.resolve().then(() => (init_webhook_handlers(), webhook_handlers_exports)); const triggerContext = { ...input, _triggered_by: "trigger_workflow" }; if (wait) { const r = await executeWebhookGraph2(env, record.graph, triggerContext, workflowName, apiKey); const isPaused = !r.success && typeof r.error === "string" && /workflow paused/i.test(r.error); return { success: r.success || isPaused, triggered_workflow: workflowName, status: r.success ? "completed" : isPaused ? "running_async" : "failed", sub_result: r }; } else { void executeWebhookGraph2(env, record.graph, triggerContext, workflowName, apiKey).catch((e) => console.error("[trigger_workflow] fire-and-forget fail", workflowName, e)); return { success: true, triggered_workflow: workflowName, mode: "fire_and_forget" }; } }; } function makeHttpRunner(url) { return async (ctx) => { const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(ctx) }); if (!res.ok) { const text = await res.text(); return { success: false, status: res.status, error: text.slice(0, 200) }; } try { return await res.json(); } catch { return { success: true, data: await res.text() }; } }; } function makeLogicRunner(canonicalId, env) { const bindingKey = LOGIC_BINDING_MAP[canonicalId]; if (!bindingKey) return null; const svc = env[bindingKey]; if (svc) { return async (ctx) => { const res = await svc.fetch(new Request("https://component/", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(ctx) })); if (!res.ok) { const text = await res.text(); return { success: false, error: `${canonicalId} \u56DE\u50B3 ${res.status}: ${text.slice(0, 200)}` }; } try { return await res.json(); } catch { return { success: false, error: `${canonicalId} \u56DE\u50B3\u975E JSON` }; } }; } return makeHttpRunner(wasmWorkerUrl(canonicalId, env.WORKER_SUBDOMAIN)); } function pickRecipeRunner(recipe, env) { return recipe.auth === "binding" ? makeBindingRecipeRunner(recipe, env) : makeRecipeRunner(recipe); } function makeBindingRecipeRunner(recipe, env) { return async (ctx) => { const ctxObj = ctx && typeof ctx === "object" ? ctx : {}; const name = recipe.binding_name ?? "AI"; const binding = env[name]; if (!binding) { return { success: false, error: `recipe "${recipe.canonical_id}" \u5BA3\u544A auth: binding\u3001binding_name: "${name}"\uFF0C\u4F46\u9019\u500B\u90E8\u7F72\u6C92\u6709\u7D81\u5B9A ${name}\u3002\u8ACB\u5728 wrangler.toml \u88DC\u4E0A\u8A72 binding \u5F8C\u91CD\u65B0\u90E8\u7F72\u3002` }; } const target = recipe.endpoint; const payload = renderBodyTemplate(recipe.body_template ?? recipe.body, ctxObj) ?? Object.fromEntries(Object.entries(ctxObj).filter(([k]) => !k.startsWith("_"))); try { const runner = binding; if (typeof runner.run !== "function") { return { success: false, error: `binding "${name}" \u6C92\u6709 run() \u65B9\u6CD5\uFF0C\u76EE\u524D binding \u578B\u53EA\u652F\u63F4 run(model, input) \u5F62\u72C0\uFF08\u5982 env.AI\uFF09\u3002` }; } const data = await runner.run(target, payload); if (recipe.response_map) { const normalized = applyResponseMap(data, recipe.response_map); return { success: true, data, text: normalized.text }; } return { success: true, data }; } catch (e) { return { success: false, error: `binding "${name}" \u547C\u53EB\u5931\u6557\uFF08${target}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }; } }; } function makeRecipeRunner(recipe) { return async (ctx) => { const ctxObj = ctx && typeof ctx === "object" ? ctx : {}; const authPath = ctxObj._auth_path ?? {}; const interpolate2 = (s) => s.replace( /\{\{(auth\.)?(\w+)\}\}/g, (_, authPrefix, k) => String(authPrefix ? authPath[k] ?? "" : ctxObj[k] ?? "") ); const method = (recipe.method ?? "POST").toUpperCase(); const authHeaders = ctxObj._auth_headers ?? {}; const headers = { "Content-Type": "application/json", ...authHeaders }; for (const [k, v] of Object.entries(recipe.headers ?? {})) { headers[k] = interpolate2(v); } let bodyStr; if (recipe.body_template) { bodyStr = JSON.stringify(renderBodyTemplate(recipe.body_template, ctxObj)); } else if (recipe.body) { bodyStr = interpolate2(JSON.stringify(recipe.body)); } else if (method !== "GET") { const bodyObj = Object.fromEntries( Object.entries(ctxObj).filter(([k]) => !k.startsWith("_")) ); bodyStr = JSON.stringify(bodyObj); } const res = await fetch(interpolate2(recipe.endpoint), { method, headers, body: bodyStr }); const data = await readBodyOnce(res); if (recipe.response_map) { const normalized = applyResponseMap(data, recipe.response_map); return { success: res.ok, status: res.status, data, text: normalized.text }; } return { success: res.ok, status: res.status, data }; }; } function makeAuthRecipeRunner(recipe) { return async (ctx) => { const ctxObj = ctx && typeof ctx === "object" ? ctx : {}; const authHeaders = ctxObj._auth_headers ?? {}; const authQuery = ctxObj._auth_query ?? {}; const path = typeof ctxObj._path === "string" ? ctxObj._path : ""; const method = (ctxObj.method ?? "POST").toUpperCase(); const url = new URL(recipe.base_url.replace(/\/$/, "") + path); for (const [k, v] of Object.entries(authQuery)) { url.searchParams.set(k, v); } const headers = { "Content-Type": "application/json", ...authHeaders }; const bodyObj = Object.fromEntries( Object.entries(ctxObj).filter(([k]) => !k.startsWith("_") && k !== "method") ); const res = await fetch(url.toString(), { method, headers, body: method !== "GET" ? JSON.stringify(bodyObj) : void 0 }); const data = await readBodyOnce(res); return { success: res.ok, status: res.status, data }; }; } async function readBodyOnce(res) { const text = await res.text(); try { return JSON.parse(text); } catch { return text; } } var WASM_HTTP_RUNNER_IDS, LOGIC_BINDING_MAP; var init_component_loader = __esm({ "cypher-executor/src/lib/component-loader.ts"() { "use strict"; init_constants3(); init_hash(); init_recipes(); init_recipe_payload(); WASM_HTTP_RUNNER_IDS = /* @__PURE__ */ new Set([ // 通用 HTTP 零件 "http_request", // 通用 code 零件(sandbox inline JS,Arcrun#10 / 07-thin-shell §3.5 code-node):獨立 Worker, // URL 走 wasmWorkerUrl 通用推導(arcrun-code.{WORKER_SUBDOMAIN}.workers.dev, // self-hosted 由 WORKER_SUBDOMAIN var 注入自己的 subdomain,無寫死官方域名)。 // 漏這行 = workflow 寫 `component: code` 落到 step 8 直接「找不到零件」(#29 發現)。 "code", // gmail / telegram / line_notify / google_sheets 已降級為 recipe(2026-05-29 Phase 2): // recipe:gmail_send / telegram_send / line_notify_send / google_sheets_read|append // 走 step 6 KV recipe 解析,不再是零件。零件目錄已刪。 "cron", // Auth primitives "auth_static_key", "auth_service_account", "auth_oauth2", "auth_mtls" ]); LOGIC_BINDING_MAP = { if_control: "SVC_IF_CONTROL", switch: "SVC_SWITCH", foreach_control: "SVC_FOREACH_CONTROL", filter: "SVC_FILTER", merge: "SVC_MERGE", try_catch: "SVC_TRY_CATCH", wait: "SVC_WAIT", set: "SVC_SET", array_ops: "SVC_ARRAY_OPS", string_ops: "SVC_STRING_OPS", number_ops: "SVC_NUMBER_OPS", date_ops: "SVC_DATE_OPS", validate_json: "SVC_VALIDATE_JSON" // ai_transform_compile / ai_transform_run 已刪除(2026-05-29): // Arcrun 是 AI 呼叫的工具,工作流不該內嵌 AI 節點回頭呼叫 AI(n8n 才需要,因它沒大腦)。 }; } }); // cypher-executor/src/lib/wasi-shim.ts async function routedKvGet(env, apiKey, key) { if (key.startsWith("auth_recipe:")) { return env.RECIPES.get(key); } const credMatch = key.match(/^([^:]+):cred:.+$/); if (credMatch) { if (credMatch[1] !== apiKey) { return null; } return env.CREDENTIALS_KV.get(key); } return null; } async function routedKvPut(env, apiKey, key, value, ttlSeconds) { const oauth2Match = key.match(/^([^:]+):oauth2:.+$/); if (oauth2Match && oauth2Match[1] === apiKey) { const opts = ttlSeconds > 0 ? { expirationTtl: ttlSeconds } : void 0; await env.CREDENTIALS_KV.put(key, value, opts); return; } } async function rsaPkcs1Sha256Sign(data, pkcs8) { const cryptoKey = await crypto.subtle.importKey( "pkcs8", pkcs8, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["sign"] ); const sig = await crypto.subtle.sign("RSASSA-PKCS1-v1_5", cryptoKey, data); return new Uint8Array(sig); } function secretGet(env, ref) { if (!/^CRED_/.test(ref)) return null; const value = env[ref]; return typeof value === "string" ? value : null; } function createArcrunHostFunctions(env, apiKey) { return { kv_get: (key) => routedKvGet(env, apiKey, key), kv_put: (key, value, ttlSeconds) => routedKvPut(env, apiKey, key, value, ttlSeconds), crypto_sign_rs256: (data, pkcs8) => rsaPkcs1Sha256Sign(data, pkcs8), secret_get: async (ref) => secretGet(env, ref) }; } var init_wasi_shim = __esm({ "cypher-executor/src/lib/wasi-shim.ts"() { "use strict"; } }); // cypher-executor/src/routes/kbdb-proxy.ts function kbdbBase(env) { const base = (env.KBDB_BASE_URL ?? "https://arcrun-kbdb.uncle6-me.workers.dev").replace(/\/$/, ""); const headers = { "Content-Type": "application/json" }; if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`; return { base, headers }; } function tenant(c) { return c.req.header("X-Arcrun-API-Key") ?? null; } function graphBase(env) { if (env.KBDB_GRAPH_URL) return env.KBDB_GRAPH_URL.replace(/\/$/, ""); return `https://kbdb-graph-plugin.${env.WORKER_SUBDOMAIN}.workers.dev`; } var kbdbProxyRouter, NEED_KEY; var init_kbdb_proxy = __esm({ "cypher-executor/src/routes/kbdb-proxy.ts"() { "use strict"; init_dist(); kbdbProxyRouter = new Hono2(); NEED_KEY = { error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }; kbdbProxyRouter.post("/kbdb/templates", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const body = await c.req.json().catch(() => null); if (!body || !body.name || !Array.isArray(body.slots)) { return c.json({ error: "name \u8207 slots[] \u5FC5\u586B" }, 400); } const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/templates`, { method: "POST", headers, // created_by 帶上租戶當溯源,但 template 本身全域可見可用 body: JSON.stringify({ name: body.name, slots: body.slots, description: body.description, created_by: owner }) }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/templates", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/templates`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/templates/:idOrName", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/templates/${encodeURIComponent(c.req.param("idOrName"))}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.post("/kbdb/records", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const body = await c.req.json().catch(() => null); if (!body || !body.template || !body.values) { return c.json({ error: "template \u8207 values \u5FC5\u586B" }, 400); } const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/records`, { method: "POST", headers, // 強制以租戶身份隔離:忽略 caller 自帶 owner_id,一律用 header 身份(防跨租戶寫入) body: JSON.stringify({ template: body.template, values: body.values, owner_id: owner }) }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/records/by-template/:template", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const res = await fetch( `${base}/records/by-template/${encodeURIComponent(c.req.param("template"))}?owner_id=${encodeURIComponent(owner)}`, { headers } ); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/records/:recordId", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/records/${encodeURIComponent(c.req.param("recordId"))}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/search", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const q = c.req.query("q"); if (!q) return c.json({ error: "q \u5FC5\u586B" }, 400); const { base, headers } = kbdbBase(c.env); const params = new URLSearchParams({ q, owner_id: owner }); for (const k of ["entry_type", "source", "library", "mode"]) { const v = c.req.query(k); if (v) params.set(k, v); } const res = await fetch(`${base}/entries/search?${params.toString()}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.post("/kbdb/entries", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const body = await c.req.json().catch(() => null); if (!body || !body.entry_type) return c.json({ error: "entry_type \u5FC5\u586B" }, 400); const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/entries`, { method: "POST", headers, // 強制以租戶身份隔離:忽略 caller 自帶 owner_id,一律用 header 身份(防跨租戶寫入) body: JSON.stringify({ ...body, owner_id: owner }) }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/entries", async (c) => { const owner = tenant(c); if (!owner) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const params = new URLSearchParams(); params.set("owner_id", owner); for (const k of ["entry_type", "parent_id", "page_name", "source", "library", "limit", "offset"]) { const v = c.req.query(k); if (v) params.set(k, v); } const q = c.req.query("q") || c.req.query("search"); if (q) params.set("q", q); const res = await fetch(`${base}/entries?${params.toString()}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/entries/:id", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/entries/${encodeURIComponent(c.req.param("id"))}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); kbdbProxyRouter.get("/kbdb/graph/neighbors/:name", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const base = graphBase(c.env); const headers = {}; if (c.env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`; try { const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(c.req.param("name"))}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); } catch (e) { return c.json({ error: `kbdb-graph-plugin \u4E0D\u53EF\u9054\uFF08${base}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502); } }); kbdbProxyRouter.get("/kbdb/map", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const owner = c.req.query("owner_id"); const qs = owner ? `?owner_id=${encodeURIComponent(owner)}` : ""; try { const res = await fetch(`${base}/map${qs}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); } catch (e) { return c.json({ success: false, error: `KBDB \u4E0D\u53EF\u9054\uFF08${base}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502); } }); kbdbProxyRouter.get("/kbdb/map/:library", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const { base, headers } = kbdbBase(c.env); const owner = c.req.query("owner_id"); const qs = owner ? `?owner_id=${encodeURIComponent(owner)}` : ""; try { const res = await fetch(`${base}/map/${encodeURIComponent(c.req.param("library"))}${qs}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); } catch (e) { return c.json({ success: false, error: `KBDB \u4E0D\u53EF\u9054\uFF08${base}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502); } }); kbdbProxyRouter.patch("/kbdb/entries/:id", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const body = await c.req.json().catch(() => ({})); const { owner_id: _drop, ...patch } = body ?? {}; const { base, headers } = kbdbBase(c.env); const res = await fetch(`${base}/entries/${encodeURIComponent(c.req.param("id"))}`, { method: "PATCH", headers, body: JSON.stringify(patch) }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); }); } }); // cypher-executor/src/routes/credentials.ts async function deriveSecretRef(apiKey, name) { const hash8 = await sha256Prefix(apiKey); return `CRED_${name.toUpperCase()}_${hash8.toUpperCase()}`; } async function storeCredential(env, apiKey, name, value, service) { const secretRef = await deriveSecretRef(apiKey, name); await putWorkerSecret(env, secretRef, value); await upsertCredentialEntry(env, apiKey, name, service, "standard", secretRef); } function validateName(name) { return typeof name === "string" && /^\w+$/.test(name); } function validSensitivity(s) { return s === "standard" || s === "high"; } async function putWorkerSecret(env, secretRef, value) { if (!env.CF_SECRETS_API_TOKEN || !env.CF_ACCOUNT_ID) { throw new Error( "\u6B64 worker \u7F3A CF_SECRETS_API_TOKEN / CF_ACCOUNT_ID \u8A2D\u5B9A\uFF0C\u5BEB\u5165\u8DEF\u5F91\u672A\u5C31\u7DD2\uFF08\u898B credential-store-migration.md T3\uFF1Aacr init/update \u61C9\u78BA\u4FDD\u9019\u5169\u9805\u5C31\u7DD2\uFF09" ); } const url = `https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/workers/scripts/${CYPHER_SCRIPT_NAME}/secrets`; const res = await fetch(url, { method: "PUT", headers: { Authorization: `Bearer ${env.CF_SECRETS_API_TOKEN}`, "Content-Type": "application/json" }, body: JSON.stringify({ name: secretRef, text: value, type: "secret_text" }) }); const body = await res.json().catch(() => null); if (!res.ok || !body?.success) { const detail = body?.errors?.map((e) => e.message).filter(Boolean).join("; ") || `HTTP ${res.status}`; throw new Error(`CF Workers Secrets \u5BEB\u5165\u5931\u6557\uFF1A${detail}`); } } async function deleteWorkerSecret(env, secretRef) { if (!env.CF_SECRETS_API_TOKEN || !env.CF_ACCOUNT_ID) { throw new Error("\u6B64 worker \u7F3A CF_SECRETS_API_TOKEN / CF_ACCOUNT_ID \u8A2D\u5B9A\uFF0C\u522A\u9664\u8DEF\u5F91\u672A\u5C31\u7DD2"); } const url = `https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/workers/scripts/${CYPHER_SCRIPT_NAME}/secrets/${secretRef}`; const res = await fetch(url, { method: "DELETE", headers: { Authorization: `Bearer ${env.CF_SECRETS_API_TOKEN}` } }); if (res.status === 404) return; const body = await res.json().catch(() => null); if (!res.ok || !body?.success) { const detail = body?.errors?.map((e) => e.message).filter(Boolean).join("; ") || `HTTP ${res.status}`; throw new Error(`CF Workers Secrets \u522A\u9664\u5931\u6557\uFF1A${detail}`); } } function parseMeta(row) { try { const m = row.metadata_json ? JSON.parse(row.metadata_json) : {}; return { service: typeof m.service === "string" ? m.service : null, sensitivity: m.sensitivity === "high" ? "high" : "standard", secret_ref: typeof m.secret_ref === "string" ? m.secret_ref : "", last_used_at: typeof m.last_used_at === "number" ? m.last_used_at : null }; } catch { return { service: null, sensitivity: "standard", secret_ref: "", last_used_at: null }; } } async function kbdbCredFetch(env, path, init) { const { base, headers } = kbdbBase(env); return fetch(`${base}${path}`, { ...init, headers: { ...headers, ...init?.headers } }); } function invalidateCredentialCache(apiKey) { delete dirCache[apiKey]; } async function getCredentialDirectory(env, apiKey) { const now2 = Date.now(); const cached = dirCache[apiKey]; if (cached && now2 - cached.fetchedAt < DIR_CACHE_TTL_MS) return cached.rows; const qs = new URLSearchParams({ owner_id: apiKey, entry_type: CREDENTIAL_ENTRY_TYPE, limit: "200" }); const res = await kbdbCredFetch(env, `/entries?${qs.toString()}`); if (!res.ok) { return []; } const body = await res.json().catch(() => null); const rows = (body?.entries ?? []).filter((e) => !!e.page_name).map((e) => { const meta = parseMeta(e); return { id: e.id, name: e.page_name, secret_ref: meta.secret_ref, service: meta.service, sensitivity: meta.sensitivity, last_used_at: meta.last_used_at }; }); dirCache[apiKey] = { rows, fetchedAt: now2 }; return rows; } async function getCredentialSecretRefs(env, apiKey) { const rows = await getCredentialDirectory(env, apiKey); const out = {}; for (const r of rows) { if (r.secret_ref) out[r.name] = r.secret_ref; } return out; } function touchLastUsed(env, apiKey, names) { const cached = dirCache[apiKey]; if (!cached || names.length === 0) return; const now2 = Math.floor(Date.now() / 1e3); for (const r of cached.rows) { if (!names.includes(r.name)) continue; const meta = { service: r.service, sensitivity: r.sensitivity, secret_ref: r.secret_ref, last_used_at: now2 }; kbdbCredFetch(env, `/entries/${encodeURIComponent(r.id)}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ metadata_json: JSON.stringify(meta) }) }).catch(() => { }); r.last_used_at = now2; } } async function findCredentialEntry(env, apiKey, name) { const qs = new URLSearchParams({ owner_id: apiKey, entry_type: CREDENTIAL_ENTRY_TYPE, page_name: name, limit: "1" }); const res = await kbdbCredFetch(env, `/entries?${qs.toString()}`); if (!res.ok) throw new Error(`KBDB /entries \u67E5\u8A62\u5931\u6557\uFF1AHTTP ${res.status}`); const body = await res.json().catch(() => null); return body?.entries?.[0] ?? null; } async function upsertCredentialEntry(env, apiKey, name, service, sensitivity, secretRef) { const existing = await findCredentialEntry(env, apiKey, name); const meta = { service, sensitivity, secret_ref: secretRef, last_used_at: existing ? parseMeta(existing).last_used_at : null }; if (existing) { const res = await kbdbCredFetch(env, `/entries/${encodeURIComponent(existing.id)}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ metadata_json: JSON.stringify(meta) }) }); if (!res.ok) throw new Error(`credential \u76EE\u9304\u66F4\u65B0\u5931\u6557\uFF1AHTTP ${res.status}`); } else { const res = await kbdbCredFetch(env, `/entries`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ entry_type: CREDENTIAL_ENTRY_TYPE, owner_id: apiKey, page_name: name, metadata_json: JSON.stringify(meta) }) }); if (!res.ok) throw new Error(`credential \u76EE\u9304\u5EFA\u7ACB\u5931\u6557\uFF1AHTTP ${res.status}`); } invalidateCredentialCache(apiKey); } async function listCredentialRows(env, apiKey) { const qs = new URLSearchParams({ owner_id: apiKey, entry_type: CREDENTIAL_ENTRY_TYPE, limit: "200" }); const res = await kbdbCredFetch(env, `/entries?${qs.toString()}`); if (!res.ok) throw new Error(`credential \u76EE\u9304\u67E5\u8A62\u5931\u6557\uFF1AHTTP ${res.status}`); const body = await res.json().catch(() => null); const rows = (body?.entries ?? []).filter((e) => !!e.page_name).map((e) => { const meta = parseMeta(e); return { name: e.page_name, service: meta.service, sensitivity: meta.sensitivity, created_at: e.created_at, last_used_at: meta.last_used_at }; }); return rows; } async function hasCredential(env, apiKey, name) { const entry = await findCredentialEntry(env, apiKey, name); return entry !== null; } async function writeCredential(env, apiKey, name, value, service, sensitivityRaw) { const sensitivity = validSensitivity(sensitivityRaw) ? sensitivityRaw : "standard"; const secretRef = await deriveSecretRef(apiKey, name); await putWorkerSecret(env, secretRef, value); await upsertCredentialEntry(env, apiKey, name, service ?? null, sensitivity, secretRef); return { secretRef, sensitivity }; } var credentialsRouter, CYPHER_SCRIPT_NAME, CREDENTIAL_ENTRY_TYPE, DIR_CACHE_TTL_MS, dirCache; var init_credentials = __esm({ "cypher-executor/src/routes/credentials.ts"() { "use strict"; init_dist(); init_hash(); init_kbdb_proxy(); credentialsRouter = new Hono2(); CYPHER_SCRIPT_NAME = "arcrun-cypher-executor"; CREDENTIAL_ENTRY_TYPE = "credential"; DIR_CACHE_TTL_MS = 6e4; dirCache = {}; credentialsRouter.post("/credentials", async (c) => { const apiKey = c.req.header("X-Arcrun-API-Key"); if (!apiKey) { return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401); } const body = await c.req.json().catch(() => null); if (!validateName(body?.name)) { return c.json({ error: "name \u5FC5\u586B\uFF0C\u53EA\u80FD\u5305\u542B\u82F1\u6587\u5B57\u6BCD\u3001\u6578\u5B57\u548C\u5E95\u7DDA" }, 400); } if (!body?.value || typeof body.value !== "string") { return c.json({ error: "value \u5FC5\u586B\uFF08credential \u660E\u6587\u503C\uFF0C\u7D93 TLS \u50B3\u8F38\uFF09" }, 400); } try { const { secretRef, sensitivity } = await writeCredential( c.env, apiKey, body.name, body.value, body.service, body.sensitivity ); return c.json({ success: true, name: body.name, service: body.service ?? null, sensitivity, secret_ref: secretRef }); } catch (e) { return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 502); } }); credentialsRouter.put("/credentials/:name", async (c) => { const apiKey = c.req.header("X-Arcrun-API-Key"); if (!apiKey) { return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401); } const name = c.req.param("name"); if (!validateName(name)) { return c.json({ error: "name \u53EA\u80FD\u5305\u542B\u82F1\u6587\u5B57\u6BCD\u3001\u6578\u5B57\u548C\u5E95\u7DDA" }, 400); } const body = await c.req.json().catch(() => null); if (!body?.value || typeof body.value !== "string") { return c.json({ error: "value \u5FC5\u586B\uFF08credential \u660E\u6587\u503C\uFF0C\u7D93 TLS \u50B3\u8F38\uFF09" }, 400); } try { const { secretRef, sensitivity } = await writeCredential( c.env, apiKey, name, body.value, body.service, body.sensitivity ); return c.json({ success: true, name, service: body.service ?? null, sensitivity, secret_ref: secretRef }); } catch (e) { return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 502); } }); credentialsRouter.delete("/credentials/:name", async (c) => { const apiKey = c.req.header("X-Arcrun-API-Key"); if (!apiKey) { return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401); } const name = c.req.param("name"); try { const entry = await findCredentialEntry(c.env, apiKey, name); if (entry) { const meta = parseMeta(entry); if (meta.secret_ref) await deleteWorkerSecret(c.env, meta.secret_ref); const res = await kbdbCredFetch(c.env, `/entries/${encodeURIComponent(entry.id)}`, { method: "DELETE" }); if (!res.ok) throw new Error(`credential \u76EE\u9304\u522A\u9664\u5931\u6557\uFF1AHTTP ${res.status}`); invalidateCredentialCache(apiKey); return c.json({ success: true, name, source: "workers-secrets" }); } await c.env.CREDENTIALS_KV.delete(`${apiKey}:cred:${name}`); return c.json({ success: true, name, source: "legacy-kv" }); } catch (e) { return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 502); } }); credentialsRouter.get("/credentials/catalog", async (c) => { const apiKey = c.req.header("X-Arcrun-API-Key"); if (!apiKey) { return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401); } try { const rows = await listCredentialRows(c.env, apiKey); return c.json({ success: true, credentials: rows, total: rows.length }); } catch (e) { return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 502); } }); credentialsRouter.get("/credentials", async (c) => { const apiKey = c.req.header("X-Arcrun-API-Key"); if (!apiKey) { return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401); } try { const rows = await listCredentialRows(c.env, apiKey); return c.json({ success: true, credentials: rows, total: rows.length }); } catch (e) { return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 502); } }); } }); // cypher-executor/src/actions/auth-dispatcher.ts async function resolveSecretsFromNewHome(env, apiKey, names) { const resolved = {}; if (names.length === 0) return resolved; const refs = await getCredentialSecretRefs(env, apiKey); if (Object.keys(refs).length === 0) return resolved; const secretGet2 = createArcrunHostFunctions(env, apiKey).secret_get; if (!secretGet2) return resolved; const resolvedNames = []; for (const name of names) { const ref = refs[name]; if (!ref) continue; const value = await secretGet2(ref); if (value === null) continue; resolved[name] = value; resolvedNames.push(name); } if (resolvedNames.length > 0) touchLastUsed(env, apiKey, resolvedNames); return resolved; } async function tryAuthDispatch(componentId, input, env, apiKey) { if (AUTH_PRIMITIVE_IDS.has(componentId)) { return null; } let service = componentId; const apiRecipe = await resolveRecipe(componentId, env.RECIPES); if (apiRecipe?.auth_service) { service = apiRecipe.auth_service; } const recipe = await resolveAuthRecipe(service, env.RECIPES); if (!recipe) return null; if (!SUPPORTED_PRIMITIVES.has(recipe.primitive)) return null; const secretNames = recipe.required_secrets.filter((s) => !s.optional).map((s) => s.key); const resolvedSecrets = await resolveSecretsFromNewHome(env, apiKey, secretNames); const primitiveUrl = wasmWorkerUrl(`auth_${recipe.primitive}`, env.WORKER_SUBDOMAIN); const res = await fetch(primitiveUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "authenticate", api_key: apiKey, service, // 只在有取到值時帶上(空物件也無妨,WASM 對 nil/空 map 同樣 fallback) resolved_secrets: resolvedSecrets }) }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error( `auth primitive "${recipe.primitive}" \u56DE\u50B3 ${res.status}: ${text.slice(0, 200)}` ); } const result = await res.json().catch(() => null); if (!result || result.success === false) { throw new Error( `auth primitive \u5931\u6557: ${result?.error ?? "\u672A\u77E5\u932F\u8AA4"}` ); } return { ...input, _auth_headers: result.auth_headers ?? {}, _auth_query: result.auth_query ?? {}, _auth_body: result.auth_body ?? {}, _auth_path: result.auth_path ?? {} }; } function collectCredentialNames(value, out) { if (typeof value === "string") { for (const m of value.matchAll(CREDENTIAL_REF)) out.add(m[1]); } else if (Array.isArray(value)) { for (const v of value) collectCredentialNames(v, out); } else if (value && typeof value === "object") { for (const v of Object.values(value)) collectCredentialNames(v, out); } } function replaceCredentialRefs(value, resolved) { if (typeof value === "string") { return value.replace( CREDENTIAL_REF, (orig, name) => Object.prototype.hasOwnProperty.call(resolved, name) ? resolved[name] : orig ); } if (Array.isArray(value)) return value.map((v) => replaceCredentialRefs(v, resolved)); if (value && typeof value === "object") { const out = {}; for (const [k, v] of Object.entries(value)) { out[k] = replaceCredentialRefs(v, resolved); } return out; } return value; } async function resolveCredentialRefs(data, env, apiKey) { const names = /* @__PURE__ */ new Set(); collectCredentialNames(data, names); if (names.size === 0) return data; const nameList = [...names]; const resolvedSecrets = await resolveSecretsFromNewHome(env, apiKey, nameList); const url = wasmWorkerUrl("auth_static_key", env.WORKER_SUBDOMAIN); const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "resolve_credentials", api_key: apiKey, names: nameList, resolved_secrets: resolvedSecrets }) }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`credential resolve \u56DE\u50B3 ${res.status}: ${text.slice(0, 200)}`); } const result = await res.json().catch(() => null); if (!result || result.success === false) { throw new Error(`credential resolve \u5931\u6557: ${result?.error ?? "\u672A\u77E5\u932F\u8AA4"}`); } return replaceCredentialRefs(data, result.credentials ?? {}); } var SUPPORTED_PRIMITIVES, AUTH_PRIMITIVE_IDS, CREDENTIAL_REF; var init_auth_dispatcher = __esm({ "cypher-executor/src/actions/auth-dispatcher.ts"() { "use strict"; init_recipes(); init_component_loader(); init_wasi_shim(); init_credentials(); SUPPORTED_PRIMITIVES = /* @__PURE__ */ new Set(["static_key", "service_account", "oauth2"]); AUTH_PRIMITIVE_IDS = /* @__PURE__ */ new Set([ "auth_static_key", "auth_service_account", "auth_oauth2", "auth_mtls" ]); CREDENTIAL_REF = /\{\{credential\.(\w+)\}\}/g; } }); // cypher-executor/node_modules/.pnpm/zod@3.23.8/node_modules/zod/lib/index.mjs function setErrorMap(map) { overrideErrorMap = map; } function getErrorMap() { return overrideErrorMap; } function addIssueToContext(ctx, issueData) { const overrideMap = getErrorMap(); const issue = makeIssue({ issueData, data: ctx.data, path: ctx.path, errorMaps: [ ctx.common.contextualErrorMap, ctx.schemaErrorMap, overrideMap, overrideMap === errorMap ? void 0 : errorMap // then global default map ].filter((x) => !!x) }); ctx.common.issues.push(issue); } function __classPrivateFieldGet(receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); } function __classPrivateFieldSet(receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; } function processCreateParams(params) { if (!params) return {}; const { errorMap: errorMap2, invalid_type_error, required_error, description } = params; if (errorMap2 && (invalid_type_error || required_error)) { throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`); } if (errorMap2) return { errorMap: errorMap2, description }; const customMap = (iss, ctx) => { var _a, _b; const { message } = params; if (iss.code === "invalid_enum_value") { return { message: message !== null && message !== void 0 ? message : ctx.defaultError }; } if (typeof ctx.data === "undefined") { return { message: (_a = message !== null && message !== void 0 ? message : required_error) !== null && _a !== void 0 ? _a : ctx.defaultError }; } if (iss.code !== "invalid_type") return { message: ctx.defaultError }; return { message: (_b = message !== null && message !== void 0 ? message : invalid_type_error) !== null && _b !== void 0 ? _b : ctx.defaultError }; }; return { errorMap: customMap, description }; } function timeRegexSource(args) { let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`; if (args.precision) { regex = `${regex}\\.\\d{${args.precision}}`; } else if (args.precision == null) { regex = `${regex}(\\.\\d+)?`; } return regex; } function timeRegex(args) { return new RegExp(`^${timeRegexSource(args)}$`); } function datetimeRegex(args) { let regex = `${dateRegexSource}T${timeRegexSource(args)}`; const opts = []; opts.push(args.local ? `Z?` : `Z`); if (args.offset) opts.push(`([+-]\\d{2}:?\\d{2})`); regex = `${regex}(${opts.join("|")})`; return new RegExp(`^${regex}$`); } function isValidIP(ip, version) { if ((version === "v4" || !version) && ipv4Regex.test(ip)) { return true; } if ((version === "v6" || !version) && ipv6Regex.test(ip)) { return true; } return false; } function floatSafeRemainder(val, step) { const valDecCount = (val.toString().split(".")[1] || "").length; const stepDecCount = (step.toString().split(".")[1] || "").length; const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount; const valInt = parseInt(val.toFixed(decCount).replace(".", "")); const stepInt = parseInt(step.toFixed(decCount).replace(".", "")); return valInt % stepInt / Math.pow(10, decCount); } function deepPartialify(schema) { if (schema instanceof ZodObject) { const newShape = {}; for (const key in schema.shape) { const fieldSchema = schema.shape[key]; newShape[key] = ZodOptional.create(deepPartialify(fieldSchema)); } return new ZodObject({ ...schema._def, shape: () => newShape }); } else if (schema instanceof ZodArray) { return new ZodArray({ ...schema._def, type: deepPartialify(schema.element) }); } else if (schema instanceof ZodOptional) { return ZodOptional.create(deepPartialify(schema.unwrap())); } else if (schema instanceof ZodNullable) { return ZodNullable.create(deepPartialify(schema.unwrap())); } else if (schema instanceof ZodTuple) { return ZodTuple.create(schema.items.map((item) => deepPartialify(item))); } else { return schema; } } function mergeValues(a, b) { const aType = getParsedType(a); const bType = getParsedType(b); if (a === b) { return { valid: true, data: a }; } else if (aType === ZodParsedType.object && bType === ZodParsedType.object) { const bKeys = util.objectKeys(b); const sharedKeys = util.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1); const newObj = { ...a, ...b }; for (const key of sharedKeys) { const sharedValue = mergeValues(a[key], b[key]); if (!sharedValue.valid) { return { valid: false }; } newObj[key] = sharedValue.data; } return { valid: true, data: newObj }; } else if (aType === ZodParsedType.array && bType === ZodParsedType.array) { if (a.length !== b.length) { return { valid: false }; } const newArray = []; for (let index = 0; index < a.length; index++) { const itemA = a[index]; const itemB = b[index]; const sharedValue = mergeValues(itemA, itemB); if (!sharedValue.valid) { return { valid: false }; } newArray.push(sharedValue.data); } return { valid: true, data: newArray }; } else if (aType === ZodParsedType.date && bType === ZodParsedType.date && +a === +b) { return { valid: true, data: a }; } else { return { valid: false }; } } function createZodEnum(values, params) { return new ZodEnum({ values, typeName: ZodFirstPartyTypeKind.ZodEnum, ...processCreateParams(params) }); } function custom(check, params = {}, fatal) { if (check) return ZodAny.create().superRefine((data, ctx) => { var _a, _b; if (!check(data)) { const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params; const _fatal = (_b = (_a = p.fatal) !== null && _a !== void 0 ? _a : fatal) !== null && _b !== void 0 ? _b : true; const p2 = typeof p === "string" ? { message: p } : p; ctx.addIssue({ code: "custom", ...p2, fatal: _fatal }); } }); return ZodAny.create(); } var util, objectUtil, ZodParsedType, getParsedType, ZodIssueCode, quotelessJson, ZodError, errorMap, overrideErrorMap, makeIssue, EMPTY_PATH, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, errorUtil, _ZodEnum_cache, _ZodNativeEnum_cache, ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv6Regex, base64Regex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, BRAND, ZodBranded, ZodPipeline, ZodReadonly, late, ZodFirstPartyTypeKind, instanceOfType, stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType, ostring, onumber, oboolean, coerce, NEVER, z; var init_lib = __esm({ "cypher-executor/node_modules/.pnpm/zod@3.23.8/node_modules/zod/lib/index.mjs"() { (function(util2) { util2.assertEqual = (val) => val; function assertIs(_arg) { } util2.assertIs = assertIs; function assertNever(_x) { throw new Error(); } util2.assertNever = assertNever; util2.arrayToEnum = (items) => { const obj = {}; for (const item of items) { obj[item] = item; } return obj; }; util2.getValidEnumValues = (obj) => { const validKeys = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number"); const filtered = {}; for (const k of validKeys) { filtered[k] = obj[k]; } return util2.objectValues(filtered); }; util2.objectValues = (obj) => { return util2.objectKeys(obj).map(function(e) { return obj[e]; }); }; util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => { const keys = []; for (const key in object) { if (Object.prototype.hasOwnProperty.call(object, key)) { keys.push(key); } } return keys; }; util2.find = (arr, checker) => { for (const item of arr) { if (checker(item)) return item; } return void 0; }; util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && isFinite(val) && Math.floor(val) === val; function joinValues(array, separator = " | ") { return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator); } util2.joinValues = joinValues; util2.jsonStringifyReplacer = (_, value) => { if (typeof value === "bigint") { return value.toString(); } return value; }; })(util || (util = {})); (function(objectUtil2) { objectUtil2.mergeShapes = (first, second) => { return { ...first, ...second // second overwrites first }; }; })(objectUtil || (objectUtil = {})); ZodParsedType = util.arrayToEnum([ "string", "nan", "number", "integer", "float", "boolean", "date", "bigint", "symbol", "function", "undefined", "null", "array", "object", "unknown", "promise", "void", "never", "map", "set" ]); getParsedType = (data) => { const t = typeof data; switch (t) { case "undefined": return ZodParsedType.undefined; case "string": return ZodParsedType.string; case "number": return isNaN(data) ? ZodParsedType.nan : ZodParsedType.number; case "boolean": return ZodParsedType.boolean; case "function": return ZodParsedType.function; case "bigint": return ZodParsedType.bigint; case "symbol": return ZodParsedType.symbol; case "object": if (Array.isArray(data)) { return ZodParsedType.array; } if (data === null) { return ZodParsedType.null; } if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { return ZodParsedType.promise; } if (typeof Map !== "undefined" && data instanceof Map) { return ZodParsedType.map; } if (typeof Set !== "undefined" && data instanceof Set) { return ZodParsedType.set; } if (typeof Date !== "undefined" && data instanceof Date) { return ZodParsedType.date; } return ZodParsedType.object; default: return ZodParsedType.unknown; } }; ZodIssueCode = util.arrayToEnum([ "invalid_type", "invalid_literal", "custom", "invalid_union", "invalid_union_discriminator", "invalid_enum_value", "unrecognized_keys", "invalid_arguments", "invalid_return_type", "invalid_date", "invalid_string", "too_small", "too_big", "invalid_intersection_types", "not_multiple_of", "not_finite" ]); quotelessJson = (obj) => { const json = JSON.stringify(obj, null, 2); return json.replace(/"([^"]+)":/g, "$1:"); }; ZodError = class _ZodError extends Error { constructor(issues) { super(); this.issues = []; this.addIssue = (sub) => { this.issues = [...this.issues, sub]; }; this.addIssues = (subs = []) => { this.issues = [...this.issues, ...subs]; }; const actualProto = new.target.prototype; if (Object.setPrototypeOf) { Object.setPrototypeOf(this, actualProto); } else { this.__proto__ = actualProto; } this.name = "ZodError"; this.issues = issues; } get errors() { return this.issues; } format(_mapper) { const mapper = _mapper || function(issue) { return issue.message; }; const fieldErrors = { _errors: [] }; const processError = (error) => { for (const issue of error.issues) { if (issue.code === "invalid_union") { issue.unionErrors.map(processError); } else if (issue.code === "invalid_return_type") { processError(issue.returnTypeError); } else if (issue.code === "invalid_arguments") { processError(issue.argumentsError); } else if (issue.path.length === 0) { fieldErrors._errors.push(mapper(issue)); } else { let curr = fieldErrors; let i = 0; while (i < issue.path.length) { const el = issue.path[i]; const terminal = i === issue.path.length - 1; if (!terminal) { curr[el] = curr[el] || { _errors: [] }; } else { curr[el] = curr[el] || { _errors: [] }; curr[el]._errors.push(mapper(issue)); } curr = curr[el]; i++; } } } }; processError(this); return fieldErrors; } static assert(value) { if (!(value instanceof _ZodError)) { throw new Error(`Not a ZodError: ${value}`); } } toString() { return this.message; } get message() { return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2); } get isEmpty() { return this.issues.length === 0; } flatten(mapper = (issue) => issue.message) { const fieldErrors = {}; const formErrors = []; for (const sub of this.issues) { if (sub.path.length > 0) { fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; fieldErrors[sub.path[0]].push(mapper(sub)); } else { formErrors.push(mapper(sub)); } } return { formErrors, fieldErrors }; } get formErrors() { return this.flatten(); } }; ZodError.create = (issues) => { const error = new ZodError(issues); return error; }; errorMap = (issue, _ctx) => { let message; switch (issue.code) { case ZodIssueCode.invalid_type: if (issue.received === ZodParsedType.undefined) { message = "Required"; } else { message = `Expected ${issue.expected}, received ${issue.received}`; } break; case ZodIssueCode.invalid_literal: message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`; break; case ZodIssueCode.unrecognized_keys: message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`; break; case ZodIssueCode.invalid_union: message = `Invalid input`; break; case ZodIssueCode.invalid_union_discriminator: message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`; break; case ZodIssueCode.invalid_enum_value: message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`; break; case ZodIssueCode.invalid_arguments: message = `Invalid function arguments`; break; case ZodIssueCode.invalid_return_type: message = `Invalid function return type`; break; case ZodIssueCode.invalid_date: message = `Invalid date`; break; case ZodIssueCode.invalid_string: if (typeof issue.validation === "object") { if ("includes" in issue.validation) { message = `Invalid input: must include "${issue.validation.includes}"`; if (typeof issue.validation.position === "number") { message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`; } } else if ("startsWith" in issue.validation) { message = `Invalid input: must start with "${issue.validation.startsWith}"`; } else if ("endsWith" in issue.validation) { message = `Invalid input: must end with "${issue.validation.endsWith}"`; } else { util.assertNever(issue.validation); } } else if (issue.validation !== "regex") { message = `Invalid ${issue.validation}`; } else { message = "Invalid"; } break; case ZodIssueCode.too_small: if (issue.type === "array") message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`; else if (issue.type === "string") message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`; else if (issue.type === "number") message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`; else if (issue.type === "date") message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`; else message = "Invalid input"; break; case ZodIssueCode.too_big: if (issue.type === "array") message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`; else if (issue.type === "string") message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`; else if (issue.type === "number") message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; else if (issue.type === "bigint") message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; else if (issue.type === "date") message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`; else message = "Invalid input"; break; case ZodIssueCode.custom: message = `Invalid input`; break; case ZodIssueCode.invalid_intersection_types: message = `Intersection results could not be merged`; break; case ZodIssueCode.not_multiple_of: message = `Number must be a multiple of ${issue.multipleOf}`; break; case ZodIssueCode.not_finite: message = "Number must be finite"; break; default: message = _ctx.defaultError; util.assertNever(issue); } return { message }; }; overrideErrorMap = errorMap; makeIssue = (params) => { const { data, path, errorMaps, issueData } = params; const fullPath = [...path, ...issueData.path || []]; const fullIssue = { ...issueData, path: fullPath }; if (issueData.message !== void 0) { return { ...issueData, path: fullPath, message: issueData.message }; } let errorMessage = ""; const maps = errorMaps.filter((m) => !!m).slice().reverse(); for (const map of maps) { errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message; } return { ...issueData, path: fullPath, message: errorMessage }; }; EMPTY_PATH = []; ParseStatus = class _ParseStatus { constructor() { this.value = "valid"; } dirty() { if (this.value === "valid") this.value = "dirty"; } abort() { if (this.value !== "aborted") this.value = "aborted"; } static mergeArray(status, results) { const arrayValue = []; for (const s of results) { if (s.status === "aborted") return INVALID; if (s.status === "dirty") status.dirty(); arrayValue.push(s.value); } return { status: status.value, value: arrayValue }; } static async mergeObjectAsync(status, pairs) { const syncPairs = []; for (const pair of pairs) { const key = await pair.key; const value = await pair.value; syncPairs.push({ key, value }); } return _ParseStatus.mergeObjectSync(status, syncPairs); } static mergeObjectSync(status, pairs) { const finalObject = {}; for (const pair of pairs) { const { key, value } = pair; if (key.status === "aborted") return INVALID; if (value.status === "aborted") return INVALID; if (key.status === "dirty") status.dirty(); if (value.status === "dirty") status.dirty(); if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) { finalObject[key.value] = value.value; } } return { status: status.value, value: finalObject }; } }; INVALID = Object.freeze({ status: "aborted" }); DIRTY = (value) => ({ status: "dirty", value }); OK = (value) => ({ status: "valid", value }); isAborted = (x) => x.status === "aborted"; isDirty = (x) => x.status === "dirty"; isValid = (x) => x.status === "valid"; isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise; (function(errorUtil2) { errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {}; errorUtil2.toString = (message) => typeof message === "string" ? message : message === null || message === void 0 ? void 0 : message.message; })(errorUtil || (errorUtil = {})); ParseInputLazyPath = class { constructor(parent, value, path, key) { this._cachedPath = []; this.parent = parent; this.data = value; this._path = path; this._key = key; } get path() { if (!this._cachedPath.length) { if (this._key instanceof Array) { this._cachedPath.push(...this._path, ...this._key); } else { this._cachedPath.push(...this._path, this._key); } } return this._cachedPath; } }; handleResult = (ctx, result) => { if (isValid(result)) { return { success: true, data: result.value }; } else { if (!ctx.common.issues.length) { throw new Error("Validation failed but no issues detected."); } return { success: false, get error() { if (this._error) return this._error; const error = new ZodError(ctx.common.issues); this._error = error; return this._error; } }; } }; ZodType = class { constructor(def) { this.spa = this.safeParseAsync; this._def = def; this.parse = this.parse.bind(this); this.safeParse = this.safeParse.bind(this); this.parseAsync = this.parseAsync.bind(this); this.safeParseAsync = this.safeParseAsync.bind(this); this.spa = this.spa.bind(this); this.refine = this.refine.bind(this); this.refinement = this.refinement.bind(this); this.superRefine = this.superRefine.bind(this); this.optional = this.optional.bind(this); this.nullable = this.nullable.bind(this); this.nullish = this.nullish.bind(this); this.array = this.array.bind(this); this.promise = this.promise.bind(this); this.or = this.or.bind(this); this.and = this.and.bind(this); this.transform = this.transform.bind(this); this.brand = this.brand.bind(this); this.default = this.default.bind(this); this.catch = this.catch.bind(this); this.describe = this.describe.bind(this); this.pipe = this.pipe.bind(this); this.readonly = this.readonly.bind(this); this.isNullable = this.isNullable.bind(this); this.isOptional = this.isOptional.bind(this); } get description() { return this._def.description; } _getType(input) { return getParsedType(input.data); } _getOrReturnCtx(input, ctx) { return ctx || { common: input.parent.common, data: input.data, parsedType: getParsedType(input.data), schemaErrorMap: this._def.errorMap, path: input.path, parent: input.parent }; } _processInputParams(input) { return { status: new ParseStatus(), ctx: { common: input.parent.common, data: input.data, parsedType: getParsedType(input.data), schemaErrorMap: this._def.errorMap, path: input.path, parent: input.parent } }; } _parseSync(input) { const result = this._parse(input); if (isAsync(result)) { throw new Error("Synchronous parse encountered promise."); } return result; } _parseAsync(input) { const result = this._parse(input); return Promise.resolve(result); } parse(data, params) { const result = this.safeParse(data, params); if (result.success) return result.data; throw result.error; } safeParse(data, params) { var _a; const ctx = { common: { issues: [], async: (_a = params === null || params === void 0 ? void 0 : params.async) !== null && _a !== void 0 ? _a : false, contextualErrorMap: params === null || params === void 0 ? void 0 : params.errorMap }, path: (params === null || params === void 0 ? void 0 : params.path) || [], schemaErrorMap: this._def.errorMap, parent: null, data, parsedType: getParsedType(data) }; const result = this._parseSync({ data, path: ctx.path, parent: ctx }); return handleResult(ctx, result); } async parseAsync(data, params) { const result = await this.safeParseAsync(data, params); if (result.success) return result.data; throw result.error; } async safeParseAsync(data, params) { const ctx = { common: { issues: [], contextualErrorMap: params === null || params === void 0 ? void 0 : params.errorMap, async: true }, path: (params === null || params === void 0 ? void 0 : params.path) || [], schemaErrorMap: this._def.errorMap, parent: null, data, parsedType: getParsedType(data) }; const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult)); return handleResult(ctx, result); } refine(check, message) { const getIssueProperties = (val) => { if (typeof message === "string" || typeof message === "undefined") { return { message }; } else if (typeof message === "function") { return message(val); } else { return message; } }; return this._refinement((val, ctx) => { const result = check(val); const setError = () => ctx.addIssue({ code: ZodIssueCode.custom, ...getIssueProperties(val) }); if (typeof Promise !== "undefined" && result instanceof Promise) { return result.then((data) => { if (!data) { setError(); return false; } else { return true; } }); } if (!result) { setError(); return false; } else { return true; } }); } refinement(check, refinementData) { return this._refinement((val, ctx) => { if (!check(val)) { ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData); return false; } else { return true; } }); } _refinement(refinement) { return new ZodEffects({ schema: this, typeName: ZodFirstPartyTypeKind.ZodEffects, effect: { type: "refinement", refinement } }); } superRefine(refinement) { return this._refinement(refinement); } optional() { return ZodOptional.create(this, this._def); } nullable() { return ZodNullable.create(this, this._def); } nullish() { return this.nullable().optional(); } array() { return ZodArray.create(this, this._def); } promise() { return ZodPromise.create(this, this._def); } or(option) { return ZodUnion.create([this, option], this._def); } and(incoming) { return ZodIntersection.create(this, incoming, this._def); } transform(transform) { return new ZodEffects({ ...processCreateParams(this._def), schema: this, typeName: ZodFirstPartyTypeKind.ZodEffects, effect: { type: "transform", transform } }); } default(def) { const defaultValueFunc = typeof def === "function" ? def : () => def; return new ZodDefault({ ...processCreateParams(this._def), innerType: this, defaultValue: defaultValueFunc, typeName: ZodFirstPartyTypeKind.ZodDefault }); } brand() { return new ZodBranded({ typeName: ZodFirstPartyTypeKind.ZodBranded, type: this, ...processCreateParams(this._def) }); } catch(def) { const catchValueFunc = typeof def === "function" ? def : () => def; return new ZodCatch({ ...processCreateParams(this._def), innerType: this, catchValue: catchValueFunc, typeName: ZodFirstPartyTypeKind.ZodCatch }); } describe(description) { const This = this.constructor; return new This({ ...this._def, description }); } pipe(target) { return ZodPipeline.create(this, target); } readonly() { return ZodReadonly.create(this); } isOptional() { return this.safeParse(void 0).success; } isNullable() { return this.safeParse(null).success; } }; cuidRegex = /^c[^\s-]{8,}$/i; cuid2Regex = /^[0-9a-z]+$/; ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/; uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i; nanoidRegex = /^[a-z0-9_-]{21}$/i; durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/; emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; ipv6Regex = /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`; dateRegex = new RegExp(`^${dateRegexSource}$`); ZodString = class _ZodString extends ZodType { _parse(input) { if (this._def.coerce) { input.data = String(input.data); } const parsedType = this._getType(input); if (parsedType !== ZodParsedType.string) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.string, received: ctx2.parsedType }); return INVALID; } const status = new ParseStatus(); let ctx = void 0; for (const check of this._def.checks) { if (check.kind === "min") { if (input.data.length < check.value) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: check.value, type: "string", inclusive: true, exact: false, message: check.message }); status.dirty(); } } else if (check.kind === "max") { if (input.data.length > check.value) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: check.value, type: "string", inclusive: true, exact: false, message: check.message }); status.dirty(); } } else if (check.kind === "length") { const tooBig = input.data.length > check.value; const tooSmall = input.data.length < check.value; if (tooBig || tooSmall) { ctx = this._getOrReturnCtx(input, ctx); if (tooBig) { addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: check.value, type: "string", inclusive: true, exact: true, message: check.message }); } else if (tooSmall) { addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: check.value, type: "string", inclusive: true, exact: true, message: check.message }); } status.dirty(); } } else if (check.kind === "email") { if (!emailRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "email", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "emoji") { if (!emojiRegex) { emojiRegex = new RegExp(_emojiRegex, "u"); } if (!emojiRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "emoji", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "uuid") { if (!uuidRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "uuid", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "nanoid") { if (!nanoidRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "nanoid", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "cuid") { if (!cuidRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "cuid", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "cuid2") { if (!cuid2Regex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "cuid2", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "ulid") { if (!ulidRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "ulid", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "url") { try { new URL(input.data); } catch (_a) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "url", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "regex") { check.regex.lastIndex = 0; const testResult = check.regex.test(input.data); if (!testResult) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "regex", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "trim") { input.data = input.data.trim(); } else if (check.kind === "includes") { if (!input.data.includes(check.value, check.position)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: { includes: check.value, position: check.position }, message: check.message }); status.dirty(); } } else if (check.kind === "toLowerCase") { input.data = input.data.toLowerCase(); } else if (check.kind === "toUpperCase") { input.data = input.data.toUpperCase(); } else if (check.kind === "startsWith") { if (!input.data.startsWith(check.value)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: { startsWith: check.value }, message: check.message }); status.dirty(); } } else if (check.kind === "endsWith") { if (!input.data.endsWith(check.value)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: { endsWith: check.value }, message: check.message }); status.dirty(); } } else if (check.kind === "datetime") { const regex = datetimeRegex(check); if (!regex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: "datetime", message: check.message }); status.dirty(); } } else if (check.kind === "date") { const regex = dateRegex; if (!regex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: "date", message: check.message }); status.dirty(); } } else if (check.kind === "time") { const regex = timeRegex(check); if (!regex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, validation: "time", message: check.message }); status.dirty(); } } else if (check.kind === "duration") { if (!durationRegex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "duration", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "ip") { if (!isValidIP(input.data, check.version)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "ip", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else if (check.kind === "base64") { if (!base64Regex.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { validation: "base64", code: ZodIssueCode.invalid_string, message: check.message }); status.dirty(); } } else { util.assertNever(check); } } return { status: status.value, value: input.data }; } _regex(regex, validation, message) { return this.refinement((data) => regex.test(data), { validation, code: ZodIssueCode.invalid_string, ...errorUtil.errToObj(message) }); } _addCheck(check) { return new _ZodString({ ...this._def, checks: [...this._def.checks, check] }); } email(message) { return this._addCheck({ kind: "email", ...errorUtil.errToObj(message) }); } url(message) { return this._addCheck({ kind: "url", ...errorUtil.errToObj(message) }); } emoji(message) { return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message) }); } uuid(message) { return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message) }); } nanoid(message) { return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message) }); } cuid(message) { return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) }); } cuid2(message) { return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) }); } ulid(message) { return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message) }); } base64(message) { return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) }); } ip(options) { return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) }); } datetime(options) { var _a, _b; if (typeof options === "string") { return this._addCheck({ kind: "datetime", precision: null, offset: false, local: false, message: options }); } return this._addCheck({ kind: "datetime", precision: typeof (options === null || options === void 0 ? void 0 : options.precision) === "undefined" ? null : options === null || options === void 0 ? void 0 : options.precision, offset: (_a = options === null || options === void 0 ? void 0 : options.offset) !== null && _a !== void 0 ? _a : false, local: (_b = options === null || options === void 0 ? void 0 : options.local) !== null && _b !== void 0 ? _b : false, ...errorUtil.errToObj(options === null || options === void 0 ? void 0 : options.message) }); } date(message) { return this._addCheck({ kind: "date", message }); } time(options) { if (typeof options === "string") { return this._addCheck({ kind: "time", precision: null, message: options }); } return this._addCheck({ kind: "time", precision: typeof (options === null || options === void 0 ? void 0 : options.precision) === "undefined" ? null : options === null || options === void 0 ? void 0 : options.precision, ...errorUtil.errToObj(options === null || options === void 0 ? void 0 : options.message) }); } duration(message) { return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) }); } regex(regex, message) { return this._addCheck({ kind: "regex", regex, ...errorUtil.errToObj(message) }); } includes(value, options) { return this._addCheck({ kind: "includes", value, position: options === null || options === void 0 ? void 0 : options.position, ...errorUtil.errToObj(options === null || options === void 0 ? void 0 : options.message) }); } startsWith(value, message) { return this._addCheck({ kind: "startsWith", value, ...errorUtil.errToObj(message) }); } endsWith(value, message) { return this._addCheck({ kind: "endsWith", value, ...errorUtil.errToObj(message) }); } min(minLength, message) { return this._addCheck({ kind: "min", value: minLength, ...errorUtil.errToObj(message) }); } max(maxLength, message) { return this._addCheck({ kind: "max", value: maxLength, ...errorUtil.errToObj(message) }); } length(len, message) { return this._addCheck({ kind: "length", value: len, ...errorUtil.errToObj(message) }); } /** * @deprecated Use z.string().min(1) instead. * @see {@link ZodString.min} */ nonempty(message) { return this.min(1, errorUtil.errToObj(message)); } trim() { return new _ZodString({ ...this._def, checks: [...this._def.checks, { kind: "trim" }] }); } toLowerCase() { return new _ZodString({ ...this._def, checks: [...this._def.checks, { kind: "toLowerCase" }] }); } toUpperCase() { return new _ZodString({ ...this._def, checks: [...this._def.checks, { kind: "toUpperCase" }] }); } get isDatetime() { return !!this._def.checks.find((ch) => ch.kind === "datetime"); } get isDate() { return !!this._def.checks.find((ch) => ch.kind === "date"); } get isTime() { return !!this._def.checks.find((ch) => ch.kind === "time"); } get isDuration() { return !!this._def.checks.find((ch) => ch.kind === "duration"); } get isEmail() { return !!this._def.checks.find((ch) => ch.kind === "email"); } get isURL() { return !!this._def.checks.find((ch) => ch.kind === "url"); } get isEmoji() { return !!this._def.checks.find((ch) => ch.kind === "emoji"); } get isUUID() { return !!this._def.checks.find((ch) => ch.kind === "uuid"); } get isNANOID() { return !!this._def.checks.find((ch) => ch.kind === "nanoid"); } get isCUID() { return !!this._def.checks.find((ch) => ch.kind === "cuid"); } get isCUID2() { return !!this._def.checks.find((ch) => ch.kind === "cuid2"); } get isULID() { return !!this._def.checks.find((ch) => ch.kind === "ulid"); } get isIP() { return !!this._def.checks.find((ch) => ch.kind === "ip"); } get isBase64() { return !!this._def.checks.find((ch) => ch.kind === "base64"); } get minLength() { let min = null; for (const ch of this._def.checks) { if (ch.kind === "min") { if (min === null || ch.value > min) min = ch.value; } } return min; } get maxLength() { let max = null; for (const ch of this._def.checks) { if (ch.kind === "max") { if (max === null || ch.value < max) max = ch.value; } } return max; } }; ZodString.create = (params) => { var _a; return new ZodString({ checks: [], typeName: ZodFirstPartyTypeKind.ZodString, coerce: (_a = params === null || params === void 0 ? void 0 : params.coerce) !== null && _a !== void 0 ? _a : false, ...processCreateParams(params) }); }; ZodNumber = class _ZodNumber extends ZodType { constructor() { super(...arguments); this.min = this.gte; this.max = this.lte; this.step = this.multipleOf; } _parse(input) { if (this._def.coerce) { input.data = Number(input.data); } const parsedType = this._getType(input); if (parsedType !== ZodParsedType.number) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.number, received: ctx2.parsedType }); return INVALID; } let ctx = void 0; const status = new ParseStatus(); for (const check of this._def.checks) { if (check.kind === "int") { if (!util.isInteger(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: "integer", received: "float", message: check.message }); status.dirty(); } } else if (check.kind === "min") { const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; if (tooSmall) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: check.value, type: "number", inclusive: check.inclusive, exact: false, message: check.message }); status.dirty(); } } else if (check.kind === "max") { const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; if (tooBig) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: check.value, type: "number", inclusive: check.inclusive, exact: false, message: check.message }); status.dirty(); } } else if (check.kind === "multipleOf") { if (floatSafeRemainder(input.data, check.value) !== 0) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.not_multiple_of, multipleOf: check.value, message: check.message }); status.dirty(); } } else if (check.kind === "finite") { if (!Number.isFinite(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.not_finite, message: check.message }); status.dirty(); } } else { util.assertNever(check); } } return { status: status.value, value: input.data }; } gte(value, message) { return this.setLimit("min", value, true, errorUtil.toString(message)); } gt(value, message) { return this.setLimit("min", value, false, errorUtil.toString(message)); } lte(value, message) { return this.setLimit("max", value, true, errorUtil.toString(message)); } lt(value, message) { return this.setLimit("max", value, false, errorUtil.toString(message)); } setLimit(kind, value, inclusive, message) { return new _ZodNumber({ ...this._def, checks: [ ...this._def.checks, { kind, value, inclusive, message: errorUtil.toString(message) } ] }); } _addCheck(check) { return new _ZodNumber({ ...this._def, checks: [...this._def.checks, check] }); } int(message) { return this._addCheck({ kind: "int", message: errorUtil.toString(message) }); } positive(message) { return this._addCheck({ kind: "min", value: 0, inclusive: false, message: errorUtil.toString(message) }); } negative(message) { return this._addCheck({ kind: "max", value: 0, inclusive: false, message: errorUtil.toString(message) }); } nonpositive(message) { return this._addCheck({ kind: "max", value: 0, inclusive: true, message: errorUtil.toString(message) }); } nonnegative(message) { return this._addCheck({ kind: "min", value: 0, inclusive: true, message: errorUtil.toString(message) }); } multipleOf(value, message) { return this._addCheck({ kind: "multipleOf", value, message: errorUtil.toString(message) }); } finite(message) { return this._addCheck({ kind: "finite", message: errorUtil.toString(message) }); } safe(message) { return this._addCheck({ kind: "min", inclusive: true, value: Number.MIN_SAFE_INTEGER, message: errorUtil.toString(message) })._addCheck({ kind: "max", inclusive: true, value: Number.MAX_SAFE_INTEGER, message: errorUtil.toString(message) }); } get minValue() { let min = null; for (const ch of this._def.checks) { if (ch.kind === "min") { if (min === null || ch.value > min) min = ch.value; } } return min; } get maxValue() { let max = null; for (const ch of this._def.checks) { if (ch.kind === "max") { if (max === null || ch.value < max) max = ch.value; } } return max; } get isInt() { return !!this._def.checks.find((ch) => ch.kind === "int" || ch.kind === "multipleOf" && util.isInteger(ch.value)); } get isFinite() { let max = null, min = null; for (const ch of this._def.checks) { if (ch.kind === "finite" || ch.kind === "int" || ch.kind === "multipleOf") { return true; } else if (ch.kind === "min") { if (min === null || ch.value > min) min = ch.value; } else if (ch.kind === "max") { if (max === null || ch.value < max) max = ch.value; } } return Number.isFinite(min) && Number.isFinite(max); } }; ZodNumber.create = (params) => { return new ZodNumber({ checks: [], typeName: ZodFirstPartyTypeKind.ZodNumber, coerce: (params === null || params === void 0 ? void 0 : params.coerce) || false, ...processCreateParams(params) }); }; ZodBigInt = class _ZodBigInt extends ZodType { constructor() { super(...arguments); this.min = this.gte; this.max = this.lte; } _parse(input) { if (this._def.coerce) { input.data = BigInt(input.data); } const parsedType = this._getType(input); if (parsedType !== ZodParsedType.bigint) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.bigint, received: ctx2.parsedType }); return INVALID; } let ctx = void 0; const status = new ParseStatus(); for (const check of this._def.checks) { if (check.kind === "min") { const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; if (tooSmall) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_small, type: "bigint", minimum: check.value, inclusive: check.inclusive, message: check.message }); status.dirty(); } } else if (check.kind === "max") { const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; if (tooBig) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_big, type: "bigint", maximum: check.value, inclusive: check.inclusive, message: check.message }); status.dirty(); } } else if (check.kind === "multipleOf") { if (input.data % check.value !== BigInt(0)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.not_multiple_of, multipleOf: check.value, message: check.message }); status.dirty(); } } else { util.assertNever(check); } } return { status: status.value, value: input.data }; } gte(value, message) { return this.setLimit("min", value, true, errorUtil.toString(message)); } gt(value, message) { return this.setLimit("min", value, false, errorUtil.toString(message)); } lte(value, message) { return this.setLimit("max", value, true, errorUtil.toString(message)); } lt(value, message) { return this.setLimit("max", value, false, errorUtil.toString(message)); } setLimit(kind, value, inclusive, message) { return new _ZodBigInt({ ...this._def, checks: [ ...this._def.checks, { kind, value, inclusive, message: errorUtil.toString(message) } ] }); } _addCheck(check) { return new _ZodBigInt({ ...this._def, checks: [...this._def.checks, check] }); } positive(message) { return this._addCheck({ kind: "min", value: BigInt(0), inclusive: false, message: errorUtil.toString(message) }); } negative(message) { return this._addCheck({ kind: "max", value: BigInt(0), inclusive: false, message: errorUtil.toString(message) }); } nonpositive(message) { return this._addCheck({ kind: "max", value: BigInt(0), inclusive: true, message: errorUtil.toString(message) }); } nonnegative(message) { return this._addCheck({ kind: "min", value: BigInt(0), inclusive: true, message: errorUtil.toString(message) }); } multipleOf(value, message) { return this._addCheck({ kind: "multipleOf", value, message: errorUtil.toString(message) }); } get minValue() { let min = null; for (const ch of this._def.checks) { if (ch.kind === "min") { if (min === null || ch.value > min) min = ch.value; } } return min; } get maxValue() { let max = null; for (const ch of this._def.checks) { if (ch.kind === "max") { if (max === null || ch.value < max) max = ch.value; } } return max; } }; ZodBigInt.create = (params) => { var _a; return new ZodBigInt({ checks: [], typeName: ZodFirstPartyTypeKind.ZodBigInt, coerce: (_a = params === null || params === void 0 ? void 0 : params.coerce) !== null && _a !== void 0 ? _a : false, ...processCreateParams(params) }); }; ZodBoolean = class extends ZodType { _parse(input) { if (this._def.coerce) { input.data = Boolean(input.data); } const parsedType = this._getType(input); if (parsedType !== ZodParsedType.boolean) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.boolean, received: ctx.parsedType }); return INVALID; } return OK(input.data); } }; ZodBoolean.create = (params) => { return new ZodBoolean({ typeName: ZodFirstPartyTypeKind.ZodBoolean, coerce: (params === null || params === void 0 ? void 0 : params.coerce) || false, ...processCreateParams(params) }); }; ZodDate = class _ZodDate extends ZodType { _parse(input) { if (this._def.coerce) { input.data = new Date(input.data); } const parsedType = this._getType(input); if (parsedType !== ZodParsedType.date) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.date, received: ctx2.parsedType }); return INVALID; } if (isNaN(input.data.getTime())) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_date }); return INVALID; } const status = new ParseStatus(); let ctx = void 0; for (const check of this._def.checks) { if (check.kind === "min") { if (input.data.getTime() < check.value) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_small, message: check.message, inclusive: true, exact: false, minimum: check.value, type: "date" }); status.dirty(); } } else if (check.kind === "max") { if (input.data.getTime() > check.value) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.too_big, message: check.message, inclusive: true, exact: false, maximum: check.value, type: "date" }); status.dirty(); } } else { util.assertNever(check); } } return { status: status.value, value: new Date(input.data.getTime()) }; } _addCheck(check) { return new _ZodDate({ ...this._def, checks: [...this._def.checks, check] }); } min(minDate, message) { return this._addCheck({ kind: "min", value: minDate.getTime(), message: errorUtil.toString(message) }); } max(maxDate, message) { return this._addCheck({ kind: "max", value: maxDate.getTime(), message: errorUtil.toString(message) }); } get minDate() { let min = null; for (const ch of this._def.checks) { if (ch.kind === "min") { if (min === null || ch.value > min) min = ch.value; } } return min != null ? new Date(min) : null; } get maxDate() { let max = null; for (const ch of this._def.checks) { if (ch.kind === "max") { if (max === null || ch.value < max) max = ch.value; } } return max != null ? new Date(max) : null; } }; ZodDate.create = (params) => { return new ZodDate({ checks: [], coerce: (params === null || params === void 0 ? void 0 : params.coerce) || false, typeName: ZodFirstPartyTypeKind.ZodDate, ...processCreateParams(params) }); }; ZodSymbol = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.symbol) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.symbol, received: ctx.parsedType }); return INVALID; } return OK(input.data); } }; ZodSymbol.create = (params) => { return new ZodSymbol({ typeName: ZodFirstPartyTypeKind.ZodSymbol, ...processCreateParams(params) }); }; ZodUndefined = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.undefined) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.undefined, received: ctx.parsedType }); return INVALID; } return OK(input.data); } }; ZodUndefined.create = (params) => { return new ZodUndefined({ typeName: ZodFirstPartyTypeKind.ZodUndefined, ...processCreateParams(params) }); }; ZodNull = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.null) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.null, received: ctx.parsedType }); return INVALID; } return OK(input.data); } }; ZodNull.create = (params) => { return new ZodNull({ typeName: ZodFirstPartyTypeKind.ZodNull, ...processCreateParams(params) }); }; ZodAny = class extends ZodType { constructor() { super(...arguments); this._any = true; } _parse(input) { return OK(input.data); } }; ZodAny.create = (params) => { return new ZodAny({ typeName: ZodFirstPartyTypeKind.ZodAny, ...processCreateParams(params) }); }; ZodUnknown = class extends ZodType { constructor() { super(...arguments); this._unknown = true; } _parse(input) { return OK(input.data); } }; ZodUnknown.create = (params) => { return new ZodUnknown({ typeName: ZodFirstPartyTypeKind.ZodUnknown, ...processCreateParams(params) }); }; ZodNever = class extends ZodType { _parse(input) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.never, received: ctx.parsedType }); return INVALID; } }; ZodNever.create = (params) => { return new ZodNever({ typeName: ZodFirstPartyTypeKind.ZodNever, ...processCreateParams(params) }); }; ZodVoid = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.undefined) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.void, received: ctx.parsedType }); return INVALID; } return OK(input.data); } }; ZodVoid.create = (params) => { return new ZodVoid({ typeName: ZodFirstPartyTypeKind.ZodVoid, ...processCreateParams(params) }); }; ZodArray = class _ZodArray extends ZodType { _parse(input) { const { ctx, status } = this._processInputParams(input); const def = this._def; if (ctx.parsedType !== ZodParsedType.array) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.array, received: ctx.parsedType }); return INVALID; } if (def.exactLength !== null) { const tooBig = ctx.data.length > def.exactLength.value; const tooSmall = ctx.data.length < def.exactLength.value; if (tooBig || tooSmall) { addIssueToContext(ctx, { code: tooBig ? ZodIssueCode.too_big : ZodIssueCode.too_small, minimum: tooSmall ? def.exactLength.value : void 0, maximum: tooBig ? def.exactLength.value : void 0, type: "array", inclusive: true, exact: true, message: def.exactLength.message }); status.dirty(); } } if (def.minLength !== null) { if (ctx.data.length < def.minLength.value) { addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: def.minLength.value, type: "array", inclusive: true, exact: false, message: def.minLength.message }); status.dirty(); } } if (def.maxLength !== null) { if (ctx.data.length > def.maxLength.value) { addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: def.maxLength.value, type: "array", inclusive: true, exact: false, message: def.maxLength.message }); status.dirty(); } } if (ctx.common.async) { return Promise.all([...ctx.data].map((item, i) => { return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i)); })).then((result2) => { return ParseStatus.mergeArray(status, result2); }); } const result = [...ctx.data].map((item, i) => { return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i)); }); return ParseStatus.mergeArray(status, result); } get element() { return this._def.type; } min(minLength, message) { return new _ZodArray({ ...this._def, minLength: { value: minLength, message: errorUtil.toString(message) } }); } max(maxLength, message) { return new _ZodArray({ ...this._def, maxLength: { value: maxLength, message: errorUtil.toString(message) } }); } length(len, message) { return new _ZodArray({ ...this._def, exactLength: { value: len, message: errorUtil.toString(message) } }); } nonempty(message) { return this.min(1, message); } }; ZodArray.create = (schema, params) => { return new ZodArray({ type: schema, minLength: null, maxLength: null, exactLength: null, typeName: ZodFirstPartyTypeKind.ZodArray, ...processCreateParams(params) }); }; ZodObject = class _ZodObject extends ZodType { constructor() { super(...arguments); this._cached = null; this.nonstrict = this.passthrough; this.augment = this.extend; } _getCached() { if (this._cached !== null) return this._cached; const shape = this._def.shape(); const keys = util.objectKeys(shape); return this._cached = { shape, keys }; } _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.object) { const ctx2 = this._getOrReturnCtx(input); addIssueToContext(ctx2, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.object, received: ctx2.parsedType }); return INVALID; } const { status, ctx } = this._processInputParams(input); const { shape, keys: shapeKeys } = this._getCached(); const extraKeys = []; if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) { for (const key in ctx.data) { if (!shapeKeys.includes(key)) { extraKeys.push(key); } } } const pairs = []; for (const key of shapeKeys) { const keyValidator = shape[key]; const value = ctx.data[key]; pairs.push({ key: { status: "valid", value: key }, value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)), alwaysSet: key in ctx.data }); } if (this._def.catchall instanceof ZodNever) { const unknownKeys = this._def.unknownKeys; if (unknownKeys === "passthrough") { for (const key of extraKeys) { pairs.push({ key: { status: "valid", value: key }, value: { status: "valid", value: ctx.data[key] } }); } } else if (unknownKeys === "strict") { if (extraKeys.length > 0) { addIssueToContext(ctx, { code: ZodIssueCode.unrecognized_keys, keys: extraKeys }); status.dirty(); } } else if (unknownKeys === "strip") ; else { throw new Error(`Internal ZodObject error: invalid unknownKeys value.`); } } else { const catchall = this._def.catchall; for (const key of extraKeys) { const value = ctx.data[key]; pairs.push({ key: { status: "valid", value: key }, value: catchall._parse( new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value) ), alwaysSet: key in ctx.data }); } } if (ctx.common.async) { return Promise.resolve().then(async () => { const syncPairs = []; for (const pair of pairs) { const key = await pair.key; const value = await pair.value; syncPairs.push({ key, value, alwaysSet: pair.alwaysSet }); } return syncPairs; }).then((syncPairs) => { return ParseStatus.mergeObjectSync(status, syncPairs); }); } else { return ParseStatus.mergeObjectSync(status, pairs); } } get shape() { return this._def.shape(); } strict(message) { errorUtil.errToObj; return new _ZodObject({ ...this._def, unknownKeys: "strict", ...message !== void 0 ? { errorMap: (issue, ctx) => { var _a, _b, _c, _d; const defaultError = (_c = (_b = (_a = this._def).errorMap) === null || _b === void 0 ? void 0 : _b.call(_a, issue, ctx).message) !== null && _c !== void 0 ? _c : ctx.defaultError; if (issue.code === "unrecognized_keys") return { message: (_d = errorUtil.errToObj(message).message) !== null && _d !== void 0 ? _d : defaultError }; return { message: defaultError }; } } : {} }); } strip() { return new _ZodObject({ ...this._def, unknownKeys: "strip" }); } passthrough() { return new _ZodObject({ ...this._def, unknownKeys: "passthrough" }); } // const AugmentFactory = // (def: Def) => // ( // augmentation: Augmentation // ): ZodObject< // extendShape, Augmentation>, // Def["unknownKeys"], // Def["catchall"] // > => { // return new ZodObject({ // ...def, // shape: () => ({ // ...def.shape(), // ...augmentation, // }), // }) as any; // }; extend(augmentation) { return new _ZodObject({ ...this._def, shape: () => ({ ...this._def.shape(), ...augmentation }) }); } /** * Prior to zod@1.0.12 there was a bug in the * inferred type of merged objects. Please * upgrade if you are experiencing issues. */ merge(merging) { const merged = new _ZodObject({ unknownKeys: merging._def.unknownKeys, catchall: merging._def.catchall, shape: () => ({ ...this._def.shape(), ...merging._def.shape() }), typeName: ZodFirstPartyTypeKind.ZodObject }); return merged; } // merge< // Incoming extends AnyZodObject, // Augmentation extends Incoming["shape"], // NewOutput extends { // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation // ? Augmentation[k]["_output"] // : k extends keyof Output // ? Output[k] // : never; // }, // NewInput extends { // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation // ? Augmentation[k]["_input"] // : k extends keyof Input // ? Input[k] // : never; // } // >( // merging: Incoming // ): ZodObject< // extendShape>, // Incoming["_def"]["unknownKeys"], // Incoming["_def"]["catchall"], // NewOutput, // NewInput // > { // const merged: any = new ZodObject({ // unknownKeys: merging._def.unknownKeys, // catchall: merging._def.catchall, // shape: () => // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), // typeName: ZodFirstPartyTypeKind.ZodObject, // }) as any; // return merged; // } setKey(key, schema) { return this.augment({ [key]: schema }); } // merge( // merging: Incoming // ): //ZodObject = (merging) => { // ZodObject< // extendShape>, // Incoming["_def"]["unknownKeys"], // Incoming["_def"]["catchall"] // > { // // const mergedShape = objectUtil.mergeShapes( // // this._def.shape(), // // merging._def.shape() // // ); // const merged: any = new ZodObject({ // unknownKeys: merging._def.unknownKeys, // catchall: merging._def.catchall, // shape: () => // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), // typeName: ZodFirstPartyTypeKind.ZodObject, // }) as any; // return merged; // } catchall(index) { return new _ZodObject({ ...this._def, catchall: index }); } pick(mask) { const shape = {}; util.objectKeys(mask).forEach((key) => { if (mask[key] && this.shape[key]) { shape[key] = this.shape[key]; } }); return new _ZodObject({ ...this._def, shape: () => shape }); } omit(mask) { const shape = {}; util.objectKeys(this.shape).forEach((key) => { if (!mask[key]) { shape[key] = this.shape[key]; } }); return new _ZodObject({ ...this._def, shape: () => shape }); } /** * @deprecated */ deepPartial() { return deepPartialify(this); } partial(mask) { const newShape = {}; util.objectKeys(this.shape).forEach((key) => { const fieldSchema = this.shape[key]; if (mask && !mask[key]) { newShape[key] = fieldSchema; } else { newShape[key] = fieldSchema.optional(); } }); return new _ZodObject({ ...this._def, shape: () => newShape }); } required(mask) { const newShape = {}; util.objectKeys(this.shape).forEach((key) => { if (mask && !mask[key]) { newShape[key] = this.shape[key]; } else { const fieldSchema = this.shape[key]; let newField = fieldSchema; while (newField instanceof ZodOptional) { newField = newField._def.innerType; } newShape[key] = newField; } }); return new _ZodObject({ ...this._def, shape: () => newShape }); } keyof() { return createZodEnum(util.objectKeys(this.shape)); } }; ZodObject.create = (shape, params) => { return new ZodObject({ shape: () => shape, unknownKeys: "strip", catchall: ZodNever.create(), typeName: ZodFirstPartyTypeKind.ZodObject, ...processCreateParams(params) }); }; ZodObject.strictCreate = (shape, params) => { return new ZodObject({ shape: () => shape, unknownKeys: "strict", catchall: ZodNever.create(), typeName: ZodFirstPartyTypeKind.ZodObject, ...processCreateParams(params) }); }; ZodObject.lazycreate = (shape, params) => { return new ZodObject({ shape, unknownKeys: "strip", catchall: ZodNever.create(), typeName: ZodFirstPartyTypeKind.ZodObject, ...processCreateParams(params) }); }; ZodUnion = class extends ZodType { _parse(input) { const { ctx } = this._processInputParams(input); const options = this._def.options; function handleResults(results) { for (const result of results) { if (result.result.status === "valid") { return result.result; } } for (const result of results) { if (result.result.status === "dirty") { ctx.common.issues.push(...result.ctx.common.issues); return result.result; } } const unionErrors = results.map((result) => new ZodError(result.ctx.common.issues)); addIssueToContext(ctx, { code: ZodIssueCode.invalid_union, unionErrors }); return INVALID; } if (ctx.common.async) { return Promise.all(options.map(async (option) => { const childCtx = { ...ctx, common: { ...ctx.common, issues: [] }, parent: null }; return { result: await option._parseAsync({ data: ctx.data, path: ctx.path, parent: childCtx }), ctx: childCtx }; })).then(handleResults); } else { let dirty = void 0; const issues = []; for (const option of options) { const childCtx = { ...ctx, common: { ...ctx.common, issues: [] }, parent: null }; const result = option._parseSync({ data: ctx.data, path: ctx.path, parent: childCtx }); if (result.status === "valid") { return result; } else if (result.status === "dirty" && !dirty) { dirty = { result, ctx: childCtx }; } if (childCtx.common.issues.length) { issues.push(childCtx.common.issues); } } if (dirty) { ctx.common.issues.push(...dirty.ctx.common.issues); return dirty.result; } const unionErrors = issues.map((issues2) => new ZodError(issues2)); addIssueToContext(ctx, { code: ZodIssueCode.invalid_union, unionErrors }); return INVALID; } } get options() { return this._def.options; } }; ZodUnion.create = (types, params) => { return new ZodUnion({ options: types, typeName: ZodFirstPartyTypeKind.ZodUnion, ...processCreateParams(params) }); }; getDiscriminator = (type) => { if (type instanceof ZodLazy) { return getDiscriminator(type.schema); } else if (type instanceof ZodEffects) { return getDiscriminator(type.innerType()); } else if (type instanceof ZodLiteral) { return [type.value]; } else if (type instanceof ZodEnum) { return type.options; } else if (type instanceof ZodNativeEnum) { return util.objectValues(type.enum); } else if (type instanceof ZodDefault) { return getDiscriminator(type._def.innerType); } else if (type instanceof ZodUndefined) { return [void 0]; } else if (type instanceof ZodNull) { return [null]; } else if (type instanceof ZodOptional) { return [void 0, ...getDiscriminator(type.unwrap())]; } else if (type instanceof ZodNullable) { return [null, ...getDiscriminator(type.unwrap())]; } else if (type instanceof ZodBranded) { return getDiscriminator(type.unwrap()); } else if (type instanceof ZodReadonly) { return getDiscriminator(type.unwrap()); } else if (type instanceof ZodCatch) { return getDiscriminator(type._def.innerType); } else { return []; } }; ZodDiscriminatedUnion = class _ZodDiscriminatedUnion extends ZodType { _parse(input) { const { ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.object) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.object, received: ctx.parsedType }); return INVALID; } const discriminator = this.discriminator; const discriminatorValue = ctx.data[discriminator]; const option = this.optionsMap.get(discriminatorValue); if (!option) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_union_discriminator, options: Array.from(this.optionsMap.keys()), path: [discriminator] }); return INVALID; } if (ctx.common.async) { return option._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }); } else { return option._parseSync({ data: ctx.data, path: ctx.path, parent: ctx }); } } get discriminator() { return this._def.discriminator; } get options() { return this._def.options; } get optionsMap() { return this._def.optionsMap; } /** * The constructor of the discriminated union schema. Its behaviour is very similar to that of the normal z.union() constructor. * However, it only allows a union of objects, all of which need to share a discriminator property. This property must * have a different value for each object in the union. * @param discriminator the name of the discriminator property * @param types an array of object schemas * @param params */ static create(discriminator, options, params) { const optionsMap = /* @__PURE__ */ new Map(); for (const type of options) { const discriminatorValues = getDiscriminator(type.shape[discriminator]); if (!discriminatorValues.length) { throw new Error(`A discriminator value for key \`${discriminator}\` could not be extracted from all schema options`); } for (const value of discriminatorValues) { if (optionsMap.has(value)) { throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`); } optionsMap.set(value, type); } } return new _ZodDiscriminatedUnion({ typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, discriminator, options, optionsMap, ...processCreateParams(params) }); } }; ZodIntersection = class extends ZodType { _parse(input) { const { status, ctx } = this._processInputParams(input); const handleParsed = (parsedLeft, parsedRight) => { if (isAborted(parsedLeft) || isAborted(parsedRight)) { return INVALID; } const merged = mergeValues(parsedLeft.value, parsedRight.value); if (!merged.valid) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_intersection_types }); return INVALID; } if (isDirty(parsedLeft) || isDirty(parsedRight)) { status.dirty(); } return { status: status.value, value: merged.data }; }; if (ctx.common.async) { return Promise.all([ this._def.left._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }), this._def.right._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }) ]).then(([left, right]) => handleParsed(left, right)); } else { return handleParsed(this._def.left._parseSync({ data: ctx.data, path: ctx.path, parent: ctx }), this._def.right._parseSync({ data: ctx.data, path: ctx.path, parent: ctx })); } } }; ZodIntersection.create = (left, right, params) => { return new ZodIntersection({ left, right, typeName: ZodFirstPartyTypeKind.ZodIntersection, ...processCreateParams(params) }); }; ZodTuple = class _ZodTuple extends ZodType { _parse(input) { const { status, ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.array) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.array, received: ctx.parsedType }); return INVALID; } if (ctx.data.length < this._def.items.length) { addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: this._def.items.length, inclusive: true, exact: false, type: "array" }); return INVALID; } const rest = this._def.rest; if (!rest && ctx.data.length > this._def.items.length) { addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: this._def.items.length, inclusive: true, exact: false, type: "array" }); status.dirty(); } const items = [...ctx.data].map((item, itemIndex) => { const schema = this._def.items[itemIndex] || this._def.rest; if (!schema) return null; return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)); }).filter((x) => !!x); if (ctx.common.async) { return Promise.all(items).then((results) => { return ParseStatus.mergeArray(status, results); }); } else { return ParseStatus.mergeArray(status, items); } } get items() { return this._def.items; } rest(rest) { return new _ZodTuple({ ...this._def, rest }); } }; ZodTuple.create = (schemas, params) => { if (!Array.isArray(schemas)) { throw new Error("You must pass an array of schemas to z.tuple([ ... ])"); } return new ZodTuple({ items: schemas, typeName: ZodFirstPartyTypeKind.ZodTuple, rest: null, ...processCreateParams(params) }); }; ZodRecord = class _ZodRecord extends ZodType { get keySchema() { return this._def.keyType; } get valueSchema() { return this._def.valueType; } _parse(input) { const { status, ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.object) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.object, received: ctx.parsedType }); return INVALID; } const pairs = []; const keyType = this._def.keyType; const valueType = this._def.valueType; for (const key in ctx.data) { pairs.push({ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)), value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)), alwaysSet: key in ctx.data }); } if (ctx.common.async) { return ParseStatus.mergeObjectAsync(status, pairs); } else { return ParseStatus.mergeObjectSync(status, pairs); } } get element() { return this._def.valueType; } static create(first, second, third) { if (second instanceof ZodType) { return new _ZodRecord({ keyType: first, valueType: second, typeName: ZodFirstPartyTypeKind.ZodRecord, ...processCreateParams(third) }); } return new _ZodRecord({ keyType: ZodString.create(), valueType: first, typeName: ZodFirstPartyTypeKind.ZodRecord, ...processCreateParams(second) }); } }; ZodMap = class extends ZodType { get keySchema() { return this._def.keyType; } get valueSchema() { return this._def.valueType; } _parse(input) { const { status, ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.map) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.map, received: ctx.parsedType }); return INVALID; } const keyType = this._def.keyType; const valueType = this._def.valueType; const pairs = [...ctx.data.entries()].map(([key, value], index) => { return { key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])), value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"])) }; }); if (ctx.common.async) { const finalMap = /* @__PURE__ */ new Map(); return Promise.resolve().then(async () => { for (const pair of pairs) { const key = await pair.key; const value = await pair.value; if (key.status === "aborted" || value.status === "aborted") { return INVALID; } if (key.status === "dirty" || value.status === "dirty") { status.dirty(); } finalMap.set(key.value, value.value); } return { status: status.value, value: finalMap }; }); } else { const finalMap = /* @__PURE__ */ new Map(); for (const pair of pairs) { const key = pair.key; const value = pair.value; if (key.status === "aborted" || value.status === "aborted") { return INVALID; } if (key.status === "dirty" || value.status === "dirty") { status.dirty(); } finalMap.set(key.value, value.value); } return { status: status.value, value: finalMap }; } } }; ZodMap.create = (keyType, valueType, params) => { return new ZodMap({ valueType, keyType, typeName: ZodFirstPartyTypeKind.ZodMap, ...processCreateParams(params) }); }; ZodSet = class _ZodSet extends ZodType { _parse(input) { const { status, ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.set) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.set, received: ctx.parsedType }); return INVALID; } const def = this._def; if (def.minSize !== null) { if (ctx.data.size < def.minSize.value) { addIssueToContext(ctx, { code: ZodIssueCode.too_small, minimum: def.minSize.value, type: "set", inclusive: true, exact: false, message: def.minSize.message }); status.dirty(); } } if (def.maxSize !== null) { if (ctx.data.size > def.maxSize.value) { addIssueToContext(ctx, { code: ZodIssueCode.too_big, maximum: def.maxSize.value, type: "set", inclusive: true, exact: false, message: def.maxSize.message }); status.dirty(); } } const valueType = this._def.valueType; function finalizeSet(elements2) { const parsedSet = /* @__PURE__ */ new Set(); for (const element of elements2) { if (element.status === "aborted") return INVALID; if (element.status === "dirty") status.dirty(); parsedSet.add(element.value); } return { status: status.value, value: parsedSet }; } const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i))); if (ctx.common.async) { return Promise.all(elements).then((elements2) => finalizeSet(elements2)); } else { return finalizeSet(elements); } } min(minSize, message) { return new _ZodSet({ ...this._def, minSize: { value: minSize, message: errorUtil.toString(message) } }); } max(maxSize, message) { return new _ZodSet({ ...this._def, maxSize: { value: maxSize, message: errorUtil.toString(message) } }); } size(size, message) { return this.min(size, message).max(size, message); } nonempty(message) { return this.min(1, message); } }; ZodSet.create = (valueType, params) => { return new ZodSet({ valueType, minSize: null, maxSize: null, typeName: ZodFirstPartyTypeKind.ZodSet, ...processCreateParams(params) }); }; ZodFunction = class _ZodFunction extends ZodType { constructor() { super(...arguments); this.validate = this.implement; } _parse(input) { const { ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.function) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.function, received: ctx.parsedType }); return INVALID; } function makeArgsIssue(args, error) { return makeIssue({ data: args, path: ctx.path, errorMaps: [ ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), errorMap ].filter((x) => !!x), issueData: { code: ZodIssueCode.invalid_arguments, argumentsError: error } }); } function makeReturnsIssue(returns, error) { return makeIssue({ data: returns, path: ctx.path, errorMaps: [ ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), errorMap ].filter((x) => !!x), issueData: { code: ZodIssueCode.invalid_return_type, returnTypeError: error } }); } const params = { errorMap: ctx.common.contextualErrorMap }; const fn = ctx.data; if (this._def.returns instanceof ZodPromise) { const me = this; return OK(async function(...args) { const error = new ZodError([]); const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => { error.addIssue(makeArgsIssue(args, e)); throw error; }); const result = await Reflect.apply(fn, this, parsedArgs); const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e) => { error.addIssue(makeReturnsIssue(result, e)); throw error; }); return parsedReturns; }); } else { const me = this; return OK(function(...args) { const parsedArgs = me._def.args.safeParse(args, params); if (!parsedArgs.success) { throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); } const result = Reflect.apply(fn, this, parsedArgs.data); const parsedReturns = me._def.returns.safeParse(result, params); if (!parsedReturns.success) { throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); } return parsedReturns.data; }); } } parameters() { return this._def.args; } returnType() { return this._def.returns; } args(...items) { return new _ZodFunction({ ...this._def, args: ZodTuple.create(items).rest(ZodUnknown.create()) }); } returns(returnType) { return new _ZodFunction({ ...this._def, returns: returnType }); } implement(func) { const validatedFunc = this.parse(func); return validatedFunc; } strictImplement(func) { const validatedFunc = this.parse(func); return validatedFunc; } static create(args, returns, params) { return new _ZodFunction({ args: args ? args : ZodTuple.create([]).rest(ZodUnknown.create()), returns: returns || ZodUnknown.create(), typeName: ZodFirstPartyTypeKind.ZodFunction, ...processCreateParams(params) }); } }; ZodLazy = class extends ZodType { get schema() { return this._def.getter(); } _parse(input) { const { ctx } = this._processInputParams(input); const lazySchema = this._def.getter(); return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx }); } }; ZodLazy.create = (getter, params) => { return new ZodLazy({ getter, typeName: ZodFirstPartyTypeKind.ZodLazy, ...processCreateParams(params) }); }; ZodLiteral = class extends ZodType { _parse(input) { if (input.data !== this._def.value) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { received: ctx.data, code: ZodIssueCode.invalid_literal, expected: this._def.value }); return INVALID; } return { status: "valid", value: input.data }; } get value() { return this._def.value; } }; ZodLiteral.create = (value, params) => { return new ZodLiteral({ value, typeName: ZodFirstPartyTypeKind.ZodLiteral, ...processCreateParams(params) }); }; ZodEnum = class _ZodEnum extends ZodType { constructor() { super(...arguments); _ZodEnum_cache.set(this, void 0); } _parse(input) { if (typeof input.data !== "string") { const ctx = this._getOrReturnCtx(input); const expectedValues = this._def.values; addIssueToContext(ctx, { expected: util.joinValues(expectedValues), received: ctx.parsedType, code: ZodIssueCode.invalid_type }); return INVALID; } if (!__classPrivateFieldGet(this, _ZodEnum_cache, "f")) { __classPrivateFieldSet(this, _ZodEnum_cache, new Set(this._def.values), "f"); } if (!__classPrivateFieldGet(this, _ZodEnum_cache, "f").has(input.data)) { const ctx = this._getOrReturnCtx(input); const expectedValues = this._def.values; addIssueToContext(ctx, { received: ctx.data, code: ZodIssueCode.invalid_enum_value, options: expectedValues }); return INVALID; } return OK(input.data); } get options() { return this._def.values; } get enum() { const enumValues = {}; for (const val of this._def.values) { enumValues[val] = val; } return enumValues; } get Values() { const enumValues = {}; for (const val of this._def.values) { enumValues[val] = val; } return enumValues; } get Enum() { const enumValues = {}; for (const val of this._def.values) { enumValues[val] = val; } return enumValues; } extract(values, newDef = this._def) { return _ZodEnum.create(values, { ...this._def, ...newDef }); } exclude(values, newDef = this._def) { return _ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), { ...this._def, ...newDef }); } }; _ZodEnum_cache = /* @__PURE__ */ new WeakMap(); ZodEnum.create = createZodEnum; ZodNativeEnum = class extends ZodType { constructor() { super(...arguments); _ZodNativeEnum_cache.set(this, void 0); } _parse(input) { const nativeEnumValues = util.getValidEnumValues(this._def.values); const ctx = this._getOrReturnCtx(input); if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) { const expectedValues = util.objectValues(nativeEnumValues); addIssueToContext(ctx, { expected: util.joinValues(expectedValues), received: ctx.parsedType, code: ZodIssueCode.invalid_type }); return INVALID; } if (!__classPrivateFieldGet(this, _ZodNativeEnum_cache, "f")) { __classPrivateFieldSet(this, _ZodNativeEnum_cache, new Set(util.getValidEnumValues(this._def.values)), "f"); } if (!__classPrivateFieldGet(this, _ZodNativeEnum_cache, "f").has(input.data)) { const expectedValues = util.objectValues(nativeEnumValues); addIssueToContext(ctx, { received: ctx.data, code: ZodIssueCode.invalid_enum_value, options: expectedValues }); return INVALID; } return OK(input.data); } get enum() { return this._def.values; } }; _ZodNativeEnum_cache = /* @__PURE__ */ new WeakMap(); ZodNativeEnum.create = (values, params) => { return new ZodNativeEnum({ values, typeName: ZodFirstPartyTypeKind.ZodNativeEnum, ...processCreateParams(params) }); }; ZodPromise = class extends ZodType { unwrap() { return this._def.type; } _parse(input) { const { ctx } = this._processInputParams(input); if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) { addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.promise, received: ctx.parsedType }); return INVALID; } const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data); return OK(promisified.then((data) => { return this._def.type.parseAsync(data, { path: ctx.path, errorMap: ctx.common.contextualErrorMap }); })); } }; ZodPromise.create = (schema, params) => { return new ZodPromise({ type: schema, typeName: ZodFirstPartyTypeKind.ZodPromise, ...processCreateParams(params) }); }; ZodEffects = class extends ZodType { innerType() { return this._def.schema; } sourceType() { return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects ? this._def.schema.sourceType() : this._def.schema; } _parse(input) { const { status, ctx } = this._processInputParams(input); const effect = this._def.effect || null; const checkCtx = { addIssue: (arg) => { addIssueToContext(ctx, arg); if (arg.fatal) { status.abort(); } else { status.dirty(); } }, get path() { return ctx.path; } }; checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx); if (effect.type === "preprocess") { const processed = effect.transform(ctx.data, checkCtx); if (ctx.common.async) { return Promise.resolve(processed).then(async (processed2) => { if (status.value === "aborted") return INVALID; const result = await this._def.schema._parseAsync({ data: processed2, path: ctx.path, parent: ctx }); if (result.status === "aborted") return INVALID; if (result.status === "dirty") return DIRTY(result.value); if (status.value === "dirty") return DIRTY(result.value); return result; }); } else { if (status.value === "aborted") return INVALID; const result = this._def.schema._parseSync({ data: processed, path: ctx.path, parent: ctx }); if (result.status === "aborted") return INVALID; if (result.status === "dirty") return DIRTY(result.value); if (status.value === "dirty") return DIRTY(result.value); return result; } } if (effect.type === "refinement") { const executeRefinement = (acc) => { const result = effect.refinement(acc, checkCtx); if (ctx.common.async) { return Promise.resolve(result); } if (result instanceof Promise) { throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead."); } return acc; }; if (ctx.common.async === false) { const inner = this._def.schema._parseSync({ data: ctx.data, path: ctx.path, parent: ctx }); if (inner.status === "aborted") return INVALID; if (inner.status === "dirty") status.dirty(); executeRefinement(inner.value); return { status: status.value, value: inner.value }; } else { return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => { if (inner.status === "aborted") return INVALID; if (inner.status === "dirty") status.dirty(); return executeRefinement(inner.value).then(() => { return { status: status.value, value: inner.value }; }); }); } } if (effect.type === "transform") { if (ctx.common.async === false) { const base = this._def.schema._parseSync({ data: ctx.data, path: ctx.path, parent: ctx }); if (!isValid(base)) return base; const result = effect.transform(base.value, checkCtx); if (result instanceof Promise) { throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`); } return { status: status.value, value: result }; } else { return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => { if (!isValid(base)) return base; return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({ status: status.value, value: result })); }); } } util.assertNever(effect); } }; ZodEffects.create = (schema, effect, params) => { return new ZodEffects({ schema, typeName: ZodFirstPartyTypeKind.ZodEffects, effect, ...processCreateParams(params) }); }; ZodEffects.createWithPreprocess = (preprocess, schema, params) => { return new ZodEffects({ schema, effect: { type: "preprocess", transform: preprocess }, typeName: ZodFirstPartyTypeKind.ZodEffects, ...processCreateParams(params) }); }; ZodOptional = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType === ZodParsedType.undefined) { return OK(void 0); } return this._def.innerType._parse(input); } unwrap() { return this._def.innerType; } }; ZodOptional.create = (type, params) => { return new ZodOptional({ innerType: type, typeName: ZodFirstPartyTypeKind.ZodOptional, ...processCreateParams(params) }); }; ZodNullable = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType === ZodParsedType.null) { return OK(null); } return this._def.innerType._parse(input); } unwrap() { return this._def.innerType; } }; ZodNullable.create = (type, params) => { return new ZodNullable({ innerType: type, typeName: ZodFirstPartyTypeKind.ZodNullable, ...processCreateParams(params) }); }; ZodDefault = class extends ZodType { _parse(input) { const { ctx } = this._processInputParams(input); let data = ctx.data; if (ctx.parsedType === ZodParsedType.undefined) { data = this._def.defaultValue(); } return this._def.innerType._parse({ data, path: ctx.path, parent: ctx }); } removeDefault() { return this._def.innerType; } }; ZodDefault.create = (type, params) => { return new ZodDefault({ innerType: type, typeName: ZodFirstPartyTypeKind.ZodDefault, defaultValue: typeof params.default === "function" ? params.default : () => params.default, ...processCreateParams(params) }); }; ZodCatch = class extends ZodType { _parse(input) { const { ctx } = this._processInputParams(input); const newCtx = { ...ctx, common: { ...ctx.common, issues: [] } }; const result = this._def.innerType._parse({ data: newCtx.data, path: newCtx.path, parent: { ...newCtx } }); if (isAsync(result)) { return result.then((result2) => { return { status: "valid", value: result2.status === "valid" ? result2.value : this._def.catchValue({ get error() { return new ZodError(newCtx.common.issues); }, input: newCtx.data }) }; }); } else { return { status: "valid", value: result.status === "valid" ? result.value : this._def.catchValue({ get error() { return new ZodError(newCtx.common.issues); }, input: newCtx.data }) }; } } removeCatch() { return this._def.innerType; } }; ZodCatch.create = (type, params) => { return new ZodCatch({ innerType: type, typeName: ZodFirstPartyTypeKind.ZodCatch, catchValue: typeof params.catch === "function" ? params.catch : () => params.catch, ...processCreateParams(params) }); }; ZodNaN = class extends ZodType { _parse(input) { const parsedType = this._getType(input); if (parsedType !== ZodParsedType.nan) { const ctx = this._getOrReturnCtx(input); addIssueToContext(ctx, { code: ZodIssueCode.invalid_type, expected: ZodParsedType.nan, received: ctx.parsedType }); return INVALID; } return { status: "valid", value: input.data }; } }; ZodNaN.create = (params) => { return new ZodNaN({ typeName: ZodFirstPartyTypeKind.ZodNaN, ...processCreateParams(params) }); }; BRAND = Symbol("zod_brand"); ZodBranded = class extends ZodType { _parse(input) { const { ctx } = this._processInputParams(input); const data = ctx.data; return this._def.type._parse({ data, path: ctx.path, parent: ctx }); } unwrap() { return this._def.type; } }; ZodPipeline = class _ZodPipeline extends ZodType { _parse(input) { const { status, ctx } = this._processInputParams(input); if (ctx.common.async) { const handleAsync = async () => { const inResult = await this._def.in._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }); if (inResult.status === "aborted") return INVALID; if (inResult.status === "dirty") { status.dirty(); return DIRTY(inResult.value); } else { return this._def.out._parseAsync({ data: inResult.value, path: ctx.path, parent: ctx }); } }; return handleAsync(); } else { const inResult = this._def.in._parseSync({ data: ctx.data, path: ctx.path, parent: ctx }); if (inResult.status === "aborted") return INVALID; if (inResult.status === "dirty") { status.dirty(); return { status: "dirty", value: inResult.value }; } else { return this._def.out._parseSync({ data: inResult.value, path: ctx.path, parent: ctx }); } } } static create(a, b) { return new _ZodPipeline({ in: a, out: b, typeName: ZodFirstPartyTypeKind.ZodPipeline }); } }; ZodReadonly = class extends ZodType { _parse(input) { const result = this._def.innerType._parse(input); const freeze = (data) => { if (isValid(data)) { data.value = Object.freeze(data.value); } return data; }; return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result); } unwrap() { return this._def.innerType; } }; ZodReadonly.create = (type, params) => { return new ZodReadonly({ innerType: type, typeName: ZodFirstPartyTypeKind.ZodReadonly, ...processCreateParams(params) }); }; late = { object: ZodObject.lazycreate }; (function(ZodFirstPartyTypeKind2) { ZodFirstPartyTypeKind2["ZodString"] = "ZodString"; ZodFirstPartyTypeKind2["ZodNumber"] = "ZodNumber"; ZodFirstPartyTypeKind2["ZodNaN"] = "ZodNaN"; ZodFirstPartyTypeKind2["ZodBigInt"] = "ZodBigInt"; ZodFirstPartyTypeKind2["ZodBoolean"] = "ZodBoolean"; ZodFirstPartyTypeKind2["ZodDate"] = "ZodDate"; ZodFirstPartyTypeKind2["ZodSymbol"] = "ZodSymbol"; ZodFirstPartyTypeKind2["ZodUndefined"] = "ZodUndefined"; ZodFirstPartyTypeKind2["ZodNull"] = "ZodNull"; ZodFirstPartyTypeKind2["ZodAny"] = "ZodAny"; ZodFirstPartyTypeKind2["ZodUnknown"] = "ZodUnknown"; ZodFirstPartyTypeKind2["ZodNever"] = "ZodNever"; ZodFirstPartyTypeKind2["ZodVoid"] = "ZodVoid"; ZodFirstPartyTypeKind2["ZodArray"] = "ZodArray"; ZodFirstPartyTypeKind2["ZodObject"] = "ZodObject"; ZodFirstPartyTypeKind2["ZodUnion"] = "ZodUnion"; ZodFirstPartyTypeKind2["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion"; ZodFirstPartyTypeKind2["ZodIntersection"] = "ZodIntersection"; ZodFirstPartyTypeKind2["ZodTuple"] = "ZodTuple"; ZodFirstPartyTypeKind2["ZodRecord"] = "ZodRecord"; ZodFirstPartyTypeKind2["ZodMap"] = "ZodMap"; ZodFirstPartyTypeKind2["ZodSet"] = "ZodSet"; ZodFirstPartyTypeKind2["ZodFunction"] = "ZodFunction"; ZodFirstPartyTypeKind2["ZodLazy"] = "ZodLazy"; ZodFirstPartyTypeKind2["ZodLiteral"] = "ZodLiteral"; ZodFirstPartyTypeKind2["ZodEnum"] = "ZodEnum"; ZodFirstPartyTypeKind2["ZodEffects"] = "ZodEffects"; ZodFirstPartyTypeKind2["ZodNativeEnum"] = "ZodNativeEnum"; ZodFirstPartyTypeKind2["ZodOptional"] = "ZodOptional"; ZodFirstPartyTypeKind2["ZodNullable"] = "ZodNullable"; ZodFirstPartyTypeKind2["ZodDefault"] = "ZodDefault"; ZodFirstPartyTypeKind2["ZodCatch"] = "ZodCatch"; ZodFirstPartyTypeKind2["ZodPromise"] = "ZodPromise"; ZodFirstPartyTypeKind2["ZodBranded"] = "ZodBranded"; ZodFirstPartyTypeKind2["ZodPipeline"] = "ZodPipeline"; ZodFirstPartyTypeKind2["ZodReadonly"] = "ZodReadonly"; })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {})); instanceOfType = (cls, params = { message: `Input not instance of ${cls.name}` }) => custom((data) => data instanceof cls, params); stringType = ZodString.create; numberType = ZodNumber.create; nanType = ZodNaN.create; bigIntType = ZodBigInt.create; booleanType = ZodBoolean.create; dateType = ZodDate.create; symbolType = ZodSymbol.create; undefinedType = ZodUndefined.create; nullType = ZodNull.create; anyType = ZodAny.create; unknownType = ZodUnknown.create; neverType = ZodNever.create; voidType = ZodVoid.create; arrayType = ZodArray.create; objectType = ZodObject.create; strictObjectType = ZodObject.strictCreate; unionType = ZodUnion.create; discriminatedUnionType = ZodDiscriminatedUnion.create; intersectionType = ZodIntersection.create; tupleType = ZodTuple.create; recordType = ZodRecord.create; mapType = ZodMap.create; setType = ZodSet.create; functionType = ZodFunction.create; lazyType = ZodLazy.create; literalType = ZodLiteral.create; enumType = ZodEnum.create; nativeEnumType = ZodNativeEnum.create; promiseType = ZodPromise.create; effectsType = ZodEffects.create; optionalType = ZodOptional.create; nullableType = ZodNullable.create; preprocessType = ZodEffects.createWithPreprocess; pipelineType = ZodPipeline.create; ostring = () => stringType().optional(); onumber = () => numberType().optional(); oboolean = () => booleanType().optional(); coerce = { string: (arg) => ZodString.create({ ...arg, coerce: true }), number: (arg) => ZodNumber.create({ ...arg, coerce: true }), boolean: (arg) => ZodBoolean.create({ ...arg, coerce: true }), bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }), date: (arg) => ZodDate.create({ ...arg, coerce: true }) }; NEVER = INVALID; z = /* @__PURE__ */ Object.freeze({ __proto__: null, defaultErrorMap: errorMap, setErrorMap, getErrorMap, makeIssue, EMPTY_PATH, addIssueToContext, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, get util() { return util; }, get objectUtil() { return objectUtil; }, ZodParsedType, getParsedType, ZodType, datetimeRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodTransformer: ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, BRAND, ZodBranded, ZodPipeline, ZodReadonly, custom, Schema: ZodType, ZodSchema: ZodType, late, get ZodFirstPartyTypeKind() { return ZodFirstPartyTypeKind; }, coerce, any: anyType, array: arrayType, bigint: bigIntType, boolean: booleanType, date: dateType, discriminatedUnion: discriminatedUnionType, effect: effectsType, "enum": enumType, "function": functionType, "instanceof": instanceOfType, intersection: intersectionType, lazy: lazyType, literal: literalType, map: mapType, nan: nanType, nativeEnum: nativeEnumType, never: neverType, "null": nullType, nullable: nullableType, number: numberType, object: objectType, oboolean, onumber, optional: optionalType, ostring, pipeline: pipelineType, preprocess: preprocessType, promise: promiseType, record: recordType, set: setType, strictObject: strictObjectType, string: stringType, symbol: symbolType, transformer: effectsType, tuple: tupleType, "undefined": undefinedType, union: unionType, unknown: unknownType, "void": voidType, NEVER, ZodIssueCode, quotelessJson, ZodError }); } }); // cypher-executor/src/lib/prompt-recipe-schema.ts var TransformSchema, KBDBBlockFragmentSchema, KVFragmentSchema, FragmentSchema, InputSchema, PromptAssemblySchema, OutputSpecSchema, PromptRecipeSchema; var init_prompt_recipe_schema = __esm({ "cypher-executor/src/lib/prompt-recipe-schema.ts"() { "use strict"; init_lib(); TransformSchema = z.string().regex(/^[a-z_]+(:.+)?$/, "transform \u5FC5\u9808\u70BA name \u6216 name:arg \u683C\u5F0F"); KBDBBlockFragmentSchema = z.object({ var: z.string().min(1), // prompt template 內的變數名 source: z.literal("kbdb_block"), block_id: z.string().optional(), // 二擇一 block_page_name: z.string().optional(), // 比 block_id 穩定 field: z.string().default("content") // 抓 block 的哪個欄位 }); KVFragmentSchema = z.object({ var: z.string().min(1), source: z.literal("kv"), key: z.string().min(1) }); FragmentSchema = z.discriminatedUnion("source", [ KBDBBlockFragmentSchema, KVFragmentSchema ]).superRefine((d, ctx) => { if (d.source === "kbdb_block" && !d.block_id && !d.block_page_name) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "block_id \u6216 block_page_name \u5FC5\u586B\u5176\u4E00" }); } }); InputSchema = z.object({ var: z.string().min(1), from: z.string().min(1), // JSONPath-lite,如 "ctx.read_drafts.blocks" transform: TransformSchema.optional(), default: z.unknown().optional() // from 取不到時的預設值(避免炸 prompt) }); PromptAssemblySchema = z.object({ system: z.string().min(1), // 模板,可含 {{var}} user: z.string().min(1) }); OutputSpecSchema = z.object({ format: z.enum(["text", "json"]).default("text"), // 若 format=json,可選 schema 做 parse 後驗證(簡化版,列必填欄位即可) required_fields: z.array(z.string()).optional() }); PromptRecipeSchema = z.object({ kind: z.literal("prompt_recipe"), name: z.string().min(1).regex(/^[a-z][a-z0-9_]*$/, "name \u70BA lowercase + underscore"), version: z.number().int().positive().default(1), description: z.string().optional(), model: z.enum(["haiku", "sonnet", "opus"]).default("sonnet"), fragments: z.array(FragmentSchema).default([]), inputs: z.array(InputSchema).default([]), prompt_assembly: PromptAssemblySchema, output: OutputSpecSchema.default({ format: "text" }) }); } }); // cypher-executor/src/lib/recipe-loader.ts async function loadPromptRecipe(recipeRef, recipesKv) { const key = recipeRef.startsWith("prompt_recipe:") ? recipeRef : `prompt_recipe:${recipeRef}`; const raw2 = await recipesKv.get(key); if (!raw2) { throw new RecipeLoadError(`\u627E\u4E0D\u5230 recipe: ${key}`, key); } let parsed; try { parsed = JSON.parse(raw2); } catch (e) { throw new RecipeLoadError( `recipe ${key} \u4E0D\u662F\u5408\u6CD5 JSON: ${e instanceof Error ? e.message : String(e)}`, key ); } const result = PromptRecipeSchema.safeParse(parsed); if (!result.success) { const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "); throw new RecipeLoadError(`recipe ${key} schema \u9A57\u8B49\u5931\u6557: ${issues}`, key); } return result.data; } var RecipeLoadError; var init_recipe_loader = __esm({ "cypher-executor/src/lib/recipe-loader.ts"() { "use strict"; init_prompt_recipe_schema(); RecipeLoadError = class extends Error { constructor(message, recipe) { super(message); this.recipe = recipe; } }; } }); // cypher-executor/src/lib/recipe-transforms.ts function applyTransform(value, spec) { const colonIdx = spec.indexOf(":"); const name = colonIdx === -1 ? spec : spec.slice(0, colonIdx); const arg = colonIdx === -1 ? void 0 : spec.slice(colonIdx + 1); const fn = transforms[name]; if (!fn) throw new Error(`\u672A\u77E5 transform: ${name}`); return fn(value, arg); } var transforms; var init_recipe_transforms = __esm({ "cypher-executor/src/lib/recipe-transforms.ts"() { "use strict"; transforms = { json_array: (v) => JSON.stringify(v ?? []), to_string: (v) => { if (v === null || v === void 0) return ""; if (typeof v === "object") return JSON.stringify(v); return String(v); }, join: (v, sep) => { if (!Array.isArray(v)) throw new Error("join: input \u4E0D\u662F array"); return v.map((x) => typeof x === "string" ? x : JSON.stringify(x)).join(sep ?? "\n"); }, markdown_list: (v) => { if (!Array.isArray(v)) throw new Error("markdown_list: input \u4E0D\u662F array"); return v.map((x) => `- ${typeof x === "string" ? x : JSON.stringify(x)}`).join("\n"); }, extract_field: (v, field) => { if (!field) throw new Error("extract_field: \u9700\u8981 field \u53C3\u6578\uFF0C\u4F8B\u5982 extract_field:page_name"); if (!Array.isArray(v)) throw new Error("extract_field: input \u4E0D\u662F array"); return v.map((x) => x && typeof x === "object" ? x[field] : void 0); }, first: (v) => { if (!Array.isArray(v)) return v; return v[0]; }, pluck_content: (v) => { if (!Array.isArray(v)) throw new Error("pluck_content: input \u4E0D\u662F array"); return v.map((b) => b && typeof b === "object" ? String(b.content ?? "") : "").filter((s) => s.length > 0).join("\n\n---\n\n"); } }; } }); // cypher-executor/src/lib/recipe-expander.ts function getByPath(ctx, path) { const parts = path.split("."); let cur = ctx; for (const p of parts) { if (cur === null || cur === void 0) return void 0; if (typeof cur !== "object") return void 0; cur = cur[p]; } return cur; } function interpolate(template, vars) { return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] !== void 0 ? vars[key] : `{{${key}}}`); } async function fetchKbdbBlock(env, apiKey, fragment) { const base = (env.KBDB_BASE_URL ?? "https://kbdb.finally.click").replace(/\/$/, ""); let url; if (fragment.block_id) { url = `${base}/blocks/${encodeURIComponent(fragment.block_id)}`; } else { url = `${base}/blocks?page_name=${encodeURIComponent(fragment.block_page_name)}&limit=1`; } const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } }); if (!res.ok) throw new Error(`KBDB fragment \u6293\u53D6\u5931\u6557 (${res.status}): ${url}`); const data = await res.json(); const block = fragment.block_id ? data : data.blocks?.[0] ?? {}; if (!block) throw new Error(`KBDB block \u4E0D\u5B58\u5728: ${fragment.block_id ?? fragment.block_page_name}`); const fieldVal = block[fragment.field]; if (fieldVal === void 0) throw new Error(`block \u7F3A\u6B04\u4F4D "${fragment.field}"`); return fieldVal; } async function resolveFragment(env, apiKey, frag) { if (frag.source === "kv") { const val = await env.RECIPES.get(frag.key); if (val === null) throw new Error(`KV \u627E\u4E0D\u5230 key: ${frag.key}`); return { var: frag.var, value: val }; } return { var: frag.var, value: await fetchKbdbBlock(env, apiKey, frag) }; } function resolveInput(input, ctx) { let val = getByPath(ctx, input.from); const beforeDefault = val; if (val === void 0) val = input.default; try { if (input.transform) val = applyTransform(val, input.transform); return { var: input.var, value: val }; } catch (e) { const valType = Array.isArray(beforeDefault) ? `array(${beforeDefault.length})` : beforeDefault === void 0 ? "undefined(default applied)" : typeof beforeDefault; throw new Error(`${e instanceof Error ? e.message : String(e)} [path=${input.from}, type=${valType}]`); } } async function expandPromptRecipe(recipeRef, ctx, env, apiKey) { const recipe = await loadPromptRecipe(recipeRef, env.RECIPES); const vars = {}; for (const frag of recipe.fragments) { const { var: name, value } = await resolveFragment(env, apiKey, frag); vars[name] = typeof value === "string" ? value : JSON.stringify(value); } for (const inp of recipe.inputs) { const { var: name, value } = resolveInput(inp, ctx); vars[name] = typeof value === "string" ? value : JSON.stringify(value); } const system = interpolate(recipe.prompt_assembly.system, vars); const user = interpolate(recipe.prompt_assembly.user, vars); const prompt = `${system} --- USER --- ${user}`; return { prompt, model: recipe.model, output_format: recipe.output.format, output_required_fields: recipe.output.required_fields }; } var init_recipe_expander = __esm({ "cypher-executor/src/lib/recipe-expander.ts"() { "use strict"; init_recipe_loader(); init_recipe_transforms(); } }); // cypher-executor/src/lib/paused-runs.ts async function readIndex(kv, apiKey) { const raw2 = await kv.get(`${IDX_PREFIX}${apiKey}`); if (!raw2) return []; try { const arr = JSON.parse(raw2); return Array.isArray(arr) ? arr : []; } catch { return []; } } async function writeIndex(kv, apiKey, entries) { const now2 = Date.now(); const fresh = entries.filter((e) => e.expires_at > now2); await kv.put(`${IDX_PREFIX}${apiKey}`, JSON.stringify(fresh), { expirationTtl: TTL_SECONDS }); } async function persistPausedRun(kv, taskId, state) { await kv.put(`${KEY_PREFIX}${taskId}`, JSON.stringify(state), { expirationTtl: TTL_SECONDS }); if (state.api_key) { const idx = await readIndex(kv, state.api_key); const filtered = idx.filter((e) => e.task_id !== taskId); filtered.unshift({ task_id: taskId, run_id: state.run_id, paused_node_id: state.paused_node_id, workflow_name: state.graph.name, expires_at: state.expires_at, persisted_at: Date.now() }); await writeIndex(kv, state.api_key, filtered.slice(0, 100)); } } async function loadPausedRun(kv, taskId) { const raw2 = await kv.get(`${KEY_PREFIX}${taskId}`); if (!raw2) return null; try { return JSON.parse(raw2); } catch { return null; } } async function listPausedRunsByApiKey(kv, apiKey, limit = 20) { const idx = await readIndex(kv, apiKey); const now2 = Date.now(); return idx.filter((e) => e.expires_at > now2).slice(0, limit); } async function consumePausedRun(kv, taskId) { const state = await loadPausedRun(kv, taskId); if (!state) return null; await kv.delete(`${KEY_PREFIX}${taskId}`).catch(() => { }); if (state.api_key) { const idx = await readIndex(kv, state.api_key); const filtered = idx.filter((e) => e.task_id !== taskId); await writeIndex(kv, state.api_key, filtered).catch(() => { }); } return state; } function isResumablePending(result) { if (!result || typeof result !== "object") return null; const r = result; if (r.pending !== true) return null; if (typeof r.task_id !== "string" || !r.task_id) return null; return { task_id: r.task_id }; } function parseRecipeOutput(result, format, requiredFields) { if (format !== "json" || !result || typeof result !== "object") return result; const r = result; const text = r.data?.text ?? r.text; if (typeof text !== "string") return result; let jsonText = String(text).trim(); const fenceMatch = jsonText.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/); if (fenceMatch) jsonText = fenceMatch[1].trim(); try { const parsed = JSON.parse(jsonText); if (requiredFields && parsed && typeof parsed === "object") { const missing = requiredFields.filter((f) => !(f in parsed)); if (missing.length > 0) { return { success: false, error: `recipe output \u7F3A\u6B04\u4F4D: ${missing.join(", ")}`, raw: parsed }; } } return { success: true, data: parsed, ...parsed && typeof parsed === "object" ? parsed : {} }; } catch (e) { return { success: false, error: `recipe output JSON parse \u5931\u6557: ${e instanceof Error ? e.message : String(e)}`, raw_text: text }; } } var KEY_PREFIX, IDX_PREFIX, TTL_SECONDS; var init_paused_runs = __esm({ "cypher-executor/src/lib/paused-runs.ts"() { "use strict"; KEY_PREFIX = "paused_run:"; IDX_PREFIX = "paused_idx:"; TTL_SECONDS = 24 * 60 * 60; } }); // cypher-executor/src/lib/magic-vars.ts function isoWeekNumber(d) { const target = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())); const dayNum = (target.getUTCDay() + 6) % 7; target.setUTCDate(target.getUTCDate() - dayNum + 3); const firstThursday = new Date(Date.UTC(target.getUTCFullYear(), 0, 4)); const weekNum = 1 + Math.round( ((target.getTime() - firstThursday.getTime()) / 864e5 - 3 + (firstThursday.getUTCDay() + 6) % 7) / 7 ); return { year: target.getUTCFullYear(), week: weekNum }; } function pad2(n) { return n.toString().padStart(2, "0"); } function buildMagicVars(now2 = /* @__PURE__ */ new Date()) { const iso = now2.toISOString(); const yyyy = now2.getUTCFullYear(); const mm = pad2(now2.getUTCMonth() + 1); const dd = pad2(now2.getUTCDate()); const hh = pad2(now2.getUTCHours()); const mi = pad2(now2.getUTCMinutes()); const ss = pad2(now2.getUTCSeconds()); const yesterday = new Date(now2.getTime() - 864e5); const yMm = pad2(yesterday.getUTCMonth() + 1); const yDd = pad2(yesterday.getUTCDate()); const { year: isoYear, week: isoWeek } = isoWeekNumber(now2); return { // 日期 / 時間(UTC) _today: `${yyyy}-${mm}-${dd}`, // 2026-05-16 _yesterday: `${yesterday.getUTCFullYear()}-${yMm}-${yDd}`, // 2026-05-15 _now: iso, // ISO 8601 _now_unix: now2.getTime(), // unix ms _now_unix_s: Math.floor(now2.getTime() / 1e3), // unix sec // 個別欄位(給 path / page_name 拼) _year: yyyy, _month: mm, _day: dd, _hour: hh, _minute: mi, _second: ss, // ISO 週(roadmap weekly archive 必備) _iso_week: `${isoYear}-W${pad2(isoWeek)}`, // 2026-W20 _iso_week_num: isoWeek, _iso_year: isoYear, // 簡單時間 slot(cron-friendly) _yyyymm: `${yyyy}${mm}`, // 202605 _yyyymmdd: `${yyyy}${mm}${dd}`, // 20260516 // 週幾(0=週日,1=週一 ... 6=週六;ISO 風格在 _iso_weekday) _weekday: now2.getUTCDay(), _iso_weekday: (now2.getUTCDay() + 6) % 7 + 1 // 1=Mon...7=Sun }; } var init_magic_vars = __esm({ "cypher-executor/src/lib/magic-vars.ts"() { "use strict"; } }); // cypher-executor/src/lib/telemetry.ts async function hashApiKey(apiKey) { if (!apiKey) return "anon"; const encoder = new TextEncoder(); const data = encoder.encode(apiKey); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.slice(0, 8).map((b) => b.toString(16).padStart(2, "0")).join(""); } function kbdbCreateBlockUrl(env) { const subdomain = env.WORKER_SUBDOMAIN || "uncle6-me"; return `https://arcrun-kbdb-create-block.${subdomain}.workers.dev`; } function recordTelemetry(env, apiKey, record, ctx) { const promise = (async () => { try { const api_key_hash = await hashApiKey(apiKey ?? ""); const platformKey = env.PLATFORM_API_KEY || apiKey || ""; if (!platformKey) { console.warn("[telemetry] no api_key, skipping"); return; } const body = { api_key: platformKey, type: "agent-telemetry", source: "cypher-executor", user_id: "platform_telemetry", content: JSON.stringify(record), metadata_json: JSON.stringify({ ...record, api_key_hash }), tags_json: JSON.stringify([ "agent-telemetry", `event:${record.event_type}` ]) }; const res = await fetch(kbdbCreateBlockUrl(env), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); if (!res.ok) { console.warn( "[telemetry] write failed", res.status, await res.text().catch(() => "no body") ); } } catch (e) { console.warn("[telemetry] exception", e); } })(); if (ctx?.waitUntil) { ctx.waitUntil(promise); } } var init_telemetry = __esm({ "cypher-executor/src/lib/telemetry.ts"() { "use strict"; } }); // cypher-executor/src/graph-executor.ts function propagateCtx(context, upstreamResult, upstreamNodeId) { const baseCtx = typeof context === "object" && context !== null ? context : {}; const baseResult = typeof upstreamResult === "object" && upstreamResult !== null ? upstreamResult : {}; return { ...baseCtx, ...baseResult, [upstreamNodeId]: upstreamResult }; } function interpolateString(s, ctx) { const single = s.match(/^\s*\{\{([\w.]+)\}\}\s*$/); if (single) { const val = getNestedValue(ctx, single[1]); return val === void 0 ? s : val; } return s.replace(/\{\{([\w.]+)\}\}/g, (_, key) => { const val = getNestedValue(ctx, key); if (val === void 0) return `{{${key}}}`; if (typeof val === "string") return val; return JSON.stringify(val); }); } function interpolateValue(v, ctx) { if (typeof v === "string") return interpolateString(v, ctx); if (Array.isArray(v)) return v.map((item) => interpolateValue(item, ctx)); if (v !== null && typeof v === "object") { const result = {}; for (const [k, val] of Object.entries(v)) { result[k] = interpolateValue(val, ctx); } return result; } return v; } function interpolateData(data, ctx) { if (!data) return {}; return interpolateValue(data, ctx); } function getNestedValue(ctx, path) { const parts = path.split("."); let cur = ctx; for (const p of parts) { if (cur === null || cur === void 0) return void 0; if (typeof cur !== "object") return void 0; cur = cur[p]; } return cur; } function readBranch(result) { if (!result || typeof result !== "object") return void 0; const r = result; const data = r.data && typeof r.data === "object" ? r.data : void 0; const named = data?.branch ?? r.branch; if (typeof named === "string") return named; const bool = data?.result ?? r.result; if (typeof bool === "boolean") return bool ? "true" : "false"; return void 0; } function isFailure(result) { if (!result || typeof result !== "object") return false; const r = result; return r["success"] === false || "error" in r; } function evaluateCondition(condition, context) { if (!context || typeof context !== "object") return false; const ctx = context; const expr = condition.replace(/result\./g, "").replace(/ctx\./g, ""); const eqMatch = expr.match(/^(\w+)\s*===?\s*(.+)$/); if (eqMatch) { const key2 = eqMatch[1]; const rawVal = eqMatch[2].trim(); const expected = rawVal === "true" ? true : rawVal === "false" ? false : rawVal.replace(/['"]/g, ""); return ctx[key2] === expected; } const gtMatch = expr.match(/^(\w+)\s*>\s*(\d+)$/); if (gtMatch) { return Number(ctx[gtMatch[1]]) > Number(gtMatch[2]); } const key = expr.trim(); if (key && key in ctx) return !!ctx[key]; return true; } function getIterableFromContext(context, key) { if (!context || typeof context !== "object") return []; const variants = [ key + "s", // paragraph → paragraphs key.replace(/y$/, "ies"), // entity → entities key.replace(/(s|x|z|ch|sh)$/, "$1es"), // box → boxes key // singular fallback ]; const obj = context; for (const v of variants) { if (Array.isArray(obj[v])) return obj[v]; } for (const val of Object.values(obj)) { if (val !== null && typeof val === "object" && !Array.isArray(val)) { for (const v of variants) { const nested = val[v]; if (Array.isArray(nested)) return nested; } } } return []; } var GraphExecutor; var init_graph_executor = __esm({ "cypher-executor/src/graph-executor.ts"() { "use strict"; init_types(); init_auth_dispatcher(); init_recipe_expander(); init_recipes(); init_paused_runs(); init_magic_vars(); init_telemetry(); GraphExecutor = class _GraphExecutor { loader; workflowLoader; env; apiKey; recordComponentReference; // kbdb-base §7.1+§7.5.h:本次執行用到的 recipe **key**(uuid 優先,舊資料 fallback canonical_id)。 // 判定單位是「工作流執行」(n8n execution):執行結束後由 executeWebhookGraph 一次性把這組 key // 各記成功/失敗到 KBDB 市場星數(per-uuid → 能區分同 canonical 的不同作者版本,§7.5.5)。執行中只收集。 usedRecipeKeys = /* @__PURE__ */ new Set(); // resumable workflow(SDD: resumable-workflow/design.md) // 暫停時持久化 state 用,需在 execute 進入時設定 currentGraph; currentRunId; constructor(loader, workflowLoader, env, apiKey) { this.loader = loader; this.workflowLoader = workflowLoader; this.env = env; this.apiKey = apiKey; } async execute(graph, initialContext, kvNamespace) { const trace = []; const kvStore = kvNamespace ? { runId: `${graph.id}-${Date.now()}`, kv: kvNamespace } : void 0; this.currentGraph = graph; this.currentRunId = kvStore?.runId ?? `${graph.id}-${Date.now()}`; const ctxWithMagic = { ...initialContext, ...buildMagicVars() }; const hasIncoming = new Set(graph.edges.map((e) => e.to)); const startNodes = graph.nodes.filter((n) => !hasIncoming.has(n.id)); if (startNodes.length === 0) { return { data: ctxWithMagic, trace }; } const fanIn = /* @__PURE__ */ new Map(); for (const node of graph.nodes) { const inDeg = graph.edges.filter((e) => e.to === node.id).length; if (inDeg > 1) { fanIn.set(node.id, { ctx: { ...ctxWithMagic }, remaining: inDeg }); } } const results = await Promise.all( startNodes.map( (node) => this.executeNode(node, graph, ctxWithMagic, /* @__PURE__ */ new Set(), trace, fanIn, kvStore) ) ); let mergedResult; if (results.length === 1) { mergedResult = results[0]; } else { mergedResult = results.reduce( (acc, r) => ({ ...acc, ...typeof r === "object" && r !== null ? r : {} }), {} ); } return { data: mergedResult, trace }; } /** * 從 paused state 繼續執行 workflow * SDD: resumable-workflow/design.md §3.2 * * 流程: * 1. 把 paused_node 當已執行(result = callbackResult,注入進 context) * 2. 找出 paused_node 的所有下游節點當新起點 * 3. 執行下游節點直到結束(或再次 paused) */ async resumeFromPaused(args) { const { graph, paused_node_id, paused_context, prior_trace, kvNamespace } = args; let { callback_result } = args; callback_result = parseRecipeOutput( callback_result, args.recipe_output_format, args.recipe_output_required_fields ); this.currentGraph = graph; this.currentRunId = `${graph.id}-resume-${Date.now()}`; const trace = [...prior_trace]; const kvStore = kvNamespace ? { runId: this.currentRunId, kv: kvNamespace } : void 0; if (kvStore) { await kvSetNodeOutput(kvStore, paused_node_id, callback_result); } const mergedContext = { ...paused_context, ...callback_result && typeof callback_result === "object" ? callback_result : {}, [paused_node_id]: callback_result }; if (kvStore) { if (!mergedContext._kv_outputs) mergedContext._kv_outputs = {}; mergedContext._kv_outputs[paused_node_id] = callback_result; } const downstreamEdges = graph.edges.filter((e) => e.from === paused_node_id); if (downstreamEdges.length === 0) { return { data: callback_result, trace }; } const fanIn = /* @__PURE__ */ new Map(); for (const node of graph.nodes) { const inDeg = graph.edges.filter((e) => e.to === node.id).length; if (inDeg > 1) { fanIn.set(node.id, { ctx: { ...mergedContext }, remaining: inDeg }); } } const visited = /* @__PURE__ */ new Set([`${paused_node_id}:${JSON.stringify(paused_context).slice(0, 50)}`]); const downstreamNodes = downstreamEdges.map((e) => graph.nodes.find((n) => n.id === e.to)).filter((n) => !!n); const results = await Promise.all( downstreamNodes.map( (node) => this.executeNode(node, graph, mergedContext, visited, trace, fanIn, kvStore) ) ); let mergedResult; if (results.length === 1) { mergedResult = results[0]; } else { mergedResult = results.reduce( (acc, r) => ({ ...acc, ...typeof r === "object" && r !== null ? r : {} }), {} ); } return { data: mergedResult, trace }; } async executeNode(node, graph, context, visited, trace, fanIn, kvStore) { const nodeKey = `${node.id}:${JSON.stringify(context).slice(0, 50)}`; if (visited.has(nodeKey)) return context; visited.add(nodeKey); const start = Date.now(); let result = context; let nodeInput = context; try { switch (node.type) { case "Input": result = node.data ?? context; nodeInput = result; break; case "Component": { if (!node.componentId) throw new Error(`\u7BC0\u9EDE ${node.id} \u7F3A\u5C11 componentId`); const runner = await this.loader(node.componentId); const ctx = context; const resolvedData = interpolateData(node.data, ctx); let mergedContext = { ...ctx, ...resolvedData }; if (this.env && this.apiKey) { mergedContext = await resolveCredentialRefs(mergedContext, this.env, this.apiKey); } if (node.componentId === "claude_api") { const baseUrl = this.env?.PUBLIC_BASE_URL ?? "https://cypher.arcrun.dev"; mergedContext.callback_url = `${baseUrl.replace(/\/$/, "")}/workflows/resume`; } if (typeof resolvedData.recipe === "string" && this.env?.RECIPES) { try { const expanded = await expandPromptRecipe( resolvedData.recipe, ctx, this.env, this.apiKey ?? "" ); mergedContext = { ...mergedContext, prompt: expanded.prompt, model: expanded.model, _recipe_output_format: expanded.output_format, _recipe_output_required_fields: expanded.output_required_fields }; } catch (e) { throw new Error(`recipe \u5C55\u958B\u5931\u6557 (${resolvedData.recipe}): ${e instanceof Error ? e.message : String(e)}`); } } if (this.env && this.apiKey) { const dispatched = await tryAuthDispatch(node.componentId, mergedContext, this.env, this.apiKey); if (dispatched) { mergedContext = dispatched; } } if (this.env?.RECIPES) { try { const apiRecipe = await resolveRecipe(node.componentId, this.env.RECIPES); if (apiRecipe) this.usedRecipeKeys.add(apiRecipe.uuid ?? apiRecipe.canonical_id); } catch { } } nodeInput = mergedContext; result = await runner(mergedContext); const pending = isResumablePending(result); if (pending && this.env?.EXEC_CONTEXT && this.currentGraph && this.currentRunId) { trace.push({ nodeId: node.id, type: node.type, input: nodeInput, output: result, duration_ms: Date.now() - start }); await persistPausedRun(this.env.EXEC_CONTEXT, pending.task_id, { run_id: this.currentRunId, graph: this.currentGraph, paused_node_id: node.id, paused_context: context, paused_pending_result: result, trace_so_far: trace, api_key: this.apiKey, expires_at: Date.now() + 24 * 60 * 60 * 1e3, recipe_output_format: mergedContext._recipe_output_format, recipe_output_required_fields: mergedContext._recipe_output_required_fields }); throw new WorkflowPaused(pending.task_id, this.currentRunId, node.id, trace); } result = parseRecipeOutput( result, mergedContext._recipe_output_format, mergedContext._recipe_output_required_fields ); if (kvStore && result !== null && result !== void 0 && graph.edges.some((e) => e.from === node.id && e.type === "PIPE")) { await kvSetNodeOutput(kvStore, node.id, result); } void this.recordComponentReference?.(node.componentId, graph.id).catch(() => { }); break; } case "Output": result = context; break; } } catch (e) { if (e instanceof WorkflowPaused) throw e; const errMsg = e.message || String(e); const duration_ms2 = Date.now() - start; trace.push({ nodeId: node.id, type: node.type, input: nodeInput, output: null, error: errMsg, duration_ms: duration_ms2 }); if (this.env && node.type === "Component") { recordTelemetry(this.env, this.apiKey, { event_type: "node_failure", workflow_name: graph.name, component_id: node.componentId, error_code: "node_error", duration_ms: duration_ms2 }); } if (e instanceof ExecutionError) throw e; throw new ExecutionError( `Node ${node.id} failed: ${errMsg}`, node.id, nodeInput, trace ); } const duration_ms = Date.now() - start; trace.push({ nodeId: node.id, type: node.type, input: nodeInput, output: result, duration_ms }); if (this.env && node.type === "Component") { recordTelemetry(this.env, this.apiKey, { event_type: "node_success", workflow_name: graph.name, component_id: node.componentId, duration_ms }); } const outEdges = graph.edges.filter((e) => e.from === node.id); for (const edge of outEdges) { const nextNode = graph.nodes.find((n) => n.id === edge.to); if (!nextNode) continue; switch (edge.type) { case "PIPE": { const pipeContext = propagateCtx(context, result, node.id); if (kvStore) { const kvOutput = await kvGetNodeOutput(kvStore, node.id); if (kvOutput !== void 0) { if (!pipeContext._kv_outputs) pipeContext._kv_outputs = {}; pipeContext._kv_outputs[node.id] = kvOutput; } } const fanInState = fanIn.get(nextNode.id); if (fanInState) { Object.assign(fanInState.ctx, pipeContext); fanInState.remaining--; if (fanInState.remaining === 0) { result = await this.executeNode(nextNode, graph, fanInState.ctx, visited, trace, fanIn, kvStore); } } else { result = await this.executeNode(nextNode, graph, pipeContext, visited, trace, fanIn, kvStore); } break; } case "ON_SUCCESS": { if (!isFailure(result)) { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } case "ON_FAIL": { if (isFailure(result)) { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } case "IF": { const passes = evaluateCondition(edge.condition ?? "true", result); if (passes) { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } // ── 條件邊(SDD workflow-discovery 3.11 / CP arcrun-usable 步驟 5 缺口①)── // 為什麼要有:`if_control` 回 {result, branch} 卻沒有邊讀得懂它, // AI 照規矩用了零件仍得寫 code 判斷走哪條 ⇒「全變成 code」的根(Arcrun#5)。 // 讀法對齊零件 output_schema:優先 data.branch(if_control/switch 的正式形狀), // 相容 top-level branch / result 布林。讀不出分支=不走(誠實,不亂挑一條)。 case "ON_TRUE": { if (readBranch(result) === "true") { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } case "ON_FALSE": { if (readBranch(result) === "false") { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } case "ON_BRANCH": { const actual = readBranch(result); if (edge.branch !== void 0 && actual !== void 0 && actual === edge.branch) { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); } break; } case "FOREACH": { const iteratorKey = edge.iterator ?? "item"; let items = getIterableFromContext(result, iteratorKey); if (items.length === 0) { items = getIterableFromContext(context, iteratorKey); } const iterResults = []; const baseForeachCtx = propagateCtx(context, result, node.id); for (const item of items) { const itemContext = { ...baseForeachCtx, [iteratorKey]: item }; const itemResult = await this.executeNode(nextNode, graph, itemContext, /* @__PURE__ */ new Set(), trace, fanIn, kvStore); iterResults.push(itemResult); } if (iterResults.length > 0) { const failures = iterResults.filter( (r) => r !== null && typeof r === "object" && r.success === false ); if (failures.length === iterResults.length) { const first = failures[0]; const errParts = []; if (first.error) errParts.push(String(first.error)); if (typeof first.status === "number") errParts.push(`HTTP ${first.status}`); const bodyData = first.data; if (bodyData && typeof bodyData.body === "string" && bodyData.body) { errParts.push(bodyData.body.slice(0, 200)); } throw new Error( `FOREACH \u6240\u6709 ${iterResults.length} \u9805\u76EE\u5747\u5931\u6557\uFF08\u9996\u9805\uFF1A${errParts.join("\uFF1B") || "\u672A\u77E5\u932F\u8AA4"}\uFF09` ); } } result = { ...result, results: iterResults }; break; } case "CALLS_SUBFLOW": { const subWorkflowId = nextNode.componentId?.replace("workflow://", "") ?? nextNode.id; if (this.workflowLoader) { const subGraph = await this.workflowLoader(subWorkflowId); const subExecutor = new _GraphExecutor(this.loader, this.workflowLoader); const subResult = await subExecutor.execute( subGraph, result, kvStore?.kv ); result = { ...result, ...subResult.data }; } break; } case "ON_CLICK": { const mergedCtx = propagateCtx(context, result, node.id); result = await this.executeNode(nextNode, graph, mergedCtx, visited, trace, fanIn, kvStore); break; } case "IS_A": { break; } case "CONTAINS": case "HAS_STYLE": case "HAS_BEHAVIOR": { break; } case "CONTINUE": break; } } return result; } }; } }); // cypher-executor/src/lib/schemas.ts var graphSchema, executeSchema; var init_schemas = __esm({ "cypher-executor/src/lib/schemas.ts"() { "use strict"; init_lib(); graphSchema = z.object({ id: z.string().min(1), name: z.string().min(1), nodes: z.array(z.object({ id: z.string(), type: z.enum(["Input", "Component", "Output"]), componentId: z.string().optional(), label: z.string().optional(), data: z.record(z.unknown()).optional() })), edges: z.array(z.object({ from: z.string(), to: z.string(), type: z.enum(["PIPE", "IF", "FOREACH", "CONTINUE", "IS_A", "ON_SUCCESS", "ON_FAIL", "ON_TRUE", "ON_FALSE", "ON_BRANCH", "ON_CLICK", "CALLS_SUBFLOW", "CONTAINS", "HAS_STYLE", "HAS_BEHAVIOR"]), condition: z.string().optional(), iterator: z.string().optional(), branch: z.string().optional() // ON_BRANCH 的具名分支(SDD workflow-discovery 3.11) })) }); executeSchema = z.object({ graph: graphSchema, context: z.record(z.unknown()).default({}) }); } }); // cypher-executor/src/actions/execution-evaluator.ts function componentVerdictsFromTrace(nodes, trace) { const componentByNodeId = /* @__PURE__ */ new Map(); for (const n of nodes) { if (n.type === "Component" && n.componentId) componentByNodeId.set(n.id, n.componentId); } const verdicts = []; for (const step of trace) { const componentId = componentByNodeId.get(step.nodeId); if (!componentId) continue; const out = step.output; const outputSaysFailed = typeof out === "object" && out !== null && !Array.isArray(out) && out.success === false; verdicts.push({ component_id: componentId, success: !step.error && !outputSaysFailed, duration_ms: Math.max(0, Number(step.duration_ms) || 0) }); } return verdicts; } async function recordComponentStats(env, nodes, trace) { try { const base = (env.REGISTRY_BASE_URL ?? (env.WORKER_SUBDOMAIN ? wasmWorkerUrl("registry", env.WORKER_SUBDOMAIN) : void 0))?.replace(/\/$/, ""); if (!base) return; const verdicts = componentVerdictsFromTrace(nodes, trace); if (verdicts.length === 0) return; await Promise.all( verdicts.map( (v) => fetch(`${base}/analytics/record`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ canonical_id: v.component_id, success: v.success, duration_ms: v.duration_ms }) }).catch(() => void 0) // 統計失敗不影響執行 ) ); } catch { } } var init_execution_evaluator = __esm({ "cypher-executor/src/actions/execution-evaluator.ts"() { "use strict"; init_component_loader(); } }); // cypher-executor/src/actions/webhook-handlers.ts var webhook_handlers_exports = {}; __export(webhook_handlers_exports, { executeWebhookGraph: () => executeWebhookGraph, generateToken: () => generateToken, validateAndParseWebhook: () => validateAndParseWebhook }); function recordRecipeStats(env, recipeKeys, ok, at, ctx) { if (recipeKeys.size === 0) return; const base = (env.KBDB_BASE_URL ?? "https://kbdb.finally.click").replace(/\/$/, ""); const headers = { "Content-Type": "application/json" }; if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`; const promise = Promise.all( [...recipeKeys].map( (key) => fetch(`${base}/recipe-stats/record`, { method: "POST", headers, body: JSON.stringify({ canonical_id: key, ok, at }) }).catch(() => void 0) ) ).then(() => void 0); if (ctx?.waitUntil) ctx.waitUntil(promise); else ; } function generateToken() { const tokenBytes = crypto.getRandomValues(new Uint8Array(16)); return Array.from(tokenBytes).map((b) => b.toString(16).padStart(2, "0")).join(""); } async function validateAndParseWebhook(raw2) { try { return JSON.parse(raw2); } catch { return null; } } async function executeWebhookGraph(env, graph, triggerContext, token, apiKey, ctx, userAgent) { const parsed = graphSchema.safeParse(graph); if (!parsed.success) { return { success: false, error: "\u5716\u5B9A\u7FA9\u5DF2\u5931\u6548", duration_ms: 0 }; } const loader = createComponentLoader(env); const executor = new GraphExecutor(loader, void 0, env, apiKey); const start = Date.now(); try { const result = await executor.execute( parsed.data, { ...triggerContext, _webhook_token: token }, env.EXEC_CONTEXT ); const duration_ms = Date.now() - start; recordTelemetry(env, apiKey, { event_type: "run_success", workflow_name: token, duration_ms, agent_user_agent: userAgent }, ctx); recordRecipeStats(env, executor.usedRecipeKeys, true, Date.now(), ctx); { const statsPromise = recordComponentStats( env, parsed.data.nodes, result.trace ); if (ctx?.waitUntil) ctx.waitUntil(statsPromise); else ; } return { success: true, data: result.data, duration_ms }; } catch (err) { const duration_ms = Date.now() - start; const errMsg = err instanceof Error ? err.message : String(err); const isPaused = /workflow paused/i.test(errMsg); recordTelemetry(env, apiKey, { event_type: isPaused ? "run_success" : "run_fail", workflow_name: token, error_code: isPaused ? "paused_awaiting_resume" : "execution_error", duration_ms, agent_user_agent: userAgent }, ctx); if (!isPaused) { recordRecipeStats(env, executor.usedRecipeKeys, false, Date.now(), ctx); } if (!isPaused && err instanceof ExecutionError) { const statsPromise = recordComponentStats( env, parsed.data.nodes, err.trace ); if (ctx?.waitUntil) ctx.waitUntil(statsPromise); else ; } if (err instanceof ExecutionError) { const traceFormatted = err.trace.map((s) => ({ node: s.nodeId, status: s.error ? "failed" : "success", ...s.error ? { error: s.error } : {} })); return { success: false, error: errMsg, trace: traceFormatted, duration_ms }; } return { success: false, error: errMsg, duration_ms }; } } var init_webhook_handlers = __esm({ "cypher-executor/src/actions/webhook-handlers.ts"() { "use strict"; init_types(); init_graph_executor(); init_schemas(); init_component_loader(); init_telemetry(); init_execution_evaluator(); } }); // cypher-executor/src/index.ts init_dist(); // cypher-executor/node_modules/.pnpm/hono@4.12.10/node_modules/hono/dist/middleware/cors/index.js var cors = (options) => { const defaults = { origin: "*", allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"], allowHeaders: [], exposeHeaders: [] }; const opts = { ...defaults, ...options }; const findAllowOrigin = ((optsOrigin) => { if (typeof optsOrigin === "string") { if (optsOrigin === "*") { if (opts.credentials) { return (origin) => origin || null; } return () => optsOrigin; } else { return (origin) => optsOrigin === origin ? origin : null; } } else if (typeof optsOrigin === "function") { return optsOrigin; } else { return (origin) => optsOrigin.includes(origin) ? origin : null; } })(opts.origin); const findAllowMethods = ((optsAllowMethods) => { if (typeof optsAllowMethods === "function") { return optsAllowMethods; } else if (Array.isArray(optsAllowMethods)) { return () => optsAllowMethods; } else { return () => []; } })(opts.allowMethods); return async function cors2(c, next) { function set(key, value) { c.res.headers.set(key, value); } const allowOrigin = await findAllowOrigin(c.req.header("origin") || "", c); if (allowOrigin) { set("Access-Control-Allow-Origin", allowOrigin); } if (opts.credentials) { set("Access-Control-Allow-Credentials", "true"); } if (opts.exposeHeaders?.length) { set("Access-Control-Expose-Headers", opts.exposeHeaders.join(",")); } if (c.req.method === "OPTIONS") { if (opts.origin !== "*" || opts.credentials) { set("Vary", "Origin"); } if (opts.maxAge != null) { set("Access-Control-Max-Age", opts.maxAge.toString()); } const allowMethods = await findAllowMethods(c.req.header("origin") || "", c); if (allowMethods.length) { set("Access-Control-Allow-Methods", allowMethods.join(",")); } let headers = opts.allowHeaders; if (!headers?.length) { const requestHeaders = c.req.header("Access-Control-Request-Headers"); if (requestHeaders) { headers = requestHeaders.split(/\s*,\s*/); } } if (headers?.length) { set("Access-Control-Allow-Headers", headers.join(",")); c.res.headers.append("Vary", "Access-Control-Request-Headers"); } c.res.headers.delete("Content-Length"); c.res.headers.delete("Content-Type"); return new Response(null, { headers: c.res.headers, status: 204, statusText: "No Content" }); } await next(); if (opts.origin !== "*" || opts.credentials) { c.header("Vary", "Origin", { append: true }); } }; }; // cypher-executor/src/lib/cron-match.ts function matchField(expr, value, min, max) { if (expr === "*") return true; for (const part of expr.split(",")) { if (matchPart(part.trim(), value, min, max)) return true; } return false; } function matchPart(part, value, min, max) { if (part.startsWith("*/")) { const step = parseInt(part.slice(2), 10); if (!Number.isFinite(step) || step <= 0) return false; return (value - min) % step === 0; } if (part.includes("-")) { const [rangePart, stepStr] = part.split("/"); const [aStr, bStr] = rangePart.split("-"); const a = parseInt(aStr, 10); const b = parseInt(bStr, 10); if (!Number.isFinite(a) || !Number.isFinite(b)) return false; if (value < a || value > b) return false; if (stepStr === void 0) return true; const step = parseInt(stepStr, 10); if (!Number.isFinite(step) || step <= 0) return false; return (value - a) % step === 0; } const n = parseInt(part, 10); if (!Number.isFinite(n)) return false; if (n < min || n > max) return false; return value === n; } function cronMatch(expr, date) { const fields = expr.trim().split(/\s+/); if (fields.length !== 5) return false; const [m, h, dom, mon, dow] = fields; return matchField(m, date.getUTCMinutes(), 0, 59) && matchField(h, date.getUTCHours(), 0, 23) && matchField(dom, date.getUTCDate(), 1, 31) && matchField(mon, date.getUTCMonth() + 1, 1, 12) && matchField(dow, date.getUTCDay(), 0, 6); } function extractCronExpr(graph) { if (!graph || typeof graph !== "object") return null; const nodes = graph.nodes; if (!Array.isArray(nodes)) return null; for (const node of nodes) { if (node.componentId !== "cron") continue; const expr = node.data?.cron_expr; if (typeof expr === "string" && expr.trim()) return expr.trim(); } return null; } // cypher-executor/src/lib/cron-index.ts var CRON_INDEX_KEY = "cron-idx:_all"; function cronEntryKey(apiKey, name) { return `${apiKey}:${name}`; } function parseCronEntryKey(entryKey) { const idx = entryKey.indexOf(":"); if (idx <= 0) return null; return { apiKey: entryKey.slice(0, idx), name: entryKey.slice(idx + 1) }; } async function readCronIndex(kv) { const raw2 = await kv.get(CRON_INDEX_KEY, "text"); if (!raw2) return {}; try { const parsed = JSON.parse(raw2); return parsed && typeof parsed === "object" ? parsed : {}; } catch { return {}; } } async function updateCronIndexEntry(kv, apiKey, name, cronExpr) { const index = await readCronIndex(kv); const entryKey = cronEntryKey(apiKey, name); if (cronExpr) { if (index[entryKey] === cronExpr) return; index[entryKey] = cronExpr; } else { if (!(entryKey in index)) return; delete index[entryKey]; } await kv.put(CRON_INDEX_KEY, JSON.stringify(index)); } // cypher-executor/src/scheduled.ts init_webhook_handlers(); init_kbdb_proxy(); async function handleScheduled(controller, env, ctx) { const now2 = new Date(controller.scheduledTime); console.log("[scheduled] tick", now2.toISOString(), "controller.cron=", controller.cron); const index = await readCronIndex(env.WEBHOOKS); const entries = Object.entries(index); let triggered = 0; for (const [entryKey, cronExpr] of entries) { const parsed = parseCronEntryKey(entryKey); if (!parsed) continue; const { apiKey, name } = parsed; if (!cronExpr) continue; if (!cronMatch(cronExpr, now2)) continue; const wfKey = `${apiKey}:wf:${name}`; const wfRaw = await env.WEBHOOKS.get(wfKey, "text"); if (!wfRaw) { console.warn("[scheduled] cron-idx \u5C0D\u61C9 workflow \u4E0D\u5B58\u5728", wfKey); continue; } let record; try { record = JSON.parse(wfRaw); } catch { continue; } triggered++; console.log("[scheduled] trigger", name, "apiKey=", apiKey.slice(0, 12) + "...", "cron=", cronExpr); const triggerContext = { api_key: apiKey, _triggered_by: "cron", _scheduled_at: now2.toISOString() }; ctx.waitUntil( executeWebhookGraph(env, record.graph, triggerContext, name, apiKey).then( (r) => console.log("[scheduled] done", name, r.success, r.duration_ms + "ms"), (e) => console.error("[scheduled] fail", name, e) ) ); } console.log(`[scheduled] scanned ${entries.length} cron-idx entries, ${triggered} triggered`); if (now2.getUTCHours() === 2 && now2.getUTCMinutes() === 30) { const { base, headers } = kbdbBase(env); ctx.waitUntil( fetch(`${base}/execution-log/cleanup`, { method: "POST", headers }).then(async (r) => { const body = await r.json().catch(() => null); console.log("[scheduled] execution-log cleanup", r.status, JSON.stringify(body)); }).catch((e) => console.error("[scheduled] execution-log cleanup failed", e)) ); } } // cypher-executor/src/routes/health.ts init_dist(); // cypher-executor/src/lib/portal-auth-store.ts init_credentials(); var AUTH_STORE_PREFIX = "ARCRUN_AUTH_STORE"; var SHARD_MAX_BYTES = 4600; var AUTH_OVERLAY_TTL_MS = 18e4; var ACCEL_KEY = "auth_store_recent"; var ACCEL_TTL_SECONDS = 600; var AUTH_ID_PREFIX = "auth:"; var AuthStoreWriteError = class extends Error { }; var overlay = null; var overlayAt = 0; function emptyStore() { return { version: 1, console: null, users: [] }; } function shardNames(env) { const bag = env; return Object.keys(bag).filter((k) => k === AUTH_STORE_PREFIX || /^ARCRUN_AUTH_STORE_\d+$/.test(k)).filter((k) => typeof bag[k] === "string" && bag[k].length > 0).sort((a, b) => shardIndex(a) - shardIndex(b)); } function shardIndex(name) { if (name === AUTH_STORE_PREFIX) return 0; return Number.parseInt(name.slice(AUTH_STORE_PREFIX.length + 1), 10) || 0; } function shardNameOf(index) { return index === 0 ? AUTH_STORE_PREFIX : `${AUTH_STORE_PREFIX}_${index}`; } function authStorePresent(env) { return shardNames(env).length > 0 || overlay !== null && Date.now() - overlayAt < AUTH_OVERLAY_TTL_MS; } function authStoreWritable(env) { return Boolean(env.CF_SECRETS_API_TOKEN && env.CF_ACCOUNT_ID); } function readAuthStore(env) { if (overlay && Date.now() - overlayAt < AUTH_OVERLAY_TTL_MS) return overlay; return readAuthStoreFromEnv(env); } function readAuthStoreFromEnv(env) { const bag = env; const out = emptyStore(); for (const name of shardNames(env)) { let parsed = null; try { parsed = JSON.parse(bag[name]); } catch { continue; } if (!parsed || typeof parsed !== "object") continue; if (parsed.console && !out.console) out.console = parsed.console; if (Array.isArray(parsed.users)) { for (const u of parsed.users) { if (u && typeof u.email === "string" && typeof u.id === "string") out.users.push(u); } } } return out; } function findAuthUserByEmail(env, email) { const needle = email.trim().toLowerCase(); return readAuthStore(env).users.find((u) => u.email.toLowerCase() === needle) ?? null; } function findAuthUserById(env, id) { return readAuthStore(env).users.find((u) => u.id === id) ?? null; } function isAuthStoreId(recordId) { return recordId.startsWith(AUTH_ID_PREFIX); } function newAuthUserId() { const arr = new Uint8Array(12); crypto.getRandomValues(arr); return AUTH_ID_PREFIX + Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join(""); } async function writeAuthStore(env, data) { if (!authStoreWritable(env)) { throw new AuthStoreWriteError( "\u9019\u53F0\u5BE6\u4F8B\u9084\u4E0D\u80FD\u5BEB\u5165\u8A8D\u8B49\u5132\u5B58\uFF08\u7F3A CF_SECRETS_API_TOKEN / CF_ACCOUNT_ID\uFF09\u3002\u8A8D\u8B49\u5206\u96E2\u9700\u8981\u9019\u5169\u9805\u624D\u5BEB\u5F97\u9032 Workers Secrets\u2014\u2014\u8ACB\u91CD\u65B0\u57F7\u884C\u5B89\u88DD\uFF0F\u66F4\u65B0\u8B93\u5B83\u5C31\u7DD2\u3002" ); } const shards = []; let current = { v: 1, console: data.console ?? null, users: [] }; for (const u of data.users) { const trial = { ...current, users: [...current.users ?? [], u] }; const size = new TextEncoder().encode(JSON.stringify(trial)).length; if (size > SHARD_MAX_BYTES && (current.users ?? []).length > 0) { shards.push(JSON.stringify(current)); current = { v: 1, users: [u] }; } else { current = trial; } } shards.push(JSON.stringify(current)); for (const s of shards) { if (new TextEncoder().encode(s).length > 5e3) { throw new AuthStoreWriteError("\u55AE\u7B46\u8A8D\u8B49\u8CC7\u6599\u8D85\u904E Cloudflare \u8B8A\u6578 5 KB \u4E0A\u9650\uFF0C\u7121\u6CD5\u5BEB\u5165\u3002"); } } const existing = shardNames(env); for (let i = 0; i < shards.length; i++) { await putWorkerSecret(env, shardNameOf(i), shards[i]); } for (const name of existing) { if (shardIndex(name) >= shards.length) await deleteWorkerSecret(env, name); } overlay = { version: 1, console: data.console ?? null, users: [...data.users] }; overlayAt = Date.now(); try { await env.SESSIONS_KV.put( ACCEL_KEY, JSON.stringify({ written_at: Date.now(), data: overlay }), { expirationTtl: ACCEL_TTL_SECONDS } ); } catch { } } async function hydrateFromAccelerator(env) { let raw2 = null; try { raw2 = await env.SESSIONS_KV.get(ACCEL_KEY); } catch { return false; } if (!raw2) return false; try { const parsed = JSON.parse(raw2); if (!parsed?.data || !Array.isArray(parsed.data.users)) return false; if (overlay && overlayAt >= (parsed.written_at ?? 0)) return false; overlay = { version: 1, console: parsed.data.console ?? null, users: parsed.data.users }; overlayAt = parsed.written_at ?? Date.now(); return true; } catch { return false; } } async function authStoreRecentlyWritten(env) { try { return Boolean(await env.SESSIONS_KV.get(ACCEL_KEY)); } catch { return false; } } function unionStores(a, b) { const byId = /* @__PURE__ */ new Map(); for (const u of [...a.users, ...b.users]) { const prev = byId.get(u.id); if (!prev || (u.updated_at ?? "") >= (prev.updated_at ?? "")) byId.set(u.id, u); } return { version: 1, console: a.console ?? b.console ?? null, users: [...byId.values()] }; } async function mutateAuthStore(env, fn) { await hydrateFromAccelerator(env); const next = unionStores(readAuthStore(env), readAuthStoreFromEnv(env)); await fn(next); await writeAuthStore(env, next); return next; } function authStoreStatus(env) { const data = readAuthStore(env); return { present: authStorePresent(env), writable: authStoreWritable(env), users: data.users.length, console_configured: Boolean(data.console), shards: shardNames(env).length }; } // cypher-executor/src/routes/health.ts var healthRouter = new Hono2(); healthRouter.get("/health", (c) => { const bundleVersion = c.env.ARCRUN_BUNDLE_VERSION; return c.json({ ok: true, ...bundleVersion ? { bundle_version: bundleVersion } : {}, auth_store: authStoreStatus(c.env), // arcrun-rag#38/#69/#25(2026-08-11):安裝器判斷「要不要重推」只比 bundle_version—— // 但這次要修的洞是「installer 從沒注入過 PORTAL_MAIL_RELAY_BASE」,跟 bundle 內容 // 版本無關(同一個 cypher 版本,有的實例有這個 var、有的沒有)。純比版本號的話, // 已經在最新版的實例(如 leo 自己那台)永遠不會因為「按更新」而重推,這個 var // 就永遠補不進去。只回布林(有沒有設,不回值本身)——不洩漏郵差網址。 mail_relay_configured: Boolean(String(c.env.PORTAL_MAIL_RELAY_BASE ?? "").trim()) }); }); healthRouter.get( "/", (c) => c.json({ service: "arcrun-cypher-executor", version: "1.0.0", status: "ok" }) ); // cypher-executor/src/routes/execute.ts init_dist(); init_types(); init_graph_executor(); init_schemas(); init_component_loader(); // cypher-executor/src/actions/execution-logger.ts init_kbdb_proxy(); function extractTarget(input) { if (!input) return void 0; const raw2 = input.page_name ?? input.path; if (raw2 === void 0 || raw2 === null) return void 0; return typeof raw2 === "string" ? raw2 : JSON.stringify(raw2); } async function writeExecutionVerdict(env, workflowId, nodes, verdict, durationMs, message, input, apiKey) { try { const { base, headers } = kbdbBase(env); await fetch(`${base}/execution-log/record`, { method: "POST", headers, body: JSON.stringify({ workflow_id: workflowId, owner_id: apiKey ?? null, verdict, duration_ms: Math.max(0, Math.round(durationMs)), message: message ?? "", target: extractTarget(input) ?? null }) }); } catch { } } // cypher-executor/src/routes/execute.ts var executeRouter = new Hono2(); executeRouter.post("/execute", async (c) => { const body = await c.req.json(); const parsed = executeSchema.safeParse(body); if (!parsed.success) { return c.json({ error: "\u5716\u5B9A\u7FA9\u9A57\u8B49\u5931\u6557", details: parsed.error.issues }, 400); } const { graph, context } = parsed.data; const apiKey = c.req.header("x-arcrun-api-key") ?? void 0; const loader = createComponentLoader(c.env); const executor = new GraphExecutor(loader, void 0, c.env, apiKey); const start = Date.now(); try { const result = await executor.execute(graph, context, c.env.EXEC_CONTEXT); const duration_ms = Date.now() - start; c.executionCtx.waitUntil( writeExecutionVerdict(c.env, graph.id, graph.nodes, "success", duration_ms, "\u57F7\u884C\u5B8C\u6210", context, apiKey) ); return c.json({ success: true, data: result.data, trace: result.trace, duration_ms }); } catch (err) { const duration_ms = Date.now() - start; const errMsg = err instanceof Error ? err.message : String(err); c.executionCtx.waitUntil( writeExecutionVerdict(c.env, graph.id, graph.nodes, "failed", duration_ms, errMsg.slice(0, 100), context, apiKey) ); if (err instanceof ExecutionError) { const traceFormatted = err.trace.map((s) => ({ node: s.nodeId, status: s.error ? "failed" : "success", ...s.error ? { error: s.error } : {} })); return c.json({ success: false, error: errMsg, failed_node: err.failed_node, failed_input: err.failed_input, trace: traceFormatted, duration_ms }, 500); } return c.json({ success: false, error: errMsg, failed_node: null, trace: [], duration_ms }, 500); } }); // cypher-executor/src/routes/cypher.ts init_dist(); // cypher-executor/src/actions/cypher-handlers.ts init_types(); init_graph_executor(); init_schemas(); init_component_loader(); init_execution_evaluator(); // cypher-executor/src/actions/triplet-parser.ts init_constants3(); function parseTriplets(rawTriplets) { const edges = []; const nodeNames = /* @__PURE__ */ new Set(); const fromSet = /* @__PURE__ */ new Set(); const toSet = /* @__PURE__ */ new Set(); for (const line of rawTriplets) { if (typeof line !== "string") continue; const parts = line.split(">>").map((s) => s.trim()); if (parts.length !== 3) continue; const [from, action, to] = parts; edges.push({ from, to, label: action }); nodeNames.add(from); nodeNames.add(to); fromSet.add(from); toSet.add(to); } if (nodeNames.size === 0) return null; const sourceNodes = new Set([...fromSet].filter((n) => !toSet.has(n))); const sinkNodes = new Set([...toSet].filter((n) => !fromSet.has(n))); return { edges, nodeNames, sourceNodes, sinkNodes }; } var INPUT_NAMES = /* @__PURE__ */ new Set(["input", "trigger", "webhook", "start"]); var OUTPUT_NAMES = /* @__PURE__ */ new Set(["output", "result", "end", "done"]); function isVirtualIoName(name) { const lower = name.toLowerCase(); return INPUT_NAMES.has(lower) || OUTPUT_NAMES.has(lower); } function resolveNodeRole(name, parsed) { if (INPUT_NAMES.has(name.toLowerCase())) return "Input"; if (OUTPUT_NAMES.has(name.toLowerCase())) return "Output"; if (parsed.sourceNodes.has(name)) return "Input"; return "Component"; } function toEdgeType(label) { const upper = label.toUpperCase(); if (VALID_EDGE_TYPES.has(upper)) return upper; return SEMANTIC_EDGE_MAP[label] ?? SEMANTIC_EDGE_MAP[upper] ?? "PIPE"; } // cypher-executor/src/actions/search-nodes.ts init_component_loader(); init_recipes(); // cypher-executor/src/lib/branch-hints.ts var BRANCH_HINTS = { if_control: { branch_field: "data.branch", branches: ["true", "false"], edge_types: ["ON_TRUE", "ON_FALSE"], usage: '\u9019\u9846\u7B97\u5B8C\u6703\u8F38\u51FA data.branch\uFF08"true"\uFF0F"false"\uFF09\u3002\u4E0B\u6E38\u63A5\u5169\u689D\u908A\uFF1AON_TRUE \u63A5\u689D\u4EF6\u6210\u7ACB\u8981\u505A\u7684\u4E8B\uFF0CON_FALSE \u63A5\u4E0D\u6210\u7ACB\u8981\u505A\u7684\u4E8B\u3002**\u4E0D\u9700\u8981\u81EA\u5DF1\u5BEB code \u5224\u65B7\u8D70\u54EA\u689D**\u2014\u2014\u5F15\u64CE\u4F9D branch \u81EA\u52D5\u9078\u8DEF\u3002', example: "\u5224\u65B7\u6709\u6C92\u6709\u65B0\u8CC7\u6599 >> ON_TRUE >> \u50B3\u5230 telegram\n\u5224\u65B7\u6709\u6C92\u6709\u65B0\u8CC7\u6599 >> ON_FALSE >> \u7D50\u675F\n\uFF08\u4E2D\u6587\u8A9E\u610F\u8A5E\u4EA6\u53EF\uFF1A\u300C\u6210\u7ACB\u6642\u300D\uFF1DON_TRUE\u3001\u300C\u5426\u5247\u300D\uFF1DON_FALSE\uFF09" }, switch: { branch_field: "data.branch", branches: "\u7531 input_schema.cases[].branch \u8207 default_branch \u6C7A\u5B9A\uFF08N \u8DEF\uFF0C\u975E\u56FA\u5B9A\u6E05\u55AE\uFF09", edge_types: ["ON_BRANCH"], usage: "\u9019\u9846\u4F9D value \u6BD4\u5C0D cases\uFF0C\u8F38\u51FA data.branch\uFF1D\u547D\u4E2D\u90A3\u500B case \u7684 branch \u540D\uFF08\u90FD\u6C92\u4E2D\u5247\u662F default_branch\uFF09\u3002\u4E0B\u6E38**\u6BCF\u689D\u8DEF\u5404\u63A5\u4E00\u689D ON_BRANCH \u908A\uFF0C\u4E26\u5728\u908A\u4E0A\u6A19 branch \u7B49\u65BC\u4F60\u5728 cases \u88E1\u53D6\u7684\u540D\u5B57**\u3002default_branch \u4E0D\u9700\u8981\u7279\u5225\u7684\u908A\u578B\uFF0C\u7167\u6A23\u7528 ON_BRANCH \u6A19\u5B83\u7684\u540D\u5B57\u5373\u53EF\u3002", example: '{"cases":[{"match":"active","branch":"branch_active"}],"default_branch":"branch_default"}\nedges: [\n {"from":"my_switch","to":"\u8655\u7406\u555F\u7528","type":"ON_BRANCH","branch":"branch_active"},\n {"from":"my_switch","to":"\u8655\u7406\u5176\u4ED6","type":"ON_BRANCH","branch":"branch_default"}\n]' }, try_catch: { branch_field: "data.branch", branches: ["try", "catch"], edge_types: ["ON_BRANCH"], usage: '\u9019\u9846\u770B\u4E0A\u6E38 error \u662F\u5426\u975E\u7A7A\uFF0C\u8F38\u51FA data.branch\uFF08"try"\uFF1D\u6C92\u932F\uFF0F"catch"\uFF1D\u6709\u932F\uFF09\u3002\u4E0B\u6E38\u63A5\u5169\u689D ON_BRANCH \u908A\uFF0Cbranch \u5206\u5225\u6A19 "try" \u8207 "catch"\u3002**\u932F\u8AA4\u8655\u7406\u4E0D\u9700\u8981\u5BEB code**\u2014\u2014\u628A\u8981\u88DC\u6551\u7684\u7BC0\u9EDE\u63A5\u5728 catch \u90A3\u689D\u908A\u5F8C\u9762\u5373\u53EF\u3002', example: 'edges: [\n {"from":"my_try_catch","to":"\u6B63\u5E38\u6D41\u7A0B","type":"ON_BRANCH","branch":"try"},\n {"from":"my_try_catch","to":"\u88DC\u6551\u6D41\u7A0B","type":"ON_BRANCH","branch":"catch"}\n]' } }; function branchHintFor(componentId) { if (!componentId) return void 0; return BRANCH_HINTS[componentId.toLowerCase()]; } // cypher-executor/src/actions/search-nodes.ts async function searchNodes(parsed, config, env, mode = "discover", target) { const nodeResults = {}; const missingNodes = []; if (mode === "compile") { for (const nodeName of parsed.nodeNames) { const role = resolveNodeRole(nodeName, parsed); if ((role === "Input" || role === "Output") && isVirtualIoName(nodeName)) { nodeResults[nodeName] = { status: "found", componentId: nodeName.toLowerCase(), type: role }; continue; } const configComponent = config?.[nodeName]?.component; nodeResults[nodeName] = { status: configComponent ? "found" : "unchecked", componentId: configComponent ?? nodeName, type: role }; } return { nodeResults, missingNodes }; } const sub = env?.WORKER_SUBDOMAIN; const registryBase = env?.REGISTRY_BASE_URL ?? (sub ? wasmWorkerUrl("registry", sub) : void 0); const wantComponents = target !== "recipe"; const wantRecipes = target !== "component"; const catalog = !wantComponents ? { status: "ok", entries: [] } : registryBase ? await fetchCatalog(registryBase) : { status: "unreachable", entries: [] }; const recipes = wantRecipes && env?.RECIPES ? await listAllRecipes2(env.RECIPES) : []; const byId = /* @__PURE__ */ new Map(); for (const e of catalog.entries) { const prev = byId.get(e.canonical_id); if (!prev || (e.score ?? 0) > (prev.score ?? 0)) byId.set(e.canonical_id, e); for (const a of e.aliases ?? []) if (!byId.has(a)) byId.set(a, e); } for (const nodeName of parsed.nodeNames) { const role = resolveNodeRole(nodeName, parsed); if ((role === "Input" || role === "Output") && isVirtualIoName(nodeName)) { nodeResults[nodeName] = { status: "found", componentId: nodeName.toLowerCase(), type: role }; continue; } const configComponent = config?.[nodeName]?.component; const componentId = configComponent ?? nodeName; if (configComponent) { nodeResults[nodeName] = { status: "found", componentId, type: role }; continue; } if (catalog.status === "unreachable") { nodeResults[nodeName] = { status: "unknown", componentId, type: role }; continue; } if (catalog.status === "no_endpoint") { const legacy = await legacyPerNodeLookup(registryBase, componentId, nodeName, role, env, recipes); nodeResults[nodeName] = legacy.info; if (legacy.missing) missingNodes.push(nodeName); continue; } const hit = byId.get(componentId); if (hit) { nodeResults[nodeName] = { status: "found", componentId, type: role, source: "component", input_schema: hit.input_schema, success_rate: typeof hit.success_rate === "number" ? hit.success_rate : void 0, stability: typeof hit.stability === "string" ? hit.stability : void 0, branch_hint: branchHintFor(componentId) }; continue; } const recipe = recipes.find((r) => r.canonical_id === componentId); if (recipe) { nodeResults[nodeName] = { status: "found", componentId: recipe.canonical_id, type: role, source: "recipe", description: recipe.description, endpoint: recipe.endpoint, payload_hint: buildPayloadHint(recipe) }; continue; } const substituted = trySubstitution(nodeName, catalog.entries, recipes); if (substituted) { nodeResults[nodeName] = { ...substituted, type: role }; continue; } const similarComponents = similarFromCatalog(catalog.entries, nodeName); const similarRecipes = similarFromRecipes(recipes, nodeName); nodeResults[nodeName] = { status: "not_found", componentId, type: role, suggestion: buildSuggestion(componentId), ...similarComponents.length > 0 ? { similar_components: similarComponents } : {}, ...similarRecipes.length > 0 ? { similar_recipes: similarRecipes } : {} }; missingNodes.push(nodeName); } return { nodeResults, missingNodes }; } async function fetchCatalog(registryBase) { try { const res = await fetch(`${registryBase}/components/catalog`, { signal: AbortSignal.timeout(1e4) }); if (res.status === 404) return { status: "no_endpoint", entries: [] }; if (!res.ok) return { status: "unreachable", entries: [] }; const body = await res.json(); return { status: "ok", entries: body.data?.components ?? [] }; } catch { return { status: "unreachable", entries: [] }; } } async function listAllRecipes2(kv) { try { const list = await kv.list({ prefix: "recipe:" }); return (await Promise.all( list.keys.map((k) => kv.get(k.name, "json")) )).filter(Boolean); } catch { return []; } } function similarFromCatalog(entries, nodeName) { const searchableOf = (e) => [e.canonical_id, e.display_name ?? "", e.description ?? "", ...e.aliases ?? [], ...e.tags ?? []].join(" ").toLowerCase(); const full = nodeName.toLowerCase(); const direct = entries.filter((e) => searchableOf(e).includes(full)).map((e) => e.canonical_id); if (direct.length > 0) return [...new Set(direct)].slice(0, 3); const tokens = extractTokens(nodeName); if (tokens.length === 0) return []; const count = /* @__PURE__ */ new Map(); for (const e of entries) { const hay = searchableOf(e); const hits = tokens.filter((t) => hay.includes(t)).length; if (hits > 0) count.set(e.canonical_id, Math.max(count.get(e.canonical_id) ?? 0, hits)); } return [...count.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([id]) => id); } function similarFromRecipes(recipes, nodeName) { const tokens = [nodeName.toLowerCase(), ...extractTokens(nodeName)]; const seen = /* @__PURE__ */ new Set(); const matched = []; for (const r of recipes) { if (seen.has(r.canonical_id)) continue; const hay = `${r.canonical_id} ${r.display_name ?? ""} ${r.description ?? ""}`.toLowerCase(); if (tokens.some((t) => hay.includes(t))) { seen.add(r.canonical_id); matched.push(r.canonical_id); } } return matched.slice(0, 3); } async function legacyPerNodeLookup(registryBase, componentId, nodeName, role, env, recipes) { const q = await fetchComponent(registryBase, componentId); if (!q.ok) return { info: { status: "unknown", componentId, type: role }, missing: false }; if (q.entry) { return { info: { status: "found", componentId, type: role, source: "component", input_schema: q.entry.input_schema, success_rate: q.entry.success_rate, stability: q.entry.stability, branch_hint: branchHintFor(componentId) }, missing: false }; } const recipe = recipes.find((r) => r.canonical_id === componentId) ?? (env?.RECIPES ? await resolveRecipe(componentId, env.RECIPES) : null); if (recipe) { return { info: { status: "found", componentId: recipe.canonical_id, type: role, source: "recipe", description: recipe.description, endpoint: recipe.endpoint, payload_hint: buildPayloadHint(recipe) }, missing: false }; } const similarComponents = await searchSimilarComponents(registryBase, nodeName); const similarRecipes = similarFromRecipes(recipes, nodeName); return { info: { status: "not_found", componentId, type: role, suggestion: buildSuggestion(componentId), ...similarComponents.length > 0 ? { similar_components: similarComponents } : {}, ...similarRecipes.length > 0 ? { similar_recipes: similarRecipes } : {} }, missing: true }; } function trySubstitution(nodeName, catalogEntries, recipes) { const lower = nodeName.toLowerCase(); const serviceHits = SERVICE_HINTS.filter((w) => lower.includes(w)); if (serviceHits.length > 0) { const matched = /* @__PURE__ */ new Map(); for (const r of recipes) { const hay = `${r.canonical_id} ${r.display_name ?? ""} ${r.description ?? ""}`.toLowerCase(); if (serviceHits.every((h) => hay.includes(h))) matched.set(r.canonical_id, r); } if (matched.size !== 1) return null; const recipe = [...matched.values()][0]; return { status: "resolved", componentId: recipe.canonical_id, source: "recipe", description: recipe.description, endpoint: recipe.endpoint, substitution: { from: nodeName, componentId: "http_request", // recipe=http_request+參數模板的具名封裝 recipe: recipe.canonical_id, reason: `\u670D\u52D9\u8A5E\u300C${serviceHits.join("\u3001")}\u300D\u552F\u4E00\u547D\u4E2D recipe\u300C${recipe.canonical_id}\u300D\uFF1Bworkflow config \u5BEB component: ${recipe.canonical_id}\uFF08\u5E95\u5C64\u96F6\u4EF6\uFF1Dhttp_request\uFF09\uFF0C\u53EA\u9700\u586B payload` } }; } const tokens = extractTokens(nodeName); if (tokens.length === 0) return null; const byCanonical = /* @__PURE__ */ new Map(); for (const e of catalogEntries) { const strongHay = [e.canonical_id, e.display_name ?? "", ...e.aliases ?? []].join(" ").toLowerCase(); const weakHay = [e.description ?? "", ...e.tags ?? []].join(" ").toLowerCase(); const strongHits = tokens.filter((t) => strongHay.includes(t)); const weakCount = tokens.filter((t) => weakHay.includes(t)).length; const score = strongHits.length * 10 + weakCount; if (score === 0) continue; const prev = byCanonical.get(e.canonical_id); if (!prev || score > prev.score) byCanonical.set(e.canonical_id, { entry: e, score, strongHits }); } const ranked = [...byCanonical.values()].sort((a, b) => b.score - a.score); const top = ranked[0]; if (!top || top.strongHits.length === 0) return null; if (ranked[1] && ranked[1].score >= top.score) return null; return { status: "resolved", componentId: top.entry.canonical_id, source: "component", input_schema: top.entry.input_schema, success_rate: typeof top.entry.success_rate === "number" ? top.entry.success_rate : void 0, stability: typeof top.entry.stability === "string" ? top.entry.stability : void 0, // 替換成分岔零件時(例「判斷有沒有新資料」→ if_control)一併附分支用法, // 否則 AI 換到零件卻不知道怎麼接兩條路,仍會退回寫 code。 branch_hint: branchHintFor(top.entry.canonical_id), substitution: { from: nodeName, componentId: top.entry.canonical_id, reason: `\u65B7\u8A5E\u300C${top.strongHits.join("\u3001")}\u300D\u547D\u4E2D\u96F6\u4EF6\u300C${top.entry.canonical_id}\u300D\uFF08${top.entry.display_name ?? ""}\uFF09\u5F37\u6B04\u4F4D\u4E14\u5206\u6578\u552F\u4E00\u6700\u9AD8\uFF1B\u53EA\u9700\u7167 input_schema \u586B payload` } }; } var SERVICE_HINTS = [ "google", "gmail", "sheets", "slides", "gdocs", "drive", "calendar", "youtube", "slack", "telegram", "discord", "line", "whatsapp", "twilio", "notion", "airtable", "trello", "jira", "asana", "linear", "github", "gitea", "gitlab", "bitbucket", "stripe", "paypal", "shopify", "hubspot", "salesforce", "openai", "anthropic", "claude", "gemini", "groq", "twitter", "facebook", "instagram", "linkedin", "dropbox", "zoom", "sendgrid", "mailgun", "kbdb" ]; var COMPUTE_HINTS = [ "encrypt", "decrypt", "cipher", "aes", "rsa", "sha", "md5", "hmac", "hash", "sign", "verify", "encode", "decode", "base64", "hex", "compress", "decompress", "zip", "gzip", "uuid", "random", "regex", "math", "calc", "sort", "dedup", "diff", "template", "render", "convert", "transform", "parse", "format", "csv", "xml" ]; function buildSuggestion(componentId) { const lower = componentId.toLowerCase(); const serviceHit = SERVICE_HINTS.find((w) => lower.includes(w)); const computeHit = COMPUTE_HINTS.find((w) => lower.includes(w)); if (serviceHit) { return `\u5169\u5EAB\u90FD\u67E5\u904E\uFF0C\u96F6\u4EF6 registry \u8207 recipe \u5EAB\u7686\u7121\u300C${componentId}\u300D\u3002\u540D\u5B57\u542B\u670D\u52D9\u8A5E\u300C${serviceHit}\u300D\uFF1D\u5916\u90E8 API \u6A23\u8C8C \u2192 \u6C92\u6709\u6B64 recipe\uFF0C\u53EF\u81EA\u5DF1\u5BEB\uFF1A\u5BEB\u6CD5\u770B skill\u300Cwrite_recipe\u300D\uFF08arcrun_get_skill('write_recipe')\uFF09\uFF0C\u5BEB\u597D\u7528 acr recipe push \u6216 POST /recipes \u88DD\u4E0A\u5373\u53EF\u7528\uFF0C\u4E0D\u7528\u6539\u5E73\u53F0\u3002`; } if (computeHit) { return `\u5169\u5EAB\u90FD\u67E5\u904E\uFF0C\u96F6\u4EF6 registry \u8207 recipe \u5EAB\u7686\u7121\u300C${componentId}\u300D\u3002\u540D\u5B57\u542B\u8A08\u7B97\u8A5E\u300C${computeHit}\u300D\uFF1D\u8A08\u7B97\u539F\u8A9E\u6A23\u8C8C \u2192 \u6C92\u6709\u6B64\u96F6\u4EF6\uFF0C\u53EF\u6295\u7A3F PR \u65B0\u589E WASM component\uFF1A\u505A\u6CD5\u770B skill\u300Cadd_new_wasm_component\u300D\uFF08arcrun_get_skill('add_new_wasm_component')\uFF09\u3002`; } return `\u5169\u5EAB\u90FD\u67E5\u904E\uFF0C\u96F6\u4EF6 registry \u8207 recipe \u5EAB\u7686\u7121\u300C${componentId}\u300D\uFF0C\u4E14\u540D\u5B57\u5224\u4E0D\u51FA\u578B\u3002\u7F3A\u5916\u90E8 API \u2192 \u81EA\u5DF1\u5BEB recipe\uFF08skill\u300Cwrite_recipe\u300D\uFF09\uFF1B\u7F3A\u8A08\u7B97\u80FD\u529B \u2192 \u6295\u7A3F\u96F6\u4EF6 PR\uFF08skill\u300Cadd_new_wasm_component\u300D\uFF0Ccomponent \u9032 WASM \u6C99\u7BB1\uFF09\u3002`; } function buildPayloadHint(recipe) { const parts = []; if (recipe.body_template) { parts.push("payload \u5DF2\u6536\u5728 recipe \u7684 body_template \u88E1\uFF0C\u4F60\u53EA\u8981\u628A {{\u8B8A\u6578}} \u5C0D\u61C9\u7684\u503C\u653E\u9032\u7BC0\u9EDE context"); } else if (recipe.body) { parts.push("payload \u5F62\u72C0\u898B body \u6B04\u4F4D\uFF08{{\u8B8A\u6578}} \u7531\u7BC0\u9EDE context \u586B\uFF09"); } else { parts.push("\u672A\u5B9A\u7FA9 body_template\uFF1A\u7BC0\u9EDE context \u6703\u6574\u5305\u7576 body \u9001\u51FA\uFF08_ \u958B\u982D\u7684\u5167\u90E8\u6B04\u4F4D\u6703\u88AB\u5254\u9664\uFF09"); } if (recipe.response_map) { parts.push("\u56DE\u61C9\u5DF2\u6B63\u898F\u5316\uFF1A\u57F7\u884C\u7D50\u679C\u9664\u4E86\u539F\u59CB data\uFF0C\u53E6\u9644 text\uFF08\u53D6\u503C\u8DEF\u5F91\u7B49\u898F\u5247\u5BEB\u5728 recipe \u88E1\uFF0C\u63DB\u6E90\u4E0D\u5FC5\u6539 workflow\uFF09"); } else { parts.push("\u672A\u5B9A\u7FA9 response_map\uFF1A\u56DE\u61C9\u539F\u6A23\u653E\u5728 data\uFF0C\u53D6\u503C\u8981\u81EA\u5DF1\u6307\u8DEF\u5F91"); } if (recipe.auth === "binding") { parts.push(`\u8A8D\u8B49\uFF1Dbinding\uFF08\u514D\u91D1\u9470\uFF0C\u7528\u5E73\u53F0\u5167\u5EFA ${recipe.binding_name ?? "AI"}\uFF09`); } else if (recipe.auth_service) { parts.push(`\u8A8D\u8B49\u8D70 auth recipe\u300C${recipe.auth_service}\u300D\uFF08\u91D1\u9470\u7531\u7CFB\u7D71\u5728\u57F7\u884C\u524D\u6CE8\u5165\uFF0C\u4F60\u4E0D\u5FC5\u4E5F\u4E0D\u8A72\u586B\uFF09`); } return { body_template: recipe.body_template, response_map: recipe.response_map, usage: parts.join("\uFF1B") + "\u3002" }; } async function fetchComponent(registryBase, id) { try { const res = await fetch(`${registryBase}/components/${encodeURIComponent(id)}`, { signal: AbortSignal.timeout(5e3) }); if (res.status === 404) return { ok: true }; if (!res.ok) return { ok: false }; const body = await res.json(); if (body.success === false) return { ok: true }; const d = body.data ?? body; return { ok: true, entry: { input_schema: d.input_schema, success_rate: typeof d.success_rate === "number" ? d.success_rate : void 0, stability: typeof d.stability === "string" ? d.stability : void 0 } }; } catch { return { ok: false }; } } function extractTokens(name) { const tokens = []; const ascii = name.toLowerCase().match(/[a-z0-9]{3,}/g) ?? []; tokens.push(...ascii); const cjkRuns = name.match(/[一-鿿]+/g) ?? []; for (const run2 of cjkRuns) { for (let i = 0; i + 2 <= run2.length; i++) tokens.push(run2.slice(i, i + 2)); } return [...new Set(tokens)].slice(0, 8); } async function searchRegistryIds(registryBase, q) { try { const res = await fetch(`${registryBase}/components/search?q=${encodeURIComponent(q)}`, { signal: AbortSignal.timeout(5e3) }); if (!res.ok) return []; const body = await res.json(); return (body.data?.results ?? []).map((r) => r.canonical_id).filter((s) => !!s); } catch { return []; } } async function searchSimilarComponents(registryBase, nodeName) { const direct = await searchRegistryIds(registryBase, nodeName); if (direct.length > 0) return direct.slice(0, 3); const tokens = extractTokens(nodeName); if (tokens.length === 0) return []; const hits = await Promise.all(tokens.map((t) => searchRegistryIds(registryBase, t))); const count = /* @__PURE__ */ new Map(); for (const ids of hits) { for (const id of ids) count.set(id, (count.get(id) ?? 0) + 1); } return [...count.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([id]) => id); } // cypher-executor/src/actions/graph-builder.ts function buildExecutionGraph(parsed, nodeResults, graphId, graphName, config) { const nodes = [...parsed.nodeNames].map((name) => { const nr = nodeResults[name]; const id = name.toLowerCase().replace(/\s+/g, "-"); const nodeConfig = config?.[name] ?? {}; const componentId = nodeConfig.component ?? nr.componentId; const { component: _component, ...staticParams } = nodeConfig; const data = Object.keys(staticParams).length > 0 ? staticParams : void 0; return { id, type: nr.type, componentId, label: name, data }; }); const edges = parsed.edges.map((e) => { let iterator; let label = e.label; const foreachMatch = label.match(/^(?:對每個|FOREACH)\s+(\w+)$/i); if (foreachMatch) { iterator = foreachMatch[1]; label = "\u5C0D\u6BCF\u500B"; } let branch; const branchMatch = label.match(/^(?:ON_BRANCH|分支)\s*[((]\s*([\w-]+)\s*[))]$/i); if (branchMatch) { branch = branchMatch[1]; label = "ON_BRANCH"; } const edge = { from: e.from.toLowerCase().replace(/\s+/g, "-"), to: e.to.toLowerCase().replace(/\s+/g, "-"), type: toEdgeType(label) }; if (iterator) edge.iterator = iterator; if (branch) edge.branch = branch; return edge; }); return { id: graphId, name: graphName, nodes, edges }; } // cypher-executor/src/actions/cypher-handlers.ts async function handleCypherSearch(triplets, env, mode = "discover", target) { const parsed = parseTriplets(triplets); if (!parsed) { throw new Error("\u7121\u6CD5\u89E3\u6790\u4EFB\u4F55\u7BC0\u9EDE"); } const { nodeResults, missingNodes } = await searchNodes(parsed, void 0, env, mode, target); const graph = buildExecutionGraph(parsed, nodeResults, "cypher-search-result", "Cypher Search Result"); return { nodes: nodeResults, cypher: { nodes: graph.nodes, edges: graph.edges }, missing: missingNodes }; } async function handleCypherExecute(triplets, context, graphId, graphName, config, env, waitUntil, apiKey) { const parsed = parseTriplets(triplets); if (!parsed) { throw new Error("\u7121\u6CD5\u89E3\u6790\u4EFB\u4F55\u7BC0\u9EDE"); } const { nodeResults } = await searchNodes(parsed, config, env, "compile"); const graph = buildExecutionGraph(parsed, nodeResults, graphId, graphName, config); const parseResult = graphSchema.safeParse(graph); if (!parseResult.success) { throw new Error("\u5716\u5B9A\u7FA9\u7522\u751F\u5931\u6557"); } const loader = createComponentLoader(env); const executor = new GraphExecutor(loader, void 0, env, apiKey); const start = Date.now(); try { const result = await executor.execute(parseResult.data, context ?? {}, env.EXEC_CONTEXT); const duration_ms = Date.now() - start; waitUntil(recordComponentStats(env, graph.nodes, result.trace)); return { success: true, data: result.data, trace: result.trace, duration_ms, graph }; } catch (err) { const duration_ms = Date.now() - start; if (err instanceof WorkflowPaused) { return { success: true, paused: true, task_id: err.task_id, run_id: err.run_id, paused_node_id: err.paused_node_id, trace: err.trace_so_far, duration_ms, graph }; } const errMsg = err instanceof Error ? err.message : String(err); if (err instanceof ExecutionError) { waitUntil(recordComponentStats(env, graph.nodes, err.trace)); const traceFormatted = err.trace.map((s) => ({ node: s.nodeId, status: s.error ? "failed" : "success", ...s.error ? { error: s.error } : {} })); throw new Error(JSON.stringify({ success: false, error: errMsg, failed_node: err.failed_node, failed_input: err.failed_input, trace: traceFormatted, duration_ms })); } throw err; } } // cypher-executor/src/actions/target-search.ts init_component_loader(); // cypher-executor/src/lib/workflow-search.ts async function fetchTenantWorkflowSearch(env, apiKey, q, mode = "semantic") { const base = (env.KBDB_BASE_URL ?? "https://arcrun-kbdb.uncle6-me.workers.dev").replace(/\/$/, ""); const headers = { "Content-Type": "application/json" }; if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`; const params = new URLSearchParams({ q, owner_id: apiKey, // 租戶隔離(只搜本租戶的 workflow) entry_type: "workflow", // base 通用 filter(Q4),只回 workflow entry mode }); return fetch(`${base}/entries/search?${params.toString()}`, { headers }); } // cypher-executor/src/actions/target-search.ts async function searchByTarget(target, query, env, apiKey) { if (target === "component") { const sub = env.WORKER_SUBDOMAIN; const registryBase = env.REGISTRY_BASE_URL ?? (sub ? wasmWorkerUrl("registry", sub) : void 0); if (!registryBase) return { ok: false, status: 502, error: "registry \u4F4D\u7F6E\u672A\u8A2D\u5B9A\uFF08WORKER_SUBDOMAIN\uFF0FREGISTRY_BASE_URL \u7686\u7F3A\uFF09" }; try { const res2 = await fetch( `${registryBase}/components/search?q=${encodeURIComponent(query)}`, { signal: AbortSignal.timeout(1e4) } ); if (!res2.ok) return { ok: false, status: 502, error: `registry \u641C\u5C0B\u5931\u6557\uFF08HTTP ${res2.status}\uFF09` }; const body2 = await res2.json(); const results = (body2.data?.results ?? []).map((r) => { if (!r || typeof r !== "object") return r; const rec = r; const hint = branchHintFor(typeof rec.canonical_id === "string" ? rec.canonical_id : void 0); return hint ? { ...rec, branch_hint: hint } : rec; }); return { ok: true, body: { target, query, results, count: body2.data?.count ?? 0 } }; } catch (e) { return { ok: false, status: 502, error: `registry \u67E5\u4E0D\u901A\uFF1A${e instanceof Error ? e.message : String(e)}` }; } } if (target === "recipe") { if (!env.RECIPES) return { ok: false, status: 502, error: "RECIPES KV \u672A\u7D81\u5B9A" }; const all = await listAllRecipes2(env.RECIPES); const q = query.toLowerCase(); const seen = /* @__PURE__ */ new Set(); const results = []; for (const r of all) { if (seen.has(r.canonical_id)) continue; const hay = `${r.canonical_id} ${r.display_name ?? ""} ${r.description ?? ""}`.toLowerCase(); if (!hay.includes(q)) continue; seen.add(r.canonical_id); results.push({ canonical_id: r.canonical_id, display_name: r.display_name, description: r.description, endpoint: r.endpoint, // 3.12:逐顆查 recipe 時也要說得出「payload 怎麼填、回應怎麼取值」 payload_hint: buildPayloadHint(r) }); } return { ok: true, body: { target, query, results, count: results.length, note: "\u641C\u7684\u662F\u672C\u90E8\u7F72\u79C1\u5EAB\uFF08workflow \u53EF\u76F4\u63A5 component: \u5F15\u7528\uFF09\u3002\u516C\u5EAB\uFF08\u591A\u4F5C\u8005\u5E02\u5834\uFF09\u8D70 MCP arcrun_recipe_search\uFF0FGET /public-recipes\u3002" } }; } if (!apiKey) return { ok: false, status: 401, error: "target=workflow \u9700\u8981 X-Arcrun-API-Key header\uFF08workflow \u641C\u5C0B\u9650\u672C\u79DF\u6236\uFF09" }; const res = await fetchTenantWorkflowSearch(env, apiKey, query); if (!res.ok) return { ok: false, status: 502, error: `workflow \u641C\u5C0B\u5931\u6557\uFF08KBDB HTTP ${res.status}\uFF09` }; const body = await res.json(); return { ok: true, body: { target, query, ...body } }; } // cypher-executor/src/routes/cypher.ts var cypherRouter = new Hono2(); var VALID_TARGETS = /* @__PURE__ */ new Set(["component", "recipe", "workflow"]); cypherRouter.post("/cypher/search", async (c) => { const body = await c.req.json(); const rawTriplets = body?.triplets; const target = typeof body?.target === "string" ? body.target : void 0; if (target !== void 0 && !VALID_TARGETS.has(target)) { return c.json({ error: `target \u53EA\u63A5\u53D7 component\uFF0Frecipe\uFF0Fworkflow\uFF0C\u6536\u5230\u300C${target}\u300D` }, 400); } const query = typeof body?.query === "string" ? body.query.trim() : ""; if (query) { if (!target) { return c.json({ error: "\u7D66 query \u5FC5\u9808\u540C\u6642\u7D66 target\uFF08component\uFF0Frecipe\uFF0Fworkflow\uFF09\uFF0C\u6307\u660E\u8981\u641C\u54EA\u500B\u5EAB" }, 400); } const apiKey = c.req.header("X-Arcrun-API-Key") ?? void 0; const r = await searchByTarget(target, query, c.env, apiKey); if (!r.ok) return c.json({ error: r.error }, r.status); return c.json(r.body); } if (!Array.isArray(rawTriplets) || rawTriplets.length === 0) { return c.json({ error: "triplets \u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32\u9663\u5217\uFF08\u6216\u7D66 query + target \u505A\u540D\u5B57\u641C\u5C0B\uFF09" }, 400); } const mode = body?.mode === "compile" ? "compile" : "discover"; if (target && mode === "compile") { return c.json({ error: "mode=compile\uFF08\u8907\u88FD\u8DEF\u5F91\uFF09\u4E0D\u67E5\u5EAB\uFF0C\u4E0D\u63A5\u53D7 target\uFF1B\u8981\u6307\u5B9A\u641C\u5C0B\u5C0D\u8C61\u8ACB\u7528 discover\uFF08\u9810\u8A2D\uFF09" }, 400); } if (target === "workflow") { return c.json({ error: 'target=workflow \u662F\u540D\u5B57\u641C\u5C0B\uFF0C\u8ACB\u6539\u5E36 { target: "workflow", query: "..." }\uFF08\u4E0D\u5403 triplets\uFF09' }, 400); } try { const now2 = /* @__PURE__ */ new Date(); const timestamp = now2.toISOString(); const versionId = `search-v1-${now2.getFullYear()}${String(now2.getMonth() + 1).padStart(2, "0")}${String(now2.getDate()).padStart(2, "0")}-${String(now2.getHours()).padStart(2, "0")}${String(now2.getMinutes()).padStart(2, "0")}${String(now2.getSeconds()).padStart(2, "0")}`; const result = await handleCypherSearch(rawTriplets, c.env, mode, target); const response = { version: versionId, timestamp, triplets: rawTriplets, nodes: result.nodes, cypher: result.cypher, missing: result.missing }; return c.json(response); } catch (err) { const errMsg = err instanceof Error ? err.message : String(err); return c.json({ error: errMsg }, 400); } }); cypherRouter.post("/cypher/execute", async (c) => { const body = await c.req.json(); if (!Array.isArray(body?.triplets) || body.triplets.length === 0) { return c.json({ error: "triplets \u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32\u9663\u5217" }, 400); } const graphId = typeof body.graph_id === "string" ? body.graph_id : `triplet-exec-${Date.now()}`; const graphName = typeof body.graph_name === "string" ? body.graph_name : "Triplet Execution"; const now2 = /* @__PURE__ */ new Date(); const timestamp = now2.toISOString(); const versionId = `execute-v1-${now2.getFullYear()}${String(now2.getMonth() + 1).padStart(2, "0")}${String(now2.getDate()).padStart(2, "0")}-${String(now2.getHours()).padStart(2, "0")}${String(now2.getMinutes()).padStart(2, "0")}${String(now2.getSeconds()).padStart(2, "0")}`; const apiKey = c.req.header("X-Arcrun-API-Key") ?? void 0; try { const result = await handleCypherExecute( body.triplets, body.context, graphId, graphName, body.config, c.env, (p) => c.executionCtx.waitUntil(p), apiKey ); const response = { version: versionId, timestamp, ...result }; return c.json(response); } catch (err) { const errMsg = err instanceof Error ? err.message : String(err); try { const parsed = JSON.parse(errMsg); const response = { version: versionId, timestamp, ...parsed }; return c.json(response, 500); } catch { return c.json({ version: versionId, timestamp, success: false, error: errMsg, duration_ms: 0 }, 500); } } }); // cypher-executor/src/routes/validate.ts init_dist(); init_schemas(); init_telemetry(); var validateRouter = new Hono2(); validateRouter.post("/validate", async (c) => { const start = Date.now(); const apiKey = c.req.header("X-Arcrun-API-Key"); const userAgent = c.req.header("User-Agent") ?? void 0; const body = await c.req.json(); const parsed = graphSchema.safeParse(body); if (!parsed.success) { recordTelemetry(c.env, apiKey, { event_type: "validation_error", error_code: "schema_failed", duration_ms: Date.now() - start, agent_user_agent: userAgent }, c.executionCtx); return c.json({ valid: false, errors: parsed.error.issues }, 400); } const nodeIds = new Set(parsed.data.nodes.map((n) => n.id)); const invalidEdges = parsed.data.edges.filter((e) => !nodeIds.has(e.from) || !nodeIds.has(e.to)); if (invalidEdges.length > 0) { recordTelemetry(c.env, apiKey, { event_type: "validation_error", error_code: "edge_node_missing", duration_ms: Date.now() - start, agent_user_agent: userAgent }, c.executionCtx); return c.json({ valid: false, errors: invalidEdges.map((e) => `\u908A ${e.from} \u2192 ${e.to} \u6307\u5411\u4E0D\u5B58\u5728\u7684\u7BC0\u9EDE`) }, 400); } return c.json({ valid: true, nodeCount: parsed.data.nodes.length, edgeCount: parsed.data.edges.length }); }); // cypher-executor/src/routes/docs.ts init_dist(); // cypher-executor/src/lib/openapi.ts var OPENAPI_SPEC = { openapi: "3.0.3", info: { title: "arcrun cypher-executor API", description: "AI Workflow Execution Engine \u2014 \u900F\u904E\u4E09\u5143\u7D44 Triplet \u6216\u5716 Graph \u5B9A\u7FA9\u5DE5\u4F5C\u6D41\uFF0C\u7CFB\u7D71\u57F7\u884C\u4E26\u56DE\u50B3\u7D50\u679C", version: "1.0.0", contact: { name: "arcrun", url: "https://github.com/arcrun/arcrun" } }, servers: [ { url: "https://cypher.arcrun.dev", description: "arcrun.dev Hosted" }, { url: "http://localhost:8787", description: "Local Development" } ], paths: { "/": { get: { summary: "Health Check", tags: ["Health"], responses: { "200": { description: "Service is running", content: { "application/json": { schema: { type: "object", properties: { service: { type: "string" }, version: { type: "string" }, status: { type: "string" } } } } } } } } }, "/cypher/search": { post: { summary: "\u641C\u5C0B\u5DE5\u4F5C\u6D41\u9700\u8981\u7684\u96F6\u4EF6", tags: ["Cypher"], description: "\u7528\u4E09\u5143\u7D44\u63CF\u8FF0\u5DE5\u4F5C\u6D41\uFF0C\u7CFB\u7D71\u89E3\u6790\u4E26\u5F9E Registry \u67E5\u8A62\u5C0D\u61C9\u96F6\u4EF6", requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { triplets: { type: "array", items: { type: "string" }, example: ["start >> \u5B8C\u6210\u5F8C >> get-data", "get-data >> \u5B8C\u6210\u5F8C >> done"], description: '\u4E09\u5143\u7D44\u9663\u5217\uFF0C\u683C\u5F0F\uFF1A"FROM >> ACTION >> TO"' }, auto_publish: { type: "boolean", default: true, description: "\u7F3A\u5931\u7684\u96F6\u4EF6\u662F\u5426\u81EA\u52D5\u7522\u751F\u767C\u4F48" } }, required: ["triplets"] } } } }, responses: { "200": { description: "\u96F6\u4EF6\u641C\u5C0B\u6210\u529F\uFF08\u542B\u7248\u672C\u865F\u548C\u6642\u6233\uFF0C\u9069\u5408 Markdown \u6587\u6A94\u8FFD\u8E64\uFF09", content: { "application/json": { schema: { type: "object", properties: { version: { type: "string", example: "search-v1-20260327-143022", description: "\u7248\u672C\u865F\uFF08endpoint-v{major}-{timestamp}\uFF09" }, timestamp: { type: "string", format: "date-time", description: "ISO 8601 \u6642\u6233" }, triplets: { type: "array", items: { type: "string" }, description: "\u56DE\u9001\u7684\u4E09\u5143\u7D44\u5217\u8868" }, nodes: { type: "object", description: "\u641C\u5C0B\u5230\u7684\u96F6\u4EF6\u53CA\u5176\u72C0\u614B" }, cypher: { type: "object", description: "\u5DE5\u4F5C\u6D41\u5716\uFF08null \u82E5\u6709\u7F3A\u5931\u96F6\u4EF6\uFF09" }, missing: { type: "array", items: { type: "string" }, description: "\u7F3A\u5931\u96F6\u4EF6\u5217\u8868" }, auto_published: { type: "object", description: "\u81EA\u52D5\u767C\u4F48\u7684\u96F6\u4EF6\uFF08\u82E5 auto_publish=true\uFF09" } } } } } }, "400": { description: "\u7121\u6CD5\u89E3\u6790\u4E09\u5143\u7D44" } } } }, "/cypher/execute": { post: { summary: "\u57F7\u884C\u5DE5\u4F5C\u6D41", tags: ["Cypher"], description: "\u76F4\u63A5\u57F7\u884C triplets\uFF0C\u56DE\u50B3\u5B8C\u6574\u57F7\u884C\u7D50\u679C\u3002\u652F\u63F4\u81EA\u52D5\u767C\u4F48\u7F3A\u5931\u96F6\u4EF6\u3002", requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { triplets: { type: "array", items: { type: "string" }, description: '\u4E09\u5143\u7D44\u9663\u5217\uFF0C\u683C\u5F0F\uFF1A"FROM >> ACTION >> TO"' }, context: { type: "object", description: "\u57F7\u884C\u4E0A\u4E0B\u6587\uFF0C\u50B3\u5165\u5404\u7BC0\u9EDE\u4F5C\u70BA\u521D\u59CB\u53C3\u6578" }, auto_publish: { type: "boolean", default: true, description: "\u7F3A\u5931\u7684\u96F6\u4EF6\u662F\u5426\u81EA\u52D5\u7522\u751F\u81E8\u6642\u5BE6\u4F5C" } }, required: ["triplets"] } } } }, responses: { "200": { description: "\u57F7\u884C\u6210\u529F\uFF08\u542B\u7248\u672C\u865F\u548C\u6642\u6233\uFF09", content: { "application/json": { schema: { type: "object", properties: { version: { type: "string", example: "execute-v1-20260327-143022", description: "\u7248\u672C\u865F\uFF08endpoint-v{major}-{timestamp}\uFF09" }, timestamp: { type: "string", format: "date-time", description: "ISO 8601 \u6642\u6233" }, success: { type: "boolean", enum: [true] }, data: { type: "object", description: "\u57F7\u884C\u7D50\u679C" }, trace: { type: "array", description: "\u57F7\u884C\u8DDF\u8E64" }, duration_ms: { type: "number" } } } } } }, "500": { description: "\u57F7\u884C\u5931\u6557\u6216\u90E8\u4EFD\u96F6\u4EF6\u7F3A\u5931\uFF08\u542B\u7248\u672C\u865F\u548C\u6642\u6233\uFF09", content: { "application/json": { schema: { type: "object", properties: { version: { type: "string", example: "execute-v1-20260327-143022", description: "\u7248\u672C\u865F\uFF08endpoint-v{major}-{timestamp}\uFF09" }, timestamp: { type: "string", format: "date-time", description: "ISO 8601 \u6642\u6233" }, success: { type: "boolean", enum: [false] }, error: { type: "string" }, missing: { type: "array", items: { type: "string" }, description: "\u7121\u6CD5\u81EA\u52D5\u767C\u4F48\u7684\u7F3A\u5931\u96F6\u4EF6" }, auto_published: { type: "object", description: "\u81EA\u52D5\u767C\u4F48\u7684\u96F6\u4EF6\u8CC7\u8A0A", additionalProperties: { type: "object", properties: { ok: { type: "boolean" }, componentId: { type: "string" }, temporary_endpoint: { type: "string", format: "uri", description: "\u81E8\u6642\u5BE6\u4F5C\u7684 URL" }, implement_by: { type: "string", format: "date-time", description: "\u5BE6\u4F5C\u622A\u6B62\u6642\u9593" } } } }, duration_ms: { type: "number" } } } } } } } } }, "/webhooks": { post: { summary: "\u5EFA\u7ACB Webhook", tags: ["Webhooks"], description: "\u5C07\u5DE5\u4F5C\u6D41\u8A3B\u518A\u6210 Webhook\uFF0C\u5F97\u5230\u516C\u958B URL", requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { triplets: { type: "array", items: { type: "string" } }, description: { type: "string" } } } } } }, responses: { "201": { description: "Webhook \u5EFA\u7ACB\u6210\u529F", content: { "application/json": { schema: { type: "object", properties: { token: { type: "string" }, webhook_url: { type: "string", format: "uri" }, description: { type: "string" }, created_at: { type: "string", format: "date-time" } } } } } } } }, get: { summary: "\u5217\u51FA\u6240\u6709 Webhooks", tags: ["Webhooks"], parameters: [ { name: "Authorization", in: "header", required: true, schema: { type: "string", example: "Bearer u6u_xxxxx" }, description: "API Key \u8A8D\u8B49" } ], responses: { "200": { description: "Webhooks \u5217\u8868", content: { "application/json": { schema: { type: "object", properties: { webhooks: { type: "array", items: { type: "object", properties: { token: { type: "string" }, description: { type: "string" }, created_at: { type: "string", format: "date-time" } } } }, total: { type: "number" } } } } } }, "401": { description: "\u672A\u6388\u6B0A" } } } }, "/webhooks/{token}": { get: { summary: "\u67E5\u8A62\u55AE\u500B Webhook", tags: ["Webhooks"], parameters: [ { name: "token", in: "path", required: true, schema: { type: "string" } } ], responses: { "200": { description: "Webhook \u8CC7\u8A0A" }, "404": { description: "Webhook \u4E0D\u5B58\u5728" } } }, delete: { summary: "\u522A\u9664 Webhook", tags: ["Webhooks"], parameters: [ { name: "token", in: "path", required: true, schema: { type: "string" } } ], responses: { "200": { description: "Webhook \u5DF2\u522A\u9664" }, "404": { description: "Webhook \u4E0D\u5B58\u5728" } } } } }, components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "header", name: "Authorization" } } } }; // cypher-executor/src/routes/docs.ts var docsRouter = new Hono2(); docsRouter.get("/openapi.json", (c) => { return c.json(OPENAPI_SPEC); }); docsRouter.get("/docs", (c) => { const specStr = JSON.stringify(OPENAPI_SPEC); const htmlStr = ` Cypher Executor API Docs